Changes to allow for dropping of the 'realms' config hash and instead
[catagits/Catalyst-Plugin-Authentication.git] / lib / Catalyst / Authentication / Store / Minimal.pm
1 package Catalyst::Authentication::Store::Minimal;
2
3 use strict;
4 use warnings;
5
6 use Catalyst::Authentication::User::Hash;
7 use Scalar::Util qw( blessed );
8 use base qw/Class::Accessor::Fast/;
9
10 BEGIN {
11     __PACKAGE__->mk_accessors(qw/userhash/);
12 }
13
14 sub new {
15     my ( $class, $config, $app, $realm) = @_;
16
17     bless { userhash => $config->{'users'} }, $class;
18 }
19
20 sub from_session {
21         my ( $self, $c, $id ) = @_;
22
23         return $id if ref $id;
24
25         $self->find_user( { id => $id } );
26 }
27
28 ## this is not necessarily a good example of what find_user can do, since all we do is   
29 ## look up with the id anyway.  find_user can be used to locate a user based on other 
30 ## combinations of data.  See C::P::Authentication::Store::DBIx::Class for a better example
31 sub find_user {
32     my ( $self, $userinfo, $c ) = @_;
33
34     my $id = $userinfo->{'id'};
35     
36     $id ||= $userinfo->{'username'};
37     
38     return unless exists $self->userhash->{$id};
39
40     my $user = $self->userhash->{$id};
41
42     if ( ref($user) eq "HASH") {
43         $user->{id} ||= $id;
44         return bless $user, "Catalyst::Authentication::User::Hash";
45     } elsif ( ref($user) && blessed($user) && $user->isa('Catalyst::Authentication::User::Hash')) {
46         return $user;
47     } else {
48         Catalyst::Exception->throw( "The user '$id' must be a hash reference or an " .
49                 "object of class Catalyst::Authentication::User::Hash");
50     }
51     return $user;
52 }
53
54 sub user_supports {
55     my $self = shift;
56
57     # choose a random user
58     scalar keys %{ $self->userhash };
59     ( undef, my $user ) = each %{ $self->userhash };
60
61     $user->supports(@_);
62 }
63
64 ## Backwards compatibility
65 #
66 # This is a backwards compatible routine.  get_user is specifically for loading a user by it's unique id
67 # find_user is capable of doing the same by simply passing { id => $id }  
68 # no new code should be written using get_user as it is deprecated.
69 sub get_user {
70     my ( $self, $id ) = @_;
71     $self->find_user({id => $id});
72 }
73
74 ## backwards compatibility
75 sub setup {
76     my $c = shift;
77
78     ### If a user does 'use Catalyst qw/Authentication::Store::Minimal/'
79     ### he will be proxied on to this setup routine (and only then --
80     ### non plugins should NOT have their setup routine invoked!)
81     ### Beware what we pass to the 'new' routine; it wants
82     ### a config has with a top level key 'users'. New style
83     ### configs do not have this, and split by realms. If we
84     ### blindly pass this to new, we will 1) overwrite what we
85     ### already passed and 2) make ->userhash undefined, which
86     ### leads to:
87     ###  Can't use an undefined value as a HASH reference at
88     ###  lib/Catalyst/Authentication/Store/Minimal.pm line 38.
89     ###
90     ### So only do this compatibility call if:
91     ### 1) we have a {users} config directive 
92     ###
93     ### Ideally we could also check for:
94     ### 2) we don't already have a ->userhash
95     ### however, that's an attribute of an object we can't 
96     ### access =/ --kane
97     
98     my $cfg = $c->config->{'Plugin::Authentication'}->{users}
99                 ? $c->config->{'Plugin::Authentication'}
100                 : undef;
101
102     $c->default_auth_store( __PACKAGE__->new( $cfg, $c ) ) if $cfg;
103     
104         $c->NEXT::setup(@_);
105 }
106
107 __PACKAGE__;
108
109 __END__
110
111 =pod
112
113 =head1 NAME
114
115 Catalyst::Authentication::Store::Minimal - Minimal authentication store
116
117 =head1 SYNOPSIS
118
119     # you probably just want Store::Minimal under most cases,
120     # but if you insist you can instantiate your own store:
121
122     use Catalyst::Authentication::Store::Minimal;
123
124     use Catalyst qw/
125         Authentication
126     /;
127
128     __PACKAGE__->config->{'Plugin::Authentication'} = 
129                     {  
130                         default_realm => 'members',
131                         realms => {
132                             members => {
133                                 credential => {
134                                     class => 'Password',
135                                     password_field => 'password',
136                                     password_type => 'clear'
137                                 },
138                                 store => {
139                                     class => 'Minimal',
140                                         users = {
141                                             bob => {
142                                                 password => "s00p3r",                                       
143                                                 editor => 'yes',
144                                                 roles => [qw/edit delete/],
145                                             },
146                                             william => {
147                                                 password => "s3cr3t",
148                                                 roles => [qw/comment/],
149                                             }
150                                         }                       
151                                     }
152                                 }
153                         }
154                     };
155
156     
157 =head1 DESCRIPTION
158
159 This authentication store lets you create a very quick and dirty user
160 database in your application's config hash.
161
162 You will need to include the Authentication plugin, and at least one Credential
163 plugin to use this Store. Credential::Password is reccommended.
164
165 It's purpose is mainly for testing, and it should probably be replaced by a
166 more "serious" store for production.
167
168 The hash in the config, as well as the user objects/hashes are freely mutable
169 at runtime.
170
171 =head1 CONFIGURATION
172
173 =over 4
174
175 =item class 
176
177 The classname used for the store. This is part of
178 L<Catalyst::Plugin::Authentication> and is the method by which
179 Catalyst::Authentication::Store::Minimal is loaded as the
180 user store. For this module to be used, this must be set to
181 'Minimal'.
182
183 =item users
184
185 This is a simple hash of users, the keys are the usenames, and the values are
186 hashrefs containing a password key/value pair, and optionally, a roles/list 
187 of role-names pair. If using roles, you will also need to add the 
188 Authorization::Roles plugin.
189
190 See the SYNOPSIS for an example.
191
192 =back
193
194 =head1 METHODS
195
196 There are no publicly exported routines in the Minimal store (or indeed in
197 most authentication stores)  However, below is a description of the routines 
198 required by L<Catalyst::Plugin::Authentication> for all authentication stores.
199
200 =head2 new( $config, $app, $realm )
201
202 Constructs a new store object, which uses the user element of the supplied config 
203 hash ref as it's backing structure.
204
205 =head2 find_user( $authinfo, $c ) 
206
207 Keys the hash by the 'id' or 'username' element in the authinfo hash and returns the user.
208
209 ... documentation fairy stopped here. ...
210
211 If the return value is unblessed it will be blessed as
212 L<Catalyst::Authentication::User::Hash>.
213
214 =head2 from_session( $id )
215
216 Delegates to C<get_user>.
217
218 =head2 user_supports( )
219
220 Chooses a random user from the hash and delegates to it.
221
222 =head2 get_user( )
223
224 =head2 setup( )
225
226 =cut
227
228