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