From f882801f168c4a822027a31f1a356a24167806c5 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Mon, 19 Nov 2012 18:06:42 +0000 Subject: [PATCH 1/1] wip --- cgi-auth-hybrid.pm | 98 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 79 insertions(+), 19 deletions(-) diff --git a/cgi-auth-hybrid.pm b/cgi-auth-hybrid.pm index 070603d..6f66113 100644 --- a/cgi-auth-hybrid.pm +++ b/cgi-auth-hybrid.pm @@ -34,9 +34,9 @@ use CGI; #---------- default callbacks ---------- -sub _def_is_logout ($$) { - my ($c,$r) = @_; - foreach my $pn (@{ $r->{S}{logout_param_names} }) { +sub has_a_param ($$) { + my ($c,$cn) = @_; + foreach my $pn (@{ $r->{S}{$cn} }) { return 1 if $r->_cm('get_param')($pn); } return 0; @@ -58,14 +58,16 @@ sub new_verifier { login_timeout => 86400, # seconds assoc_param_name => 'cah_associd', password_param_name => 'password', - logout_param_names => [qw(logout)], + logout_param_names => [qw(cah_logout)], + loggedout_param_names => [qw(cah_loggedout)], promise_check_mutate => 0, get_param => sub { $_[0]->param($_[2]) }, get_cah_cookie => sub { $_[0]->cookie($s->{S}{cookie_name}) }, get_method => sub { $_[0]->request_method() }, is_login => sub { defined $_[1]->_rp('password_param_name') }, login_ok => sub { die }, - is_logout => \&_def_is_logout, + is_logout => sub { $_[1]->has_a_param('logout_param_names') }, + is_loggedout => sub { $_[1]->has_a_param('loggedout_param_names') }, is_page => sub { return 1 }, }, Dbh => undef, @@ -143,7 +145,7 @@ sub _rp ($$@) { # u update of information by JS, mutating # i login # o logout - +# O "you have just logged out" page load # in cook and par, # a, aN anything including - @@ -166,7 +168,10 @@ sub _rp ($$@) { # any - POST nrmuoi bug or attack, fail # any - GET rmuoi bug or attack, fail # any any GET muoi bug or attack, fail - # any t any nrmuo bug or attack, fail + # any t any nrmu bug or attack, fail + # + # - - GET O "just logged out" page + # (any other) O bug or attack, fail # # a1 a2 POST o logout # if a1 is valid, revoke it @@ -176,15 +181,19 @@ sub _rp ($$@) { # (which contains link to login form) # # - t POST i complain about cookies being disabled + # (with link to login form) # # any n POST i complain about stale login form # show new login form # # x1 t2 POST i login (or switch user) - # revoke x1 if it was valid and !=t2 - # upgrade t2 to y2 in our db (setting username) - # set cookie to t2 - # redirect to GET of remaining params + # if bad + # show new login form + # if good + # revoke x1 if it was valid and !=t2 + # upgrade t2 to y2 in our db (setting username) + # set cookie to t2 + # redirect to GET of remaining params # # t1 a2 ANY nrmu treat as - a2 ANY # @@ -229,12 +238,16 @@ sub _rp ($$@) { # -/n n GET rmu user not logged in # fail # - # -/n n POST nrmu user not logged in + # -/n n POST n m user not logged in + # show login form + # + # -/n n POST r u user not logged in # fail sub check_divert ($) { my ($r) = @_; + my $meth = $r->_ch('get_method'); my $cookv = $r->_ch('get_cah_cookie'); my $parmv = $r->_rp('assoc_param_name'); @@ -247,24 +260,71 @@ sub check_divert ($) { $r->_db_perhaps_revoke($cookv); $r->_db_perhaps_revoke($parmv); $r->_queue_set_cookie(''); - return 'REDIRECT-LOGGEDOUT'; + return 'REDIRECT-LOGGEDOUT' + } + if ($r->_ch('is_loggedout')) { + die unless $meth eq 'GET'; + die unless $cookt; + die unless $parmt; + return ('SMALLPAGE-LOGGEDOUT', "You have been logged out."); } if ($r->_ch('is_login')) { - return 'NOCOOKIE' if !$cookt && $parmt eq 't'; - return 'LOGIN-STALE' if $parmt eq 'n'; + $r->_must_be_post(); + return ('LOGIN-STALE', + "This session was stale and you need to log in again.") + if $parmt eq 'n'; + die unless $parmt eq 't' || $parmt eq 'y'; + $r->_queue_preserve_params(); + return ('SMALLPAGE-NOCOOKIE', + "You do not seem to have cookies enabled. ". + "You must enable cookies as we use them for login.") + if !$cookt && $parmt eq 't'; + return ('LOGIN-BAD', + "Incorrect username/password.") + unless defined $username && length $username; $r->_db_perhaps_revoke($cookv) if defined $cookv && !(defined $parmv && $cookv eq $parmv); $r->_queue_set_cookie($parmv); my $username = $r->_ch('login_ok'); - return 'LOGIN-BAD' unless defined $username && length $username; $r->_db_record_login_ok($parmv,$username); return 'REDIRECT-LOGGEDIN'; } if (!$r->{S}{promise_check_mutate}) { - something with method get, check parameter, etc. - return 'FRONTPAGE'; + if ($meth ne 'POST') { + return 'MAINPAGEONLY'; + # NB caller must then ignore params & path! + # if this is too hard they can spit out a small form + # with a "click to continue" + } + } + if ($cookt eq 't') { + $cookt = undef; } - + die if $parmt eq 't'; + + if ($cookt eq 'y' && $parmt eq 'y' && $cookv ne $parmv) { + $r->_db_perhaps_revoke($parmv) if $meth eq 'POST'; + $parmt = 'n'; + } + + if ($cookt ne 'y') { + die unless !$cookt || $cookt eq 'n'; + die unless !$parmt || $parmt eq 'n' || $parmt eq 'y'; + if ($meth eq 'GET') { + $r->_queue_preserve_params(); + return ('LOGIN-INCOMINGLINK', + "You need to log in again."); + } else { + return ('LOGIN-FRESH', + "You need to log in again."); + } + } + + die unless $cookt eq 'y'; + die unless $parmt eq 'y'; + die unless $cookv eq $parmv; + return ''; +} UP TO HERE -- 2.30.2