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