81fed8d488d22e18144067d830735f885171a924
[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.1504";
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                 }
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