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