| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Catalyst::Plugin::Authentication; |
|
2
|
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
53516
|
use Moose; |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
4
|
|
|
|
|
|
|
use namespace::clean -except => 'meta'; |
|
5
|
|
|
|
|
|
|
use MRO::Compat; |
|
6
|
|
|
|
|
|
|
use Tie::RefHash; |
|
7
|
|
|
|
|
|
|
use Class::Inspector; |
|
8
|
|
|
|
|
|
|
use Catalyst::Authentication::Realm; |
|
9
|
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
with 'MooseX::Emulate::Class::Accessor::Fast'; |
|
11
|
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
__PACKAGE__->mk_accessors(qw/_user/); |
|
13
|
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
our $VERSION = "0.10023"; |
|
15
|
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
sub set_authenticated { |
|
17
|
|
|
|
|
|
|
my ( $c, $user, $realmname ) = @_; |
|
18
|
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
$c->user($user); |
|
20
|
|
|
|
|
|
|
$c->request->{user} = $user; # compatibility kludge |
|
21
|
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
if (!$realmname) { |
|
23
|
|
|
|
|
|
|
$realmname = 'default'; |
|
24
|
|
|
|
|
|
|
} |
|
25
|
|
|
|
|
|
|
my $realm = $c->get_auth_realm($realmname); |
|
26
|
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
if (!$realm) { |
|
28
|
|
|
|
|
|
|
Catalyst::Exception->throw( |
|
29
|
|
|
|
|
|
|
"set_authenticated called with nonexistant realm: '$realmname'."); |
|
30
|
|
|
|
|
|
|
} |
|
31
|
|
|
|
|
|
|
$user->auth_realm($realm->name); |
|
32
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
$c->persist_user(); |
|
34
|
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
$c->maybe::next::method($user, $realmname); |
|
36
|
|
|
|
|
|
|
} |
|
37
|
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
sub user { |
|
39
|
|
|
|
|
|
|
my $c = shift; |
|
40
|
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
if (@_) { |
|
42
|
|
|
|
|
|
|
return $c->_user(@_); |
|
43
|
|
|
|
|
|
|
} |
|
44
|
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
if ( defined($c->_user) ) { |
|
46
|
|
|
|
|
|
|
return $c->_user; |
|
47
|
|
|
|
|
|
|
} else { |
|
48
|
|
|
|
|
|
|
return $c->auth_restore_user; |
|
49
|
|
|
|
|
|
|
} |
|
50
|
|
|
|
|
|
|
} |
|
51
|
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
# change this to allow specification of a realm - to verify the user is part of that realm |
|
53
|
|
|
|
|
|
|
# in addition to verifying that they exist. |
|
54
|
|
|
|
|
|
|
sub user_exists { |
|
55
|
|
|
|
|
|
|
my $c = shift; |
|
56
|
|
|
|
|
|
|
return defined($c->_user) || defined($c->find_realm_for_persisted_user); |
|
57
|
|
|
|
|
|
|
} |
|
58
|
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
# works like user_exists - except only returns true if user |
|
60
|
|
|
|
|
|
|
# exists AND is in the realm requested. |
|
61
|
|
|
|
|
|
|
sub user_in_realm { |
|
62
|
|
|
|
|
|
|
my ($c, $realmname) = @_; |
|
63
|
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
if (defined($c->_user)) { |
|
65
|
|
|
|
|
|
|
return ($c->_user->auth_realm eq $realmname); |
|
66
|
|
|
|
|
|
|
} else { |
|
67
|
|
|
|
|
|
|
my $realm = $c->find_realm_for_persisted_user; |
|
68
|
|
|
|
|
|
|
if ($realm) { |
|
69
|
|
|
|
|
|
|
return ($realm->name eq $realmname); |
|
70
|
|
|
|
|
|
|
} else { |
|
71
|
|
|
|
|
|
|
return undef; |
|
72
|
|
|
|
|
|
|
} |
|
73
|
|
|
|
|
|
|
} |
|
74
|
|
|
|
|
|
|
} |
|
75
|
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
sub __old_save_user_in_session { |
|
77
|
|
|
|
|
|
|
my ( $c, $user, $realmname ) = @_; |
|
78
|
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
$c->session->{__user_realm} = $realmname; |
|
80
|
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
# we want to ask the store for a user prepared for the session. |
|
82
|
|
|
|
|
|
|
# but older modules split this functionality between the user and the |
|
83
|
|
|
|
|
|
|
# store. We try the store first. If not, we use the old method. |
|
84
|
|
|
|
|
|
|
my $realm = $c->get_auth_realm($realmname); |
|
85
|
|
|
|
|
|
|
if ($realm->{'store'}->can('for_session')) { |
|
86
|
|
|
|
|
|
|
$c->session->{__user} = $realm->{'store'}->for_session($c, $user); |
|
87
|
|
|
|
|
|
|
} else { |
|
88
|
|
|
|
|
|
|
$c->session->{__user} = $user->for_session; |
|
89
|
|
|
|
|
|
|
} |
|
90
|
|
|
|
|
|
|
} |
|
91
|
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
sub persist_user { |
|
93
|
|
|
|
|
|
|
my $c = shift; |
|
94
|
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
if ($c->user_exists) { |
|
96
|
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
## if we have a valid session handler - we store the |
|
98
|
|
|
|
|
|
|
## realm in the session. If not - we have to hope that |
|
99
|
|
|
|
|
|
|
## the realm can recognize its frozen user somehow. |
|
100
|
|
|
|
|
|
|
if ($c->can('session') && |
|
101
|
|
|
|
|
|
|
$c->config->{'Plugin::Authentication'}{'use_session'} && |
|
102
|
|
|
|
|
|
|
$c->session_is_valid) { |
|
103
|
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
$c->session->{'__user_realm'} = $c->_user->auth_realm; |
|
105
|
|
|
|
|
|
|
} |
|
106
|
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
my $realm = $c->get_auth_realm($c->_user->auth_realm); |
|
108
|
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
# used to call $realm->save_user_in_session |
|
110
|
|
|
|
|
|
|
$realm->persist_user($c, $c->user); |
|
111
|
|
|
|
|
|
|
} |
|
112
|
|
|
|
|
|
|
} |
|
113
|
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
## this was a short lived method to update user information - |
|
116
|
|
|
|
|
|
|
## you should use persist_user instead. |
|
117
|
|
|
|
|
|
|
sub update_user_in_session { |
|
118
|
|
|
|
|
|
|
my $c = shift; |
|
119
|
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
return $c->persist_user; |
|
121
|
|
|
|
|
|
|
} |
|
122
|
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
sub logout { |
|
124
|
|
|
|
|
|
|
my $c = shift; |
|
125
|
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
$c->user(undef); |
|
127
|
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
my $realm = $c->find_realm_for_persisted_user; |
|
129
|
|
|
|
|
|
|
if ($realm) { |
|
130
|
|
|
|
|
|
|
$realm->remove_persisted_user($c); |
|
131
|
|
|
|
|
|
|
} |
|
132
|
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
$c->maybe::next::method(@_); |
|
134
|
|
|
|
|
|
|
} |
|
135
|
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
sub find_user { |
|
137
|
|
|
|
|
|
|
my ( $c, $userinfo, $realmname ) = @_; |
|
138
|
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
$realmname ||= 'default'; |
|
140
|
|
|
|
|
|
|
my $realm = $c->get_auth_realm($realmname); |
|
141
|
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
if (!$realm) { |
|
143
|
|
|
|
|
|
|
Catalyst::Exception->throw( |
|
144
|
|
|
|
|
|
|
"find_user called with nonexistant realm: '$realmname'."); |
|
145
|
|
|
|
|
|
|
} |
|
146
|
|
|
|
|
|
|
return $realm->find_user($userinfo, $c); |
|
147
|
|
|
|
|
|
|
} |
|
148
|
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
## Consider making this a public method. - would make certain things easier when |
|
150
|
|
|
|
|
|
|
## dealing with things pre-auth restore. |
|
151
|
|
|
|
|
|
|
sub find_realm_for_persisted_user { |
|
152
|
|
|
|
|
|
|
my $c = shift; |
|
153
|
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
my $realm; |
|
155
|
|
|
|
|
|
|
if ($c->can('session') |
|
156
|
|
|
|
|
|
|
and $c->config->{'Plugin::Authentication'}{'use_session'} |
|
157
|
|
|
|
|
|
|
and $c->session_is_valid |
|
158
|
|
|
|
|
|
|
and exists($c->session->{'__user_realm'})) { |
|
159
|
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
$realm = $c->auth_realms->{$c->session->{'__user_realm'}}; |
|
161
|
|
|
|
|
|
|
if ($realm->user_is_restorable($c)) { |
|
162
|
|
|
|
|
|
|
return $realm; |
|
163
|
|
|
|
|
|
|
} |
|
164
|
|
|
|
|
|
|
} else { |
|
165
|
|
|
|
|
|
|
## we have no choice but to ask each realm whether it has a persisted user. |
|
166
|
|
|
|
|
|
|
foreach my $realmname (@{$c->_auth_realm_restore_order}) { |
|
167
|
|
|
|
|
|
|
my $realm = $c->auth_realms->{$realmname} |
|
168
|
|
|
|
|
|
|
|| Catalyst::Exception->throw("Could not find authentication realm '$realmname'"); |
|
169
|
|
|
|
|
|
|
return $realm |
|
170
|
|
|
|
|
|
|
if $realm->user_is_restorable($c); |
|
171
|
|
|
|
|
|
|
} |
|
172
|
|
|
|
|
|
|
} |
|
173
|
|
|
|
|
|
|
return undef; |
|
174
|
|
|
|
|
|
|
} |
|
175
|
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
sub auth_restore_user { |
|
177
|
|
|
|
|
|
|
my ( $c, $frozen_user, $realmname ) = @_; |
|
178
|
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
my $realm; |
|
180
|
|
|
|
|
|
|
if (defined($realmname)) { |
|
181
|
|
|
|
|
|
|
$realm = $c->get_auth_realm($realmname); |
|
182
|
|
|
|
|
|
|
} else { |
|
183
|
|
|
|
|
|
|
$realm = $c->find_realm_for_persisted_user; |
|
184
|
|
|
|
|
|
|
} |
|
185
|
|
|
|
|
|
|
return undef unless $realm; # FIXME die unless? This is an internal inconsistency |
|
186
|
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
$c->_user( my $user = $realm->restore_user( $c, $frozen_user ) ); |
|
188
|
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
# this sets the realm the user originated in. |
|
190
|
|
|
|
|
|
|
$user->auth_realm($realm->name) if $user; |
|
191
|
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
return $user; |
|
193
|
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
} |
|
195
|
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
# we can't actually do our setup in setup because the model has not yet been loaded. |
|
197
|
|
|
|
|
|
|
# So we have to trigger off of setup_finished. :-( |
|
198
|
|
|
|
|
|
|
sub setup { |
|
199
|
|
|
|
|
|
|
my $app = shift; |
|
200
|
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
$app->_authentication_initialize(); |
|
202
|
|
|
|
|
|
|
$app->next::method(@_); |
|
203
|
|
|
|
|
|
|
} |
|
204
|
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
## the actual initialization routine. whee. |
|
206
|
|
|
|
|
|
|
sub _authentication_initialize { |
|
207
|
|
|
|
|
|
|
my $app = shift; |
|
208
|
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
## let's avoid recreating / configuring everything if we have already done it, eh? |
|
210
|
|
|
|
|
|
|
if ($app->can('_auth_realms')) { return }; |
|
211
|
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
## make classdata where it is used. |
|
213
|
|
|
|
|
|
|
$app->mk_classdata( '_auth_realms' => {}); |
|
214
|
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
## the order to attempt restore in - If we don't have session - we have |
|
216
|
|
|
|
|
|
|
## no way to be sure where a frozen user came from - so we have to |
|
217
|
|
|
|
|
|
|
## ask each realm if it can restore the user. Unfortunately it is possible |
|
218
|
|
|
|
|
|
|
## that multiple realms could restore the user from the data we have - |
|
219
|
|
|
|
|
|
|
## So we have to determine at setup time what order to ask the realms in. |
|
220
|
|
|
|
|
|
|
## The default is to use the user_restore_priority values defined in the realm |
|
221
|
|
|
|
|
|
|
## config. if they are not defined - we go by alphabetical order. Note that |
|
222
|
|
|
|
|
|
|
## the 'default' realm always gets first chance at it unless it is explicitly |
|
223
|
|
|
|
|
|
|
## placed elsewhere by user_restore_priority. Remember this only comes |
|
224
|
|
|
|
|
|
|
## into play if session is disabled. |
|
225
|
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
$app->mk_classdata( '_auth_realm_restore_order' => []); |
|
227
|
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
my $cfg = $app->config->{'Plugin::Authentication'}; |
|
229
|
|
|
|
|
|
|
my $realmshash; |
|
230
|
|
|
|
|
|
|
if (!defined($cfg)) { |
|
231
|
|
|
|
|
|
|
if (exists($app->config->{'authentication'})) { |
|
232
|
|
|
|
|
|
|
$cfg = $app->config->{'authentication'}; |
|
233
|
|
|
|
|
|
|
$app->config->{'Plugin::Authentication'} = $app->config->{'authentication'}; |
|
234
|
|
|
|
|
|
|
} else { |
|
235
|
|
|
|
|
|
|
$cfg = {}; |
|
236
|
|
|
|
|
|
|
} |
|
237
|
|
|
|
|
|
|
} else { |
|
238
|
|
|
|
|
|
|
# the realmshash contains the various configured realms. By default this is |
|
239
|
|
|
|
|
|
|
# the main $app->config->{'Plugin::Authentication'} hash - but if that is |
|
240
|
|
|
|
|
|
|
# not defined, or there is a subkey {'realms'} then we use that. |
|
241
|
|
|
|
|
|
|
$realmshash = $cfg; |
|
242
|
|
|
|
|
|
|
} |
|
243
|
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
## If we have a sub-key of {'realms'} then we use that for realm configuration |
|
245
|
|
|
|
|
|
|
if (exists($cfg->{'realms'})) { |
|
246
|
|
|
|
|
|
|
$realmshash = $cfg->{'realms'}; |
|
247
|
|
|
|
|
|
|
} |
|
248
|
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
# old default was to force use_session on. This must remain for that |
|
250
|
|
|
|
|
|
|
# reason - but if use_session is already in the config, we respect its setting. |
|
251
|
|
|
|
|
|
|
if (!exists($cfg->{'use_session'})) { |
|
252
|
|
|
|
|
|
|
$cfg->{'use_session'} = 1; |
|
253
|
|
|
|
|
|
|
} |
|
254
|
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
## if we have a realms hash |
|
256
|
|
|
|
|
|
|
if (ref($realmshash) eq 'HASH') { |
|
257
|
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
my %auth_restore_order; |
|
259
|
|
|
|
|
|
|
my $authcount = 2; |
|
260
|
|
|
|
|
|
|
my $defaultrealm = 'default'; |
|
261
|
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
foreach my $realm (sort keys %{$realmshash}) { |
|
263
|
|
|
|
|
|
|
if (ref($realmshash->{$realm}) eq 'HASH' && |
|
264
|
|
|
|
|
|
|
(exists($realmshash->{$realm}{credential}) || exists($realmshash->{$realm}{class}))) { |
|
265
|
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
$app->setup_auth_realm($realm, $realmshash->{$realm}); |
|
267
|
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
if (exists($realmshash->{$realm}{'user_restore_priority'})) { |
|
269
|
|
|
|
|
|
|
$auth_restore_order{$realm} = $realmshash->{$realm}{'user_restore_priority'}; |
|
270
|
|
|
|
|
|
|
} else { |
|
271
|
|
|
|
|
|
|
$auth_restore_order{$realm} = $authcount++; |
|
272
|
|
|
|
|
|
|
} |
|
273
|
|
|
|
|
|
|
} |
|
274
|
|
|
|
|
|
|
} |
|
275
|
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
# if we have a 'default_realm' in the config hash and we don't already |
|
277
|
|
|
|
|
|
|
# have a realm called 'default', we point default at the realm specified |
|
278
|
|
|
|
|
|
|
if (exists($cfg->{'default_realm'}) && !$app->get_auth_realm('default')) { |
|
279
|
|
|
|
|
|
|
if ($app->_set_default_auth_realm($cfg->{'default_realm'})) { |
|
280
|
|
|
|
|
|
|
$defaultrealm = $cfg->{'default_realm'}; |
|
281
|
|
|
|
|
|
|
$auth_restore_order{'default'} = $auth_restore_order{$cfg->{'default_realm'}}; |
|
282
|
|
|
|
|
|
|
delete($auth_restore_order{$cfg->{'default_realm'}}); |
|
283
|
|
|
|
|
|
|
} |
|
284
|
|
|
|
|
|
|
} |
|
285
|
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
## if the default realm did not have a defined priority in its config - we put it at the front. |
|
287
|
|
|
|
|
|
|
if (!exists($realmshash->{$defaultrealm}{'user_restore_priority'})) { |
|
288
|
|
|
|
|
|
|
$auth_restore_order{'default'} = 1; |
|
289
|
|
|
|
|
|
|
} |
|
290
|
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
@{$app->_auth_realm_restore_order} = sort { $auth_restore_order{$a} <=> $auth_restore_order{$b} } keys %auth_restore_order; |
|
292
|
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
} else { |
|
294
|
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
## BACKWARDS COMPATIBILITY - if realms is not defined - then we are probably dealing |
|
296
|
|
|
|
|
|
|
## with an old-school config. The only caveat here is that we must add a classname |
|
297
|
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
## also - we have to treat {store} as {stores}{default} - because |
|
299
|
|
|
|
|
|
|
## while it is not a clear as a valid config in the docs, it |
|
300
|
|
|
|
|
|
|
## is functional with the old api. Whee! |
|
301
|
|
|
|
|
|
|
if (exists($cfg->{'store'}) && !exists($cfg->{'stores'}{'default'})) { |
|
302
|
|
|
|
|
|
|
$cfg->{'stores'}{'default'} = $cfg->{'store'}; |
|
303
|
|
|
|
|
|
|
} |
|
304
|
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
push @{$app->_auth_realm_restore_order}, 'default'; |
|
306
|
|
|
|
|
|
|
foreach my $storename (keys %{$cfg->{'stores'}}) { |
|
307
|
|
|
|
|
|
|
my $realmcfg = { |
|
308
|
|
|
|
|
|
|
store => { class => $cfg->{'stores'}{$storename} }, |
|
309
|
|
|
|
|
|
|
}; |
|
310
|
|
|
|
|
|
|
$app->setup_auth_realm($storename, $realmcfg); |
|
311
|
|
|
|
|
|
|
} |
|
312
|
|
|
|
|
|
|
} |
|
313
|
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
} |
|
315
|
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
# set up realmname. |
|
317
|
|
|
|
|
|
|
sub setup_auth_realm { |
|
318
|
|
|
|
|
|
|
my ($app, $realmname, $config) = @_; |
|
319
|
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
my $realmclass = $config->{class}; |
|
321
|
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
if( !$realmclass ) { |
|
323
|
|
|
|
|
|
|
$realmclass = 'Catalyst::Authentication::Realm'; |
|
324
|
|
|
|
|
|
|
} elsif ($realmclass !~ /^\+(.*)$/ ) { |
|
325
|
|
|
|
|
|
|
$realmclass = "Catalyst::Authentication::Realm::${realmclass}"; |
|
326
|
|
|
|
|
|
|
} else { |
|
327
|
|
|
|
|
|
|
$realmclass = $1; |
|
328
|
|
|
|
|
|
|
} |
|
329
|
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
Catalyst::Utils::ensure_class_loaded( $realmclass ); |
|
331
|
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
my $realm = $realmclass->new($realmname, $config, $app); |
|
333
|
|
|
|
|
|
|
if ($realm) { |
|
334
|
|
|
|
|
|
|
$app->auth_realms->{$realmname} = $realm; |
|
335
|
|
|
|
|
|
|
} else { |
|
336
|
|
|
|
|
|
|
$app->log->debug("realm initialization for '$realmname' failed."); |
|
337
|
|
|
|
|
|
|
} |
|
338
|
|
|
|
|
|
|
return $realm; |
|
339
|
|
|
|
|
|
|
} |
|
340
|
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
sub auth_realms { |
|
342
|
|
|
|
|
|
|
my $self = shift; |
|
343
|
|
|
|
|
|
|
$self->_authentication_initialize(); # Ensure _auth_realms created! |
|
344
|
|
|
|
|
|
|
return($self->_auth_realms); |
|
345
|
|
|
|
|
|
|
} |
|
346
|
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
sub get_auth_realm { |
|
348
|
|
|
|
|
|
|
my ($app, $realmname) = @_; |
|
349
|
|
|
|
|
|
|
return $app->auth_realms->{$realmname}; |
|
350
|
|
|
|
|
|
|
} |
|
351
|
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
|
|
353
|
|
|
|
|
|
|
# Very internal method. Vital Valuable Urgent, Do not touch on pain of death. |
|
354
|
|
|
|
|
|
|
# Using this method just assigns the default realm to be the value associated |
|
355
|
|
|
|
|
|
|
# with the realmname provided. It WILL overwrite any real realm called 'default' |
|
356
|
|
|
|
|
|
|
# so can be very confusing if used improperly. It's used properly already. |
|
357
|
|
|
|
|
|
|
# Translation: don't use it. |
|
358
|
|
|
|
|
|
|
sub _set_default_auth_realm { |
|
359
|
|
|
|
|
|
|
my ($app, $realmname) = @_; |
|
360
|
|
|
|
|
|
|
|
|
361
|
|
|
|
|
|
|
if (exists($app->auth_realms->{$realmname})) { |
|
362
|
|
|
|
|
|
|
$app->auth_realms->{'default'} = $app->auth_realms->{$realmname}; |
|
363
|
|
|
|
|
|
|
} |
|
364
|
|
|
|
|
|
|
return $app->get_auth_realm('default'); |
|
365
|
|
|
|
|
|
|
} |
|
366
|
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
sub authenticate { |
|
368
|
|
|
|
|
|
|
my ($app, $userinfo, $realmname) = @_; |
|
369
|
|
|
|
|
|
|
|
|
370
|
|
|
|
|
|
|
if (!$realmname) { |
|
371
|
|
|
|
|
|
|
$realmname = 'default'; |
|
372
|
|
|
|
|
|
|
} |
|
373
|
|
|
|
|
|
|
|
|
374
|
|
|
|
|
|
|
my $realm = $app->get_auth_realm($realmname); |
|
375
|
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
## note to self - make authenticate throw an exception if realm is invalid. |
|
377
|
|
|
|
|
|
|
|
|
378
|
|
|
|
|
|
|
if ($realm) { |
|
379
|
|
|
|
|
|
|
return $realm->authenticate($app, $userinfo); |
|
380
|
|
|
|
|
|
|
} else { |
|
381
|
|
|
|
|
|
|
Catalyst::Exception->throw( |
|
382
|
|
|
|
|
|
|
"authenticate called with nonexistant realm: '$realmname'."); |
|
383
|
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
} |
|
385
|
|
|
|
|
|
|
return undef; |
|
386
|
|
|
|
|
|
|
} |
|
387
|
|
|
|
|
|
|
|
|
388
|
|
|
|
|
|
|
## BACKWARDS COMPATIBILITY -- Warning: Here be monsters! |
|
389
|
|
|
|
|
|
|
# |
|
390
|
|
|
|
|
|
|
# What follows are backwards compatibility routines - for use with Stores and Credentials |
|
391
|
|
|
|
|
|
|
# that have not been updated to work with C::P::Authentication v0.10. |
|
392
|
|
|
|
|
|
|
# These are here so as to not break people's existing installations, but will go away |
|
393
|
|
|
|
|
|
|
# in a future version. |
|
394
|
|
|
|
|
|
|
# |
|
395
|
|
|
|
|
|
|
# The old style of configuration only supports a single store, as each store module |
|
396
|
|
|
|
|
|
|
# sets itself as the default store upon being loaded. This is the only supported |
|
397
|
|
|
|
|
|
|
# 'compatibility' mode. |
|
398
|
|
|
|
|
|
|
# |
|
399
|
|
|
|
|
|
|
|
|
400
|
|
|
|
|
|
|
sub get_user { |
|
401
|
|
|
|
|
|
|
my ( $c, $uid, @rest ) = @_; |
|
402
|
|
|
|
|
|
|
|
|
403
|
|
|
|
|
|
|
return $c->find_user( {'id' => $uid, 'rest'=>\@rest }, 'default' ); |
|
404
|
|
|
|
|
|
|
} |
|
405
|
|
|
|
|
|
|
|
|
406
|
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
## this should only be called when using old-style authentication plugins. IF this gets |
|
408
|
|
|
|
|
|
|
## called in a new-style config - it will OVERWRITE the store of your default realm. Don't do it. |
|
409
|
|
|
|
|
|
|
## also - this is a partial setup - because no credential is instantiated... in other words it ONLY |
|
410
|
|
|
|
|
|
|
## works with old-style auth plugins and C::P::Authentication in compatibility mode. Trying to combine |
|
411
|
|
|
|
|
|
|
## this with a realm-type config will probably crash your app. |
|
412
|
|
|
|
|
|
|
sub default_auth_store { |
|
413
|
|
|
|
|
|
|
my $self = shift; |
|
414
|
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
my $realm = $self->get_auth_realm('default'); |
|
416
|
|
|
|
|
|
|
if (!$realm) { |
|
417
|
|
|
|
|
|
|
$realm = $self->setup_auth_realm('default', { class => 'Compatibility' }); |
|
418
|
|
|
|
|
|
|
} |
|
419
|
|
|
|
|
|
|
if ( my $new = shift ) { |
|
420
|
|
|
|
|
|
|
$realm->store($new); |
|
421
|
|
|
|
|
|
|
|
|
422
|
|
|
|
|
|
|
my $storeclass; |
|
423
|
|
|
|
|
|
|
if (ref($new)) { |
|
424
|
|
|
|
|
|
|
$storeclass = ref($new); |
|
425
|
|
|
|
|
|
|
} else { |
|
426
|
|
|
|
|
|
|
$storeclass = $new; |
|
427
|
|
|
|
|
|
|
} |
|
428
|
|
|
|
|
|
|
|
|
429
|
|
|
|
|
|
|
# BACKWARDS COMPATIBILITY - if the store class does not define find_user, we define it in terms |
|
430
|
|
|
|
|
|
|
# of get_user and add it to the class. this is because the auth routines use find_user, |
|
431
|
|
|
|
|
|
|
# and rely on it being present. (this avoids per-call checks) |
|
432
|
|
|
|
|
|
|
if (!$storeclass->can('find_user')) { |
|
433
|
|
|
|
|
|
|
no strict 'refs'; |
|
434
|
|
|
|
|
|
|
*{"${storeclass}::find_user"} = sub { |
|
435
|
|
|
|
|
|
|
my ($self, $info) = @_; |
|
436
|
|
|
|
|
|
|
my @rest = @{$info->{rest}} if exists($info->{rest}); |
|
437
|
|
|
|
|
|
|
$self->get_user($info->{id}, @rest); |
|
438
|
|
|
|
|
|
|
}; |
|
439
|
|
|
|
|
|
|
} |
|
440
|
|
|
|
|
|
|
} |
|
441
|
|
|
|
|
|
|
|
|
442
|
|
|
|
|
|
|
return $self->get_auth_realm('default')->store; |
|
443
|
|
|
|
|
|
|
} |
|
444
|
|
|
|
|
|
|
|
|
445
|
|
|
|
|
|
|
## BACKWARDS COMPATIBILITY |
|
446
|
|
|
|
|
|
|
## this only ever returns a hash containing 'default' - as that is the only |
|
447
|
|
|
|
|
|
|
## supported mode of calling this. |
|
448
|
|
|
|
|
|
|
sub auth_store_names { |
|
449
|
|
|
|
|
|
|
my $self = shift; |
|
450
|
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
my %hash = ( $self->get_auth_realm('default')->store => 'default' ); |
|
452
|
|
|
|
|
|
|
} |
|
453
|
|
|
|
|
|
|
|
|
454
|
|
|
|
|
|
|
sub get_auth_store { |
|
455
|
|
|
|
|
|
|
my ( $self, $name ) = @_; |
|
456
|
|
|
|
|
|
|
|
|
457
|
|
|
|
|
|
|
if ($name ne 'default') { |
|
458
|
|
|
|
|
|
|
Carp::croak "get_auth_store called on non-default realm '$name'. Only default supported in compatibility mode"; |
|
459
|
|
|
|
|
|
|
} else { |
|
460
|
|
|
|
|
|
|
$self->default_auth_store(); |
|
461
|
|
|
|
|
|
|
} |
|
462
|
|
|
|
|
|
|
} |
|
463
|
|
|
|
|
|
|
|
|
464
|
|
|
|
|
|
|
sub get_auth_store_name { |
|
465
|
|
|
|
|
|
|
my ( $self, $store ) = @_; |
|
466
|
|
|
|
|
|
|
return 'default'; |
|
467
|
|
|
|
|
|
|
} |
|
468
|
|
|
|
|
|
|
|
|
469
|
|
|
|
|
|
|
# sub auth_stores is only used internally - here for completeness |
|
470
|
|
|
|
|
|
|
sub auth_stores { |
|
471
|
|
|
|
|
|
|
my $self = shift; |
|
472
|
|
|
|
|
|
|
|
|
473
|
|
|
|
|
|
|
my %hash = ( 'default' => $self->get_auth_realm('default')->store); |
|
474
|
|
|
|
|
|
|
} |
|
475
|
|
|
|
|
|
|
|
|
476
|
|
|
|
|
|
|
__PACKAGE__->meta->make_immutable; |
|
477
|
|
|
|
|
|
|
__PACKAGE__; |
|
478
|
|
|
|
|
|
|
|
|
479
|
|
|
|
|
|
|
__END__ |
|
480
|
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
=pod |
|
482
|
|
|
|
|
|
|
|
|
483
|
|
|
|
|
|
|
=head1 NAME |
|
484
|
|
|
|
|
|
|
|
|
485
|
|
|
|
|
|
|
Catalyst::Plugin::Authentication - Infrastructure plugin for the Catalyst authentication framework. |
|
486
|
|
|
|
|
|
|
|
|
487
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
488
|
|
|
|
|
|
|
|
|
489
|
|
|
|
|
|
|
use Catalyst qw/ |
|
490
|
|
|
|
|
|
|
Authentication |
|
491
|
|
|
|
|
|
|
/; |
|
492
|
|
|
|
|
|
|
|
|
493
|
|
|
|
|
|
|
# later on ... |
|
494
|
|
|
|
|
|
|
$c->authenticate({ username => 'myusername', |
|
495
|
|
|
|
|
|
|
password => 'mypassword' }); |
|
496
|
|
|
|
|
|
|
my $age = $c->user->get('age'); |
|
497
|
|
|
|
|
|
|
$c->logout; |
|
498
|
|
|
|
|
|
|
|
|
499
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
500
|
|
|
|
|
|
|
|
|
501
|
|
|
|
|
|
|
The authentication plugin provides generic user support for Catalyst apps. It |
|
502
|
|
|
|
|
|
|
is the basis for both authentication (checking the user is who they claim to |
|
503
|
|
|
|
|
|
|
be), and authorization (allowing the user to do what the system authorises |
|
504
|
|
|
|
|
|
|
them to do). |
|
505
|
|
|
|
|
|
|
|
|
506
|
|
|
|
|
|
|
Using authentication is split into two parts. A Store is used to actually |
|
507
|
|
|
|
|
|
|
store the user information, and can store any amount of data related to the |
|
508
|
|
|
|
|
|
|
user. Credentials are used to verify users, using information from the store, |
|
509
|
|
|
|
|
|
|
given data from the frontend. A Credential and a Store are paired to form a |
|
510
|
|
|
|
|
|
|
'Realm'. A Catalyst application using the authentication framework must have |
|
511
|
|
|
|
|
|
|
at least one realm, and may have several. |
|
512
|
|
|
|
|
|
|
|
|
513
|
|
|
|
|
|
|
To implement authentication in a Catalyst application you need to add this |
|
514
|
|
|
|
|
|
|
module, and specify at least one realm in the configuration. |
|
515
|
|
|
|
|
|
|
|
|
516
|
|
|
|
|
|
|
Authentication data can also be stored in a session, if the application |
|
517
|
|
|
|
|
|
|
is using the L<Catalyst::Plugin::Session> module. |
|
518
|
|
|
|
|
|
|
|
|
519
|
|
|
|
|
|
|
B<NOTE> in version 0.10 of this module, the interface to this module changed. |
|
520
|
|
|
|
|
|
|
Please see L</COMPATIBILITY ROUTINES> for more information. |
|
521
|
|
|
|
|
|
|
|
|
522
|
|
|
|
|
|
|
=head1 INTRODUCTION |
|
523
|
|
|
|
|
|
|
|
|
524
|
|
|
|
|
|
|
=head2 The Authentication/Authorization Process |
|
525
|
|
|
|
|
|
|
|
|
526
|
|
|
|
|
|
|
Web applications typically need to identify a user - to tell the user apart |
|
527
|
|
|
|
|
|
|
from other users. This is usually done in order to display private information |
|
528
|
|
|
|
|
|
|
that is only that user's business, or to limit access to the application so |
|
529
|
|
|
|
|
|
|
that only certain entities can access certain parts. |
|
530
|
|
|
|
|
|
|
|
|
531
|
|
|
|
|
|
|
This process is split up into several steps. First you ask the user to identify |
|
532
|
|
|
|
|
|
|
themselves. At this point you can't be sure that the user is really who they |
|
533
|
|
|
|
|
|
|
claim to be. |
|
534
|
|
|
|
|
|
|
|
|
535
|
|
|
|
|
|
|
Then the user tells you who they are, and backs this claim with some piece of |
|
536
|
|
|
|
|
|
|
information that only the real user could give you. For example, a password is |
|
537
|
|
|
|
|
|
|
a secret that is known to both the user and you. When the user tells you this |
|
538
|
|
|
|
|
|
|
password you can assume they're in on the secret and can be trusted (ignore |
|
539
|
|
|
|
|
|
|
identity theft for now). Checking the password, or any other proof is called |
|
540
|
|
|
|
|
|
|
B<credential verification>. |
|
541
|
|
|
|
|
|
|
|
|
542
|
|
|
|
|
|
|
By this time you know exactly who the user is - the user's identity is |
|
543
|
|
|
|
|
|
|
B<authenticated>. This is where this module's job stops, and your application |
|
544
|
|
|
|
|
|
|
or other plugins step in. |
|
545
|
|
|
|
|
|
|
|
|
546
|
|
|
|
|
|
|
The next logical step is B<authorization>, the process of deciding what a user |
|
547
|
|
|
|
|
|
|
is (or isn't) allowed to do. For example, say your users are split into two |
|
548
|
|
|
|
|
|
|
main groups - regular users and administrators. You want to verify that the |
|
549
|
|
|
|
|
|
|
currently logged in user is indeed an administrator before performing the |
|
550
|
|
|
|
|
|
|
actions in an administrative part of your application. These decisions may be |
|
551
|
|
|
|
|
|
|
made within your application code using just the information available after |
|
552
|
|
|
|
|
|
|
authentication, or it may be facilitated by a number of plugins. |
|
553
|
|
|
|
|
|
|
|
|
554
|
|
|
|
|
|
|
=head2 The Components In This Framework |
|
555
|
|
|
|
|
|
|
|
|
556
|
|
|
|
|
|
|
=head3 Realms |
|
557
|
|
|
|
|
|
|
|
|
558
|
|
|
|
|
|
|
Configuration of the Catalyst::Plugin::Authentication framework is done in |
|
559
|
|
|
|
|
|
|
terms of realms. In simplest terms, a realm is a pairing of a Credential |
|
560
|
|
|
|
|
|
|
verifier and a User storage (Store) backend. As of version 0.10003, realms are |
|
561
|
|
|
|
|
|
|
now objects that you can create and customize. |
|
562
|
|
|
|
|
|
|
|
|
563
|
|
|
|
|
|
|
An application can have any number of Realms, each of which operates |
|
564
|
|
|
|
|
|
|
independent of the others. Each realm has a name, which is used to identify it |
|
565
|
|
|
|
|
|
|
as the target of an authentication request. This name can be anything, such as |
|
566
|
|
|
|
|
|
|
'users' or 'members'. One realm must be defined as the default_realm, which is |
|
567
|
|
|
|
|
|
|
used when no realm name is specified. More information about configuring |
|
568
|
|
|
|
|
|
|
realms is available in the configuration section. |
|
569
|
|
|
|
|
|
|
|
|
570
|
|
|
|
|
|
|
=head3 Credential Verifiers |
|
571
|
|
|
|
|
|
|
|
|
572
|
|
|
|
|
|
|
When user input is transferred to the L<Catalyst> application |
|
573
|
|
|
|
|
|
|
(typically via form inputs) the application may pass this information |
|
574
|
|
|
|
|
|
|
into the authentication system through the C<< $c->authenticate() >> |
|
575
|
|
|
|
|
|
|
method. From there, it is passed to the appropriate Credential |
|
576
|
|
|
|
|
|
|
verifier. |
|
577
|
|
|
|
|
|
|
|
|
578
|
|
|
|
|
|
|
These plugins check the data, and ensure that it really proves the user is who |
|
579
|
|
|
|
|
|
|
they claim to be. |
|
580
|
|
|
|
|
|
|
|
|
581
|
|
|
|
|
|
|
Credential verifiers compatible with versions of this module 0.10x and |
|
582
|
|
|
|
|
|
|
upwards should be in the namespace |
|
583
|
|
|
|
|
|
|
C<Catalyst::Authentication::Credential>. |
|
584
|
|
|
|
|
|
|
|
|
585
|
|
|
|
|
|
|
=head3 Storage Backends |
|
586
|
|
|
|
|
|
|
|
|
587
|
|
|
|
|
|
|
The authentication data also identifies a user, and the Storage backend modules |
|
588
|
|
|
|
|
|
|
use this data to locate and return a standardized object-oriented |
|
589
|
|
|
|
|
|
|
representation of a user. |
|
590
|
|
|
|
|
|
|
|
|
591
|
|
|
|
|
|
|
When a user is retrieved from a store it is not necessarily authenticated. |
|
592
|
|
|
|
|
|
|
Credential verifiers accept a set of authentication data and use this |
|
593
|
|
|
|
|
|
|
information to retrieve the user from the store they are paired with. |
|
594
|
|
|
|
|
|
|
|
|
595
|
|
|
|
|
|
|
Storage backends compatible with versions of this module 0.10x and |
|
596
|
|
|
|
|
|
|
upwards should be in the namespace |
|
597
|
|
|
|
|
|
|
C<Catalyst::Authentication::Store>. |
|
598
|
|
|
|
|
|
|
|
|
599
|
|
|
|
|
|
|
=head3 The Core Plugin |
|
600
|
|
|
|
|
|
|
|
|
601
|
|
|
|
|
|
|
This plugin on its own is the glue, providing realm configuration, session |
|
602
|
|
|
|
|
|
|
integration, and other goodness for the other plugins. |
|
603
|
|
|
|
|
|
|
|
|
604
|
|
|
|
|
|
|
=head3 Other Plugins |
|
605
|
|
|
|
|
|
|
|
|
606
|
|
|
|
|
|
|
More layers of plugins can be stacked on top of the authentication code. For |
|
607
|
|
|
|
|
|
|
example, L<Catalyst::Plugin::Session::PerUser> provides an abstraction of |
|
608
|
|
|
|
|
|
|
browser sessions that is more persistent per user. |
|
609
|
|
|
|
|
|
|
L<Catalyst::Plugin::Authorization::Roles> provides an accepted way to separate |
|
610
|
|
|
|
|
|
|
and group users into categories, and then check which categories the current |
|
611
|
|
|
|
|
|
|
user belongs to. |
|
612
|
|
|
|
|
|
|
|
|
613
|
|
|
|
|
|
|
=head1 EXAMPLE |
|
614
|
|
|
|
|
|
|
|
|
615
|
|
|
|
|
|
|
Let's say we were storing users in a simple Perl hash. Users are |
|
616
|
|
|
|
|
|
|
verified by supplying a password which is matched within the hash. |
|
617
|
|
|
|
|
|
|
|
|
618
|
|
|
|
|
|
|
This means that our application will begin like this: |
|
619
|
|
|
|
|
|
|
|
|
620
|
|
|
|
|
|
|
package MyApp; |
|
621
|
|
|
|
|
|
|
|
|
622
|
|
|
|
|
|
|
use Catalyst qw/ |
|
623
|
|
|
|
|
|
|
Authentication |
|
624
|
|
|
|
|
|
|
/; |
|
625
|
|
|
|
|
|
|
|
|
626
|
|
|
|
|
|
|
__PACKAGE__->config( 'Plugin::Authentication' => |
|
627
|
|
|
|
|
|
|
{ |
|
628
|
|
|
|
|
|
|
default => { |
|
629
|
|
|
|
|
|
|
credential => { |
|
630
|
|
|
|
|
|
|
class => 'Password', |
|
631
|
|
|
|
|
|
|
password_field => 'password', |
|
632
|
|
|
|
|
|
|
password_type => 'clear' |
|
633
|
|
|
|
|
|
|
}, |
|
634
|
|
|
|
|
|
|
store => { |
|
635
|
|
|
|
|
|
|
class => 'Minimal', |
|
636
|
|
|
|
|
|
|
users => { |
|
637
|
|
|
|
|
|
|
bob => { |
|
638
|
|
|
|
|
|
|
password => "s00p3r", |
|
639
|
|
|
|
|
|
|
editor => 'yes', |
|
640
|
|
|
|
|
|
|
roles => [qw/edit delete/], |
|
641
|
|
|
|
|
|
|
}, |
|
642
|
|
|
|
|
|
|
william => { |
|
643
|
|
|
|
|
|
|
password => "s3cr3t", |
|
644
|
|
|
|
|
|
|
roles => [qw/comment/], |
|
645
|
|
|
|
|
|
|
} |
|
646
|
|
|
|
|
|
|
} |
|
647
|
|
|
|
|
|
|
} |
|
648
|
|
|
|
|
|
|
} |
|
649
|
|
|
|
|
|
|
} |
|
650
|
|
|
|
|
|
|
); |
|
651
|
|
|
|
|
|
|
|
|
652
|
|
|
|
|
|
|
This tells the authentication plugin what realms are available, which |
|
653
|
|
|
|
|
|
|
credential and store modules are used, and the configuration of each. With |
|
654
|
|
|
|
|
|
|
this code loaded, we can now attempt to authenticate users. |
|
655
|
|
|
|
|
|
|
|
|
656
|
|
|
|
|
|
|
To show an example of this, let's create an authentication controller: |
|
657
|
|
|
|
|
|
|
|
|
658
|
|
|
|
|
|
|
package MyApp::Controller::Auth; |
|
659
|
|
|
|
|
|
|
|
|
660
|
|
|
|
|
|
|
sub login : Local { |
|
661
|
|
|
|
|
|
|
my ( $self, $c ) = @_; |
|
662
|
|
|
|
|
|
|
|
|
663
|
|
|
|
|
|
|
if ( my $user = $c->req->params->{user} |
|
664
|
|
|
|
|
|
|
and my $password = $c->req->params->{password} ) |
|
665
|
|
|
|
|
|
|
{ |
|
666
|
|
|
|
|
|
|
if ( $c->authenticate( { username => $user, |
|
667
|
|
|
|
|
|
|
password => $password } ) ) { |
|
668
|
|
|
|
|
|
|
$c->res->body( "hello " . $c->user->get("name") ); |
|
669
|
|
|
|
|
|
|
} else { |
|
670
|
|
|
|
|
|
|
# login incorrect |
|
671
|
|
|
|
|
|
|
} |
|
672
|
|
|
|
|
|
|
} |
|
673
|
|
|
|
|
|
|
else { |
|
674
|
|
|
|
|
|
|
# invalid form input |
|
675
|
|
|
|
|
|
|
} |
|
676
|
|
|
|
|
|
|
} |
|
677
|
|
|
|
|
|
|
|
|
678
|
|
|
|
|
|
|
This code should be self-explanatory. If all the necessary fields are supplied, |
|
679
|
|
|
|
|
|
|
call the C<authenticate> method on the context object. If it succeeds the |
|
680
|
|
|
|
|
|
|
user is logged in. |
|
681
|
|
|
|
|
|
|
|
|
682
|
|
|
|
|
|
|
The credential verifier will attempt to retrieve the user whose |
|
683
|
|
|
|
|
|
|
details match the authentication information provided to |
|
684
|
|
|
|
|
|
|
C<< $c->authenticate() >>. Once it fetches the user the password is |
|
685
|
|
|
|
|
|
|
checked and if it matches the user will be B<authenticated> and |
|
686
|
|
|
|
|
|
|
C<< $c->user >> will contain the user object retrieved from the store. |
|
687
|
|
|
|
|
|
|
|
|
688
|
|
|
|
|
|
|
In the above case, the default realm is checked, but we could just as easily |
|
689
|
|
|
|
|
|
|
check an alternate realm. If this were an admin login, for example, we could |
|
690
|
|
|
|
|
|
|
authenticate on the admin realm by simply changing the C<< $c->authenticate() >> |
|
691
|
|
|
|
|
|
|
call: |
|
692
|
|
|
|
|
|
|
|
|
693
|
|
|
|
|
|
|
if ( $c->authenticate( { username => $user, |
|
694
|
|
|
|
|
|
|
password => $password }, 'admin' ) ) { |
|
695
|
|
|
|
|
|
|
$c->res->body( "hello " . $c->user->get("name") ); |
|
696
|
|
|
|
|
|
|
} ... |
|
697
|
|
|
|
|
|
|
|
|
698
|
|
|
|
|
|
|
|
|
699
|
|
|
|
|
|
|
Now suppose we want to restrict the ability to edit to a user with an |
|
700
|
|
|
|
|
|
|
'editor' value of yes. |
|
701
|
|
|
|
|
|
|
|
|
702
|
|
|
|
|
|
|
The restricted action might look like this: |
|
703
|
|
|
|
|
|
|
|
|
704
|
|
|
|
|
|
|
sub edit : Local { |
|
705
|
|
|
|
|
|
|
my ( $self, $c ) = @_; |
|
706
|
|
|
|
|
|
|
|
|
707
|
|
|
|
|
|
|
$c->detach("unauthorized") |
|
708
|
|
|
|
|
|
|
unless $c->user_exists |
|
709
|
|
|
|
|
|
|
and $c->user->get('editor') eq 'yes'; |
|
710
|
|
|
|
|
|
|
|
|
711
|
|
|
|
|
|
|
# do something restricted here |
|
712
|
|
|
|
|
|
|
} |
|
713
|
|
|
|
|
|
|
|
|
714
|
|
|
|
|
|
|
(Note that if you have multiple realms, you can use |
|
715
|
|
|
|
|
|
|
C<< $c->user_in_realm('realmname') >> in place of |
|
716
|
|
|
|
|
|
|
C<< $c->user_exists(); >> This will essentially perform the same |
|
717
|
|
|
|
|
|
|
verification as user_exists, with the added requirement that if there |
|
718
|
|
|
|
|
|
|
is a user, it must have come from the realm specified.) |
|
719
|
|
|
|
|
|
|
|
|
720
|
|
|
|
|
|
|
The above example is somewhat similar to role based access control. |
|
721
|
|
|
|
|
|
|
L<Catalyst::Authentication::Store::Minimal> treats the roles field as |
|
722
|
|
|
|
|
|
|
an array of role names. Let's leverage this. Add the role authorization |
|
723
|
|
|
|
|
|
|
plugin: |
|
724
|
|
|
|
|
|
|
|
|
725
|
|
|
|
|
|
|
use Catalyst qw/ |
|
726
|
|
|
|
|
|
|
... |
|
727
|
|
|
|
|
|
|
Authorization::Roles |
|
728
|
|
|
|
|
|
|
/; |
|
729
|
|
|
|
|
|
|
|
|
730
|
|
|
|
|
|
|
sub edit : Local { |
|
731
|
|
|
|
|
|
|
my ( $self, $c ) = @_; |
|
732
|
|
|
|
|
|
|
|
|
733
|
|
|
|
|
|
|
$c->detach("unauthorized") unless $c->check_user_roles("edit"); |
|
734
|
|
|
|
|
|
|
|
|
735
|
|
|
|
|
|
|
# do something restricted here |
|
736
|
|
|
|
|
|
|
} |
|
737
|
|
|
|
|
|
|
|
|
738
|
|
|
|
|
|
|
This is somewhat simpler and will work if you change your store, too, since the |
|
739
|
|
|
|
|
|
|
role interface is consistent. |
|
740
|
|
|
|
|
|
|
|
|
741
|
|
|
|
|
|
|
Let's say your app grows, and you now have 10,000 users. It's no longer |
|
742
|
|
|
|
|
|
|
efficient to maintain a hash of users, so you move this data to a database. |
|
743
|
|
|
|
|
|
|
You can accomplish this simply by installing the L<DBIx::Class|Catalyst::Authentication::Store::DBIx::Class> Store and |
|
744
|
|
|
|
|
|
|
changing your config: |
|
745
|
|
|
|
|
|
|
|
|
746
|
|
|
|
|
|
|
__PACKAGE__->config( 'Plugin::Authentication' => |
|
747
|
|
|
|
|
|
|
{ |
|
748
|
|
|
|
|
|
|
default_realm => 'members', |
|
749
|
|
|
|
|
|
|
members => { |
|
750
|
|
|
|
|
|
|
credential => { |
|
751
|
|
|
|
|
|
|
class => 'Password', |
|
752
|
|
|
|
|
|
|
password_field => 'password', |
|
753
|
|
|
|
|
|
|
password_type => 'clear' |
|
754
|
|
|
|
|
|
|
}, |
|
755
|
|
|
|
|
|
|
store => { |
|
756
|
|
|
|
|
|
|
class => 'DBIx::Class', |
|
757
|
|
|
|
|
|
|
user_model => 'MyApp::Users', |
|
758
|
|
|
|
|
|
|
role_column => 'roles', |
|
759
|
|
|
|
|
|
|
} |
|
760
|
|
|
|
|
|
|
} |
|
761
|
|
|
|
|
|
|
} |
|
762
|
|
|
|
|
|
|
); |
|
763
|
|
|
|
|
|
|
|
|
764
|
|
|
|
|
|
|
The authentication system works behind the scenes to load your data from the |
|
765
|
|
|
|
|
|
|
new source. The rest of your application is completely unchanged. |
|
766
|
|
|
|
|
|
|
|
|
767
|
|
|
|
|
|
|
|
|
768
|
|
|
|
|
|
|
=head1 CONFIGURATION |
|
769
|
|
|
|
|
|
|
|
|
770
|
|
|
|
|
|
|
# example |
|
771
|
|
|
|
|
|
|
__PACKAGE__->config( 'Plugin::Authentication' => |
|
772
|
|
|
|
|
|
|
{ |
|
773
|
|
|
|
|
|
|
default_realm => 'members', |
|
774
|
|
|
|
|
|
|
|
|
775
|
|
|
|
|
|
|
members => { |
|
776
|
|
|
|
|
|
|
credential => { |
|
777
|
|
|
|
|
|
|
class => 'Password', |
|
778
|
|
|
|
|
|
|
password_field => 'password', |
|
779
|
|
|
|
|
|
|
password_type => 'clear' |
|
780
|
|
|
|
|
|
|
}, |
|
781
|
|
|
|
|
|
|
store => { |
|
782
|
|
|
|
|
|
|
class => 'DBIx::Class', |
|
783
|
|
|
|
|
|
|
user_model => 'MyApp::Users', |
|
784
|
|
|
|
|
|
|
role_column => 'roles', |
|
785
|
|
|
|
|
|
|
} |
|
786
|
|
|
|
|
|
|
}, |
|
787
|
|
|
|
|
|
|
admins => { |
|
788
|
|
|
|
|
|
|
credential => { |
|
789
|
|
|
|
|
|
|
class => 'Password', |
|
790
|
|
|
|
|
|
|
password_field => 'password', |
|
791
|
|
|
|
|
|
|
password_type => 'clear' |
|
792
|
|
|
|
|
|
|
}, |
|
793
|
|
|
|
|
|
|
store => { |
|
794
|
|
|
|
|
|
|
class => '+MyApp::Authentication::Store::NetAuth', |
|
795
|
|
|
|
|
|
|
authserver => '192.168.10.17' |
|
796
|
|
|
|
|
|
|
} |
|
797
|
|
|
|
|
|
|
} |
|
798
|
|
|
|
|
|
|
} |
|
799
|
|
|
|
|
|
|
); |
|
800
|
|
|
|
|
|
|
|
|
801
|
|
|
|
|
|
|
NOTE: Until version 0.10008 of this module, you would need to put all the |
|
802
|
|
|
|
|
|
|
realms inside a "realms" key in the configuration. Please see |
|
803
|
|
|
|
|
|
|
L</COMPATIBILITY CONFIGURATION> for more information |
|
804
|
|
|
|
|
|
|
|
|
805
|
|
|
|
|
|
|
=over 4 |
|
806
|
|
|
|
|
|
|
|
|
807
|
|
|
|
|
|
|
=item use_session |
|
808
|
|
|
|
|
|
|
|
|
809
|
|
|
|
|
|
|
Whether or not to store the user's logged in state in the session, if the |
|
810
|
|
|
|
|
|
|
application is also using L<Catalyst::Plugin::Session>. This |
|
811
|
|
|
|
|
|
|
value is set to true per default. |
|
812
|
|
|
|
|
|
|
|
|
813
|
|
|
|
|
|
|
However, even if use_session is disabled, if any code touches $c->session, a session |
|
814
|
|
|
|
|
|
|
object will be auto-vivified and session Cookies will be sent in the headers. To |
|
815
|
|
|
|
|
|
|
prevent accidental session creation, check if a session already exists with |
|
816
|
|
|
|
|
|
|
if ($c->sessionid) { ... }. If the session doesn't exist, then don't place |
|
817
|
|
|
|
|
|
|
anything in the session to prevent an unecessary session from being created. |
|
818
|
|
|
|
|
|
|
|
|
819
|
|
|
|
|
|
|
=item default_realm |
|
820
|
|
|
|
|
|
|
|
|
821
|
|
|
|
|
|
|
This defines which realm should be used as when no realm is provided to methods |
|
822
|
|
|
|
|
|
|
that require a realm such as authenticate or find_user. |
|
823
|
|
|
|
|
|
|
|
|
824
|
|
|
|
|
|
|
=item realm refs |
|
825
|
|
|
|
|
|
|
|
|
826
|
|
|
|
|
|
|
The Plugin::Authentication config hash contains the series of realm |
|
827
|
|
|
|
|
|
|
configurations you want to use for your app. The only rule here is |
|
828
|
|
|
|
|
|
|
that there must be at least one. A realm consists of a name, which is used |
|
829
|
|
|
|
|
|
|
to reference the realm, a credential and a store. You may also put your |
|
830
|
|
|
|
|
|
|
realm configurations within a subelement called 'realms' if you desire to |
|
831
|
|
|
|
|
|
|
separate them from the remainder of your configuration. Note that if you use |
|
832
|
|
|
|
|
|
|
a 'realms' subelement, you must put ALL of your realms within it. |
|
833
|
|
|
|
|
|
|
|
|
834
|
|
|
|
|
|
|
You can also specify a realm class to instantiate instead of the default |
|
835
|
|
|
|
|
|
|
L<Catalyst::Authentication::Realm> class using the 'class' element within the |
|
836
|
|
|
|
|
|
|
realm config. |
|
837
|
|
|
|
|
|
|
|
|
838
|
|
|
|
|
|
|
Each realm config contains two hashes, one called 'credential' and one called |
|
839
|
|
|
|
|
|
|
'store', each of which provide configuration details to the respective modules. |
|
840
|
|
|
|
|
|
|
The contents of these hashes is specific to the module being used, with the |
|
841
|
|
|
|
|
|
|
exception of the 'class' element, which tells the core Authentication module the |
|
842
|
|
|
|
|
|
|
classname to instantiate. |
|
843
|
|
|
|
|
|
|
|
|
844
|
|
|
|
|
|
|
The 'class' element follows the standard Catalyst mechanism of class |
|
845
|
|
|
|
|
|
|
specification. If a class is prefixed with a +, it is assumed to be a complete |
|
846
|
|
|
|
|
|
|
class name. Otherwise it is considered to be a portion of the class name. For |
|
847
|
|
|
|
|
|
|
credentials, the classname 'B<Password>', for example, is expanded to |
|
848
|
|
|
|
|
|
|
Catalyst::Authentication::Credential::B<Password>. For stores, the |
|
849
|
|
|
|
|
|
|
classname 'B<storename>' is expanded to: |
|
850
|
|
|
|
|
|
|
Catalyst::Authentication::Store::B<storename>. |
|
851
|
|
|
|
|
|
|
|
|
852
|
|
|
|
|
|
|
=back |
|
853
|
|
|
|
|
|
|
|
|
854
|
|
|
|
|
|
|
=head1 METHODS |
|
855
|
|
|
|
|
|
|
|
|
856
|
|
|
|
|
|
|
=head2 $c->authenticate( $userinfo [, $realm ]) |
|
857
|
|
|
|
|
|
|
|
|
858
|
|
|
|
|
|
|
Attempts to authenticate the user using the information in the $userinfo hash |
|
859
|
|
|
|
|
|
|
reference using the realm $realm. $realm may be omitted, in which case the |
|
860
|
|
|
|
|
|
|
default realm is checked. |
|
861
|
|
|
|
|
|
|
|
|
862
|
|
|
|
|
|
|
=head2 $c->user( ) |
|
863
|
|
|
|
|
|
|
|
|
864
|
|
|
|
|
|
|
Returns the currently logged in user, or undef if there is none. |
|
865
|
|
|
|
|
|
|
Normally the user is re-retrieved from the store. |
|
866
|
|
|
|
|
|
|
For L<Catalyst::Authentication::Store::DBIx::Class> the user is re-restored |
|
867
|
|
|
|
|
|
|
using the primary key of the user table. |
|
868
|
|
|
|
|
|
|
Thus B<user> can throw an error even though B<user_exists> |
|
869
|
|
|
|
|
|
|
returned true. |
|
870
|
|
|
|
|
|
|
|
|
871
|
|
|
|
|
|
|
=head2 $c->user_exists( ) |
|
872
|
|
|
|
|
|
|
|
|
873
|
|
|
|
|
|
|
Returns true if a user is logged in right now. The difference between |
|
874
|
|
|
|
|
|
|
B<user_exists> and B<user> is that user_exists will return true if a user is logged |
|
875
|
|
|
|
|
|
|
in, even if it has not been yet retrieved from the storage backend. If you only |
|
876
|
|
|
|
|
|
|
need to know if the user is logged in, depending on the storage mechanism this |
|
877
|
|
|
|
|
|
|
can be much more efficient. |
|
878
|
|
|
|
|
|
|
B<user_exists> only looks into the session while B<user> is trying to restore the user. |
|
879
|
|
|
|
|
|
|
|
|
880
|
|
|
|
|
|
|
=head2 $c->user_in_realm( $realm ) |
|
881
|
|
|
|
|
|
|
|
|
882
|
|
|
|
|
|
|
Works like user_exists, except that it only returns true if a user is both |
|
883
|
|
|
|
|
|
|
logged in right now and was retrieved from the realm provided. |
|
884
|
|
|
|
|
|
|
|
|
885
|
|
|
|
|
|
|
=head2 $c->logout( ) |
|
886
|
|
|
|
|
|
|
|
|
887
|
|
|
|
|
|
|
Logs the user out. Deletes the currently logged in user from C<< $c->user >> |
|
888
|
|
|
|
|
|
|
and the session. It does not delete the session. |
|
889
|
|
|
|
|
|
|
|
|
890
|
|
|
|
|
|
|
=head2 $c->find_user( $userinfo, $realm ) |
|
891
|
|
|
|
|
|
|
|
|
892
|
|
|
|
|
|
|
Fetch a particular users details, matching the provided user info, from the realm |
|
893
|
|
|
|
|
|
|
specified in $realm. |
|
894
|
|
|
|
|
|
|
|
|
895
|
|
|
|
|
|
|
$user = $c->find_user({ id => $id }); |
|
896
|
|
|
|
|
|
|
$c->set_authenticated($user); # logs the user in and calls persist_user |
|
897
|
|
|
|
|
|
|
|
|
898
|
|
|
|
|
|
|
=head2 persist_user() |
|
899
|
|
|
|
|
|
|
|
|
900
|
|
|
|
|
|
|
Under normal circumstances the user data is only saved to the session during |
|
901
|
|
|
|
|
|
|
initial authentication. This call causes the auth system to save the |
|
902
|
|
|
|
|
|
|
currently authenticated user's data across requests. Useful if you have |
|
903
|
|
|
|
|
|
|
changed the user data and want to ensure that future requests reflect the |
|
904
|
|
|
|
|
|
|
most current data. Assumes that at the time of this call, $c->user |
|
905
|
|
|
|
|
|
|
contains the most current data. |
|
906
|
|
|
|
|
|
|
|
|
907
|
|
|
|
|
|
|
=head2 find_realm_for_persisted_user() |
|
908
|
|
|
|
|
|
|
|
|
909
|
|
|
|
|
|
|
Private method, do not call from user code! |
|
910
|
|
|
|
|
|
|
|
|
911
|
|
|
|
|
|
|
=head1 INTERNAL METHODS |
|
912
|
|
|
|
|
|
|
|
|
913
|
|
|
|
|
|
|
These methods are for Catalyst::Plugin::Authentication B<INTERNAL USE> only. |
|
914
|
|
|
|
|
|
|
Please do not use them in your own code, whether application or credential / |
|
915
|
|
|
|
|
|
|
store modules. If you do, you will very likely get the nasty shock of having |
|
916
|
|
|
|
|
|
|
to fix / rewrite your code when things change. They are documented here only |
|
917
|
|
|
|
|
|
|
for reference. |
|
918
|
|
|
|
|
|
|
|
|
919
|
|
|
|
|
|
|
=head2 $c->set_authenticated( $user, $realmname ) |
|
920
|
|
|
|
|
|
|
|
|
921
|
|
|
|
|
|
|
Marks a user as authenticated. This is called from within the authenticate |
|
922
|
|
|
|
|
|
|
routine when a credential returns a user. $realmname defaults to 'default'. |
|
923
|
|
|
|
|
|
|
You can use find_user to get $user |
|
924
|
|
|
|
|
|
|
|
|
925
|
|
|
|
|
|
|
=head2 $c->auth_restore_user( $user, $realmname ) |
|
926
|
|
|
|
|
|
|
|
|
927
|
|
|
|
|
|
|
Used to restore a user from the session. In most cases this is called without |
|
928
|
|
|
|
|
|
|
arguments to restore the user via the session. Can be called with arguments |
|
929
|
|
|
|
|
|
|
when restoring a user from some other method. Currently not used in this way. |
|
930
|
|
|
|
|
|
|
|
|
931
|
|
|
|
|
|
|
=head2 $c->auth_realms( ) |
|
932
|
|
|
|
|
|
|
|
|
933
|
|
|
|
|
|
|
Returns a hashref containing realmname -> realm instance pairs. Realm |
|
934
|
|
|
|
|
|
|
instances contain an instantiated store and credential object as the 'store' |
|
935
|
|
|
|
|
|
|
and 'credential' elements, respectively |
|
936
|
|
|
|
|
|
|
|
|
937
|
|
|
|
|
|
|
=head2 $c->get_auth_realm( $realmname ) |
|
938
|
|
|
|
|
|
|
|
|
939
|
|
|
|
|
|
|
Retrieves the realm instance for the realmname provided. |
|
940
|
|
|
|
|
|
|
|
|
941
|
|
|
|
|
|
|
=head2 $c->update_user_in_session |
|
942
|
|
|
|
|
|
|
|
|
943
|
|
|
|
|
|
|
This was a short-lived method to update user information - you should use persist_user instead. |
|
944
|
|
|
|
|
|
|
|
|
945
|
|
|
|
|
|
|
=head2 $c->setup_auth_realm( ) |
|
946
|
|
|
|
|
|
|
|
|
947
|
|
|
|
|
|
|
=head1 OVERRIDDEN METHODS |
|
948
|
|
|
|
|
|
|
|
|
949
|
|
|
|
|
|
|
=head2 $c->setup( ) |
|
950
|
|
|
|
|
|
|
|
|
951
|
|
|
|
|
|
|
=head1 SEE ALSO |
|
952
|
|
|
|
|
|
|
|
|
953
|
|
|
|
|
|
|
This list might not be up to date. Below are modules known to work with the updated |
|
954
|
|
|
|
|
|
|
API of 0.10 and are therefore compatible with realms. |
|
955
|
|
|
|
|
|
|
|
|
956
|
|
|
|
|
|
|
=head2 Realms |
|
957
|
|
|
|
|
|
|
|
|
958
|
|
|
|
|
|
|
L<Catalyst::Authentication::Realm> |
|
959
|
|
|
|
|
|
|
|
|
960
|
|
|
|
|
|
|
=head2 User Storage Backends |
|
961
|
|
|
|
|
|
|
|
|
962
|
|
|
|
|
|
|
=over |
|
963
|
|
|
|
|
|
|
|
|
964
|
|
|
|
|
|
|
=item L<Catalyst::Authentication::Store::Minimal> |
|
965
|
|
|
|
|
|
|
|
|
966
|
|
|
|
|
|
|
=item L<Catalyst::Authentication::Store::DBIx::Class> |
|
967
|
|
|
|
|
|
|
|
|
968
|
|
|
|
|
|
|
=item L<Catalyst::Authentication::Store::LDAP> |
|
969
|
|
|
|
|
|
|
|
|
970
|
|
|
|
|
|
|
=item L<Catalyst::Authentication::Store::RDBO> |
|
971
|
|
|
|
|
|
|
|
|
972
|
|
|
|
|
|
|
=item L<Catalyst::Authentication::Store::Model::KiokuDB> |
|
973
|
|
|
|
|
|
|
|
|
974
|
|
|
|
|
|
|
=item L<Catalyst::Authentication::Store::Jifty::DBI> |
|
975
|
|
|
|
|
|
|
|
|
976
|
|
|
|
|
|
|
=item L<Catalyst::Authentication::Store::Htpasswd> |
|
977
|
|
|
|
|
|
|
|
|
978
|
|
|
|
|
|
|
=back |
|
979
|
|
|
|
|
|
|
|
|
980
|
|
|
|
|
|
|
=head2 Credential verification |
|
981
|
|
|
|
|
|
|
|
|
982
|
|
|
|
|
|
|
=over |
|
983
|
|
|
|
|
|
|
|
|
984
|
|
|
|
|
|
|
=item L<Catalyst::Authentication::Credential::Password> |
|
985
|
|
|
|
|
|
|
|
|
986
|
|
|
|
|
|
|
=item L<Catalyst::Authentication::Credential::HTTP> |
|
987
|
|
|
|
|
|
|
|
|
988
|
|
|
|
|
|
|
=item L<Catalyst::Authentication::Credential::OpenID> |
|
989
|
|
|
|
|
|
|
|
|
990
|
|
|
|
|
|
|
=item L<Catalyst::Authentication::Credential::Authen::Simple> |
|
991
|
|
|
|
|
|
|
|
|
992
|
|
|
|
|
|
|
=item L<Catalyst::Authentication::Credential::Flickr> |
|
993
|
|
|
|
|
|
|
|
|
994
|
|
|
|
|
|
|
=item L<Catalyst::Authentication::Credential::Testing> |
|
995
|
|
|
|
|
|
|
|
|
996
|
|
|
|
|
|
|
=item L<Catalyst::Authentication::Credential::AuthTkt> |
|
997
|
|
|
|
|
|
|
|
|
998
|
|
|
|
|
|
|
=item L<Catalyst::Authentication::Credential::Kerberos> |
|
999
|
|
|
|
|
|
|
|
|
1000
|
|
|
|
|
|
|
=back |
|
1001
|
|
|
|
|
|
|
|
|
1002
|
|
|
|
|
|
|
=head2 Authorization |
|
1003
|
|
|
|
|
|
|
|
|
1004
|
|
|
|
|
|
|
L<Catalyst::Plugin::Authorization::ACL>, |
|
1005
|
|
|
|
|
|
|
L<Catalyst::Plugin::Authorization::Roles> |
|
1006
|
|
|
|
|
|
|
|
|
1007
|
|
|
|
|
|
|
=head2 Internals Documentation |
|
1008
|
|
|
|
|
|
|
|
|
1009
|
|
|
|
|
|
|
L<Catalyst::Plugin::Authentication::Internals> |
|
1010
|
|
|
|
|
|
|
|
|
1011
|
|
|
|
|
|
|
=head2 Misc |
|
1012
|
|
|
|
|
|
|
|
|
1013
|
|
|
|
|
|
|
L<Catalyst::Plugin::Session>, |
|
1014
|
|
|
|
|
|
|
L<Catalyst::Plugin::Session::PerUser> |
|
1015
|
|
|
|
|
|
|
|
|
1016
|
|
|
|
|
|
|
=head1 DON'T SEE ALSO |
|
1017
|
|
|
|
|
|
|
|
|
1018
|
|
|
|
|
|
|
This module along with its sub plugins deprecate a great number of other |
|
1019
|
|
|
|
|
|
|
modules. These include L<Catalyst::Plugin::Authentication::Simple>, |
|
1020
|
|
|
|
|
|
|
L<Catalyst::Plugin::Authentication::CDBI>. |
|
1021
|
|
|
|
|
|
|
|
|
1022
|
|
|
|
|
|
|
=head1 INCOMPATABILITIES |
|
1023
|
|
|
|
|
|
|
|
|
1024
|
|
|
|
|
|
|
The realms-based configuration and functionality of the 0.10 update |
|
1025
|
|
|
|
|
|
|
of L<Catalyst::Plugin::Authentication> required a change in the API used by |
|
1026
|
|
|
|
|
|
|
credentials and stores. It has a compatibility mode which allows use of |
|
1027
|
|
|
|
|
|
|
modules that have not yet been updated. This, however, completely mimics the |
|
1028
|
|
|
|
|
|
|
older api and disables the new realm-based features. In other words you cannot |
|
1029
|
|
|
|
|
|
|
mix the older credential and store modules with realms, or realm-based |
|
1030
|
|
|
|
|
|
|
configs. The changes required to update modules are relatively minor and are |
|
1031
|
|
|
|
|
|
|
covered in L<Catalyst::Plugin::Authentication::Internals>. We hope that most |
|
1032
|
|
|
|
|
|
|
modules will move to the compatible list above very quickly. |
|
1033
|
|
|
|
|
|
|
|
|
1034
|
|
|
|
|
|
|
=head1 COMPATIBILITY CONFIGURATION |
|
1035
|
|
|
|
|
|
|
|
|
1036
|
|
|
|
|
|
|
Until version 0.10008 of this module, you needed to put all the |
|
1037
|
|
|
|
|
|
|
realms inside a "realms" key in the configuration. |
|
1038
|
|
|
|
|
|
|
|
|
1039
|
|
|
|
|
|
|
# example |
|
1040
|
|
|
|
|
|
|
__PACKAGE__->config( 'Plugin::Authentication' => |
|
1041
|
|
|
|
|
|
|
{ |
|
1042
|
|
|
|
|
|
|
default_realm => 'members', |
|
1043
|
|
|
|
|
|
|
realms => { |
|
1044
|
|
|
|
|
|
|
members => { |
|
1045
|
|
|
|
|
|
|
... |
|
1046
|
|
|
|
|
|
|
}, |
|
1047
|
|
|
|
|
|
|
}, |
|
1048
|
|
|
|
|
|
|
} |
|
1049
|
|
|
|
|
|
|
); |
|
1050
|
|
|
|
|
|
|
|
|
1051
|
|
|
|
|
|
|
If you use the old, deprecated C<< __PACKAGE__->config( 'authentication' ) >> |
|
1052
|
|
|
|
|
|
|
configuration key, then the realms key is still required. |
|
1053
|
|
|
|
|
|
|
|
|
1054
|
|
|
|
|
|
|
=head1 COMPATIBILITY ROUTINES |
|
1055
|
|
|
|
|
|
|
|
|
1056
|
|
|
|
|
|
|
In version 0.10 of L<Catalyst::Plugin::Authentication>, the API |
|
1057
|
|
|
|
|
|
|
changed. For app developers, this change is fairly minor, but for |
|
1058
|
|
|
|
|
|
|
Credential and Store authors, the changes are significant. |
|
1059
|
|
|
|
|
|
|
|
|
1060
|
|
|
|
|
|
|
Please see the documentation in version 0.09 of |
|
1061
|
|
|
|
|
|
|
Catalyst::Plugin::Authentication for a better understanding of how the old API |
|
1062
|
|
|
|
|
|
|
functioned. |
|
1063
|
|
|
|
|
|
|
|
|
1064
|
|
|
|
|
|
|
The items below are still present in the plugin, though using them is |
|
1065
|
|
|
|
|
|
|
deprecated. They remain only as a transition tool, for those sites which can |
|
1066
|
|
|
|
|
|
|
not yet be upgraded to use the new system due to local customizations or use |
|
1067
|
|
|
|
|
|
|
of Credential / Store modules that have not yet been updated to work with the |
|
1068
|
|
|
|
|
|
|
new API. |
|
1069
|
|
|
|
|
|
|
|
|
1070
|
|
|
|
|
|
|
These routines should not be used in any application using realms |
|
1071
|
|
|
|
|
|
|
functionality or any of the methods described above. These are for reference |
|
1072
|
|
|
|
|
|
|
purposes only. |
|
1073
|
|
|
|
|
|
|
|
|
1074
|
|
|
|
|
|
|
=head2 $c->login( ) |
|
1075
|
|
|
|
|
|
|
|
|
1076
|
|
|
|
|
|
|
This method is used to initiate authentication and user retrieval. Technically |
|
1077
|
|
|
|
|
|
|
this is part of the old Password credential module and it still resides in the |
|
1078
|
|
|
|
|
|
|
L<Password|Catalyst::Plugin::Authentication::Credential::Password> class. It is |
|
1079
|
|
|
|
|
|
|
included here for reference only. |
|
1080
|
|
|
|
|
|
|
|
|
1081
|
|
|
|
|
|
|
=head2 $c->default_auth_store( ) |
|
1082
|
|
|
|
|
|
|
|
|
1083
|
|
|
|
|
|
|
Return the store whose name is 'default'. |
|
1084
|
|
|
|
|
|
|
|
|
1085
|
|
|
|
|
|
|
This is set to C<< $c->config( 'Plugin::Authentication' => { store => # Store} ) >> if that value exists, |
|
1086
|
|
|
|
|
|
|
or by using a Store plugin: |
|
1087
|
|
|
|
|
|
|
|
|
1088
|
|
|
|
|
|
|
# load the Minimal authentication store. |
|
1089
|
|
|
|
|
|
|
use Catalyst qw/Authentication Authentication::Store::Minimal/; |
|
1090
|
|
|
|
|
|
|
|
|
1091
|
|
|
|
|
|
|
Sets the default store to |
|
1092
|
|
|
|
|
|
|
L<Catalyst::Plugin::Authentication::Store::Minimal>. |
|
1093
|
|
|
|
|
|
|
|
|
1094
|
|
|
|
|
|
|
=head2 $c->get_auth_store( $name ) |
|
1095
|
|
|
|
|
|
|
|
|
1096
|
|
|
|
|
|
|
Return the store whose name is $name. |
|
1097
|
|
|
|
|
|
|
|
|
1098
|
|
|
|
|
|
|
=head2 $c->get_auth_store_name( $store ) |
|
1099
|
|
|
|
|
|
|
|
|
1100
|
|
|
|
|
|
|
Return the name of the store $store. |
|
1101
|
|
|
|
|
|
|
|
|
1102
|
|
|
|
|
|
|
=head2 $c->auth_stores( ) |
|
1103
|
|
|
|
|
|
|
|
|
1104
|
|
|
|
|
|
|
A hash keyed by name, with the stores registered in the app. |
|
1105
|
|
|
|
|
|
|
|
|
1106
|
|
|
|
|
|
|
=head2 $c->register_auth_stores( %stores_by_name ) |
|
1107
|
|
|
|
|
|
|
|
|
1108
|
|
|
|
|
|
|
Register stores into the application. |
|
1109
|
|
|
|
|
|
|
|
|
1110
|
|
|
|
|
|
|
=head2 $c->auth_store_names( ) |
|
1111
|
|
|
|
|
|
|
|
|
1112
|
|
|
|
|
|
|
=head2 $c->get_user( ) |
|
1113
|
|
|
|
|
|
|
|
|
1114
|
|
|
|
|
|
|
=head1 SUPPORT |
|
1115
|
|
|
|
|
|
|
|
|
1116
|
|
|
|
|
|
|
Please use the rt.cpan.org bug tracker, and git patches are wecome. |
|
1117
|
|
|
|
|
|
|
|
|
1118
|
|
|
|
|
|
|
Questions on usage should be directed to the Catalyst mailing list |
|
1119
|
|
|
|
|
|
|
or the #catalyst irc channel. |
|
1120
|
|
|
|
|
|
|
|
|
1121
|
|
|
|
|
|
|
=head1 AUTHORS |
|
1122
|
|
|
|
|
|
|
|
|
1123
|
|
|
|
|
|
|
Yuval Kogman, C<nothingmuch@woobling.org> - original author |
|
1124
|
|
|
|
|
|
|
|
|
1125
|
|
|
|
|
|
|
Jay Kuri, C<jayk@cpan.org> - Large rewrite |
|
1126
|
|
|
|
|
|
|
|
|
1127
|
|
|
|
|
|
|
=head1 PRIMARY MAINTAINER |
|
1128
|
|
|
|
|
|
|
|
|
1129
|
|
|
|
|
|
|
Tomas Doran (t0m), C<bobtfish@bobtfish.net> |
|
1130
|
|
|
|
|
|
|
|
|
1131
|
|
|
|
|
|
|
=head1 ADDITIONAL CONTRIBUTORS |
|
1132
|
|
|
|
|
|
|
|
|
1133
|
|
|
|
|
|
|
=over |
|
1134
|
|
|
|
|
|
|
|
|
1135
|
|
|
|
|
|
|
=item Jess Robinson |
|
1136
|
|
|
|
|
|
|
|
|
1137
|
|
|
|
|
|
|
=item David Kamholz |
|
1138
|
|
|
|
|
|
|
|
|
1139
|
|
|
|
|
|
|
=item kmx |
|
1140
|
|
|
|
|
|
|
|
|
1141
|
|
|
|
|
|
|
=item Nigel Metheringham |
|
1142
|
|
|
|
|
|
|
|
|
1143
|
|
|
|
|
|
|
=item Florian Ragwitz C<rafl@debian.org> |
|
1144
|
|
|
|
|
|
|
|
|
1145
|
|
|
|
|
|
|
=item Stephan Jauernick C<stephanj@cpan.org> |
|
1146
|
|
|
|
|
|
|
|
|
1147
|
|
|
|
|
|
|
=item Oskari Ojala (Okko), C<perl@okko.net> |
|
1148
|
|
|
|
|
|
|
|
|
1149
|
|
|
|
|
|
|
=item John Napiorkowski (jnap) C<jjnapiork@cpan.org> |
|
1150
|
|
|
|
|
|
|
|
|
1151
|
|
|
|
|
|
|
=back |
|
1152
|
|
|
|
|
|
|
|
|
1153
|
|
|
|
|
|
|
=head1 COPYRIGHT & LICENSE |
|
1154
|
|
|
|
|
|
|
|
|
1155
|
|
|
|
|
|
|
Copyright (c) 2005 - 2012 |
|
1156
|
|
|
|
|
|
|
the Catalyst::Plugin::Authentication L</AUTHORS>, |
|
1157
|
|
|
|
|
|
|
L</PRIMARY MAINTAINER> and L</ADDITIONAL CONTRIBUTORS> |
|
1158
|
|
|
|
|
|
|
as listed above. |
|
1159
|
|
|
|
|
|
|
|
|
1160
|
|
|
|
|
|
|
This program is free software; you can redistribute |
|
1161
|
|
|
|
|
|
|
it and/or modify it under the same terms as Perl itself. |
|
1162
|
|
|
|
|
|
|
|
|
1163
|
|
|
|
|
|
|
=cut |
|
1164
|
|
|
|
|
|
|
|