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