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