completing namespace change
[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.10";
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     
50     return $user->from_session($frozenuser, $c);
51 }
52
53 sub for_session {
54     my ($self, $c, $user) = @_;
55     
56     return $user->for_session($c);
57 }
58
59 sub find_user {
60     my ( $self, $authinfo, $c ) = @_;
61     
62     my $user = $self->config->{'store_user_class'}->new($self->{'config'}, $c);
63
64     return $user->load($authinfo, $c);
65
66 }
67
68 sub user_supports {
69     my $self = shift;
70     # this can work as a class method on the user class
71     $self->config->{'store_user_class'}->supports( @_ );
72 }
73
74 sub auto_create_user {
75     my( $self, $authinfo, $c ) = @_;
76     my $res = $self->config->{'store_user_class'}->new($self->{'config'}, $c);
77     return $res->auto_create( $authinfo, $c );
78 }
79
80 sub auto_update_user {
81     my( $self, $authinfo, $c, $res ) = @_;
82     $res->auto_update( $authinfo, $c );
83     return $res;
84 }
85
86 __PACKAGE__;
87
88 __END__
89
90 =head1 NAME
91
92 Catalyst::Authentication::Store::DBIx::Class - A storage class for Catalyst Authentication using DBIx::Class
93
94 =head1 VERSION
95
96 This documentation refers to version 0.10.
97
98 =head1 SYNOPSIS
99
100     use Catalyst qw/
101                     Authentication
102                     Authorization::Roles/;
103
104     __PACKAGE__->config->{authentication} = 
105                     {  
106                         default_realm => 'members',
107                         realms => {
108                             members => {
109                                 credential => {
110                                     class => 'Password',
111                                     password_field => 'password',
112                                     password_type => 'clear'
113                                 },
114                                 store => {
115                                     class => 'DBIx::Class',
116                                     user_class => 'MyApp::Users',
117                                     id_field => 'user_id',
118                                     role_relation => 'roles',
119                                     role_field => 'rolename',                   
120                                 }
121                             }
122                         }
123                     };
124
125     # Log a user in:
126     
127     sub login : Global {
128         my ( $self, $c ) = @_;
129         
130         $c->authenticate({  
131                           username => $c->req->params->username,
132                           password => $c->req->params->password,
133                           status => [ 'registered', 'loggedin', 'active']
134                           }))
135     }
136     
137     # verify a role 
138     
139     if ( $c->check_user_roles( 'editor' ) ) {
140         # do editor stuff
141     }
142     
143 =head1 DESCRIPTION
144
145 The Catalyst::Authentication::Store::DBIx::Class class provides 
146 access to authentication information stored in a database via DBIx::Class.
147
148 =head1 CONFIGURATION
149
150 The DBIx::Class authentication store is activated by setting the store
151 config's B<class> element to DBIx::Class as shown above.  See the 
152 L<Catalyst::Plugin::Authentication> documentation for more details on 
153 configuring the store.
154
155 The DBIx::Class storage module has several configuration options
156
157
158     __PACKAGE__->config->{authentication} = 
159                     {  
160                         default_realm => 'members',
161                         realms => {
162                             members => {
163                                 credential => {
164                                     # ...
165                                 },
166                                 store => {
167                                     class => 'DBIx::Class',
168                                     user_class => 'MyApp::Users',
169                                     id_field => 'user_id',
170                                     role_relation => 'roles',
171                                     role_field => 'rolename',
172                                     ignore_fields_in_find => [ 'remote_name' ]          
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 id_field
191
192 Contains the field name containing the unique identifier for a user.  This is 
193 used when storing and retrieving a user from the session.  The value in this
194 field should correspond to a single user in the database.  Defaults to 'id'.
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->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 store_user_class
227
228 This allows you to override the authentication user class that the 
229 DBIx::Class store module uses to perform it's work.  Most of the
230 work done in this module is actually done by the user class, 
231 L<Catalyst::Authentication::Store::DBIx::Class::User>, so
232 overriding this doesn't make much sense unless you are using your
233 own class to extend the functionality of the existing class.  
234 Chances are you do not want to set this.
235
236 =back
237
238 =head1 USAGE 
239
240 The L<Catalyst::Authentication::Store::DBIx::Class> storage module
241 is not called directly from application code.  You interface with it 
242 through the $c->authenticate() call.  
243
244 There are three methods you can use to retrieve information from the DBIx::Class
245 storage module.  They are Simple retrieval, and the advanced retrieval methods
246 Searchargs and Resultset.
247
248 =head2 Simple Retrieval 
249
250 The first, and most common, method is simple retrieval. As it's name implies
251 simple retrieval allows you to simply to provide the column => value pairs
252 that should be used to locate the user in question. An example of this usage
253 is below:
254
255     if ($c->authenticate({  
256                           username => $c->req->params->{'username'},
257                           password => $c->req->params->{'password'},
258                           status => [ 'registered', 'active', 'loggedin']
259                          })) {
260
261         # ... authenticated user code here
262     }
263
264 The above example would attempt to retrieve a user whose username column
265 matched the username provided, and whose status column matched one of the
266 values provided. These name => value pairs are used more or less directly in
267 the DBIx::Class' search() routine, so in most cases, you can use DBIx::Class
268 syntax to retrieve the user according to whatever rules you have.
269
270 NOTE: Because the password in most cases is encrypted - it is not used
271 directly but it's encryption and comparison with the value provided is usually
272 handled by the Password Credential. Part of the Password Credential's behavior
273 is to remove the password argument from the authinfo that is passed to the
274 storage module. See L<Catalyst::Authentication::Credential::Password>.
275
276 One thing you need to know about this retrieval method is that the name
277 portion of the pair is checked against the user class' column list. Pairs are
278 only used if a matching column is found. Other pairs will be ignored. This
279 means that you can only provide simple name-value pairs, and that some more
280 advanced DBIx::Class constructs, such as '-or', '-and', etc. are in most cases
281 not possible using this method. For queries that require this level of
282 functionality, see the 'searchargs' method below.
283
284 =head2 Advanced Retrieval
285
286 The Searchargs and Resultset retrieval methods are used when more advanced
287 features of the underlying L<DBIx::Class> schema are required. These methods
288 provide a direct interface with the DBIx::Class schema and therefore
289 require a better understanding of the DBIx::Class module.  
290
291 =head3 The dbix_class key
292
293 Since the format of these arguments are often complex, they are not keys in
294 the base authinfo hash.  Instead, both of these arguments are placed within 
295 a hash attached to the store-specific 'dbix_class' key in the base $authinfo 
296 hash.  When the DBIx::Class authentication store sees the 'dbix_class' key
297 in the passed authinfo hash, all the other information in the authinfo hash
298 is ignored and only the values within the 'dbix_class' hash are used as 
299 though they were passed directly within the authinfo hash.  In other words, if
300 'dbix_class' is present, it replaces the authinfo hash for processing purposes.
301
302 The 'dbix_class' hash can be used to directly pass arguments to the
303 DBIx::Class authentication store. Reasons to do this are to avoid credential
304 modification of the authinfo hash, or to avoid overlap between credential and
305 store key names. It's a good idea to avoid using it in this way unless you are
306 sure you have an overlap/modification issue. However, the two advanced
307 retrieval methods, B<searchargs> and B<resultset>, require it's use, as they 
308 are only processed as part of the 'dbix_class' hash
309
310 =over 4
311
312 =item Searchargs
313
314 The B<searchargs> method of retrieval allows you to specify an arrayref containing
315 the two arguments to the search() method from L<DBIx::Class::ResultSet>.  If provided,
316 all other args are ignored, and the search args provided are used directly to locate
317 the user.  An example will probably make more sense:
318
319     if ($c->authenticate(
320         { 
321             password => $password,
322             'dbix_class' => 
323                 {
324                     searchargs = [ { -or => [ username => $username,
325                                               email => $email,
326                                               clientid => $clientid ] 
327                                    },
328                                    { prefetch => qw/ preferences / } 
329                                  ]
330                 }
331         } ) ) 
332     {
333         # do successful authentication actions here.
334     }
335
336 The above would allow authentication based on any of the three items -
337 username, email or clientid and would prefetch the data related to that user
338 from the preferences table. The searchargs array is passed directly to the
339 search() method associated with the user_class.
340
341 =item Resultset
342
343 The B<resultset> method of retrieval allows you to directly specify a
344 resultset to be used for user retrieval. This allows you to create a resultset
345 within your login action and use it for retrieving the user. A simple example:
346
347     my $rs = $c->model('MyApp::User')->search({ email => $c->request->params->{'email'} });
348        ... # further $rs adjustments
349        
350     if ($c->authenticate({ 
351                            password => $password,
352                            'dbix_class' => {  resultset = $rs }
353                          })) {
354        # do successful authentication actions here.
355     } 
356
357 Be aware that the resultset method will not verify that you are passing a
358 resultset that is attached to the same user_class as specified in the config.
359
360 NOTE: All of these methods of user retrieval, including the resultset method,
361 consider the first row returned to be the matching user. In most cases there
362 will be only one matching row, but it is easy to produce multiple rows,
363 especially when using the advanced retrieval methods. Remember, what you get
364 when you use this module is what you would get when calling
365 search(...)->first;
366
367 NOTE ALSO:  The user info used to save the user to the session and to retrieve
368 it is the same regardless of what method of retrieval was used.  In short,
369 the value in the id field (see 'id_field' config item) is used to retrieve the 
370 user from the database upon restoring from the session.  When the DBIx::Class storage
371 module does this, it does so by doing a simple search using the id field.  In other
372 words, it will not use the same arguments you used to request the user initially. 
373 This is especially important to those using the advanced methods of user retrieval. 
374 If you need more complicated logic when reviving the user from the session, you will
375 most likely want to subclass the L<Catalyst::Authentication::Store::DBIx::Class::User> class 
376 and provide your own for_session and from_session routines.
377
378 =back
379
380
381 =head1 METHODS
382
383 There are no publicly exported routines in the DBIx::Class authentication 
384 store (or indeed in most authentication stores)  However, below is a 
385 description of the routines required by L<Catalyst::Plugin::Authentication> 
386 for all authentication stores.  Please see the documentation for 
387 L<Catalyst::Plugin::Authentication::Internals> for more information.
388
389
390 =head2 new ( $config, $app )
391
392 Constructs a new store object.
393
394 =head2 find_user ( $authinfo, $c ) 
395
396 Finds a user using the information provided in the $authinfo hashref and
397 returns the user, or undef on failure; This is usually called from the
398 Credential. This translates directly to a call to
399 L<Catalyst::Authentication::Store::DBIx::Class::User>'s load() method.
400
401 =head2 for_session ( $c, $user )
402
403 Prepares a user to be stored in the session. Currently returns the value of
404 the user's id field - (as indicated by the 'id_field' config element)
405
406 =head2 from_session ( $c, $frozenuser)
407
408 Revives a user from the session based on the info provided in $frozenuser.
409 Currently treats $frozenuser as an id and retrieves a user with a matching id.
410
411 =head2 user_supports
412
413 Provides information about what the user object supports.  
414
415 =head2 auto_update_user( $authinfo, $c, $res )
416
417 This method is called if the realm's auto_update_user setting is true. It
418 will delegate to the user object's C<auto_update> method.
419
420 =head2 auto_create_user( $authinfo, $c )
421
422 This method is called if the realm's auto_create_user setting is true. It
423 will delegate to the user class' (resultset) C<auto_create> method.
424
425 =head1 NOTES
426
427 As of the current release, session storage consists of simply storing the user's
428 id in the session, and then using that same id to re-retrieve the users information
429 from the database upon restoration from the session.  More dynamic storage of
430 user information in the session is intended for a future release.
431
432 =head1 BUGS AND LIMITATIONS
433
434 None known currently, please email the author if you find any.
435
436 =head1 SEE ALSO
437
438 L<Catalyst::Plugin::Authentication>, L<Catalyst::Plugin::Authentication::Internals>,
439 and L<Catalyst::Plugin::Authorization::Roles>
440
441 =head1 AUTHOR
442
443 Jason Kuri (jayk@cpan.org)
444
445 =head1 LICENSE
446
447 Copyright (c) 2007 the aforementioned authors. All rights
448 reserved. This program is free software; you can redistribute
449 it and/or modify it under the same terms as Perl itself.
450
451 =cut