Refactor Authentication + some slight doc + perltidy
[catagits/Catalyst-Plugin-Authentication.git] / lib / Catalyst / Plugin / Authentication.pm
1 #!/usr/bin/perl
2
3 package Catalyst::Plugin::Authentication;
4
5 use base qw/Class::Accessor::Fast Class::Data::Inheritable/;
6
7 BEGIN {
8     __PACKAGE__->mk_accessors(qw/_user/);
9     __PACKAGE__->mk_classdata($_) for qw/_auth_stores _auth_store_names/;
10 }
11
12 use strict;
13 use warnings;
14
15 use Tie::RefHash;
16 use Class::Inspector;
17
18 our $VERSION = "0.01";
19
20 sub set_authenticated {
21     my ( $c, $user ) = @_;
22
23     $c->user($user);
24     $c->request->{user} = $user;    # compatibility kludge
25
26     if (    $c->isa("Catalyst::Plugin::Session")
27         and $c->config->{authentication}{use_session}
28         and $user->supports("session") )
29     {
30         $c->save_user_in_session($user);
31     }
32 }
33
34 sub user {
35     my $c = shift;
36
37     if (@_) {
38         return $c->_user(@_);
39     }
40
41     my $user = $c->_user;
42
43     if ( $user and !Scalar::Util::blessed($user) ) {
44         return $c->auth_restore_user($user);
45     }
46
47     return $user;
48 }
49
50 sub save_user_in_session {
51     my ( $c, $user ) = @_;
52
53     my $store = $user->store || ref $user;
54     $c->session->{__user_store} = $c->get_auth_store_name($store) || $store;
55     $c->session->{__user} = $user->for_session;
56 }
57
58 sub logout {
59     my $c = shift;
60
61     $c->user(undef);
62
63     if (    $c->isa("Catalyst::Plugin::Session")
64         and $c->config->{authentication}{use_session} )
65     {
66         delete @{ $c->session }{qw/__user __user_store/};
67     }
68 }
69
70 sub get_user {
71     my ( $c, $uid ) = @_;
72
73     if ( my $store = $c->default_auth_store ) {
74         return $store->get_user($uid);
75     }
76     else {
77         Catalyst::Exception->throw(
78                 "The user id $uid was passed to an authentication "
79               . "plugin, but no default store was specified" );
80     }
81 }
82
83 sub prepare {
84     my $c = shift->NEXT::prepare(@_);
85
86     if (    $c->isa("Catalyst::Plugin::Session")
87         and $c->default_auth_store
88         and !$c->user )
89     {
90         if ( $c->sessionid and my $frozen_user = $c->session->{__user} ) {
91             $c->_user($frozen_user);
92         }
93     }
94
95     return $c;
96 }
97
98 sub auth_restore_user {
99     my ( $c, $frozen_user, $store_name ) = @_;
100
101     $store_name  ||= $c->session->{__user_store};
102     $frozen_user ||= $c->session->{__user};
103
104     my $store = $c->get_auth_store($store_name);
105     $c->_user( my $user = $store->from_session( $c, $frozen_user ) );
106
107     return $user;
108
109 }
110
111 sub setup {
112     my $c = shift;
113
114     my $cfg = $c->config->{authentication} || {};
115
116     %$cfg = (
117         use_session => 1,
118         %$cfg,
119     );
120
121     $c->register_auth_stores(
122         default => $cfg->{store},
123         %{ $cfg->{stores} || {} },
124     );
125
126     $c->NEXT::setup(@_);
127 }
128
129 sub get_auth_store {
130     my ( $self, $name ) = @_;
131     $self->auth_stores->{$name} || ( Class::Inspector->loaded($name) && $name );
132 }
133
134 sub get_auth_store_name {
135     my ( $self, $store ) = @_;
136     $self->auth_store_names->{$store};
137 }
138
139 sub register_auth_stores {
140     my ( $self, %new ) = @_;
141
142     foreach my $name ( keys %new ) {
143         my $store = $new{$name} or next;
144         $self->auth_stores->{$name}       = $store;
145         $self->auth_store_names->{$store} = $name;
146     }
147 }
148
149 sub auth_stores {
150     my $self = shift;
151     $self->_auth_stores(@_) || $self->_auth_stores( {} );
152 }
153
154 sub auth_store_names {
155     my $self = shift;
156
157     unless ( $self->_auth_store_names ) {
158         tie my %hash, 'Tie::RefHash';
159         $self->_auth_store_names( \%hash );
160     }
161
162     $self->_auth_store_names;
163 }
164
165 sub default_auth_store {
166     my $self = shift;
167
168     if ( my $new = shift ) {
169         $self->register_auth_stores( default => $new );
170     }
171
172     $self->get_auth_store("default");
173 }
174
175 __PACKAGE__;
176
177 __END__
178
179 =pod
180
181 =head1 NAME
182
183 Catalyst::Plugin::Authentication - 
184
185 =head1 SYNOPSIS
186
187         use Catalyst qw/
188                 Authentication
189                 Authentication::Store::Foo
190                 Authentication::Credential::Password
191         /;
192
193 =head1 DESCRIPTION
194
195 The authentication plugin is used by the various authentication and
196 authorization plugins in catalyst.
197
198 It defines the notion of a logged in user, and provides integration with the 
199
200 =head1 METHODS
201
202 =over 4 
203
204 =item logout
205
206 Delete the currently logged in user from C<user> and the session.
207
208 =item user
209
210 Returns the currently logged user or undef if there is none.
211
212 =item get_user $uid
213
214 Delegate C<get_user> to the default store.
215
216 =item default_auth_store
217
218 Returns C<< $c->config->{authentication}{store} >>.
219
220 =back
221
222 =head1 INTERNAL METHODS
223
224 =over 4
225
226 =item set_authenticated $user
227
228 Marks a user as authenticated. Should be called from a
229 C<Catalyst::Plugin::Authentication::Credential> plugin after successful
230 authentication.
231
232 This involves setting C<user> and the internal data in C<session> if
233 L<Catalyst::Plugin::Session> is loaded.
234
235 =item auth_restore_user $user
236
237 Used to restore a user from the session, by C<user> only when it's actually
238 needed.
239
240 =item save_user_in_session $user
241
242 Used to save the user in a session.
243
244 =item prepare
245
246 Revives a user from the session object if there is one.
247
248 =item setup
249
250 Sets the default configuration parameters.
251
252 =item 
253
254 =back
255
256 =head1 CONFIGURATION
257
258 =over 4
259
260 =item use_session
261
262 Whether or not to store the user's logged in state in the session, if the
263 application is also using the L<Catalyst::Plugin::Authentication> plugin.
264
265 =back
266
267 =cut
268
269