added role self_check and self_check_any to User store
[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.1505";
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 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     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.1503.
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                     check_roles   => 'check_roles',
118                     check_roles_any => 'check_roles_any',
119                 }
120             }
121         }
122     });
123
124     # Log a user in:
125
126     sub login : Global {
127         my ( $self, $ctx ) = @_;
128
129         $ctx->authenticate({
130                           screen_name => $ctx->req->params->{username},
131                           password => $ctx->req->params->{password},
132                           status => [ 'registered', 'loggedin', 'active']
133                           }))
134     }
135
136     # verify a role
137
138     if ( $ctx->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. You can also use
153 L<Catalyst::Authentication::Realm::SimpleDB> for a simplified setup.
154
155 The DBIx::Class storage module has several configuration options
156
157
158     __PACKAGE__->config('Plugin::Authentication' => {
159         default_realm => 'members',
160         realms => {
161             members => {
162                 credential => {
163                     # ...
164                 },
165                 store => {
166                     class => 'DBIx::Class',
167                     user_model => 'MyApp::User',
168                     role_relation => 'roles',
169                     role_field => 'rolename',
170                     ignore_fields_in_find => [ 'remote_name' ],
171                     use_userdata_from_session => 1,
172                     check_roles   => 'check_roles',
173                     check_roles_any => 'check_roles_any',
174                 }
175             }
176         }
177     });
178
179 =over 4
180
181 =item class
182
183 Class is part of the core Catalyst::Plugin::Authentication module; it
184 contains the class name of the store to be used.
185
186 =item user_model
187
188 Contains the model name (as passed to C<< $ctx->model() >>) of the DBIx::Class schema
189 to use as the source for user information. This config item is B<REQUIRED>.
190
191 (Note that this option used to be called C<< user_class >>. C<< user_class >> is
192 still functional, but should be used only for compatibility with previous configs.
193 The setting called C<< user_class >> on other authentication stores is
194 present, but named C<< store_user_class >> in this store)
195
196 =item role_column
197
198 If your role information is stored in the same table as the rest of your user
199 information, this item tells the module which field contains your role
200 information.  The DBIx::Class authentication store expects the data in this
201 field to be a series of role names separated by some combination of spaces,
202 commas, or pipe characters.
203
204 =item role_relation
205
206 If your role information is stored in a separate table, this is the name of
207 the relation that will lead to the roles the user is in.  If this is
208 specified, then a role_field is also required.  Also when using this method
209 it is expected that your role table will return one row for each role
210 the user is in.
211
212 =item role_field
213
214 This is the name of the field in the role table that contains the string
215 identifying the role.
216
217 =item ignore_fields_in_find
218
219 This item is an array containing fields that may be passed to the
220 C<< $ctx->authenticate() >> routine (and therefore find_user in the storage class), but
221 which should be ignored when creating the DBIx::Class search to retrieve a
222 user. This makes it possible to avoid problems when a credential requires an
223 authinfo element whose name overlaps with a column name in your users table.
224 If this doesn't make sense to you, you probably don't need it.
225
226 =item use_userdata_from_session
227
228 Under normal circumstances, on each request the user's data is re-retrieved
229 from the database using the primary key for the user table.  When this flag
230 is set in the configuration, it causes the DBIx::Class store to avoid this
231 database hit on session restore.  Instead, the user object's column data
232 is retrieved from the session and used as-is.
233
234 B<NOTE>: Since the user object's column
235 data is only stored in the session during the initial authentication of
236 the user, turning this on can potentially lead to a situation where the data
237 in C<< $ctx->user >> is different from what is stored the database.  You can force
238 a reload of the data from the database at any time by calling C<< $ctx->user->get_object(1); >>
239 Note that this will update C<< $ctx->user >> for the remainder of this request.
240 It will NOT update the session.  If you need to update the session
241 you should call C<< $ctx->update_user_in_session() >> as well.
242
243 =item store_user_class
244
245 This allows you to override the authentication user class that the
246 DBIx::Class store module uses to perform its work.  Most of the
247 work done in this module is actually done by the user class,
248 L<Catalyst::Authentication::Store::DBIx::Class::User>, so
249 overriding this doesn't make much sense unless you are using your
250 own class to extend the functionality of the existing class.
251 Chances are you do not want to set this.
252
253 =item id_field
254
255 In most cases, this config variable does not need to be set, as
256 Catalyst::Authentication::Store::DBIx::Class will determine the primary
257 key of the user table on its own.  If you need to override the default,
258 or your user table has multiple primary keys, then id_field
259 should contain the column name that should be used to restore the user.
260 A given value in this column should correspond to a single user in the database.
261 Note that this is used B<ONLY> when restoring a user from the session and
262 has no bearing whatsoever in the initial authentication process.  Note also
263 that if use_userdata_from_session is enabled, this config parameter
264 is not used at all.
265
266 =item check_roles
267
268 If this option of set, checking the user has all the roles will be delegated to the
269 specified method on the user row. This allows for you to override the role
270 check, if you want to check virtual roles, or make super roles etc.
271
272 You should set the value to the name of the method on the user row to call
273
274     __PACKAGE__->config('Plugin::Authentication' => {
275         realms => {
276             members => {
277                 store => {
278                     check_roles   => 'custom_check_roles',
279                     check_roles_any => 'custom_check_roles_any',
280                 }
281             }
282         }
283     });
284
285
286 \@roles, and \@wanted_roles will be passed, where \@roles is the list of user roles
287 and \@wanted_roles is the list of wanted roles.
288
289 Should return true if user has the role.
290
291 You will have to check the whole set yourself, eg this is the default behaviour
292 when not setting 'check_roles'
293
294     use Set::Object;
295
296     sub custom_check_roles {
297         my ( $self, $roles, $wanted_roles ) = @_;
298
299         my $have = Set::Object->new(@$roles);
300         my $need = Set::Object->new(@$wanted_roles);
301
302         if ( $have->superset($need) ) {
303             return 1;
304         }
305     }
306
307 =item check_roles_any
308
309 Same as check_roles, except it's for checking that the user has at least one of
310 the roles
311
312 This is the default when check_roles_any is not set
313
314     use Set::Object;
315
316     sub custom_check_roles_any {
317         my ( $self, $roles, $wanted_roles ) = @_;
318
319         my $have = Set::Object->new(@$roles);
320         my $need = Set::Object->new(@$wanted_roles);
321
322         if ( $have->intersection($need)->size > 0 ) {
323             return 1;
324         }
325     }
326
327 =back
328
329 =head1 USAGE
330
331 The L<Catalyst::Authentication::Store::DBIx::Class> storage module
332 is not called directly from application code.  You interface with it
333 through the $ctx->authenticate() call.
334
335 There are three methods you can use to retrieve information from the DBIx::Class
336 storage module.  They are Simple retrieval, and the advanced retrieval methods
337 Searchargs and Resultset.
338
339 =head2 Simple Retrieval
340
341 The first, and most common, method is simple retrieval. As its name implies
342 simple retrieval allows you to simply to provide the column => value pairs
343 that should be used to locate the user in question. An example of this usage
344 is below:
345
346     if ($ctx->authenticate({
347                           screen_name => $ctx->req->params->{'username'},
348                           password => $ctx->req->params->{'password'},
349                           status => [ 'registered', 'active', 'loggedin']
350                          })) {
351
352         # ... authenticated user code here
353     }
354
355 The above example would attempt to retrieve a user whose username column (here,
356 screen_name) matched the username provided, and whose status column matched one of the
357 values provided. These name => value pairs are used more or less directly in
358 the DBIx::Class search() routine, so in most cases, you can use DBIx::Class
359 syntax to retrieve the user according to whatever rules you have.
360
361 NOTE: Because the password in most cases is encrypted - it is not used
362 directly but its encryption and comparison with the value provided is usually
363 handled by the Password Credential. Part of the Password Credential's behavior
364 is to remove the password argument from the authinfo that is passed to the
365 storage module. See L<Catalyst::Authentication::Credential::Password>.
366
367 One thing you need to know about this retrieval method is that the name
368 portion of the pair is checked against the user class's column list. Pairs are
369 only used if a matching column is found. Other pairs will be ignored. This
370 means that you can only provide simple name-value pairs, and that some more
371 advanced DBIx::Class constructs, such as '-or', '-and', etc. are in most cases
372 not possible using this method. For queries that require this level of
373 functionality, see the 'searchargs' method below.
374
375 =head2 Advanced Retrieval
376
377 The Searchargs and Resultset retrieval methods are used when more advanced
378 features of the underlying L<DBIx::Class> schema are required. These methods
379 provide a direct interface with the DBIx::Class schema and therefore
380 require a better understanding of the DBIx::Class module.
381
382 =head3 The dbix_class key
383
384 Since the format of these arguments are often complex, they are not keys in
385 the base authinfo hash.  Instead, both of these arguments are placed within
386 a hash attached to the store-specific 'dbix_class' key in the base $authinfo
387 hash.  When the DBIx::Class authentication store sees the 'dbix_class' key
388 in the passed authinfo hash, all the other information in the authinfo hash
389 is ignored and only the values within the 'dbix_class' hash are used as
390 though they were passed directly within the authinfo hash.  In other words, if
391 'dbix_class' is present, it replaces the authinfo hash for processing purposes.
392
393 The 'dbix_class' hash can be used to directly pass arguments to the
394 DBIx::Class authentication store. Reasons to do this are to avoid credential
395 modification of the authinfo hash, or to avoid overlap between credential and
396 store key names. It's a good idea to avoid using it in this way unless you are
397 sure you have an overlap/modification issue. However, the two advanced
398 retrieval methods, B<searchargs>, B<result> and B<resultset>, require its use,
399 as they are only processed as part of the 'dbix_class' hash.
400
401 =over 4
402
403 =item Searchargs
404
405 The B<searchargs> method of retrieval allows you to specify an arrayref containing
406 the two arguments to the search() method from L<DBIx::Class::ResultSet>.  If provided,
407 all other args are ignored, and the search args provided are used directly to locate
408 the user.  An example will probably make more sense:
409
410     if ($ctx->authenticate(
411         {
412             password => $password,
413             'dbix_class' =>
414                 {
415                     searchargs => [ { -or => [ username => $username,
416                                               email => $email,
417                                               clientid => $clientid ]
418                                    },
419                                    { prefetch => qw/ preferences / }
420                                  ]
421                 }
422         } ) )
423     {
424         # do successful authentication actions here.
425     }
426
427 The above would allow authentication based on any of the three items -
428 username, email, or clientid - and would prefetch the data related to that user
429 from the preferences table. The searchargs array is passed directly to the
430 search() method associated with the user_model.
431
432 =item Result
433
434 The B<result> method of retrieval allows you to look up the user yourself and
435 pass on the loaded user to the authentication store.
436
437     my $user = $ctx->model('MyApp::User')->find({ ... });
438
439     if ($ctx->authenticate({ dbix_class => { result => $user } })) {
440         ...
441     }
442
443 Be aware that the result method will not verify that you are passing a result
444 that is attached to the same user_model as specified in the config or even
445 loaded from the database, as opposed to existing only in memory. It's your
446 responsibility to make sure of that.
447
448 =item Resultset
449
450 The B<resultset> method of retrieval allows you to directly specify a
451 resultset to be used for user retrieval. This allows you to create a resultset
452 within your login action and use it for retrieving the user. A simple example:
453
454     my $rs = $ctx->model('MyApp::User')->search({ email => $ctx->request->params->{'email'} });
455        ... # further $rs adjustments
456
457     if ($ctx->authenticate({
458                            password => $password,
459                            'dbix_class' => { resultset => $rs }
460                          })) {
461        # do successful authentication actions here.
462     }
463
464 Be aware that the resultset method will not verify that you are passing a
465 resultset that is attached to the same user_model as specified in the config.
466
467 NOTE: The resultset and searchargs methods of user retrieval, consider the first
468 row returned to be the matching user. In most cases there will be only one
469 matching row, but it is easy to produce multiple rows, especially when using the
470 advanced retrieval methods. Remember, what you get when you use this module is
471 what you would get when calling search(...)->first;
472
473 NOTE ALSO:  The user info used to save the user to the session and to retrieve
474 it is the same regardless of what method of retrieval was used.  In short,
475 the value in the id field (see 'id_field' config item) is used to retrieve the
476 user from the database upon restoring from the session.  When the DBIx::Class storage
477 module does this, it does so by doing a simple search using the id field.  In other
478 words, it will not use the same arguments you used to request the user initially.
479 This is especially important to those using the advanced methods of user retrieval.
480 If you need more complicated logic when reviving the user from the session, you will
481 most likely want to subclass the L<Catalyst::Authentication::Store::DBIx::Class::User> class
482 and provide your own for_session and from_session routines.
483
484 =back
485
486
487 =head1 METHODS
488
489 There are no publicly exported routines in the DBIx::Class authentication
490 store (or indeed in most authentication stores). However, below is a
491 description of the routines required by L<Catalyst::Plugin::Authentication>
492 for all authentication stores.  Please see the documentation for
493 L<Catalyst::Plugin::Authentication::Internals> for more information.
494
495
496 =head2 new ( $config, $app )
497
498 Constructs a new store object.
499
500 =head2 find_user ( $authinfo, $c )
501
502 Finds a user using the information provided in the $authinfo hashref and
503 returns the user, or undef on failure. This is usually called from the
504 Credential. This translates directly to a call to
505 L<Catalyst::Authentication::Store::DBIx::Class::User>'s load() method.
506
507 =head2 for_session ( $c, $user )
508
509 Prepares a user to be stored in the session. Currently returns the value of
510 the user's id field (as indicated by the 'id_field' config element)
511
512 =head2 from_session ( $c, $frozenuser)
513
514 Revives a user from the session based on the info provided in $frozenuser.
515 Currently treats $frozenuser as an id and retrieves a user with a matching id.
516
517 =head2 user_supports
518
519 Provides information about what the user object supports.
520
521 =head2 auto_update_user( $authinfo, $c, $res )
522
523 This method is called if the realm's auto_update_user setting is true. It
524 will delegate to the user object's C<auto_update> method.
525
526 =head2 auto_create_user( $authinfo, $c )
527
528 This method is called if the realm's auto_create_user setting is true. It
529 will delegate to the user class's (resultset) C<auto_create> method.
530
531 =head1 NOTES
532
533 As of the current release, session storage consists of simply storing the user's
534 id in the session, and then using that same id to re-retrieve the user's information
535 from the database upon restoration from the session.  More dynamic storage of
536 user information in the session is intended for a future release.
537
538 =head1 BUGS AND LIMITATIONS
539
540 None known currently; please email the author if you find any.
541
542 =head1 SEE ALSO
543
544 L<Catalyst::Plugin::Authentication>, L<Catalyst::Plugin::Authentication::Internals>,
545 and L<Catalyst::Plugin::Authorization::Roles>
546
547 =head1 AUTHOR
548
549 Jason Kuri (jayk@cpan.org)
550
551 =head1 LICENSE
552
553 Copyright (c) 2007 the aforementioned authors. All rights
554 reserved. This program is free software; you can redistribute
555 it and/or modify it under the same terms as Perl itself.
556
557 =cut