Commit | Line | Data |
79dc6a68 |
1 | NAME |
2 | Catalyst::Plugin::Authentication - Infrastructure plugin for the |
3 | Catalyst authentication framework. |
4 | |
5 | SYNOPSIS |
6 | use Catalyst qw/ |
7 | Authentication |
8 | /; |
9 | |
10 | # later on ... |
11 | $c->authenticate({ username => 'myusername', |
12 | password => 'mypassword' }); |
13 | my $age = $c->user->get('age'); |
14 | $c->logout; |
15 | |
16 | DESCRIPTION |
17 | The authentication plugin provides generic user support for Catalyst |
18 | apps. It is the basis for both authentication (checking the user is who |
19 | they claim to be), and authorization (allowing the user to do what the |
20 | system authorises them to do). |
21 | |
22 | Using authentication is split into two parts. A Store is used to |
23 | actually store the user information, and can store any amount of data |
24 | related to the user. Credentials are used to verify users, using |
25 | information from the store, given data from the frontend. A Credential |
26 | and a Store are paired to form a 'Realm'. A Catalyst application using |
27 | the authentication framework must have at least one realm, and may have |
28 | several. |
29 | |
30 | To implement authentication in a Catalyst application you need to add |
31 | this module, and specify at least one realm in the configuration. |
32 | |
33 | Authentication data can also be stored in a session, if the application |
34 | is using the Catalyst::Plugin::Session module. |
35 | |
36 | NOTE in version 0.10 of this module, the interface to this module |
37 | changed. Please see "COMPATIBILITY ROUTINES" for more information. |
38 | |
39 | INTRODUCTION |
40 | The Authentication/Authorization Process |
41 | Web applications typically need to identify a user - to tell the user |
42 | apart from other users. This is usually done in order to display private |
43 | information that is only that user's business, or to limit access to the |
44 | application so that only certain entities can access certain parts. |
45 | |
46 | This process is split up into several steps. First you ask the user to |
47 | identify themselves. At this point you can't be sure that the user is |
48 | really who they claim to be. |
49 | |
50 | Then the user tells you who they are, and backs this claim with some |
51 | piece of information that only the real user could give you. For |
52 | example, a password is a secret that is known to both the user and you. |
53 | When the user tells you this password you can assume they're in on the |
54 | secret and can be trusted (ignore identity theft for now). Checking the |
55 | password, or any other proof is called credential verification. |
56 | |
57 | By this time you know exactly who the user is - the user's identity is |
58 | authenticated. This is where this module's job stops, and your |
59 | application or other plugins step in. |
60 | |
61 | The next logical step is authorization, the process of deciding what a |
62 | user is (or isn't) allowed to do. For example, say your users are split |
63 | into two main groups - regular users and administrators. You want to |
64 | verify that the currently logged in user is indeed an administrator |
65 | before performing the actions in an administrative part of your |
66 | application. These decisions may be made within your application code |
67 | using just the information available after authentication, or it may be |
68 | facilitated by a number of plugins. |
69 | |
70 | The Components In This Framework |
71 | Realms |
72 | Configuration of the Catalyst::Plugin::Authentication framework is done |
73 | in terms of realms. In simplest terms, a realm is a pairing of a |
74 | Credential verifier and a User storage (Store) backend. |
75 | |
76 | An application can have any number of Realms, each of which operates |
77 | independant of the others. Each realm has a name, which is used to |
78 | identify it as the target of an authentication request. This name can be |
79 | anything, such as 'users' or 'members'. One realm must be defined as the |
80 | default_realm, which is used when no realm name is specified. More |
81 | information about configuring realms is available in the configuration |
82 | section. |
83 | |
84 | Credential Verifiers |
85 | When user input is transferred to the Catalyst application (typically |
86 | via form inputs) the application may pass this information into the |
87 | authentication system through the $c->authenticate() method. From there, |
88 | it is passed to the appropriate Credential verifier. |
89 | |
90 | These plugins check the data, and ensure that it really proves the user |
91 | is who they claim to be. |
92 | |
93 | Storage Backends |
94 | The authentication data also identifies a user, and the Storage backend |
95 | modules use this data to locate and return a standardized |
96 | object-oriented representation of a user. |
97 | |
98 | When a user is retrieved from a store it is not necessarily |
99 | authenticated. Credential verifiers accept a set of authentication data |
100 | and use this information to retrieve the user from the store they are |
101 | paired with. |
102 | |
103 | The Core Plugin |
104 | This plugin on its own is the glue, providing realm configuration, |
105 | session integration, and other goodness for the other plugins. |
106 | |
107 | Other Plugins |
108 | More layers of plugins can be stacked on top of the authentication code. |
109 | For example, Catalyst::Plugin::Session::PerUser provides an abstraction |
110 | of browser sessions that is more persistent per users. |
111 | Catalyst::Plugin::Authorization::Roles provides an accepted way to |
112 | separate and group users into categories, and then check which |
113 | categories the current user belongs to. |
114 | |
115 | EXAMPLE |
116 | Let's say we were storing users in a simple perl hash. Users are |
117 | verified by supplying a password which is matched within the hash. |
118 | |
119 | This means that our application will begin like this: |
120 | |
121 | package MyApp; |
122 | |
123 | use Catalyst qw/ |
124 | Authentication |
125 | /; |
126 | |
127 | __PACKAGE__->config->{authentication} = |
128 | { |
129 | default_realm => 'members', |
130 | realms => { |
131 | members => { |
132 | credential => { |
133 | class => 'Password', |
134 | password_field => 'password', |
135 | password_type => 'clear' |
136 | }, |
137 | store => { |
138 | class => 'Minimal', |
139 | users = { |
140 | bob => { |
141 | password => "s00p3r", |
142 | editor => 'yes', |
143 | roles => [qw/edit delete/], |
144 | }, |
145 | william => { |
146 | password => "s3cr3t", |
147 | roles => [qw/comment/], |
148 | } |
149 | } |
150 | } |
151 | } |
152 | } |
153 | }; |
154 | |
155 | This tells the authentication plugin what realms are available, which |
156 | credential and store modules are used, and the configuration of each. |
157 | With this code loaded, we can now attempt to authenticate users. |
158 | |
159 | To show an example of this, let's create an authentication controller: |
160 | |
161 | package MyApp::Controller::Auth; |
162 | |
163 | sub login : Local { |
164 | my ( $self, $c ) = @_; |
165 | |
166 | if ( my $user = $c->req->param("user") |
167 | and my $password = $c->req->param("password") ) |
168 | { |
169 | if ( $c->authenticate( { username => $user, |
170 | password => $password } ) ) { |
171 | $c->res->body( "hello " . $c->user->get("name") ); |
172 | } else { |
173 | # login incorrect |
174 | } |
175 | } |
176 | else { |
177 | # invalid form input |
178 | } |
179 | } |
180 | |
181 | This code should be very readable. If all the necessary fields are |
182 | supplied, call the "authenticate" method from the controller. If it |
183 | succeeds the user is logged in. |
184 | |
185 | The credential verifier will attempt to retrieve the user whose details |
186 | match the authentication information provided to $c->authenticate(). |
187 | Once it fetches the user the password is checked and if it matches the |
188 | user will be authenticated and "$c->user" will contain the user object |
189 | retrieved from the store. |
190 | |
191 | In the above case, the default realm is checked, but we could just as |
192 | easily check an alternate realm. If this were an admin login, for |
193 | example, we could authenticate on the admin realm by simply changing the |
194 | $c->authenticate() call: |
195 | |
196 | if ( $c->authenticate( { username => $user, |
197 | password => $password }, 'admin' )l ) { |
198 | $c->res->body( "hello " . $c->user->get("name") ); |
199 | } ... |
200 | |
201 | Now suppose we want to restrict the ability to edit to a user with an |
202 | 'editor' value of yes. |
203 | |
204 | The restricted action might look like this: |
205 | |
206 | sub edit : Local { |
207 | my ( $self, $c ) = @_; |
208 | |
209 | $c->detach("unauthorized") |
210 | unless $c->user_exists |
211 | and $c->user->get('editor') eq 'yes'; |
212 | |
213 | # do something restricted here |
214 | } |
215 | |
216 | (Note that if you have multiple realms, you can use |
217 | $c->user_in_realm('realmname') in place of $c->user_exists(); This will |
218 | essentially perform the same verification as user_exists, with the added |
219 | requirement that if there is a user, it must have come from the realm |
220 | specified.) |
221 | |
222 | The above example is somewhat similar to role based access control. |
223 | Catalyst::Plugin::Authentication::Store::Minimal treats the roles field |
224 | as an array of role names. Let's leverage this. Add the role |
225 | authorization plugin: |
226 | |
227 | use Catalyst qw/ |
228 | ... |
229 | Authorization::Roles |
230 | /; |
231 | |
232 | sub edit : Local { |
233 | my ( $self, $c ) = @_; |
234 | |
235 | $c->detach("unauthorized") unless $c->check_roles("edit"); |
236 | |
237 | # do something restricted here |
238 | } |
239 | |
240 | This is somewhat simpler and will work if you change your store, too, |
241 | since the role interface is consistent. |
242 | |
243 | Let's say your app grew, and you now have 10000 users. It's no longer |
244 | efficient to maintain a hash of users, so you move this data to a |
245 | database. You can accomplish this simply by installing the DBIx::Class |
246 | Store and changing your config: |
247 | |
248 | __PACKAGE__->config->{authentication} = |
249 | { |
250 | default_realm => 'members', |
251 | realms => { |
252 | members => { |
253 | credential => { |
254 | class => 'Password', |
255 | password_field => 'password', |
256 | password_type => 'clear' |
257 | }, |
258 | store => { |
259 | class => 'DBIx::Class', |
260 | user_class => 'MyApp::Users', |
261 | role_column => 'roles' |
262 | } |
263 | } |
264 | } |
265 | }; |
266 | |
267 | The authentication system works behind the scenes to load your data from |
268 | the new source. The rest of your application is completely unchanged. |
269 | |
270 | CONFIGURATION |
271 | # example |
272 | __PACKAGE__->config->{authentication} = |
273 | { |
274 | default_realm => 'members', |
275 | realms => { |
276 | members => { |
277 | credential => { |
278 | class => 'Password', |
279 | password_field => 'password', |
280 | password_type => 'clear' |
281 | }, |
282 | store => { |
283 | class => 'DBIx::Class', |
284 | user_class => 'MyApp::Users', |
285 | role_column => 'roles' |
286 | } |
287 | }, |
288 | admins => { |
289 | credential => { |
290 | class => 'Password', |
291 | password_field => 'password', |
292 | password_type => 'clear' |
293 | }, |
294 | store => { |
295 | class => '+MyApp::Authentication::Store::NetAuth', |
296 | authserver => '192.168.10.17' |
297 | } |
298 | } |
299 | |
300 | } |
301 | }; |
302 | |
303 | use_session |
304 | |
305 | Whether or not to store the user's logged in state in the session, |
306 | if the application is also using Catalyst::Plugin::Session. This |
307 | value is set to true per default. |
308 | |
309 | default_realm |
310 | |
311 | This defines which realm should be used as when no realm is provided |
312 | to methods that require a realm such as authenticate or find_user. |
313 | |
314 | realms |
315 | |
316 | This contains the series of realm configurations you want to use for |
317 | your app. The only rule here is that there must be at least one. A |
318 | realm consists of a name, which is used to reference the realm, a |
319 | credential and a store. |
320 | |
321 | Each realm config contains two hashes, one called 'credential' and |
322 | one called 'store', each of which provide configuration details to |
323 | the respective modules. The contents of these hashes is specific to |
324 | the module being used, with the exception of the 'class' element, |
325 | which tells the core Authentication module the classname to |
326 | instantiate. |
327 | |
328 | The 'class' element follows the standard Catalyst mechanism of class |
329 | specification. If a class is prefixed with a +, it is assumed to be |
330 | a complete class name. Otherwise it is considered to be a portion of |
331 | the class name. For credentials, the classname 'Password', for |
332 | example, is expanded to |
333 | Catalyst::Plugin::Authentication::Credential::Password. For stores, |
334 | the classname 'storename' is expanded to: |
335 | Catalyst::Plugin::Authentication::Store::storename. |
336 | |
337 | METHODS |
338 | authenticate( $userinfo, $realm ) |
339 | Attempts to authenticate the user using the information in the |
340 | $userinfo hash reference using the realm $realm. $realm may be |
341 | omitted, in which case the default realm is checked. |
342 | |
343 | user |
344 | Returns the currently logged in user or undef if there is none. |
345 | |
346 | user_exists |
347 | Returns true if a user is logged in right now. The difference |
348 | between user_exists and user is that user_exists will return true if |
349 | a user is logged in, even if it has not been yet retrieved from the |
350 | storage backend. If you only need to know if the user is logged in, |
351 | depending on the storage mechanism this can be much more efficient. |
352 | |
353 | user_in_realm ( $realm ) |
354 | Works like user_exists, except that it only returns true if a user |
355 | is both logged in right now and was retrieved from the realm |
356 | provided. |
357 | |
358 | logout |
359 | Logs the user out, Deletes the currently logged in user from |
360 | $c->user and the session. |
361 | |
362 | find_user( $userinfo, $realm ) |
363 | Fetch a particular users details, matching the provided user info, |
364 | from the realm specified in $realm. |
365 | |
366 | INTERNAL METHODS |
367 | These methods are for Catalyst::Plugin::Authentication INTERNAL USE |
368 | only. Please do not use them in your own code, whether application or |
369 | credential / store modules. If you do, you will very likely get the |
370 | nasty shock of having to fix / rewrite your code when things change. |
371 | They are documented here only for reference. |
372 | |
373 | set_authenticated ( $user, $realmname ) |
374 | Marks a user as authenticated. This is called from within the |
375 | authenticate routine when a credential returns a user. $realmname |
376 | defaults to 'default' |
377 | |
378 | auth_restore_user ( $user, $realmname ) |
379 | Used to restore a user from the session. In most cases this is |
380 | called without arguments to restore the user via the session. Can be |
381 | called with arguments when restoring a user from some other method. |
382 | Currently not used in this way. |
383 | |
384 | save_user_in_session ( $user, $realmname ) |
385 | Used to save the user in a session. Saves $user in session, marked |
386 | as originating in $realmname. Both arguments are required. |
387 | |
388 | auth_realms |
389 | Returns a hashref containing realmname -> realm instance pairs. |
390 | Realm instances contain an instantiated store and credential object |
391 | as the 'store' and 'credential' elements, respectively |
392 | |
393 | get_auth_realm ( $realmname ) |
394 | Retrieves the realm instance for the realmname provided. |
395 | |
396 | |
397 | |
398 | SEE ALSO |
399 | This list might not be up to date. Below are modules known to work with |
400 | the updated API of 0.10 and are therefore compatible with realms. |
401 | |
402 | User Storage Backends |
403 | Catalyst::Plugin::Authentication::Store::Minimal, |
404 | Catalyst::Plugin::Authentication::Store::DBIx::Class, |
405 | |
406 | Credential verification |
407 | Catalyst::Plugin::Authentication::Credential::Password, |
408 | |
409 | Authorization |
410 | Catalyst::Plugin::Authorization::ACL, |
411 | Catalyst::Plugin::Authorization::Roles |
412 | |
413 | Internals Documentation |
414 | Catalyst::Plugin::Authentication::Internals |
415 | |
416 | Misc |
417 | Catalyst::Plugin::Session, Catalyst::Plugin::Session::PerUser |
418 | |
419 | DON'T SEE ALSO |
420 | This module along with its sub plugins deprecate a great number of other |
421 | modules. These include Catalyst::Plugin::Authentication::Simple, |
422 | Catalyst::Plugin::Authentication::CDBI. |
423 | |
424 | At the time of writing these plugins have not yet been replaced or |
425 | updated, but should be eventually: |
426 | Catalyst::Plugin::Authentication::OpenID, |
427 | Catalyst::Plugin::Authentication::LDAP, |
428 | Catalyst::Plugin::Authentication::CDBI::Basic, |
429 | Catalyst::Plugin::Authentication::Basic::Remote. |
430 | |
431 | INCOMPATABILITIES |
432 | The realms based configuration and functionality of the 0.10 update of |
433 | Catalyst::Plugin::Authentication required a change in the API used by |
434 | credentials and stores. It has a compatibility mode which allows use of |
435 | modules that have not yet been updated. This, however, completely mimics |
436 | the older api and disables the new realm-based features. In other words |
437 | you can not mix the older credential and store modules with realms, or |
438 | realm-based configs. The changes required to update modules are |
439 | relatively minor and are covered in |
440 | Catalyst::Plugin::Authentication::Internals. We hope that most modules |
441 | will move to the compatible list above very quickly. |
442 | |
443 | COMPATIBILITY ROUTINES |
444 | In version 0.10 of Catalyst::Plugin::Authentication, the API changed. |
445 | For app developers, this change is fairly minor, but for Credential and |
446 | Store authors, the changes are significant. |
447 | |
448 | Please see the documentation in version 0.09 of |
449 | Catalyst::Plugin::Authentication for a better understanding of how the |
450 | old API functioned. |
451 | |
452 | The items below are still present in the plugin, though using them is |
453 | deprecated. They remain only as a transition tool, for those sites which |
454 | can not yet be upgraded to use the new system due to local |
455 | customizations or use of Credential / Store modules that have not yet |
456 | been updated to work with the new API. |
457 | |
458 | These routines should not be used in any application using realms |
459 | functionality or any of the methods described above. These are for |
460 | reference purposes only. |
461 | |
462 | login |
463 | This method is used to initiate authentication and user retrieval. |
464 | Technically this is part of the old Password credential module and |
465 | it still resides in the Password class. It is included here for |
466 | reference only. |
467 | |
468 | default_auth_store |
469 | Return the store whose name is 'default'. |
470 | |
471 | This is set to "$c->config->{authentication}{store}" if that value |
472 | exists, or by using a Store plugin: |
473 | |
474 | # load the Minimal authentication store. |
475 | use Catalyst qw/Authentication Authentication::Store::Minimal/; |
476 | |
477 | Sets the default store to |
478 | Catalyst::Plugin::Authentication::Store::Minimal. |
479 | |
480 | get_auth_store $name |
481 | Return the store whose name is $name. |
482 | |
483 | get_auth_store_name $store |
484 | Return the name of the store $store. |
485 | |
486 | auth_stores |
487 | A hash keyed by name, with the stores registered in the app. |
488 | |
489 | register_auth_stores %stores_by_name |
490 | Register stores into the application. |
491 | |
492 | AUTHORS |
493 | Yuval Kogman, "nothingmuch@woobling.org" |
494 | |
495 | Jay Kuri, "jayk@cpan.org" |
496 | |
497 | Jess Robinson |
498 | |
499 | David Kamholz |
500 | |
501 | COPYRIGHT & LICENSE |
502 | Copyright (c) 2005 the aforementioned authors. All rights |
503 | reserved. This program is free software; you can redistribute |
504 | it and/or modify it under the same terms as Perl itself. |
505 | |
506 | POD ERRORS |
507 | Hey! The above document had some coding errors, which are explained |
508 | below: |
509 | |
510 | Around line 672: |
511 | You can't have =items (as at line 706) unless the first thing after |
512 | the =over is an =item |
513 | |