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