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