1CGI::Ex::Auth(3)      User Contributed Perl Documentation     CGI::Ex::Auth(3)
2
3
4

NAME

6       CGI::Ex::Auth - Handle logins nicely.
7

VERSION

9       version 2.54
10

SYNOPSIS

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

DESCRIPTION

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

METHODS

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

LICENSE

510       This module may be distributed under the same terms as Perl itself.
511

AUTHORS

513       Paul Seamons <perl at seamons dot com>
514
515
516
517perl v5.36.0                      2023-01-20                  CGI::Ex::Auth(3)
Impressum