added role self_check and self_check_any to User store
[catagits/Catalyst-Authentication-Store-DBIx-Class.git] / lib / Catalyst / Authentication / Store / DBIx / Class.pm
CommitLineData
6727afe2 1package Catalyst::Authentication::Store::DBIx::Class;
5000f545 2
3use strict;
4use warnings;
5use base qw/Class::Accessor::Fast/;
6
06e84fc7 7our $VERSION= "0.1505";
6727afe2 8
b33ee900 9
10BEGIN {
11 __PACKAGE__->mk_accessors(qw/config/);
12}
13
6727afe2 14
5000f545 15sub new {
16 my ( $class, $config, $app ) = @_;
17
4bebb973 18 ## figure out if we are overriding the default store user class
b33ee900 19 $config->{'store_user_class'} = (exists($config->{'store_user_class'})) ? $config->{'store_user_class'} :
6727afe2 20 "Catalyst::Authentication::Store::DBIx::Class::User";
b33ee900 21
5000f545 22 ## make sure the store class is loaded.
b33ee900 23 Catalyst::Utils::ensure_class_loaded( $config->{'store_user_class'} );
4bebb973 24
b33ee900 25 ## fields can be specified to be ignored during user location. This allows
ff7203cb 26 ## the store to ignore certain fields in the authinfo hash.
4bebb973 27
b33ee900 28 $config->{'ignore_fields_in_find'} ||= [ ];
29
30 my $self = {
31 config => $config
32 };
5000f545 33
34 bless $self, $class;
b33ee900 35
5000f545 36}
37
ba48c9c3 38## --jk note to self:
fff51ece 39## let's use DBIC's get_columns method to return a hash and save / restore that
ba48c9c3 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
4bebb973 42## return a real object.
5000f545 43sub from_session {
44 my ( $self, $c, $frozenuser ) = @_;
45
f26005a7 46# return $frozenuser if ref $frozenuser;
47
b33ee900 48 my $user = $self->config->{'store_user_class'}->new($self->{'config'}, $c);
b33ee900 49 return $user->from_session($frozenuser, $c);
5000f545 50}
51
52sub for_session {
53 my ($self, $c, $user) = @_;
4bebb973 54
5000f545 55 return $user->for_session($c);
56}
57
58sub find_user {
59 my ( $self, $authinfo, $c ) = @_;
4bebb973 60
b33ee900 61 my $user = $self->config->{'store_user_class'}->new($self->{'config'}, $c);
5000f545 62
b33ee900 63 return $user->load($authinfo, $c);
64
65}
5000f545 66
67sub user_supports {
b33ee900 68 my $self = shift;
69 # this can work as a class method on the user class
70 $self->config->{'store_user_class'}->supports( @_ );
5000f545 71}
72
67f6319b 73sub auto_create_user {
fb689852 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
67f6319b 79sub auto_update_user {
fb689852 80 my( $self, $authinfo, $c, $res ) = @_;
81 $res->auto_update( $authinfo, $c );
82 return $res;
83}
84
5000f545 85__PACKAGE__;
86
87__END__
88
89=head1 NAME
90
6727afe2 91Catalyst::Authentication::Store::DBIx::Class - A storage class for Catalyst Authentication using DBIx::Class
5000f545 92
93=head1 VERSION
94
a1c47a34 95This documentation refers to version 0.1503.
5000f545 96
97=head1 SYNOPSIS
98
93102ff5 99 use Catalyst qw/
100 Authentication
101 Authorization::Roles/;
102
f23f0b31 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',
b3c995e9 117 check_roles => 'check_roles',
118 check_roles_any => 'check_roles_any',
f23f0b31 119 }
120 }
121 }
122 });
93102ff5 123
124 # Log a user in:
4bebb973 125
93102ff5 126 sub login : Global {
f23f0b31 127 my ( $self, $ctx ) = @_;
4bebb973 128
f23f0b31 129 $ctx->authenticate({
130 screen_name => $ctx->req->params->{username},
131 password => $ctx->req->params->{password},
c1d29ab7 132 status => [ 'registered', 'loggedin', 'active']
133 }))
93102ff5 134 }
4bebb973 135
136 # verify a role
137
f23f0b31 138 if ( $ctx->check_user_roles( 'editor' ) ) {
93102ff5 139 # do editor stuff
140 }
4bebb973 141
5000f545 142=head1 DESCRIPTION
143
4bebb973 144The Catalyst::Authentication::Store::DBIx::Class class provides
93102ff5 145access to authentication information stored in a database via DBIx::Class.
146
147=head1 CONFIGURATION
148
149The DBIx::Class authentication store is activated by setting the store
f55cb81e 150config's B<class> element to DBIx::Class as shown above. See the
151L<Catalyst::Plugin::Authentication> documentation for more details on
152configuring the store. You can also use
153L<Catalyst::Authentication::Realm::SimpleDB> for a simplified setup.
93102ff5 154
155The DBIx::Class storage module has several configuration options
156
93102ff5 157
f23f0b31 158 __PACKAGE__->config('Plugin::Authentication' => {
159 default_realm => 'members',
160 realms => {
161 members => {
162 credential => {
163 # ...
164 },
165 store => {
166 class => 'DBIx::Class',
167 user_model => 'MyApp::User',
168 role_relation => 'roles',
169 role_field => 'rolename',
170 ignore_fields_in_find => [ 'remote_name' ],
171 use_userdata_from_session => 1,
b3c995e9 172 check_roles => 'check_roles',
173 check_roles_any => 'check_roles_any',
f23f0b31 174 }
175 }
176 }
177 });
93102ff5 178
b81ead77 179=over 4
180
93102ff5 181=item class
182
fff51ece 183Class is part of the core Catalyst::Plugin::Authentication module; it
93102ff5 184contains the class name of the store to be used.
185
f55cb81e 186=item user_model
5000f545 187
f23f0b31 188Contains the model name (as passed to C<< $ctx->model() >>) of the DBIx::Class schema
f55cb81e 189to use as the source for user information. This config item is B<REQUIRED>.
88b34b66 190
4bebb973 191(Note that this option used to be called C<< user_class >>. C<< user_class >> is
88b34b66 192still functional, but should be used only for compatibility with previous configs.
193The setting called C<< user_class >> on other authentication stores is
194present, but named C<< store_user_class >> in this store)
5000f545 195
93102ff5 196=item role_column
5000f545 197
93102ff5 198If your role information is stored in the same table as the rest of your user
199information, this item tells the module which field contains your role
200information. The DBIx::Class authentication store expects the data in this
4bebb973 201field to be a series of role names separated by some combination of spaces,
202commas, or pipe characters.
5000f545 203
93102ff5 204=item role_relation
5000f545 205
93102ff5 206If your role information is stored in a separate table, this is the name of
4bebb973 207the relation that will lead to the roles the user is in. If this is
fff51ece 208specified, then a role_field is also required. Also when using this method
4bebb973 209it is expected that your role table will return one row for each role
93102ff5 210the user is in.
5000f545 211
93102ff5 212=item role_field
5000f545 213
4bebb973 214This is the name of the field in the role table that contains the string
215identifying the role.
5000f545 216
93102ff5 217=item ignore_fields_in_find
5000f545 218
c1d29ab7 219This item is an array containing fields that may be passed to the
f23f0b31 220C<< $ctx->authenticate() >> routine (and therefore find_user in the storage class), but
c1d29ab7 221which should be ignored when creating the DBIx::Class search to retrieve a
222user. This makes it possible to avoid problems when a credential requires an
223authinfo element whose name overlaps with a column name in your users table.
224If this doesn't make sense to you, you probably don't need it.
5000f545 225
f26005a7 226=item use_userdata_from_session
227
4bebb973 228Under normal circumstances, on each request the user's data is re-retrieved
229from the database using the primary key for the user table. When this flag
f26005a7 230is set in the configuration, it causes the DBIx::Class store to avoid this
4bebb973 231database hit on session restore. Instead, the user object's column data
232is retrieved from the session and used as-is.
f26005a7 233
234B<NOTE>: Since the user object's column
4bebb973 235data is only stored in the session during the initial authentication of
f26005a7 236the user, turning this on can potentially lead to a situation where the data
f23f0b31 237in C<< $ctx->user >> is different from what is stored the database. You can force
238a reload of the data from the database at any time by calling C<< $ctx->user->get_object(1); >>
239Note that this will update C<< $ctx->user >> for the remainder of this request.
f26005a7 240It will NOT update the session. If you need to update the session
f23f0b31 241you should call C<< $ctx->update_user_in_session() >> as well.
f26005a7 242
93102ff5 243=item store_user_class
5000f545 244
4bebb973 245This allows you to override the authentication user class that the
28aa2168 246DBIx::Class store module uses to perform its work. Most of the
4bebb973 247work done in this module is actually done by the user class,
6727afe2 248L<Catalyst::Authentication::Store::DBIx::Class::User>, so
93102ff5 249overriding this doesn't make much sense unless you are using your
4bebb973 250own class to extend the functionality of the existing class.
93102ff5 251Chances are you do not want to set this.
5000f545 252
f7e6d29f 253=item id_field
254
255In most cases, this config variable does not need to be set, as
256Catalyst::Authentication::Store::DBIx::Class will determine the primary
4bebb973 257key of the user table on its own. If you need to override the default,
f7e6d29f 258or your user table has multiple primary keys, then id_field
259should contain the column name that should be used to restore the user.
260A given value in this column should correspond to a single user in the database.
4bebb973 261Note that this is used B<ONLY> when restoring a user from the session and
f7e6d29f 262has no bearing whatsoever in the initial authentication process. Note also
263that if use_userdata_from_session is enabled, this config parameter
264is not used at all.
265
b3c995e9 266=item check_roles
267
268If this option of set, checking the user has all the roles will be delegated to the
269specified method on the user row. This allows for you to override the role
270check, if you want to check virtual roles, or make super roles etc.
271
272You should set the value to the name of the method on the user row to call
273
274 __PACKAGE__->config('Plugin::Authentication' => {
275 realms => {
276 members => {
277 store => {
278 check_roles => 'custom_check_roles',
279 check_roles_any => 'custom_check_roles_any',
280 }
281 }
282 }
283 });
284
285
286\@roles, and \@wanted_roles will be passed, where \@roles is the list of user roles
287and \@wanted_roles is the list of wanted roles.
288
289Should return true if user has the role.
290
291You will have to check the whole set yourself, eg this is the default behaviour
292when not setting 'check_roles'
293
294 use Set::Object;
295
296 sub custom_check_roles {
297 my ( $self, $roles, $wanted_roles ) = @_;
298
299 my $have = Set::Object->new(@$roles);
300 my $need = Set::Object->new(@$wanted_roles);
301
302 if ( $have->superset($need) ) {
303 return 1;
304 }
305 }
306
307=item check_roles_any
308
309Same as check_roles, except it's for checking that the user has at least one of
310the roles
311
312This is the default when check_roles_any is not set
313
314 use Set::Object;
315
316 sub custom_check_roles_any {
317 my ( $self, $roles, $wanted_roles ) = @_;
318
319 my $have = Set::Object->new(@$roles);
320 my $need = Set::Object->new(@$wanted_roles);
321
322 if ( $have->intersection($need)->size > 0 ) {
323 return 1;
324 }
325 }
326
93102ff5 327=back
5000f545 328
4bebb973 329=head1 USAGE
5000f545 330
6727afe2 331The L<Catalyst::Authentication::Store::DBIx::Class> storage module
4bebb973 332is not called directly from application code. You interface with it
f23f0b31 333through the $ctx->authenticate() call.
5000f545 334
c1d29ab7 335There are three methods you can use to retrieve information from the DBIx::Class
336storage module. They are Simple retrieval, and the advanced retrieval methods
337Searchargs and Resultset.
338
4bebb973 339=head2 Simple Retrieval
c1d29ab7 340
28aa2168 341The first, and most common, method is simple retrieval. As its name implies
c1d29ab7 342simple retrieval allows you to simply to provide the column => value pairs
343that should be used to locate the user in question. An example of this usage
344is below:
345
f23f0b31 346 if ($ctx->authenticate({
347 screen_name => $ctx->req->params->{'username'},
348 password => $ctx->req->params->{'password'},
c1d29ab7 349 status => [ 'registered', 'active', 'loggedin']
350 })) {
351
352 # ... authenticated user code here
353 }
354
4bebb973 355The above example would attempt to retrieve a user whose username column (here,
f7e6d29f 356screen_name) matched the username provided, and whose status column matched one of the
c1d29ab7 357values provided. These name => value pairs are used more or less directly in
fff51ece 358the DBIx::Class search() routine, so in most cases, you can use DBIx::Class
c1d29ab7 359syntax to retrieve the user according to whatever rules you have.
360
361NOTE: Because the password in most cases is encrypted - it is not used
28aa2168 362directly but its encryption and comparison with the value provided is usually
c1d29ab7 363handled by the Password Credential. Part of the Password Credential's behavior
364is to remove the password argument from the authinfo that is passed to the
6727afe2 365storage module. See L<Catalyst::Authentication::Credential::Password>.
c1d29ab7 366
367One thing you need to know about this retrieval method is that the name
fff51ece 368portion of the pair is checked against the user class's column list. Pairs are
c1d29ab7 369only used if a matching column is found. Other pairs will be ignored. This
370means that you can only provide simple name-value pairs, and that some more
371advanced DBIx::Class constructs, such as '-or', '-and', etc. are in most cases
372not possible using this method. For queries that require this level of
373functionality, see the 'searchargs' method below.
374
375=head2 Advanced Retrieval
376
377The Searchargs and Resultset retrieval methods are used when more advanced
378features of the underlying L<DBIx::Class> schema are required. These methods
379provide a direct interface with the DBIx::Class schema and therefore
4bebb973 380require a better understanding of the DBIx::Class module.
c1d29ab7 381
382=head3 The dbix_class key
383
384Since the format of these arguments are often complex, they are not keys in
4bebb973 385the base authinfo hash. Instead, both of these arguments are placed within
386a hash attached to the store-specific 'dbix_class' key in the base $authinfo
c1d29ab7 387hash. When the DBIx::Class authentication store sees the 'dbix_class' key
388in the passed authinfo hash, all the other information in the authinfo hash
4bebb973 389is ignored and only the values within the 'dbix_class' hash are used as
c1d29ab7 390though they were passed directly within the authinfo hash. In other words, if
391'dbix_class' is present, it replaces the authinfo hash for processing purposes.
392
393The 'dbix_class' hash can be used to directly pass arguments to the
394DBIx::Class authentication store. Reasons to do this are to avoid credential
395modification of the authinfo hash, or to avoid overlap between credential and
396store key names. It's a good idea to avoid using it in this way unless you are
397sure you have an overlap/modification issue. However, the two advanced
6bd97524 398retrieval methods, B<searchargs>, B<result> and B<resultset>, require its use,
399as they are only processed as part of the 'dbix_class' hash.
c1d29ab7 400
401=over 4
402
403=item Searchargs
404
405The B<searchargs> method of retrieval allows you to specify an arrayref containing
ad93b3e9 406the two arguments to the search() method from L<DBIx::Class::ResultSet>. If provided,
c1d29ab7 407all other args are ignored, and the search args provided are used directly to locate
408the user. An example will probably make more sense:
409
f23f0b31 410 if ($ctx->authenticate(
4bebb973 411 {
c1d29ab7 412 password => $password,
4bebb973 413 'dbix_class' =>
c1d29ab7 414 {
f26005a7 415 searchargs => [ { -or => [ username => $username,
c1d29ab7 416 email => $email,
4bebb973 417 clientid => $clientid ]
c1d29ab7 418 },
4bebb973 419 { prefetch => qw/ preferences / }
c1d29ab7 420 ]
421 }
4bebb973 422 } ) )
c1d29ab7 423 {
424 # do successful authentication actions here.
425 }
426
427The above would allow authentication based on any of the three items -
fff51ece 428username, email, or clientid - and would prefetch the data related to that user
c1d29ab7 429from the preferences table. The searchargs array is passed directly to the
f55cb81e 430search() method associated with the user_model.
c1d29ab7 431
6bd97524 432=item Result
433
434The B<result> method of retrieval allows you to look up the user yourself and
435pass on the loaded user to the authentication store.
436
437 my $user = $ctx->model('MyApp::User')->find({ ... });
438
439 if ($ctx->authenticate({ dbix_class => { result => $user } })) {
440 ...
441 }
442
443Be aware that the result method will not verify that you are passing a result
444that is attached to the same user_model as specified in the config or even
445loaded from the database, as opposed to existing only in memory. It's your
446responsibility to make sure of that.
447
c1d29ab7 448=item Resultset
449
450The B<resultset> method of retrieval allows you to directly specify a
451resultset to be used for user retrieval. This allows you to create a resultset
452within your login action and use it for retrieving the user. A simple example:
453
f23f0b31 454 my $rs = $ctx->model('MyApp::User')->search({ email => $ctx->request->params->{'email'} });
c1d29ab7 455 ... # further $rs adjustments
4bebb973 456
f23f0b31 457 if ($ctx->authenticate({
c1d29ab7 458 password => $password,
fff51ece 459 'dbix_class' => { resultset => $rs }
c1d29ab7 460 })) {
461 # do successful authentication actions here.
4bebb973 462 }
c1d29ab7 463
464Be aware that the resultset method will not verify that you are passing a
f55cb81e 465resultset that is attached to the same user_model as specified in the config.
c1d29ab7 466
6bd97524 467NOTE: The resultset and searchargs methods of user retrieval, consider the first
468row returned to be the matching user. In most cases there will be only one
469matching row, but it is easy to produce multiple rows, especially when using the
470advanced retrieval methods. Remember, what you get when you use this module is
471what you would get when calling search(...)->first;
c1d29ab7 472
473NOTE ALSO: The user info used to save the user to the session and to retrieve
474it is the same regardless of what method of retrieval was used. In short,
4bebb973 475the value in the id field (see 'id_field' config item) is used to retrieve the
c1d29ab7 476user from the database upon restoring from the session. When the DBIx::Class storage
477module does this, it does so by doing a simple search using the id field. In other
4bebb973 478words, it will not use the same arguments you used to request the user initially.
479This is especially important to those using the advanced methods of user retrieval.
c1d29ab7 480If you need more complicated logic when reviving the user from the session, you will
4bebb973 481most likely want to subclass the L<Catalyst::Authentication::Store::DBIx::Class::User> class
c1d29ab7 482and provide your own for_session and from_session routines.
483
484=back
5000f545 485
6727afe2 486
93102ff5 487=head1 METHODS
5000f545 488
4bebb973 489There are no publicly exported routines in the DBIx::Class authentication
490store (or indeed in most authentication stores). However, below is a
491description of the routines required by L<Catalyst::Plugin::Authentication>
492for all authentication stores. Please see the documentation for
93102ff5 493L<Catalyst::Plugin::Authentication::Internals> for more information.
494
6727afe2 495
496=head2 new ( $config, $app )
93102ff5 497
c1d29ab7 498Constructs a new store object.
93102ff5 499
4bebb973 500=head2 find_user ( $authinfo, $c )
93102ff5 501
c1d29ab7 502Finds a user using the information provided in the $authinfo hashref and
fff51ece 503returns the user, or undef on failure. This is usually called from the
c1d29ab7 504Credential. This translates directly to a call to
6727afe2 505L<Catalyst::Authentication::Store::DBIx::Class::User>'s load() method.
93102ff5 506
6727afe2 507=head2 for_session ( $c, $user )
93102ff5 508
c1d29ab7 509Prepares a user to be stored in the session. Currently returns the value of
fff51ece 510the user's id field (as indicated by the 'id_field' config element)
93102ff5 511
6727afe2 512=head2 from_session ( $c, $frozenuser)
93102ff5 513
c1d29ab7 514Revives a user from the session based on the info provided in $frozenuser.
93102ff5 515Currently treats $frozenuser as an id and retrieves a user with a matching id.
516
6727afe2 517=head2 user_supports
93102ff5 518
4bebb973 519Provides information about what the user object supports.
93102ff5 520
76e7a763 521=head2 auto_update_user( $authinfo, $c, $res )
522
523This method is called if the realm's auto_update_user setting is true. It
524will delegate to the user object's C<auto_update> method.
67f6319b 525
76e7a763 526=head2 auto_create_user( $authinfo, $c )
67f6319b 527
76e7a763 528This method is called if the realm's auto_create_user setting is true. It
fff51ece 529will delegate to the user class's (resultset) C<auto_create> method.
5000f545 530
531=head1 NOTES
532
93102ff5 533As of the current release, session storage consists of simply storing the user's
fff51ece 534id in the session, and then using that same id to re-retrieve the user's information
93102ff5 535from the database upon restoration from the session. More dynamic storage of
536user information in the session is intended for a future release.
5000f545 537
538=head1 BUGS AND LIMITATIONS
539
fff51ece 540None known currently; please email the author if you find any.
5000f545 541
542=head1 SEE ALSO
543
93102ff5 544L<Catalyst::Plugin::Authentication>, L<Catalyst::Plugin::Authentication::Internals>,
545and L<Catalyst::Plugin::Authorization::Roles>
5000f545 546
547=head1 AUTHOR
548
b33ee900 549Jason Kuri (jayk@cpan.org)
5000f545 550
c1d29ab7 551=head1 LICENSE
5000f545 552
c1d29ab7 553Copyright (c) 2007 the aforementioned authors. All rights
93102ff5 554reserved. This program is free software; you can redistribute
555it and/or modify it under the same terms as Perl itself.
5000f545 556
557=cut