File Coverage

blib/lib/Catalyst/Authentication/Store/DBIx/Class.pm
Criterion Covered Total %
statement 10 32 31.2
branch 0 2 0.0
condition 0 2 0.0
subroutine 4 11 36.3
pod 7 7 100.0
total 21 54 38.8


line stmt bran cond sub pod time code
1             package Catalyst::Authentication::Store::DBIx::Class;
2              
3 1     1   21022 use strict;
  1         2  
  1         24  
4 1     1   5 use warnings;
  1         2  
  1         34  
5 1     1   5 use base qw/Class::Accessor::Fast/;
  1         6  
  1         812  
6              
7             our $VERSION= "0.1506";
8              
9              
10             BEGIN {
11 1     1   1406772 __PACKAGE__->mk_accessors(qw/config/);
12             }
13              
14              
15             sub new {
16 0     0 1   my ( $class, $config, $app ) = @_;
17              
18             ## figure out if we are overriding the default store user class
19 0 0         $config->{'store_user_class'} = (exists($config->{'store_user_class'})) ? $config->{'store_user_class'} :
20             "Catalyst::Authentication::Store::DBIx::Class::User";
21              
22             ## make sure the store class is loaded.
23 0           Catalyst::Utils::ensure_class_loaded( $config->{'store_user_class'} );
24              
25             ## fields can be specified to be ignored during user location. This allows
26             ## the store to ignore certain fields in the authinfo hash.
27              
28 0   0       $config->{'ignore_fields_in_find'} ||= [ ];
29              
30 0           my $self = {
31             config => $config
32             };
33              
34 0           bless $self, $class;
35              
36             }
37              
38             ## --jk note to self:
39             ## let's use DBIC's get_columns method to return a hash and save / restore that
40             ## from the session. Then we can respond to get() calls, etc. in most cases without
41             ## resorting to a DB call. If user_object is called, THEN we can hit the DB and
42             ## return a real object.
43             sub from_session {
44 0     0 1   my ( $self, $c, $frozenuser ) = @_;
45              
46             # return $frozenuser if ref $frozenuser;
47              
48 0           my $user = $self->config->{'store_user_class'}->new($self->{'config'}, $c);
49 0           return $user->from_session($frozenuser, $c);
50             }
51              
52             sub for_session {
53 0     0 1   my ($self, $c, $user) = @_;
54              
55 0           return $user->for_session($c);
56             }
57              
58             sub find_user {
59 0     0 1   my ( $self, $authinfo, $c ) = @_;
60              
61 0           my $user = $self->config->{'store_user_class'}->new($self->{'config'}, $c);
62              
63 0           return $user->load($authinfo, $c);
64              
65             }
66              
67             sub user_supports {
68 0     0 1   my $self = shift;
69             # this can work as a class method on the user class
70 0           $self->config->{'store_user_class'}->supports( @_ );
71             }
72              
73             sub auto_create_user {
74 0     0 1   my( $self, $authinfo, $c ) = @_;
75 0           my $res = $self->config->{'store_user_class'}->new($self->{'config'}, $c);
76 0           return $res->auto_create( $authinfo, $c );
77             }
78              
79             sub auto_update_user {
80 0     0 1   my( $self, $authinfo, $c, $res ) = @_;
81 0           $res->auto_update( $authinfo, $c );
82 0           return $res;
83             }
84              
85             __PACKAGE__;
86              
87             __END__
88              
89             =head1 NAME
90              
91             Catalyst::Authentication::Store::DBIx::Class - A storage class for Catalyst Authentication using DBIx::Class
92              
93             =head1 VERSION
94              
95             This documentation refers to version 0.1506.
96              
97             =head1 SYNOPSIS
98              
99             use Catalyst qw/
100             Authentication
101             Authorization::Roles/;
102              
103             __PACKAGE__->config('Plugin::Authentication' => {
104             default_realm => 'members',
105             realms => {
106             members => {
107             credential => {
108             class => 'Password',
109             password_field => 'password',
110             password_type => 'clear'
111             },
112             store => {
113             class => 'DBIx::Class',
114             user_model => 'MyApp::User',
115             role_relation => 'roles',
116             role_field => 'rolename',
117             }
118             }
119             }
120             });
121              
122             # Log a user in:
123              
124             sub login : Global {
125             my ( $self, $ctx ) = @_;
126              
127             $ctx->authenticate({
128             screen_name => $ctx->req->params->{username},
129             password => $ctx->req->params->{password},
130             status => [ 'registered', 'loggedin', 'active']
131             }))
132             }
133              
134             # verify a role
135              
136             if ( $ctx->check_user_roles( 'editor' ) ) {
137             # do editor stuff
138             }
139              
140             =head1 DESCRIPTION
141              
142             The Catalyst::Authentication::Store::DBIx::Class class provides
143             access to authentication information stored in a database via DBIx::Class.
144              
145             =head1 CONFIGURATION
146              
147             The DBIx::Class authentication store is activated by setting the store
148             config's B<class> element to DBIx::Class as shown above. See the
149             L<Catalyst::Plugin::Authentication> documentation for more details on
150             configuring the store. You can also use
151             L<Catalyst::Authentication::Realm::SimpleDB> for a simplified setup.
152              
153             The DBIx::Class storage module has several configuration options
154              
155              
156             __PACKAGE__->config('Plugin::Authentication' => {
157             default_realm => 'members',
158             realms => {
159             members => {
160             credential => {
161             # ...
162             },
163             store => {
164             class => 'DBIx::Class',
165             user_model => 'MyApp::User',
166             role_relation => 'roles',
167             role_field => 'rolename',
168             ignore_fields_in_find => [ 'remote_name' ],
169             use_userdata_from_session => 1,
170             }
171             }
172             }
173             });
174              
175             =over 4
176              
177             =item class
178              
179             Class is part of the core Catalyst::Plugin::Authentication module; it
180             contains the class name of the store to be used.
181              
182             =item user_model
183              
184             Contains the model name (as passed to C<< $ctx->model() >>) of the DBIx::Class schema
185             to use as the source for user information. This config item is B<REQUIRED>.
186              
187             (Note that this option used to be called C<< user_class >>. C<< user_class >> is
188             still functional, but should be used only for compatibility with previous configs.
189             The setting called C<< user_class >> on other authentication stores is
190             present, but named C<< store_user_class >> in this store)
191              
192             =item role_column
193              
194             If your role information is stored in the same table as the rest of your user
195             information, this item tells the module which field contains your role
196             information. The DBIx::Class authentication store expects the data in this
197             field to be a series of role names separated by some combination of spaces,
198             commas, or pipe characters.
199              
200             =item role_relation
201              
202             If your role information is stored in a separate table, this is the name of
203             the relation that will lead to the roles the user is in. If this is
204             specified, then a role_field is also required. Also when using this method
205             it is expected that your role table will return one row for each role
206             the user is in.
207              
208             =item role_field
209              
210             This is the name of the field in the role table that contains the string
211             identifying the role.
212              
213             =item ignore_fields_in_find
214              
215             This item is an array containing fields that may be passed to the
216             C<< $ctx->authenticate() >> routine (and therefore find_user in the storage class), but
217             which should be ignored when creating the DBIx::Class search to retrieve a
218             user. This makes it possible to avoid problems when a credential requires an
219             authinfo element whose name overlaps with a column name in your users table.
220             If this doesn't make sense to you, you probably don't need it.
221              
222             =item use_userdata_from_session
223              
224             Under normal circumstances, on each request the user's data is re-retrieved
225             from the database using the primary key for the user table. When this flag
226             is set in the configuration, it causes the DBIx::Class store to avoid this
227             database hit on session restore. Instead, the user object's column data
228             is retrieved from the session and used as-is.
229              
230             B<NOTE>: Since the user object's column
231             data is only stored in the session during the initial authentication of
232             the user, turning this on can potentially lead to a situation where the data
233             in C<< $ctx->user >> is different from what is stored the database. You can force
234             a reload of the data from the database at any time by calling C<< $ctx->user->get_object(1); >>
235             Note that this will update C<< $ctx->user >> for the remainder of this request.
236             It will NOT update the session. If you need to update the session
237             you should call C<< $ctx->update_user_in_session() >> as well.
238              
239             =item store_user_class
240              
241             This allows you to override the authentication user class that the
242             DBIx::Class store module uses to perform its work. Most of the
243             work done in this module is actually done by the user class,
244             L<Catalyst::Authentication::Store::DBIx::Class::User>, so
245             overriding this doesn't make much sense unless you are using your
246             own class to extend the functionality of the existing class.
247             Chances are you do not want to set this.
248              
249             =item id_field
250              
251             In most cases, this config variable does not need to be set, as
252             Catalyst::Authentication::Store::DBIx::Class will determine the primary
253             key of the user table on its own. If you need to override the default,
254             or your user table has multiple primary keys, then id_field
255             should contain the column name that should be used to restore the user.
256             A given value in this column should correspond to a single user in the database.
257             Note that this is used B<ONLY> when restoring a user from the session and
258             has no bearing whatsoever in the initial authentication process. Note also
259             that if use_userdata_from_session is enabled, this config parameter
260             is not used at all.
261              
262             =back
263              
264             =head1 USAGE
265              
266             The L<Catalyst::Authentication::Store::DBIx::Class> storage module
267             is not called directly from application code. You interface with it
268             through the $ctx->authenticate() call.
269              
270             There are three methods you can use to retrieve information from the DBIx::Class
271             storage module. They are Simple retrieval, and the advanced retrieval methods
272             Searchargs and Resultset.
273              
274             =head2 Simple Retrieval
275              
276             The first, and most common, method is simple retrieval. As its name implies
277             simple retrieval allows you to simply to provide the column => value pairs
278             that should be used to locate the user in question. An example of this usage
279             is below:
280              
281             if ($ctx->authenticate({
282             screen_name => $ctx->req->params->{'username'},
283             password => $ctx->req->params->{'password'},
284             status => [ 'registered', 'active', 'loggedin']
285             })) {
286              
287             # ... authenticated user code here
288             }
289              
290             The above example would attempt to retrieve a user whose username column (here,
291             screen_name) matched the username provided, and whose status column matched one of the
292             values provided. These name => value pairs are used more or less directly in
293             the DBIx::Class search() routine, so in most cases, you can use DBIx::Class
294             syntax to retrieve the user according to whatever rules you have.
295              
296             NOTE: Because the password in most cases is encrypted - it is not used
297             directly but its encryption and comparison with the value provided is usually
298             handled by the Password Credential. Part of the Password Credential's behavior
299             is to remove the password argument from the authinfo that is passed to the
300             storage module. See L<Catalyst::Authentication::Credential::Password>.
301              
302             One thing you need to know about this retrieval method is that the name
303             portion of the pair is checked against the user class's column list. Pairs are
304             only used if a matching column is found. Other pairs will be ignored. This
305             means that you can only provide simple name-value pairs, and that some more
306             advanced DBIx::Class constructs, such as '-or', '-and', etc. are in most cases
307             not possible using this method. For queries that require this level of
308             functionality, see the 'searchargs' method below.
309              
310             =head2 Advanced Retrieval
311              
312             The Searchargs and Resultset retrieval methods are used when more advanced
313             features of the underlying L<DBIx::Class> schema are required. These methods
314             provide a direct interface with the DBIx::Class schema and therefore
315             require a better understanding of the DBIx::Class module.
316              
317             =head3 The dbix_class key
318              
319             Since the format of these arguments are often complex, they are not keys in
320             the base authinfo hash. Instead, both of these arguments are placed within
321             a hash attached to the store-specific 'dbix_class' key in the base $authinfo
322             hash. When the DBIx::Class authentication store sees the 'dbix_class' key
323             in the passed authinfo hash, all the other information in the authinfo hash
324             is ignored and only the values within the 'dbix_class' hash are used as
325             though they were passed directly within the authinfo hash. In other words, if
326             'dbix_class' is present, it replaces the authinfo hash for processing purposes.
327              
328             The 'dbix_class' hash can be used to directly pass arguments to the
329             DBIx::Class authentication store. Reasons to do this are to avoid credential
330             modification of the authinfo hash, or to avoid overlap between credential and
331             store key names. It's a good idea to avoid using it in this way unless you are
332             sure you have an overlap/modification issue. However, the two advanced
333             retrieval methods, B<searchargs>, B<result> and B<resultset>, require its use,
334             as they are only processed as part of the 'dbix_class' hash.
335              
336             =over 4
337              
338             =item Searchargs
339              
340             The B<searchargs> method of retrieval allows you to specify an arrayref containing
341             the two arguments to the search() method from L<DBIx::Class::ResultSet>. If provided,
342             all other args are ignored, and the search args provided are used directly to locate
343             the user. An example will probably make more sense:
344              
345             if ($ctx->authenticate(
346             {
347             password => $password,
348             'dbix_class' =>
349             {
350             searchargs => [ { -or => [ username => $username,
351             email => $email,
352             clientid => $clientid ]
353             },
354             { prefetch => qw/ preferences / }
355             ]
356             }
357             } ) )
358             {
359             # do successful authentication actions here.
360             }
361              
362             The above would allow authentication based on any of the three items -
363             username, email, or clientid - and would prefetch the data related to that user
364             from the preferences table. The searchargs array is passed directly to the
365             search() method associated with the user_model.
366              
367             =item Result
368              
369             The B<result> method of retrieval allows you to look up the user yourself and
370             pass on the loaded user to the authentication store.
371              
372             my $user = $ctx->model('MyApp::User')->find({ ... });
373              
374             if ($ctx->authenticate({ dbix_class => { result => $user } })) {
375             ...
376             }
377              
378             Be aware that the result method will not verify that you are passing a result
379             that is attached to the same user_model as specified in the config or even
380             loaded from the database, as opposed to existing only in memory. It's your
381             responsibility to make sure of that.
382              
383             =item Resultset
384              
385             The B<resultset> method of retrieval allows you to directly specify a
386             resultset to be used for user retrieval. This allows you to create a resultset
387             within your login action and use it for retrieving the user. A simple example:
388              
389             my $rs = $ctx->model('MyApp::User')->search({ email => $ctx->request->params->{'email'} });
390             ... # further $rs adjustments
391              
392             if ($ctx->authenticate({
393             password => $password,
394             'dbix_class' => { resultset => $rs }
395             })) {
396             # do successful authentication actions here.
397             }
398              
399             Be aware that the resultset method will not verify that you are passing a
400             resultset that is attached to the same user_model as specified in the config.
401              
402             NOTE: The resultset and searchargs methods of user retrieval, consider the first
403             row returned to be the matching user. In most cases there will be only one
404             matching row, but it is easy to produce multiple rows, especially when using the
405             advanced retrieval methods. Remember, what you get when you use this module is
406             what you would get when calling search(...)->first;
407              
408             NOTE ALSO: The user info used to save the user to the session and to retrieve
409             it is the same regardless of what method of retrieval was used. In short,
410             the value in the id field (see 'id_field' config item) is used to retrieve the
411             user from the database upon restoring from the session. When the DBIx::Class storage
412             module does this, it does so by doing a simple search using the id field. In other
413             words, it will not use the same arguments you used to request the user initially.
414             This is especially important to those using the advanced methods of user retrieval.
415             If you need more complicated logic when reviving the user from the session, you will
416             most likely want to subclass the L<Catalyst::Authentication::Store::DBIx::Class::User> class
417             and provide your own for_session and from_session routines.
418              
419             =back
420              
421              
422             =head1 METHODS
423              
424             There are no publicly exported routines in the DBIx::Class authentication
425             store (or indeed in most authentication stores). However, below is a
426             description of the routines required by L<Catalyst::Plugin::Authentication>
427             for all authentication stores. Please see the documentation for
428             L<Catalyst::Plugin::Authentication::Internals> for more information.
429              
430              
431             =head2 new ( $config, $app )
432              
433             Constructs a new store object.
434              
435             =head2 find_user ( $authinfo, $c )
436              
437             Finds a user using the information provided in the $authinfo hashref and
438             returns the user, or undef on failure. This is usually called from the
439             Credential. This translates directly to a call to
440             L<Catalyst::Authentication::Store::DBIx::Class::User>'s load() method.
441              
442             =head2 for_session ( $c, $user )
443              
444             Prepares a user to be stored in the session. Currently returns the value of
445             the user's id field (as indicated by the 'id_field' config element)
446              
447             =head2 from_session ( $c, $frozenuser)
448              
449             Revives a user from the session based on the info provided in $frozenuser.
450             Currently treats $frozenuser as an id and retrieves a user with a matching id.
451              
452             =head2 user_supports
453              
454             Provides information about what the user object supports.
455              
456             =head2 auto_update_user( $authinfo, $c, $res )
457              
458             This method is called if the realm's auto_update_user setting is true. It
459             will delegate to the user object's C<auto_update> method.
460              
461             =head2 auto_create_user( $authinfo, $c )
462              
463             This method is called if the realm's auto_create_user setting is true. It
464             will delegate to the user class's (resultset) C<auto_create> method.
465              
466             =head1 NOTES
467              
468             As of the current release, session storage consists of simply storing the user's
469             id in the session, and then using that same id to re-retrieve the user's information
470             from the database upon restoration from the session. More dynamic storage of
471             user information in the session is intended for a future release.
472              
473             =head1 BUGS AND LIMITATIONS
474              
475             None known currently; please email the author if you find any.
476              
477             =head1 SEE ALSO
478              
479             L<Catalyst::Plugin::Authentication>, L<Catalyst::Plugin::Authentication::Internals>,
480             and L<Catalyst::Plugin::Authorization::Roles>
481              
482             =head1 AUTHOR
483              
484             Jason Kuri (jayk@cpan.org)
485              
486             =head1 LICENSE
487              
488             Copyright (c) 2007 the aforementioned authors. All rights
489             reserved. This program is free software; you can redistribute
490             it and/or modify it under the same terms as Perl itself.
491              
492             =cut