Commit | Line | Data |
649de93b |
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 |
45c7644b |
20 | one credential and one store. A pairing of a store and a credential |
649de93b |
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 | =head2 INITIALIZATION |
38 | |
39 | When the authentication module is loaded, it reads it's configuration to |
40 | determine the realms to set up for the application and which realm is to be |
41 | the default. For each realm defined in the application's config, |
42 | L<Catalyst::Plugin::Authentication|Catalyst::Plugin::Authentication> |
43 | instantiates both a new credential object and a new store object. See below |
44 | for the details of how credentials and stores are instantiated. |
45 | |
46 | NOTE: The instances created will remain active throughout the entire |
47 | lifetime of the application, and so should be relatively lightweight. |
48 | Care should be taken to ensure that they do not grow, or retain |
49 | information per request, because they will be involved in each |
50 | authentication request and could therefore substantially |
51 | hurt memory consumption over time. |
52 | |
53 | =head2 AUTHENTICATION |
54 | |
55 | When C<$c-E<gt>authenticate()> is called from within an application, the |
56 | objects created in the initialization process come into play. |
57 | C<$c-E<gt>authenticate()> takes two arguments. The first is a hash reference |
58 | containing all the information available about the user. This will be used to |
59 | locate the user in the store and verify the user's credentials. The second |
60 | argument is the realm to authenticate against. If the second argument is |
61 | omitted, the default realm is assumed. |
62 | |
63 | The main authentication module then locates the credential and store objects |
64 | for the realm specified and calls the credential object's C<authenticate()> |
65 | method. It provides three arguments, first the application object, or C<$c>, |
66 | then a reference to the store object, and finally the hashref provided in the |
67 | C<$c-E<gt>authenticate> call. The main authentication module expects the |
68 | return value to be a reference to a user object upon successful |
69 | authentication. If it receives anything aside from a reference, it is |
70 | considered to be an authentication failure. Upon success, the returned user is |
71 | marked as authenticated and the application can act accordingly, using |
72 | C<$c-E<gt>user> to access the authenticated user, etc. |
73 | |
74 | Astute readers will note that the main |
75 | L<Catalyst::Plugin::Authentication|Catalyst::Plugin::Authentication> module |
76 | does not interact with the store in any way, save for passing a reference to |
77 | it to the credential. This is correct. The credential object is responsible |
78 | for obtaining the user from the provided store using information from the |
79 | userinfo hashref and/or data obtained during the credential verification |
80 | process. |
81 | |
82 | =head1 WRITING A STORE |
83 | |
45c7644b |
84 | There are two parts to an authentication store, the store object and the user object. |
649de93b |
85 | |
86 | =head2 STORAGE BACKEND |
87 | |
45c7644b |
88 | Writing a store is actually quite simple. There are only five methods |
649de93b |
89 | that must be implemented. They are: |
90 | |
91 | new() - instantiates the store object |
92 | find_user() - locates a user using data contained in the hashref |
93 | for_session() - prepares a user to be stored in the session |
94 | from_session() - does any restoration required when obtaining a user from the session |
95 | user_supports() - provides information about what the user object supports |
96 | |
97 | =head3 STORE METHODS |
98 | |
99 | =over 4 |
100 | |
101 | =item new( $config, $app ) |
102 | |
103 | The C<new()> method is called only once, during the setup process of |
104 | L<Catalyst::Plugin::Authentication|Catalyst::Plugin::Authentication>. The |
105 | first argument, C<$config>, is a hash reference containing the configuration |
106 | information for the store module. The second argument is a reference to the |
107 | Catalyst application. |
108 | |
c5fbff80 |
109 | Note that when new() is called, Catalyst has not yet loaded |
110 | the various controller and model classes, nor is it definite |
111 | that other plugins have been loaded, so your new() method |
112 | must not rely on any of those being present. If any of |
113 | this is required for your store to function, you should |
649de93b |
114 | defer that part of initialization until the first method call. |
4b69b736 |
115 | |
649de93b |
116 | The C<new()> method should return a blessed reference to your store object. |
117 | |
118 | =item find_user( $authinfo, $c ) |
119 | |
120 | This is the workhorse of any authentication store. It's job is to take the |
121 | information provided to it via the C<$authinfo> hashref and locate the user |
122 | that matches it. It should return a reference to a user object. A return value |
123 | of anything else is considered to mean no user was found that matched the |
124 | information provided. |
125 | |
126 | How C<find_user()> accomplishes it's job is entirely up to you, the author, as |
127 | is what $authinfo is required to contain. Many stores will simply use a |
128 | username element in $authinfo to locate the user, but more advanced functionality |
129 | is possible and you may bend the $authinfo to your needs. Be aware, however, that |
c5fbff80 |
130 | both Credentials and Stores usually work with the same $authinfo hash, so take |
131 | care to avoid overlapping element names. |
649de93b |
132 | |
133 | Please note that this routine may be called numerous times in various |
134 | circumstances, and that a successful match for a user here does B<NOT> |
135 | necessarily constitute successful authentication. Your store class should |
136 | never assume this and in most cases C<$c> B<should not be modified> by your |
137 | store object. |
138 | |
139 | =item for_session( $c, $user ) |
140 | |
141 | This method is responsible for preparing a user object for storage in the session. |
142 | It should return information that can be placed in the session and later used to |
143 | restore a user object (using the C<from_session()> method). It should therefore |
144 | ensure that whatever information provided can be used by the C<from_session()> |
145 | method to locate the unique user being saved. Note that there is no guarantee |
146 | that the same Catalyst instance will receive both the C<for_session()> and |
147 | C<from_session()> calls. You should take care to provide information that can |
148 | be used to restore a user, regardless of the current state of the application. |
149 | A good rule of thumb is that if C<from_session()> can revive the user with the |
150 | given information even if the Catalyst application has just started up, you are |
151 | in good shape. |
152 | |
153 | =item from_session( $c, $frozenuser ) |
154 | |
155 | This method is called whenever a user is being restored from the session. |
156 | C<$frozenuser> contains the information that was stored in the session for the user. |
157 | This will under normal circumstances be the exact data your store returned from |
158 | the previous call to C<for_session()>. C<from_session()> should return a valid |
159 | user object. |
160 | |
161 | =item user_supports( $feature, ... ) |
162 | |
163 | This method allows credentials and other objects to inquire as to what the |
164 | underlying user object is capable of. This is pretty-well free-form and the |
165 | main purpose is to allow graceful integration with credentials and |
166 | applications that may provide advanced functionality based on whether the |
167 | underlying user object can do certain things. In most cases you will want to |
168 | pass this directly to the underlying user class' C<supports> method. Note that |
169 | this is used as a B<class> method against the user class and therefore must |
170 | be able to function without an instantiated user object. |
171 | |
172 | =back |
173 | |
174 | =head2 USER OBJECT |
175 | |
176 | The user object is an important piece of your store module. It will be the |
177 | part of the system that the application developer will interact with most. As |
178 | such, the API for the user object is very rigid. All user objects B<MUST> |
179 | inherit from |
180 | L<Catalyst::Plugin::Authentication::User|Catalyst::Plugin::Authentication::User>. |
181 | |
182 | =head3 USER METHODS |
183 | |
184 | The routines required by the |
185 | L<Catalyst::Plugin::Authentication|Catalyst::Plugin::Authentication> plugin |
186 | are below. Note that of these, only get_object is strictly required, as the |
187 | L<Catalyst::Plugin::Authentication::User|Catalyst::Plugin::Authentication::User> |
188 | base class contains reasonable implementations of the rest. If you do choose |
4b69b736 |
189 | to implement only the C<get_object()> routine, please read the base class code |
190 | and documentation so that you fully understand how the other routines will be |
649de93b |
191 | implemented for you. |
192 | |
193 | Also, your user object can implement whatever additional methods you require |
194 | to provide the functionality you need. So long as the below are implemented, |
195 | and you don't overlap the base class' methods with incompatible routines, you |
196 | should experience no problems. |
197 | |
198 | =over 4 |
199 | |
200 | =item id( ) |
201 | |
202 | The C<id()> method should return a unique id (scalar) that can be used to |
203 | retreive this user from the store. Often this will be provided to the store's |
204 | C<find_user()> routine as C<id =E<gt> $user-E<gt>id> so you should ensure that your |
205 | store's C<find_user()> can cope with that. |
206 | |
207 | =item supports_features( ) |
208 | |
209 | This method should return a hashref of 'extra' features supported. This is for |
210 | more flexible integration with some Credentials / applications. It is not |
211 | required that you support anything, and returning C<undef> is perfectly |
212 | acceptable and in most cases what you will do. |
213 | |
214 | =item get( $fieldname ) |
215 | |
216 | This method should return the value of the field matching fieldname provided, |
217 | or undef if there is no field matching that fieldname. In most cases this will |
218 | access the underlying storage mechanism for the user data and return the |
219 | information. This is used as a standard method of accessing an authenticated |
220 | user's data, and MUST be implemented by all user objects. |
221 | |
c5fbff80 |
222 | Note: There is no equivalent 'set' method. Each user class is |
223 | likely to vary greatly in how data must be saved and it is |
224 | therefore impractical to try to provide a standard way of |
225 | accomplishing it. When an application developer needs to save |
226 | data, they should obtain the underlying object / data by |
227 | calling get_object, and work with it directly. |
649de93b |
228 | |
229 | |
230 | =item get_object( ) |
231 | |
232 | This method returns the underlying user object. If your user object is backed |
233 | by another object class, this method should return that underlying object. |
234 | This allows the application developer to obtain an editable object. Generally |
235 | speaking this will only be done by developers who know what they are doing and |
236 | require advanced functionality which is either unforeseen or inconsistent |
237 | across user classes. If your object is not backed by another class, or you |
238 | need to provide additional intermediate functionality, it is perfectly |
239 | reasonable to return C<$self>. |
240 | |
241 | =back |
242 | |
243 | |
4b69b736 |
244 | =head1 WRITING A CREDENTIAL |
245 | |
c5fbff80 |
246 | Compared to writing a store, writing a credential is very simple. There is only |
247 | one class to implement, and it consists of only two required routines. They are: |
248 | |
249 | new() - instantiates the credential object |
250 | authenticate() - performs the authentication and returns a user object |
251 | |
252 | =head2 CREDENTIAL METHODS |
253 | |
254 | =over 4 |
255 | |
256 | =item new( $config, $app ) |
257 | |
258 | Like the Store method of the same name, the C<new()> method is called only |
259 | once, during the setup process of |
260 | L<Catalyst::Plugin::Authentication|Catalyst::Plugin::Authentication>. The |
261 | first argument, C<$config>, is a hash reference containing the configuration |
262 | information for the credential module. The second argument is a reference |
263 | to the Catalyst application. |
264 | |
265 | Again, when the credential's new() method is called, Catalyst |
266 | has not yet loaded the various controller and model classes. |
267 | |
268 | The new method should perform any necessary setup required and instantiate |
269 | your credential object. It should return your instantiated credential. |
270 | |
271 | =item authenticate( $c, $authstore, $authinfo ) |
272 | |
273 | This is the workhorse of your credential. When $c->authenticate() is called |
274 | the L<Catalyst::Plugin::Authentication|Catalyst::Plugin::Authentication> module retrieves the |
275 | store object from the realm and passes it, along with the $authinfo hash |
276 | to your credential's authenticate method. Your module should use the |
277 | $authinfo hash to obtain the user from the store passed, and then perform |
278 | any credential verification steps necessary to authenticate the user. This |
279 | method should return the user object returned by the authentication store if |
280 | credential verification succeeded. It should return undef on failure. |
281 | |
282 | How your credential module performs the credential verification is entirely |
283 | up to you. In most cases, the credential will retrieve a user from the store |
284 | first (using the stores find_user() method), and then validate the user's |
285 | information. However, this does not have to be the case. |
286 | |
287 | It is perfectly acceptable for your credential to perform other tasks prior to |
288 | attempting to retrieve the user from the store. It may also make sense for |
289 | your credential to perform activities which help to locate the user in |
290 | question, for example, finding a user id based on an encrypted token. |
291 | In these scenarios, the $authinfo hash passed to the store's find_user() |
292 | can be different than that which is passed in to $c->authenticate(). Once |
293 | again this is perfectly acceptable if it makes sense for your credential, |
294 | though you are strongly advised to note this behavior clearly in your |
295 | credential's documentation - as application authors are almost |
296 | certainly expecting the user to be found using the information provided |
297 | to $c->authenticate(). |
298 | |
299 | Look at the L<Catalyst::Plugin::Authentication::Credential::Password|Catalyst::Plugin::Authentication::Credential::Password> |
300 | module source to see this in action. In order to avoid possible |
301 | mismatches between the encrypted and unencrypted passwords, the password |
302 | credential actually removes the provided password from the authinfo |
303 | array. It does this because, in many cases, the store's password |
304 | field will be encrypted in some way, and the password passed to |
305 | $c->authenticate is almost certainly in plaintext. |
306 | |
307 | NOTE: You should always assume that a store is going to use all |
308 | the information passed to it to locate the user in question. |
309 | If there are fields in the $authinfo hash that you are sure |
310 | are specific to your credential, you may want to consider |
311 | removing them before user retrieval. A better solution is to |
312 | place those arguments that are specific to your credential |
313 | within their own subhash named after your module. |
314 | |
315 | The L<Catalyst::Plugin::Authentication::Store::DBIx::Class|Catalyst::Plugin::Authentication::Store::DBIx::Class> module does this |
316 | in order to encapsulate arguments intended specifically for |
317 | that module. See the L<Catalyst::Plugin::Authentication::Store::DBIx::Class::User|Catalyst::Plugin::Authentication::Store::DBIx::Class::User> |
318 | source for details. |
319 | |
320 | =back |
321 | |
322 | =head1 AUTHORS |
323 | |
324 | Jay Kuri, C<jayk@cpan.org> |
325 | |
326 | =head1 COPYRIGHT & LICENSE |
327 | |
328 | Copyright (c) 2005 the aforementioned authors. All rights |
329 | reserved. This program is free software; you can redistribute |
330 | it and/or modify it under the same terms as Perl itself. |
331 | |
332 | =cut |
333 | |
334 | |