Added overview - to clarify how the system really works.
[catagits/Catalyst-Plugin-Authentication.git] / lib / Catalyst / Plugin / Authentication / Internals.pod
1
2 =head1 NAME
3
4 Catalyst::Plugin::Authentication::Internals - All about authentication Stores and Credentials
5
6 =head1 INTRODUCTION
7
8 L<Catalyst::Plugin::Authentication|Catalyst::Plugin::Authentication> provides
9 a standard authentication interface to application developers using the
10 Catalyst framework. It is designed to allow application developers to use
11 various methods of user storage and credential verification. It is also
12 designed to provide for minimal change to the application when switching
13 between different storage and credential verification methods.
14
15 While L<Catalyst::Plugin::Authentication|Catalyst::Plugin::Authentication>
16 provides the interface to the application developer, the actual work of
17 verifying the credentials and retrieving users is delegated to separate
18 modules. These modules are called B<Credentials> and storage backends, or
19 B<Stores>, respectively. For authentication to function there must be at least
20 one credential and one store. A pairing of a store and a credential
21 is referred to as a B<Realm>. There may be any number of realms defined for an
22 application, though most applications will not require more than one or two.
23
24 The details of using this module can be found in the
25 L<Catalyst::Plugin::Authentication|Catalyst::Plugin::Authentication>
26 documentation.
27
28 What follows is an explanation of how the module functions internally and what
29 is required to implement a credential or a store.
30
31 =head1 OVERVIEW
32
33 There are two main entry points you need to be aware of when writing a store
34 or credential module. The first is initialization and the second is during the
35 actual call to the Catalyst application's authenticate method.  
36
37 A simplified description of the authentication process follows:
38
39
40
41 B<Initialization>
42
43 =over 4
44
45 B<Realm Setup> - for each realm:
46
47 =over 4
48
49 1) The Store is instantiated using new() method
50
51 2) The Credential Instantiated using new() method
52
53 3) Credential and Store objects tied to realm for use during requests
54
55 =back
56
57 =back
58
59 B<Authentication>
60
61 =over 4
62
63 C<< $c->authenticate( $userinfo, $realm ) >> called
64
65 =over 4
66
67 1) Credential / Store objects retrieved for realm provided
68
69 2) Credential's authenticate() method called
70
71 =over 4 
72
73 The realm's store object and the authinfo hash provided to the
74 credential object's authenticate call. In most cases the
75 credential object will attempt to retrieve a user from the store
76 provided by using the Store's find_user() method. It will then
77 usually compare the retrieved user's information with the
78 information provided in the $authinfo hash. This is how the
79 default 'Password' credential functions. If the credentials match,
80 the authenticate() method should return a user object.
81
82 =back
83
84 3) User object stored in session
85
86 =over 4
87
88 If the user object supports session storage, the successfully
89 authenticated user will be placed in session storage. This is done
90 by calling the store object's for_session() method, which should
91 return serialized data (IE a scalar). This serialized data is
92 passed back to the store via the from_session() method, so the
93 data should contain enough information for the store to recreate /
94 reload the user.
95
96 =back
97
98 =back
99
100 =back
101
102 B<Sessions> - Per-Request operations
103
104 =over 4
105
106 When any user-related activity occurs, and $c->authenticate has not
107 yet been called, the Catalyst::Plugin::Authentication module will
108 attempt to restore the user from the session (if one is available).
109 There is only one step in this process: 
110
111 =over 4
112
113 1) Store object's from_session() is called
114
115 =back 
116     
117 The serialized data previously returned by the store's for_session()
118 method is provided to the from_session() method. The from_session()
119 method should return a valid user object.
120
121 Note that the for_session() is only called during the original
122 $c->authenticate() call, so if changes are made to the user that need
123 to be reflected in your session data, you will want to call the
124 $c->save_user_in_session() method - which will perform the session
125 storage process again (complete with call to for_session()).
126
127 =back
128
129 More detailed information about these processes is below.
130
131 =head2 INITIALIZATION
132
133 When the authentication module is loaded, it reads it's configuration to
134 determine the realms to set up for the application and which realm is to be
135 the default. For each realm defined in the application's config,
136 L<Catalyst::Plugin::Authentication|Catalyst::Plugin::Authentication>
137 instantiates both a new credential object and a new store object. See below
138 for the details of how credentials and stores are instantiated.
139
140 B<NOTE>: The instances created will remain active throughout the entire 
141 lifetime of the application, and so should be relatively lightweight. 
142 Care should be taken to ensure that they do not grow, or retain 
143 information per request, because they will be involved in each 
144 authentication request and could therefore substantially
145 hurt memory consumption over time.  
146
147 =head2 AUTHENTICATION
148
149 When C<$c-E<gt>authenticate()> is called from within an application, the
150 objects created in the initialization process come into play.
151 C<$c-E<gt>authenticate()> takes two arguments. The first is a hash reference
152 containing all the information available about the user. This will be used to
153 locate the user in the store and verify the user's credentials. The second
154 argument is the realm to authenticate against. If the second argument is
155 omitted, the default realm is assumed. 
156
157 The main authentication module then locates the credential and store objects
158 for the realm specified and calls the credential object's C<authenticate()>
159 method. It provides three arguments, first the application object, or C<$c>,
160 then a reference to the store object, and finally the hashref provided in the
161 C<$c-E<gt>authenticate> call. The main authentication module expects the
162 return value to be a reference to a user object upon successful
163 authentication. If it receives anything aside from a reference, it is
164 considered to be an authentication failure. Upon success, the returned user is
165 marked as authenticated and the application can act accordingly, using
166 C<$c-E<gt>user> to access the authenticated user, etc.
167
168 Astute readers will note that the main
169 L<Catalyst::Plugin::Authentication|Catalyst::Plugin::Authentication> module
170 does not interact with the store in any way, save for passing a reference to
171 it to the credential. This is correct. The credential object is responsible
172 for obtaining the user from the provided store using information from the
173 userinfo hashref and/or data obtained during the credential verification
174 process.
175
176 =head1 WRITING A STORE
177
178 There are two parts to an authentication store, the store object and the user object.
179
180 =head2 STORAGE BACKEND
181
182 Writing a store is actually quite simple.  There are only five methods
183 that must be implemented. They are:
184
185     new()           - instantiates the store object
186     find_user()     - locates a user using data contained in the hashref
187     for_session()   - prepares a user to be stored in the session
188     from_session()  - does any restoration required when obtaining a user from the session
189     user_supports() - provides information about what the user object supports
190
191 =head3 STORE METHODS
192
193 =over 4
194
195 =item new( $config, $app )
196
197 The C<new()> method is called only once, during the setup process of
198 L<Catalyst::Plugin::Authentication|Catalyst::Plugin::Authentication>. The
199 first argument, C<$config>, is a hash reference containing the configuration
200 information for the store module. The second argument is a reference to the
201 Catalyst application.
202
203 Note that when new() is called, Catalyst has not yet loaded 
204 the various controller and model classes, nor is it definite
205 that other plugins have been loaded, so your new() method 
206 must not rely on any of those being present.  If any of 
207 this is required for your store to function, you should
208 defer that part of initialization until the first method call. 
209
210 The C<new()> method should return a blessed reference to your store object.
211
212 =item find_user( $authinfo, $c ) 
213
214 This is the workhorse of any authentication store. It's job is to take the
215 information provided to it via the C<$authinfo> hashref and locate the user
216 that matches it. It should return a reference to a user object. A return value
217 of anything else is considered to mean no user was found that matched the
218 information provided.
219
220 How C<find_user()> accomplishes it's job is entirely up to you, the author, as
221 is what $authinfo is required to contain.  Many stores will simply use a 
222 username element in $authinfo to locate the user, but more advanced functionality
223 is possible and you may bend the $authinfo to your needs.  Be aware, however, that
224 both Credentials and Stores usually work with the same $authinfo hash, so take 
225 care to avoid overlapping element names.
226
227 Please note that this routine may be called numerous times in various
228 circumstances, and that a successful match for a user here does B<NOT>
229 necessarily constitute successful authentication. Your store class should
230 never assume this and in most cases C<$c> B<should not be modified> by your
231 store object.
232
233 =item for_session( $c, $user )
234
235 This method is responsible for preparing a user object for storage in the session.
236 It should return information that can be placed in the session and later used to 
237 restore a user object (using the C<from_session()> method).  It should therefore
238 ensure that whatever information provided can be used by the C<from_session()>
239 method to locate the unique user being saved.  Note that there is no guarantee
240 that the same Catalyst instance will receive both the C<for_session()> and 
241 C<from_session()> calls.  You should take care to provide information that can
242 be used to restore a user, regardless of the current state of the application. 
243 A good rule of thumb is that if C<from_session()> can revive the user with the
244 given information even if the Catalyst application has just started up, you are 
245 in good shape.
246
247 =item from_session( $c, $frozenuser )
248
249 This method is called whenever a user is being restored from the session.  
250 C<$frozenuser> contains the information that was stored in the session for the user.
251 This will under normal circumstances be the exact data your store returned from 
252 the previous call to C<for_session()>.  C<from_session()> should return a valid
253 user object.
254
255 =item user_supports( $feature, ...  )
256
257 This method allows credentials and other objects to inquire as to what the
258 underlying user object is capable of. This is pretty-well free-form and the
259 main purpose is to allow graceful integration with credentials and
260 applications that may provide advanced functionality based on whether the
261 underlying user object can do certain things. In most cases you will want to
262 pass this directly to the underlying user class' C<supports> method. Note that 
263 this is used as a B<class> method against the user class and therefore must 
264 be able to function without an instantiated user object. 
265
266 =back
267
268 =head2 USER OBJECT
269
270 The user object is an important piece of your store module. It will be the
271 part of the system that the application developer will interact with most. As
272 such, the API for the user object is very rigid. All user objects B<MUST>
273 inherit from
274 L<Catalyst::Plugin::Authentication::User|Catalyst::Plugin::Authentication::User>.
275
276 =head3 USER METHODS
277
278 The routines required by the
279 L<Catalyst::Plugin::Authentication|Catalyst::Plugin::Authentication> plugin
280 are below. Note that of these, only get_object is strictly required, as the
281 L<Catalyst::Plugin::Authentication::User|Catalyst::Plugin::Authentication::User>
282 base class contains reasonable implementations of the rest. If you do choose
283 to implement only the C<get_object()> routine, please read the base class code
284 and documentation so that you fully understand how the other routines will be
285 implemented for you.
286
287 Also, your user object can implement whatever additional methods you require
288 to provide the functionality you need. So long as the below are implemented,
289 and you don't overlap the base class' methods with incompatible routines, you
290 should experience no problems.
291
292 =over 4
293
294 =item id( )
295
296 The C<id()> method should return a unique id (scalar) that can be used to 
297 retreive this user from the store.  Often this will be provided to the store's
298 C<find_user()> routine as C<id =E<gt> $user-E<gt>id> so you should ensure that your 
299 store's C<find_user()> can cope with that. 
300
301 =item supports( $feature, $subfeature ... )
302
303 This method checks to see if the user class supports a particular feature.  It
304 is implemented such that each argument provides a subfeature of the previous 
305 argument. In other words, passing 'foo', 'bar'  would return true if the user
306 supported the 'foo' feature, and the 'bar' feature of 'foo'.   This is implemented
307 in Catalyst::Plugin::Authentication::User, so if your class inherits from that, you
308 do not need to implement this and can instead implement supported_features(). 
309
310 B<Note:> If you want the authentication module to be able to save your user in
311 the session you must return true when presented with the feature 'session'.
312
313 =item supported_features( )
314
315 This method should return a hashref of features supported by the user class.
316 This is for more flexible integration with some Credentials / applications. It
317 is not required that you support anything, and returning C<undef> is perfectly
318 acceptable and in most cases what you will do.
319
320 =item get( $fieldname )
321
322 This method should return the value of the field matching fieldname provided,
323 or undef if there is no field matching that fieldname. In most cases this will
324 access the underlying storage mechanism for the user data and return the
325 information. This is used as a standard method of accessing an authenticated
326 user's data, and MUST be implemented by all user objects.  
327
328 B<Note>: There is no equivalent 'set' method. Each user class is 
329 likely to vary greatly in how data must be saved and it is 
330 therefore impractical to try to provide a standard way of 
331 accomplishing it. When an application developer needs to save 
332 data, they should obtain the underlying object / data by 
333 calling get_object, and work with it directly.
334     
335
336 =item get_object( )
337
338 This method returns the underlying user object. If your user object is backed
339 by another object class, this method should return that underlying object.
340 This allows the application developer to obtain an editable object. Generally
341 speaking this will only be done by developers who know what they are doing and
342 require advanced functionality which is either unforeseen or inconsistent
343 across user classes. If your object is not backed by another class, or you
344 need to provide additional intermediate functionality, it is perfectly
345 reasonable to return C<$self>.
346
347 =back 
348
349
350 =head1 WRITING A CREDENTIAL
351
352 Compared to writing a store, writing a credential is very simple.  There is only
353 one class to implement, and it consists of only two required routines. They are:
354
355     new()           - instantiates the credential object
356     authenticate()  - performs the authentication and returns a user object
357     
358 =head2 CREDENTIAL METHODS
359
360 =over 4
361
362 =item new( $config, $app )
363
364 Like the Store method of the same name, the C<new()> method is called only 
365 once, during the setup process of 
366 L<Catalyst::Plugin::Authentication|Catalyst::Plugin::Authentication>. The
367 first argument, C<$config>, is a hash reference containing the configuration
368 information for the credential module. The second argument is a reference 
369 to the Catalyst application.
370
371 Again, when the credential's new() method is called, Catalyst 
372 has not yet loaded the various controller and model classes. 
373
374 The new method should perform any necessary setup required and instantiate 
375 your credential object.  It should return your instantiated credential.
376
377 =item authenticate( $c, $authstore, $authinfo )
378
379 This is the workhorse of your credential.  When $c->authenticate() is called
380 the L<Catalyst::Plugin::Authentication|Catalyst::Plugin::Authentication> module retrieves the
381 store object from the realm and passes it, along with the $authinfo hash
382 to your credential's authenticate method.  Your module should use the 
383 $authinfo hash to obtain the user from the store passed, and then perform 
384 any credential verification steps necessary to authenticate the user.  This
385 method should return the user object returned by the authentication store if
386 credential verification succeeded.  It should return undef on failure.  
387
388 How your credential module performs the credential verification is entirely
389 up to you.  In most cases, the credential will retrieve a user from the store
390 first (using the stores find_user() method), and then validate the user's 
391 information.  However, this does not have to be the case.  
392
393 It is perfectly acceptable for your credential to perform other tasks prior to
394 attempting to retrieve the user from the store. It may also make sense for
395 your credential to perform activities which help to locate the user in
396 question, for example, finding a user id based on an encrypted token.
397 In these scenarios, the $authinfo hash passed to the store's find_user()
398 can be different than that which is passed in to $c->authenticate(). Once
399 again this is perfectly acceptable if it makes sense for your credential,
400 though you are strongly advised to note this behavior clearly in your 
401 credential's documentation - as application authors are almost 
402 certainly expecting the user to be found using the information provided 
403 to $c->authenticate().
404
405 Look at the L<Catalyst::Plugin::Authentication::Credential::Password|Catalyst::Plugin::Authentication::Credential::Password>
406 module source to see this in action.  In order to avoid possible 
407 mismatches between the encrypted and unencrypted passwords, the password 
408 credential actually removes the provided password from the authinfo 
409 array.  It does this because, in many cases, the store's password 
410 field will be encrypted in some way, and the password passed to 
411 $c->authenticate is almost certainly in plaintext. 
412
413 NOTE: You should always assume that a store is going to use all
414 the information passed to it to locate the user in question. 
415 If there are fields in the $authinfo hash that you are sure
416 are specific to your credential, you may want to consider 
417 removing them before user retrieval.  A better solution is to
418 place those arguments that are specific to your credential 
419 within their own subhash named after your module.
420  
421 The L<Catalyst::Plugin::Authentication::Store::DBIx::Class|Catalyst::Plugin::Authentication::Store::DBIx::Class> module does this
422 in order to encapsulate arguments intended specifically for 
423 that module. See the L<Catalyst::Plugin::Authentication::Store::DBIx::Class::User|Catalyst::Plugin::Authentication::Store::DBIx::Class::User>
424 source for details.
425
426 =back
427
428 =head1 AUTHORS
429
430 Jay Kuri, C<jayk@cpan.org>
431
432 =head1 COPYRIGHT & LICENSE
433
434 Copyright (c) 2005 the aforementioned authors. All rights
435 reserved. This program is free software; you can redistribute
436 it and/or modify it under the same terms as Perl itself.
437
438 =cut
439
440