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