chiark / gitweb /
db_setup_stmts: new setting
[cgi-auth-flexible.git] / cgi-auth-flexible.pm
index 8c3cb49d4cc33e172d281c0d94b66679668b68b7..940e5dc2223fcbcb47042c84aa02afa22644d66c 100644 (file)
@@ -32,7 +32,7 @@ BEGIN {
     @EXPORT      = qw();
     %EXPORT_TAGS = ( );     # eg: TAG => [ qw!name1 name2! ],
 
     @EXPORT      = qw();
     %EXPORT_TAGS = ( );     # eg: TAG => [ qw!name1 name2! ],
 
-    @EXPORT_OK   = qw();
+    @EXPORT_OK   = qw(@default_db_setup_stmts);
 }
 our @EXPORT_OK;
 
 }
 our @EXPORT_OK;
 
@@ -50,6 +50,7 @@ use Data::Dumper;
 use File::Copy;
 use Cwd qw/realpath/;
 
 use File::Copy;
 use Cwd qw/realpath/;
 
+
 #---------- public utilities ----------
 
 sub flatten_params ($) {
 #---------- public utilities ----------
 
 sub flatten_params ($) {
@@ -76,10 +77,11 @@ sub has_a_param ($$) {
 
 sub get_params ($) {
     my ($r) = @_;
 
 sub get_params ($) {
     my ($r) = @_;
-    my %p;
     my $c = $r->{Cgi};
     my $c = $r->{Cgi};
-    foreach my $name ($c->param()) {
-       $p{$name} = [ $c->param($name) ];
+    my $vars = $c->Vars();
+    my %p;
+    foreach my $name (keys %$vars) {
+       $p{$name} = [ split "\0", $vars->{$name} ];
     }
     return \%p;
 }
     }
     return \%p;
 }
@@ -178,8 +180,9 @@ sub gen_plain_login_link ($$) {
 sub gen_srcdump_link_html ($$$$) {
     my ($c,$r,$anchor,$specval) = @_;
     my %params = ($r->{S}{srcdump_param_name} => [ $specval ]);
 sub gen_srcdump_link_html ($$$$) {
     my ($c,$r,$anchor,$specval) = @_;
     my %params = ($r->{S}{srcdump_param_name} => [ $specval ]);
-    return '<a href="'.escapeHTML($r->url_with_query_params(\%params)).'">'.
-       $anchor."</a>";
+    return '<a href="'.
+       escapeHTML($r->url_with_query_params(\%params,'SRCDUMP')).
+       '">'.$anchor."</a>";
 }
 sub gen_plain_licence_link_html ($$) {
     my ($c,$r) = @_;
 }
 sub gen_plain_licence_link_html ($$) {
     my ($c,$r) = @_;
@@ -199,6 +202,18 @@ sub gen_plain_footer_html ($$) {
            '</address>');
 }
 
            '</address>');
 }
 
+our @default_db_setup_stmts =
+    ("CREATE TABLE $v->{S}{assocdb_table} (".
+     " assochash VARCHAR PRIMARY KEY,".
+     " username VARCHAR NOT NULL,".
+     " last INTEGER NOT NULL".
+     ")"
+     ,
+     "CREATE INDEX $v->{S}{assocdb_table}_timeout_index".
+     " ON $v->{S}{assocdb_table}".
+     " (last)"
+    );
+
 #---------- licence and source code ----------
 
 sub srcdump_dump ($$$) {
 #---------- licence and source code ----------
 
 sub srcdump_dump ($$$) {
@@ -236,6 +251,7 @@ sub srcdump_process_item ($$$$$$) {
     my $upwards = $item;
     for (;;) {
        $upwards =~ s#/+$##;
     my $upwards = $item;
     for (;;) {
        $upwards =~ s#/+$##;
+       $upwards =~ s#/+\.$##;
        last unless $upwards =~ m#[^/]#;
        foreach my $try (@{ $v->{S}{srcdump_vcs_dirs} }) {
 #print STDERR "TRY $item $upwards $try\n";
        last unless $upwards =~ m#[^/]#;
        foreach my $try (@{ $v->{S}{srcdump_vcs_dirs} }) {
 #print STDERR "TRY $item $upwards $try\n";
@@ -244,13 +260,16 @@ sub srcdump_process_item ($$$$$$) {
                next;
            }
 #print STDERR "VCS $item $upwards $try\n";
                next;
            }
 #print STDERR "VCS $item $upwards $try\n";
-           return if $dirsdone->{$upwards}++;
+            if ($dirsdone->{$upwards}++) {
+               $outfn->("srcdump_process_item: did $upwards,".
+                        " skipping $item");
+               return;
+           }
 #print STDERR "VCS $item $upwards $try GO\n";
            $try =~ m/\w+/ or die;
 #print STDERR "VCS $item $upwards $try GO\n";
            $try =~ m/\w+/ or die;
-           return $v->_ch(('srcdump_byvcs_'.lc $&),
-                          $dumpdir, $upwards, $outfn);
+           return $v->_ch('srcdump_byvcs', $dumpdir, $upwards, $outfn, lc $&);
        }
        }
-       $upwards =~ s#/*[^/]+##;
+       $upwards =~ s#/*[^/]+$##;
     }
     return $v->_ch('srcdump_novcs', $dumpdir, $item, $outfn);
 }
     }
     return $v->_ch('srcdump_novcs', $dumpdir, $item, $outfn);
 }
@@ -264,7 +283,7 @@ sub srcdump_novcs ($$$$$) {
            $script .= " \\! -name '$excl'";
        }
        $script .= " -print0";
            $script .= " \\! -name '$excl'";
        }
        $script .= " -print0";
-       return srcdump_dir_cpio($c,$v,$dumpdir,$item,$outfn,$script);
+       return srcdump_dir_cpio($c,$v,$dumpdir,$item,$outfn,'novcs',$script);
     } elsif (-f _) {
        return srcdump_file($c,$v,$dumpdir,$item,$outfn);
     } else {
     } elsif (-f _) {
        return srcdump_file($c,$v,$dumpdir,$item,$outfn);
     } else {
@@ -272,14 +291,12 @@ sub srcdump_novcs ($$$$$) {
     }
 }
 
     }
 }
 
-sub srcdump_byvcs_git ($$$$$) {
-    my ($c, $v, $dumpdir, $dir, $outfn) = @_;
+sub srcdump_byvcs ($$$$$$) {
+    my ($c, $v, $dumpdir, $dir, $outfn, $vcs) = @_;
 #print STDERR "BYVCS GIT $dir\n";
 #print STDERR "BYVCS GIT $dir\n";
-    return srcdump_dir_cpio($c,$v,$dumpdir,$dir,$outfn,"
-                 git ls-files -z
-                 git ls-files -z --others --exclude-from=.gitignore
-                 find .git -print0
-                            ");
+    my $script = $v->{S}{"srcdump_vcsscript"}{$vcs};
+    die "no script for vcs $vcs" unless defined $script;
+    return srcdump_dir_cpio($c,$v,$dumpdir,$dir,$outfn,$vcs,$script);
 }
 
 sub srcdump_file ($$$$) {
 }
 
 sub srcdump_file ($$$$) {
@@ -288,9 +305,9 @@ sub srcdump_file ($$$$) {
     copy($file,$outfile) or die "$file $outfile $!";
 }
 
     copy($file,$outfile) or die "$file $outfile $!";
 }
 
-sub srcdump_dir_cpio ($$$$$) {
-    my ($c,$v,$dumpdir,$dir,$outfn,$script) = @_;
-    my $outfile = $outfn->("srcdump_dir_cpio saved $dir", "tar");
+sub srcdump_dir_cpio ($$$$$$$) {
+    my ($c,$v,$dumpdir,$dir,$outfn,$how,$script) = @_;
+    my $outfile = $outfn->("srcdump_dir_cpio $how saved $dir", "tar");
 #print STDERR "CPIO $dir >$script<\n";
     my $pid = fork();
     defined $pid or die $!;
 #print STDERR "CPIO $dir >$script<\n";
     my $pid = fork();
     defined $pid or die $!;
@@ -313,7 +330,7 @@ sub srcdump_dir_cpio ($$$$$) {
        die $!;
     }
     $!=0; (waitpid $pid, 0) == $pid or die "$!";
        die $!;
     }
     $!=0; (waitpid $pid, 0) == $pid or die "$!";
-    die "$dir ($script) $outfile $?" if $?;
+    die "$dir ($how $script) $outfile $?" if $?;
 }
 
 sub srcdump_dirscan_prepare ($$) {
 }
 
 sub srcdump_dirscan_prepare ($$) {
@@ -359,14 +376,14 @@ sub srcdump_dirscan_prepare ($$) {
        }
        if (!lstat "$item") {
            die "stat $item $!" unless $!==&ENOENT;
        }
        if (!lstat "$item") {
            die "stat $item $!" unless $!==&ENOENT;
-           $outfn->("srcdump_dirscan_prepare stat ENOENT: skipping $item");
+           $outfn->("srcdump_dirscan_prepare stat ENOENT, skipping $item");
            next;
        };
        if (-l _) {
            $item = realpath($item);
            if (!defined $item) {
                die "realpath $item $!" unless $!==&ENOENT;
            next;
        };
        if (-l _) {
            $item = realpath($item);
            if (!defined $item) {
                die "realpath $item $!" unless $!==&ENOENT;
-               $outfn->("srcdump_dirscan_prepare realpath ENOENT:".
+               $outfn->("srcdump_dirscan_prepare realpath ENOENT,".
                         " skipping $item");
            }
        }
                         " skipping $item");
            }
        }
@@ -381,6 +398,7 @@ sub srcdump_dirscan_prepare ($$) {
        $dirsdone{$item}++;
     }
     close $reportfh or die $!;
        $dirsdone{$item}++;
     }
     close $reportfh or die $!;
+    srcdump_install($c,$v, $dumpdir, 'licence', 'text/plain');
     $!=0;
     my @cmd = (qw(tar -zvvcf), "$dumpdir/source.tmp",
               "-C", $dumpdir, qw(  --), @srcfiles);
     $!=0;
     my @cmd = (qw(tar -zvvcf), "$dumpdir/source.tmp",
               "-C", $dumpdir, qw(  --), @srcfiles);
@@ -390,7 +408,6 @@ sub srcdump_dirscan_prepare ($$) {
        die "tar failed";
     }
     die "licence file not found" unless defined $needlicence;
        die "tar failed";
     }
     die "licence file not found" unless defined $needlicence;
-    srcdump_install($c,$v, $dumpdir, 'licence', 'text/plain');
     srcdump_install($c,$v, $dumpdir, 'source', 'application/octet-stream');
     close $lockf or die $!;
 }
     srcdump_install($c,$v, $dumpdir, 'source', 'application/octet-stream');
     close $lockf or die $!;
 }
@@ -422,6 +439,7 @@ sub new_verifier {
            assocdb_user => '',
            assocdb_password => '',
            assocdb_table => 'caf_assocs',
            assocdb_user => '',
            assocdb_password => '',
            assocdb_table => 'caf_assocs',
+           assocdb_setup_stmts => [@_default_db_setup_statements],
            random_source => '/dev/urandom',
            secretbits => 128, # bits
            hash_algorithm => "SHA-256",
            random_source => '/dev/urandom',
            secretbits => 128, # bits
            hash_algorithm => "SHA-256",
@@ -443,14 +461,13 @@ sub new_verifier {
            get_path_info => sub { $_[0]->path_info() },
            get_cookie => sub { $_[0]->cookie($_[1]->{S}{cookie_name}) },
            get_method => sub { $_[0]->request_method() },
            get_path_info => sub { $_[0]->path_info() },
            get_cookie => sub { $_[0]->cookie($_[1]->{S}{cookie_name}) },
            get_method => sub { $_[0]->request_method() },
-           check_https => sub { !!$_[0]->https() },
+           is_https => sub { !!$_[0]->https() },
            get_url => sub { $_[0]->url(); },
             is_login => sub { defined $_[1]->_rp('password_param_name') },
             login_ok => \&login_ok_password,
             username_password_error => sub { die },
            is_logout => sub { $_[1]->has_a_param('logout_param_names') },
            is_loggedout => sub { $_[1]->has_a_param('loggedout_param_names') },
            get_url => sub { $_[0]->url(); },
             is_login => sub { defined $_[1]->_rp('password_param_name') },
             login_ok => \&login_ok_password,
             username_password_error => sub { die },
            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 },
            handle_divert => sub { return 0 },
            do_redirect => \&do_redirect_cgi, # this hook is allowed to throw
            cookie_path => "/",
            handle_divert => sub { return 0 },
            do_redirect => \&do_redirect_cgi, # this hook is allowed to throw
            cookie_path => "/",
@@ -474,11 +491,13 @@ sub new_verifier {
                $_[2] =~ m#^/etc/|^/usr/(?!local/)(?!lib/cgi)#;
            },
            srcdump_process_item => \&srcdump_process_item,
                $_[2] =~ m#^/etc/|^/usr/(?!local/)(?!lib/cgi)#;
            },
            srcdump_process_item => \&srcdump_process_item,
-           srcdump_vcs_dirs => [qw(.git .hg .svn CVS)],
-           srcdump_byvcs_git => \&srcdump_byvcs_git,
-           srcdump_byvcs_hg => \&srcdump_byvcs_hg,
-           srcdump_byvcs_svn => \&srcdump_byvcs_svn,
-           srcdump_byvcs_cvs => \&srcdump_byvcs_cvs,
+           srcdump_vcs_dirs => [qw(.git .hg .bzr .svn)],
+           srcdump_vcsscript => [git => "
+                 git ls-files -z
+                 git ls-files -z --others --exclude-from=.gitignore
+                 find .git -print0
+                            "],
+           srcdump_byvcs => \&srcdump_byvcs,
            srcdump_novcs => \&srcdump_novcs,
            srcdump_excludes => [qw(*~ *.bak *.tmp), '#*#'],
            dump => \&dump_plain,
            srcdump_novcs => \&srcdump_novcs,
            srcdump_excludes => [qw(*~ *.bak *.tmp), '#*#'],
            dump => \&dump_plain,
@@ -490,7 +509,9 @@ sub new_verifier {
     };
     my ($k,$v);
     while (($k,$v,@_) = @_) {
     };
     my ($k,$v);
     while (($k,$v,@_) = @_) {
-       die "unknown setting $k" unless exists $verifier->{S}{$k};
+       die "unknown setting $k" unless
+           $k =~ m/^promise_/ or
+           exists $verifier->{S}{$k};
        $verifier->{S}{$k} = $v;
     }
     bless $verifier, $class;
        $verifier->{S}{$k} = $v;
     }
     bless $verifier, $class;
@@ -535,14 +556,9 @@ sub _dbopen ($) {
     }
     $v->{Dbh} = $dbh;
 
     }
     $v->{Dbh} = $dbh;
 
-    $v->_db_setup_do("CREATE TABLE $v->{S}{assocdb_table} (".
-                    " assochash VARCHAR PRIMARY KEY,".
-                    " username VARCHAR NOT NULL,".
-                    " last INTEGER NOT NULL".
-                    ")");
-    $v->_db_setup_do("CREATE INDEX $v->{S}{assocdb_table}_timeout_index".
-                    " ON $v->{S}{assocdb_table}".
-                     " (last)");
+    foreach my $stmt (@default_db_setup_stmts) {
+       $v->_db_setup_do($stmt);
+    }
     return $dbh;
 }
 
     return $dbh;
 }
 
@@ -656,9 +672,9 @@ my @ca = (-name => $r->{S}{cookie_name},
 
 # pages/param-sets are
 #   n normal non-mutating page
 
 # pages/param-sets are
 #   n normal non-mutating page
-#   r retrieval of information for JS, non-mutating
+#   r retrieval of information for JS etc., non-mutating
 #   m mutating page
 #   m mutating page
-#   u update of information by JS, mutating
+#   u update of information by JS etc., mutating
 #   i login
 #   o logout
 #   O "you have just logged out" page load
 #   i login
 #   o logout
 #   O "you have just logged out" page load
@@ -778,7 +794,7 @@ sub _check_divert_core ($) {
 
     my $cooks = $r->_ch('get_cookie');
 
 
     my $cooks = $r->_ch('get_cookie');
 
-    if ($r->{S}{encrypted_only} && !$r->_ch('check_https')) {
+    if ($r->{S}{encrypted_only} && !$r->_ch('is_https')) {
         return ({ Kind => 'REDIRECT-HTTPS',
                   Message => $r->_gt("Redirecting to secure server..."),
                   CookieSecret => undef,
         return ({ Kind => 'REDIRECT-HTTPS',
                   Message => $r->_gt("Redirecting to secure server..."),
                   CookieSecret => undef,
@@ -824,7 +840,7 @@ sub _check_divert_core ($) {
                                          " enabled.  You must enable cookies".
                                          " as we use them for login."),
                       CookieSecret => $r->_fresh_secret(),
                                          " enabled.  You must enable cookies".
                                          " as we use them for login."),
                       CookieSecret => $r->_fresh_secret(),
-                      Params => $r->chain_params() })
+                      Params => $r->_chain_params() })
         }
         if (!$cookt || $cookt eq 'n' || $cookh ne $parmh) {
             $r->_db_revoke($cookh);
         }
         if (!$cookt || $cookt eq 'n' || $cookh ne $parmh) {
             $r->_db_revoke($cookh);
@@ -842,13 +858,13 @@ sub _check_divert_core ($) {
             return ({ Kind => 'LOGIN-BAD',
                       Message => $login_errormessage,
                       CookieSecret => $cooks,
             return ({ Kind => 'LOGIN-BAD',
                       Message => $login_errormessage,
                       CookieSecret => $cooks,
-                      Params => $r->chain_params() })
+                      Params => $r->_chain_params() })
         }
        $r->_db_record_login_ok($parmh,$username);
        return ({ Kind => 'REDIRECT-LOGGEDIN',
                  Message => $r->_gt("Logging in..."),
                  CookieSecret => $cooks,
         }
        $r->_db_record_login_ok($parmh,$username);
        return ({ Kind => 'REDIRECT-LOGGEDIN',
                  Message => $r->_gt("Logging in..."),
                  CookieSecret => $cooks,
-                 Params => $r->chain_params() });
+                 Params => $r->_chain_params() });
     }
     if ($cookt eq 't') {
        $cookt = '';
     }
     if ($cookt eq 't') {
        $cookt = '';
@@ -868,7 +884,7 @@ sub _check_divert_core ($) {
            return ({ Kind => 'LOGIN-INCOMINGLINK',
                      Message => $r->_gt("You need to log in."),
                      CookieSecret => $news,
            return ({ Kind => 'LOGIN-INCOMINGLINK',
                      Message => $r->_gt("You need to log in."),
                      CookieSecret => $news,
-                     Params => $r->chain_params() });
+                     Params => $r->_chain_params() });
        } else {
            $r->_db_revoke($parmh);
            return ({ Kind => 'LOGIN-FRESH',
        } else {
            $r->_db_revoke($parmh);
            return ({ Kind => 'LOGIN-FRESH',
@@ -895,13 +911,21 @@ sub _check_divert_core ($) {
         die unless $parmt eq 'y';
         die unless $cookh eq $parmh;
     }
         die unless $parmt eq 'y';
         die unless $cookh eq $parmh;
     }
+    $r->{ParmT} = $parmt;
     $r->{AssocSecret} = $cooks;
     $r->{UserOK} = $cooku;
 #print STDERR "C-D-C OK\n";
     return undef;
 }
 
     $r->{AssocSecret} = $cooks;
     $r->{UserOK} = $cooku;
 #print STDERR "C-D-C OK\n";
     return undef;
 }
 
-sub chain_params ($) {
+sub _chain_params ($) {
+# =item C<< $authreq->_chain_params() >>
+#
+# Returns a hash of the "relevant" parameters to this request, in a form
+# used by C<url_with_query_params>.  This is all of the query parameters
+# which are not related to CGI::Auth::Flexible.  The PATH_INFO from the
+# request is returned as the parameter C<< '' >>.
+
     my ($r) = @_;
     my %p = %{ $r->_ch('get_params') };
     foreach my $pncn (keys %{ $r->{S} }) {
     my ($r) = @_;
     my %p = %{ $r->_ch('get_params') };
     foreach my $pncn (keys %{ $r->{S} }) {
@@ -1024,12 +1048,16 @@ sub get_username ($) {
     return $r->{UserOK};
 }
 
     return $r->{UserOK};
 }
 
-sub url_with_query_params ($$) {
-    my ($r, $params) = @_;
+sub url_with_query_params ($$;$) {
+    my ($r, $params, $nonpagetype) = @_;
 #print STDERR "PARAMS ",Dumper($params);
     my $uri = URI->new($r->_ch('get_url'));
     $uri->path($uri->path() . $params->{''}[0]) if $params->{''};
 #print STDERR "PARAMS ",Dumper($params);
     my $uri = URI->new($r->_ch('get_url'));
     $uri->path($uri->path() . $params->{''}[0]) if $params->{''};
-    $uri->query_form(flatten_params($params));
+    my @flatparams = flatten_params($params);
+    if (defined $nonpagetype && $r->need_add_hidden('GET',$nonpagetype)) {
+       push @flatparams, $r->{S}{assoc_param_name}, $r->secret_hidden_val();
+    }
+    $uri->query_form(@flatparams);
     return $uri->as_string();
 }
 
     return $uri->as_string();
 }
 
@@ -1061,7 +1089,7 @@ sub check_ok ($) {
     }
 
     if ($kind =~ m/^REDIRECT-/) {
     }
 
     if ($kind =~ m/^REDIRECT-/) {
-       # for redirects, we honour stored NextParams and SetCookie,
+       # for redirects, we honour stored Params and Cookie,
        # as we would for non-divert
        if ($kind eq 'REDIRECT-LOGGEDOUT') {
            $params->{$r->{S}{loggedout_param_names}[0]} = [ 1 ];
        # as we would for non-divert
        if ($kind eq 'REDIRECT-LOGGEDOUT') {
            $params->{$r->{S}{loggedout_param_names}[0]} = [ 1 ];
@@ -1269,11 +1297,39 @@ sub check_mutate ($) {
     $r->_must_be_post();
 }
 
     $r->_must_be_post();
 }
 
-sub mutate_ok ($) {
-    my ($r) = @_;
+our %_resource_get_needs_secret_hidden =
+    (map { $_ => 0 } qw(PAGE FRAME IFRAME SRCDUMP STYLESHEET FAVICON ROBOTS),
+     map { $_ => 1 } qw(IMAGE SCRIPT AJAX-XML AJAX-JSON AJAX-OTHER));
+
+sub update_get_need_add_hidden ($$;$) {
+    my ($r, $reqtype, $value, $force) = @_;
+    my $hash = ref $r
+       ? ($r->{GetNeedsSecretHidden} ||= { })
+       : \%_resource_get_needs_secret_hidden;
+    return if !$force &&
+       (exists $_resource_get_needs_secret_hidden{$reqtype} ||
+        exists $hash->{$reqtype});
+    $hash->{$reqtype} = $value;
+}
+
+sub need_add_hidden ($$) {
+    my ($r, $method, $reqtype) = @_;
+    return 1 if $method ne 'GET';
+    if (ref $r) {
+       my $ent = $r->{GetNeedsSecretHidden}{$reqtype};
+       return $ent if defined $ent;
+    }
+    my $ent = $_resource_get_needs_secret_hidden{$reqtype};
+    return $ent if defined $ent;
+    die "unsupported nonpage GET type $reqtype";
+}
+
+sub check_nonpage ($$) {
+    my ($r, $reqtype) = @_;
     $r->_assert_checked();
     $r->_assert_checked();
-    die if $r->{Divert};
-    return $r->_is_post();
+    return unless $r->resource_get_needs_secret_hidden($nonpagetype);
+    return if $r->{ParmT};
+    die "missing hidden secret parameter on nonpage request $nonpagetype";
 }
 
 #---------- output ----------
 }
 
 #---------- output ----------
@@ -1307,41 +1363,3 @@ sub secret_cookie ($) {
 }
 
 1;
 }
 
 1;
-
-__END__
-
-=head1 NAME
-
-CGI::Auth::Flexible - web authentication optionally using cookies
-
-=head1 SYNOPSYS
-
- my $verifier = CGI::Auth::Flexible->new_verifier(setting => value,...);
- my $authreq = $verifier->new_request($cgi_request_object);
-
- my $authreq = CGI::Auth::Flexible->new_request($cgi_request_object,
-                                              setting => value,...);
-
-=head1 USAGE PATTERN FOR SIMPLE APPLICATIONS
-
- $authreq->check_ok() or return;
-
- blah blah blah
- $authreq->check_mutate();
- blah blah blah
-
-=head1 USAGE PATTERN FOR FANCY APPLICATIONS
-
- my $divert_kind = $authreq->check_divert();
- if ($divert_kind) {
-     if ($divert_kind eq 'LOGGEDOUT') {
-        print "goodbye you are now logged out" and quit
-     } elsif ($divert_kind eq 'NOCOOKIES') {
-        print "you need cookies" and quit
-     ... etc.
-     }
- }
-
- blah blah blah
- $authreq->check_mutate();
- blah blah blah