1CGI::Ex::Auth(3) User Contributed Perl Documentation CGI::Ex::Auth(3)
2
3
4
6 CGI::Ex::Auth - Handle logins nicely.
7
9 use CGI::Ex::Auth;
10
11 ### authorize the user
12 my $auth = CGI::Ex::Auth->get_valid_auth({
13 get_pass_by_user => \&get_pass_by_user,
14 });
15
16
17 sub get_pass_by_user {
18 my $auth = shift;
19 my $user = shift;
20 my $pass = some_way_of_getting_password($user);
21 return $pass;
22 }
23
24 ### OR - if you are using a OO based CGI or Application
25
26 sub require_authentication {
27 my $self = shift;
28
29 return $self->{'auth'} = CGI::Ex::Auth->get_valid_auth({
30 get_pass_by_user => sub {
31 my ($auth, $user) = @_;
32 return $self->get_pass($user);
33 },
34 });
35 }
36
37 sub get_pass {
38 my ($self, $user) = @_;
39 return $self->loopup_and_cache_pass($user);
40 }
41
43 CGI::Ex::Auth allows for auto-expiring, safe and easy web based logins.
44 Auth uses javascript modules that perform MD5 hashing to cram the
45 password on the client side before passing them through the internet.
46
47 For the stored cookie you can choose to use simple cram mechanisms,
48 secure hash cram tokens, auto expiring logins (not cookie based), and
49 Crypt::Blowfish protection. You can also choose to keep passwords
50 plaintext and to use perl's crypt for testing passwords. Or you can
51 completely replace the cookie parsing/generating and let Auth handle
52 requesting, setting, and storing the cookie.
53
54 A theoretical downside to this module is that it does not use a session
55 to preserve state so get_pass_by_user has to happen on every request
56 (any authenticated area has to verify authentication each time - unless
57 the verify_token method is completely overridden). In theory you
58 should be checking the password everytime a user makes a request to
59 make sure the password is still valid. A definite plus is that you
60 don't need to use a session if you don't want to. It is up to the
61 interested reader to add caching to the get_pass_by_user method.
62
63 In the end, the only truly secure login method is across an https
64 connection. Any connection across non-https (non-secure) is
65 susceptible to cookie hijacking or tcp hijacking - though the
66 possibility of this is normally small and typically requires access to
67 a machine somewhere in your TCP chain. If in doubt - you should try to
68 use https - but even then you need to guard the logged in area against
69 cross-site javascript exploits. A discussion of all security issues is
70 far beyond the scope of this documentation.
71
73 "new"
74 Constructor. Takes a hashref of properties as arguments.
75
76 Many of the methods which may be overridden in a subclass, or may
77 be passed as properties to the new constuctor such as in the
78 following:
79
80 CGI::Ex::Auth->new({
81 get_pass_by_user => \&my_pass_sub,
82 key_user => 'my_user',
83 key_pass => 'my_pass',
84 login_header => \"<h1>My Login</h1>",
85 });
86
87 The following methods will look for properties of the same name.
88 Each of these will be described separately.
89
90 cgix
91 cleanup_user
92 cookie_domain
93 cookie_secure
94 cookie_path
95 cookies
96 expires_min
97 form
98 form_name
99 get_pass_by_user
100 js_uri_path
101 key_cookie
102 key_expires_min
103 key_logout
104 key_pass
105 key_redirect
106 key_save
107 key_time
108 key_user
109 key_verify
110 key_loggedout
111 bounce_on_logout
112 login_footer
113 login_form
114 login_header
115 login_script
116 login_template
117 handle_success
118 handle_failure
119 success_hook
120 failure_hook
121 logout_hook
122 no_cookie_verify
123 path_info
124 script_name
125 secure_hash_keys
126 template_args
127 template_include_path
128 template_obj
129 text_user
130 text_pass
131 text_save
132 text_submit
133 hide_save
134 use_base64
135 use_blowfish
136 use_crypt
137 use_plaintext
138 use_session_cookie
139 verify_token
140 verify_payload
141 verify_user
142
143 "generate_token"
144 Takes either an auth_data object from a auth_data returned by
145 verify_token, or a hashref of arguments.
146
147 Possible arguments are:
148
149 user - the username we are generating the token for
150 real_pass - the password of the user (if use_plaintext is false
151 and use_crypt is false, the password can be an md5sum
152 of the user's password)
153 use_blowfish - indicates that we should use Crypt::Blowfish to protect
154 the generated token. The value of this argument is used
155 as the key. Default is false.
156 use_base64 - indicates that we should use Base64 encoding to protect
157 the generated token. Default is true. Will not be
158 used if use_blowfish is true.
159 use_plaintext - indicates that we should keep the password in plaintext
160 use_crypt - also indicates that we should keep the password in plaintext
161 expires_min - says how many minutes until the generated token expires.
162 Values <= 0 indicate to not ever expire. Used only on cram
163 types.
164 payload - a payload that will be passed to generate_payload and then
165 will be added to cram type tokens. It cannot contain a /.
166 prefer_simple_cram
167 - If the secure_hash_keys method returns keys, and it is a non-plaintext
168 token, generate_token will create a secure_hash_cram. Set
169 this value to true to tell it to use a simple_cram. This
170 is generally only useful in testing.
171
172 The following are types of tokens that can be generated by
173 generate_token. Each type includes pseudocode and a sample of a
174 generated that token.
175
176 plaintext:
177 user := "paul"
178 real_pass := "123qwe"
179 token := join("/", user, real_pass);
180
181 use_base64 := 0
182 token == "paul/123qwe"
183
184 use_base64 := 1
185 token == "cGF1bC8xMjNxd2U="
186
187 use_blowfish := "foobarbaz"
188 token == "6da702975190f0fe98a746f0d6514683"
189
190 Notes: This token will be used if either use_plaintext or use_crypt is set.
191 The real_pass can also be the md5_sum of the password. If real_pass is an md5_sum
192 of the password but the get_pass_by_user hook returns the crypt'ed password, the
193 token will not be able to be verified.
194
195 simple_cram:
196 user := "paul"
197 real_pass := "123qwe"
198 server_time := 1148512991 # a time in seconds since epoch
199 expires_min := 6 * 60
200 payload := "something"
201
202 md5_pass := md5_sum(real_pass) # if it isn't already a 32 digit md5 sum
203 str := join("/", user, server_time, expires_min, payload, md5_pass)
204 md5_str := md5(sum_str)
205 token := join("/", user, server_time, expires_min, payload, md5_str)
206
207 use_base64 := 0
208 token == "paul/1148512991/360/something/16d0ba369a4c9781b5981eb89224ce30"
209
210 use_base64 := 1
211 token == "cGF1bC8xMTQ4NTEyOTkxLzM2MC9zb21ldGhpbmcvMTZkMGJhMzY5YTRjOTc4MWI1OTgxZWI4OTIyNGNlMzA="
212
213 Notes: use_blowfish is available as well
214
215 secure_hash_cram:
216 user := "paul"
217 real_pass := "123qwe"
218 server_time := 1148514034 # a time in seconds since epoch
219 expires_min := 6 * 60
220 payload := "something"
221 secure_hash := ["aaaa", "bbbb", "cccc", "dddd"]
222 rand1 := 3 # int(rand(length(secure_hash)))
223 rand2 := 39163 # int(rand(100000))
224
225 md5_pass := md5_sum(real_pass) # if it isn't already a 32 digit md5 sum
226
227 sh_str1 := join(".", "sh", secure_hash[rand1], rand2)
228 sh_str2 := join(".", "sh", rand1, rand2)
229 str := join("/", user, server_time, expires_min, payload, md5_pass, sh_str1)
230 md5_str := md5(sum_str)
231 token := join("/", user, server_time, expires_min, payload, md5_str, sh_str2)
232
233 use_base64 := 0
234 token == "paul/1148514034/360/something/06db2914c9fd4e11499e0652bcf67dae/sh.3.39163"
235
236 Notes: use_blowfish is available as well. The secure_hash keys need to be set in the
237 "secure_hash_keys" property of the CGI::Ex::Auth object.
238
239 "get_valid_auth"
240 Performs the core logic. Returns an auth object on successful
241 login. Returns false on errored login (with the details of the
242 error stored in $@). If a false value is returned, execution of
243 the CGI should be halted. get_valid_auth WILL NOT automatically
244 stop execution.
245
246 $auth->get_valid_auth || exit;
247
248 Optionally, the class and a list of arguments may be passed. This
249 will create a new object using the passed arguments, and then run
250 get_valid_auth.
251
252 CGI::Ex::Auth->get_valid_auth({key_user => 'my_user'}) || exit;
253
254 "check_valid_auth"
255 Runs get_valid_auth with login_print and location_bounce set to do
256 nothing. This allows for obtaining login data without forcing an
257 html login page to appear.
258
259 "login_print"
260 Called if login errored. Defaults to printing a very basic (but
261 adequate) page loaded from login_template..
262
263 You will want to override it with a template from your own system.
264 The hook that is called will be passed the step to print (currently
265 only "get_login_info" and "no_cookies"), and a hash containing the
266 form variables as well as the following:
267
268 "login_hash_common"
269 Passed to the template swapped during login_print.
270
271 %$form, # any keys passed to the login script
272 error # The text "Login Failed" if a login occurred
273 login_data # A login data object if they failed authentication.
274 key_user # $self->key_user, # the username fieldname
275 key_pass # $self->key_pass, # the password fieldname
276 key_time # $self->key_time, # the server time field name
277 key_save # $self->key_save, # the save password checkbox field name
278 key_redirect # $self->key_redirect, # the redirect fieldname
279 form_name # $self->form_name, # the name of the form
280 script_name # $self->script_name, # where the server will post back to
281 path_info # $self->path_info, # $ENV{PATH_INFO} if any
282 md5_js_path # $self->js_uri_path ."/CGI/Ex/md5.js", # script for cramming
283 $self->key_user # $data->{'user'}, # the username (if any)
284 $self->key_pass # '', # intentional blankout
285 $self->key_time # $self->server_time, # the server's time
286 $self->key_expires_min # $self->expires_min # how many minutes crams are valid
287 text_user # $self->text_user # template text Username:
288 text_pass # $self->text_pass # template text Password:
289 text_save # $self->text_save # template text Save Password ?
290 text_submit # $self->text_submit # template text Login
291 hide_save # $self->hide_save # 0
292
293 "bounce_on_logout"
294 Default 0. If true, will location bounce to script returned by
295 logout_redirect passing the key key_logout. If false, will simply
296 show the login screen.
297
298 "key_loggedout"
299 Key to bounce with in the form during a logout should
300 bounce_on_logout return true. Default is "loggedout".
301
302 "key_logout"
303 If the form hash contains a true value in this field name, the
304 current user will be logged out. Default is "cea_logout".
305
306 "key_cookie"
307 The name of the auth cookie. Default is "cea_user".
308
309 "key_verify"
310 A field name used during a bounce to see if cookies exist. Default
311 is "cea_verify".
312
313 "key_user"
314 The form field name used to pass the username. Default is
315 "cea_user".
316
317 "key_pass"
318 The form field name used to pass the password. Default is
319 "cea_pass".
320
321 "key_save"
322 Works in conjunction with key_expires_min. If key_save is true,
323 then the cookie will be set to be saved for longer than the current
324 session (If it is a plaintext variety it will be given a 20 year
325 life rather than being a session cookie. If it is a cram variety,
326 the expires_min portion of the cram will be set to -1). If it is
327 set to false, the cookie will be available only for the session (If
328 it is a plaintext variety, the cookie will be session based and
329 will be removed on the next loggout. If it is a cram variety then
330 the cookie will only be good for expires_min minutes.
331
332 Default is "cea_save".
333
334 "key_expires_min"
335 The name of the form field that contains how long cram type cookies
336 will be valid if key_save contains a false value.
337
338 Default key name is "cea_expires_min". Default field value is 6 *
339 60 (six hours).
340
341 This value will have no effect when use_plaintext or use_crypt is
342 set.
343
344 A value of -1 means no expiration.
345
346 "failed_sleep"
347 Number of seconds to sleep if the passed tokens are invalid. Does
348 not apply if validation failed because of expired tokens. Default
349 value is 0. Setting to 0 disables any sleeping.
350
351 "form_name"
352 The name of the html login form to attach the javascript to.
353 Default is "cea_form".
354
355 "verify_token"
356 This method verifies the token that was passed either via the form
357 or via cookies. It will accept plaintext or crammed tokens (A
358 listing of the available algorithms for creating tokes is listed
359 below). It also allows for armoring the token with base64
360 encoding, or using blowfish encryption. A listing of creating
361 these tokens can be found under generate_token.
362
363 "parse_token"
364 Used by verify_token to remove armor from the passed tokens and
365 split the token into its parts. Returns true if it was able to
366 parse the passed token.
367
368 "cleanup_user"
369 Called by verify_token. Default is to do no modification. Allows
370 for usernames to be lowercased, or canonized in some other way.
371 Should return the cleaned username.
372
373 "verify_user"
374 Called by verify_token. Single argument is the username. May or
375 may not be an initial check to see if the username is ok. The
376 username will already be cleaned at this point. Default return is
377 true.
378
379 "get_pass_by_user"
380 Called by verify_token. Given the cleaned, verified username,
381 should return a valid password for the user. It can always return
382 plaintext. If use_crypt is enabled, it should return the crypted
383 password. If use_plaintext and use_crypt are not enabled, it may
384 return the md5 sum of the password.
385
386 get_pass_by_user => sub {
387 my ($auth_obj, $user) = @_;
388 my $pass = $some_obj->get_pass({user => $user});
389 return $pass;
390 }
391
392 Alternately, get_pass_by_user may return a hashref of data items
393 that will be added to the data object if the token is valid. The
394 hashref must also contain a key named real_pass or password that
395 contains the password. Note that keys passed back in the hashref
396 that are already in the data object will override those in the data
397 object.
398
399 get_pass_by_user => sub {
400 my ($auth_obj, $user) = @_;
401 my ($pass, $user_id) = $some_obj->get_pass({user => $user});
402 return {
403 password => $pass,
404 user_id => $user_id,
405 };
406 }
407
408 "verify_password"
409 Called by verify_token. Passed the password to check as well as
410 the auth data object. Should return true if the password matches.
411 Default method can handle md5, crypt, cram, secure_hash_cram, and
412 plaintext (all of the default types supported by generate_token).
413 If a property named verify_password exists, it will be used and
414 called as a coderef rather than using the default method.
415
416 "verify_payload"
417 Called by verify_token. Passed the password to check as well as
418 the auth data object. Should return true if the payload is valid.
419 Default method returns true without performing any checks on the
420 payload. If a property named verify_password exists, it will be
421 used and called as a coderef rather than using the default method.
422
423 "cgix"
424 Returns a CGI::Ex object.
425
426 "form"
427 A hash of passed form info. Defaults to CGI::Ex::get_form.
428
429 "cookies"
430 The current cookies. Defaults to CGI::Ex::get_cookies.
431
432 "login_template"
433 Should return either a template filename to use for the login
434 template, or it should return a reference to a string that contains
435 the template. The contents will be used in login_print and passed
436 to the template engine.
437
438 Default login_template is the values of login_header, login_form,
439 login_script, and login_script concatenated together.
440
441 Values from login_hash_common will be passed to the template
442 engine, and will also be used to fill in the form.
443
444 The basic values are capable of handling most needs so long as
445 appropriate headers and css styles are used.
446
447 "login_header"
448 Should return a header to use in the default login_template. The
449 default value will try to PROCESS a file called login_header.tt
450 that should be located in directory specified by the
451 template_include_path method.
452
453 It should ideally supply css styles that format the login_form as
454 desired.
455
456 "login_footer"
457 Same as login_header - but for the footer. Will look for
458 login_footer.tt by default.
459
460 "login_form"
461 An html chunk that contains the necessary form fields to login the
462 user. The basic chunk has a username text entry, password text
463 entry, save password checkbox, and submit button, and any hidden
464 fields necessary for logging in the user.
465
466 "login_script"
467 Contains javascript that will attach to the form from login_form.
468 This script is capable of taking the login_fields and creating an
469 md5 cram which prevents the password from being passed plaintext.
470
471 "text_user, text_pass, text_save"
472 The text items shown in the default login template. The default
473 values are:
474
475 text_user "Username:"
476 text_pass "Password:"
477 text_save "Save Password ?"
478
479 "disable_simple_cram"
480 Disables simple cram type from being an available type. Default is
481 false. If set, then one of use_plaintext, use_crypt, or
482 secure_hash_keys should be set. Setting this option allows for
483 payloads to be generated by the server only - otherwise a user who
484 understands the algorithm could generate a valid simple_cram cookie
485 with a custom payload.
486
487 Another option would be to only accept payloads from tokens if
488 use_blowfish is set and armor was equal to "blowfish."
489
491 This module may be distributed under the same terms as Perl itself.
492
494 Paul Seamons <perl at seamons dot com>
495
496
497
498perl v5.30.0 2019-07-26 CGI::Ex::Auth(3)