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