Apache-SecSess

 view release on metacpan or  search on metacpan

SecSess.pm  view on Meta::CPAN

	my($self, $r) = @_;
	my $log = $r->log;
	my($cred, $resp, $msg);

	## don't perform in subrequests
	unless ($r->is_initial_req) { return OK; }

	$log->debug(ref($self), "->authen():");

	$cred = $self->getCredentials($r);
	$resp = $self->validateCredentials($r, $cred);
	if (ref($resp)) {
		if ($msg = $resp->{message}) { $log->info($msg); }
		unless ($resp->{uri}) { return SERVER_ERROR; }
		$r->header_out(Location => $resp->{uri});
		return REDIRECT;
	}
	return OK;
}

## authorize request

SecSess.pm  view on Meta::CPAN

	my($self, $r) = @_;
	my $log = $r->log;
	my($cred, $resp, $msg);

	## don't perform in subrequests
	unless ($r->is_initial_req) { return OK; }

	$log->debug(ref($self), "->renew():");

	$cred = $self->getCredentials($r);
	$resp = $self->validateCredentials($r, $cred);
	unless (ref($resp)) { $log->error($resp); return SERVER_ERROR; } 
	unless ($resp->{renew}) { # make sure credentials are sufficiently fresh
		$log->warn("Timeout before renewal."); # or replay attempt?
		if ($msg = $resp->{message}) { $log->info($msg); }
		unless ($resp->{uri}) { return SERVER_ERROR; }
		$r->header_out(Location => $resp->{uri});
		return REDIRECT;
	}
	$resp = $self->issueCredentials($r);
	unless (ref($resp)) { $log->error($resp); return SERVER_ERROR; } 

SecSess.pm  view on Meta::CPAN

	unless ($r->is_initial_req) { return OK; }

	$log->debug(ref($self), "->changeid():");

	## admin functions must be explicitly allowed in httpd.conf
	unless ($r->dir_config('SecSess::AllowRemoteAdmin') eq 'true') { 
		$log->error('Remote administration not permitted.');
		return FORBIDDEN;
	}

	## get credentials and validate them in usual way
	$cred = $self->getCredentials($r);
	$resp = $self->validateCredentials($r, $cred);
	if (ref($resp)) {
		if ($msg = $resp->{message}) { $log->info($msg); }
		unless ($resp->{uri}) { return SERVER_ERROR; }
		$r->header_out(Location => $resp->{uri});
		return REDIRECT;
	}

	## make sure request is consistent and comes from an administrator
	$resp = $self->verifyAdminRequest($r);
	unless (ref($resp)) { $log->error($resp); return SERVER_ERROR; } 

SecSess.pm  view on Meta::CPAN

sub issueURL { my $self = shift; return $self->{issueURL}; }
sub chainURLS { my $self = shift; return $self->{chainURLS}; }

## admin form
sub adminURL { my $self = shift; return $self->{adminURL}; }

#
# routines
#

## validate common hash credentials from
sub validateCredentials {
	my $self = shift;
	my($r, $cred) = @_;
	my $log = $r->log;
	my($uri, $requri, $resp, $uid);

    $log->debug(ref($self), "->validateCredentials():");

	## were illegitimate credentials found?
	unless (defined($cred)) { # probably a key-change, treat as timeout
		# but possibly tampering, so log as warning
		$log->warn("Decryption Error");
		$uri = $self->timeoutURL;
		return {
			message => "Decryption failure, redirecting to '$uri'.",
			uri => "$uri?type=notvalid"
		};

SecSess.pm  view on Meta::CPAN

			uri => $uri
		};
	}

	## set user id for Apache 
	$uid = $cred->{uid};
	$log->debug("Setting user ID: '$uid'.");
	$r->user($uid);
 
	## checksum is good, examine the protection qualities and freshness
	if ($resp = $self->validateQOP($r, $cred)) { return $resp; }
	if ($resp = $self->validateAge($r, $cred)) { return $resp; }

	## user authenticated
	$log->info("User '$uid' authenticated.");
	return undef;
}

## validate quality of protection
sub validateQOP {
	my $self = shift;
	my($r, $cred) = @_;
	my($uri, $requri);

	unless ($cred->{qop} >= $self->minSessQOP) {
		$uri = $self->authenURL;
		$requri = $self->requested_uri($r);
		return {
			message => "Insufficient session protection.",
			uri => "$uri?url=$requri"

SecSess.pm  view on Meta::CPAN

		$requri = $self->requested_uri($r);
		return {
			message => "Insufficient authentication protection.",
			uri => "$uri?url=$requri"
		}
	}

	return undef;
}

## validated time stamp
sub validateAge {
	my $self = shift;
	my($r, $cred) = @_;
	my($life, $idle, $renew, $uid, $ts, $t, $uri, $requri);

	## get object timing constants
	$life =  $self->lifeTime;
	$idle =  $self->idleTime;
	$renew = $self->renewRate;

	## check times
	$uid = $cred->{uid};
	$ts = $cred->{timestamp};
	$t = time;
	$r->log->debug(sprintf(
		"validateAge(): uid = '%s', time - ts = %.02f (min):"
			. " vs renew = %d, idle = %d, life = %d",
		$uid, ($t-$ts)/60.0, $renew, $idle, $life
	));
	if ($t > $ts + 60*$life) { # hard timeout
		$uri = $self->timeoutURL;
		return {
			message => "Expired, redirecting '$uid' to '$uri?type=expire'.",
			uri => "$uri?type=expire"
		};
	}

SecSess.pm  view on Meta::CPAN

  renewRate => <minutes>

A session which is constantly active will have a transparent
renewal (resetting an implicit 'idle timer') every period of the 
specified number of minutes.

=head2 Quality of Protection Arguments

minSessQOP => 128, minAuthQOP => 128, authQOP => 128, sessQOP => 128

When credentials are validated during a request, two checks of the 
qualities of protection (QOP's) are made, namely that

        qop >= minSessQOP
and 
        authqop >= minAuthQOP

where qop and authqop indicate the session and user authentication 
protection or strength roughly measured in bits.  They are the signed 
values appearing *inside* the credential hash described above.  In the 
case of cookies, where multiple credentials with different security 

SecSess/Cookie.pm  view on Meta::CPAN

		my($bs, $ba) = split(',', $b);
		return ($bs <=> $as) ? ($bs <=> $as) : ($ba <=> $aa);
	} (keys %ckys);
	$max = $tags[0];
	unless (defined($max)) { return 'No cookie found.'; }
	$log->debug(sprintf("Found Cookie: %s:%s=%s", $realm, $max, $ckys{$max}));

	return $self->{wrapper}->unwraphash($ckys{$max});
}

## validate (usually non-cookie) credentials used to authenicate user
sub verifyIdentity { my $self = shift; return undef }

## issue cookies
sub issueCredentials {
	my $self = shift;
	my($r) = @_;
	my $log = $r->log;
	my(@cky, %args, $url);

	$log->debug(ref($self), "->issueCredentials():");

SecSess/Cookie.pm  view on Meta::CPAN


	## check if *new* user is valid
	$status = $self->{dbo}->get_user_status($newuid);
	unless ($status eq 'enabled') {
		return {
			message => "User '$newuid' unavailable: '$status'.",
			uri => "$form?msg=$status"
		};
	}
	
	## validate super user's password
	$msg = $self->{dbo}->validate_user_pass($uid, $pw);
	unless ($msg eq 'OK') {
		return {
			message => "Incorrect superuser password for '$uid'.",
			uri => "$form?msg=$msg"
		};
	}
	
	## everything looks good, allow the change of identity
	return {
		message => "Superuser '$uid' changing to user '$newuid'",

SecSess/Cookie/BasicAuth.pm  view on Meta::CPAN


use Apache::Constants qw(:common :response);
use Apache::SecSess::Cookie;

use vars qw(@ISA $VERSION);

$VERSION = sprintf("%d.%02d", (q$Name: SecSess_Release_0_09 $ =~ /\d+/g));

@ISA = qw(Apache::SecSess::Cookie);

## validate (usually non-cookie) credentials used to authenicate user
sub verifyIdentity {
	my $self = shift;
	my($r) = @_;
	my $log = $r->log;
	my($uid, $res, $pw, $msg);

    $log->debug(ref($self), "->verifyIdentity():");

	## read password and user id if present, bail otherwise
	($res, $pw) = $r->get_basic_auth_pw;

SecSess/Cookie/BasicAuth.pm  view on Meta::CPAN

	}
	$uid = $r->user;
	unless ($uid && $pw) {
		$r->note_basic_auth_failure;
		return {
			message => "Basic auth failed, uid: '$uid', pw: '$pw'.",
			auth_required => 'true'
		};
	}

	## validate user and password
	$msg = $self->{dbo}->validate_user_pass($uid, $pw);
	unless ($msg eq 'OK') {
		return {
			message => $msg,
			auth_required => 'true',
		};
	}

	return undef;
}

SecSess/Cookie/LoginForm.pm  view on Meta::CPAN

use strict;

use Apache::SecSess::Cookie;

use vars qw(@ISA $VERSION);

$VERSION = sprintf("%d.%02d", (q$Name: SecSess_Release_0_09 $ =~ /\d+/g));

@ISA = qw(Apache::SecSess::Cookie);

## validate (usually non-cookie) credentials used to authenicate user
sub verifyIdentity {
	my $self = shift;
	my($r) = @_;
	my $log = $r->log;
	my(%params, $uid, $pw, %args, $url, $form, $msg);

    $log->debug(ref($self), "->verifyIdentity():");

	## is this the initial visit to the form?
	unless ($r->method eq 'POST') { # allow no GET for now ...

SecSess/Cookie/LoginForm.pm  view on Meta::CPAN

		}
	}

	## extract user ID, password and other data
	%params = $r->content;
	$uid = $params{uid};
	$pw = $params{pw};
	%args = $r->args;
	$url = $args{url};

	## validate user and password
	$msg = $self->{dbo}->validate_user_pass($uid, $pw);
	unless ($msg eq 'OK') {
		$form = $self->authenURL;
		$form .= "?msg=$msg";
		$form .= "&url=$url" if $url;
		return {
			message => "Auth error code: '$msg'",
			uri => $form
		};
	}

SecSess/Cookie/URL.pm  view on Meta::CPAN


use Apache::SecSess::Cookie;
use Apache::SecSess::Wrapper;

use vars qw(@ISA $VERSION);

$VERSION = sprintf("%d.%02d", (q$Name: SecSess_Release_0_09 $ =~ /\d+/g));

@ISA = qw(Apache::SecSess::Cookie);

## validate (usually non-cookie) credentials used to authenicate user
sub verifyIdentity {
	my $self = shift;
	my($r) = @_;
	my $log = $r->log;
	my(%args, $ctxt, $urlcred);

    $log->debug(ref($self), "->verifyIdentity():");

	## extract ciphertext from URL
	%args = $r->args;
	$ctxt = $args{$self->authRealm};
	$urlcred = $self->{wrapper}->unwraphash($ctxt);

	## validate URL credentials as we would at higher level
	return $self->validateCredentials($r, $urlcred);
}

1;

__END__
What are you looking at?

SecSess/Cookie/X509.pm  view on Meta::CPAN

use strict;

use Apache::SecSess::Cookie;

use vars qw(@ISA $VERSION);

$VERSION = sprintf("%d.%02d", (q$Name: SecSess_Release_0_09 $ =~ /\d+/g));

@ISA = qw(Apache::SecSess::Cookie);

## validate (usually non-cookie) credentials used to authenicate user
sub verifyIdentity {
	my $self = shift;
	my($r) = @_;
	my $log = $r->log;
	my($subr, $email, $uid);

    $log->debug(ref($self), "->verifyIdentity():");

	## resolve user ID from certificate DN email
	$subr = $r->lookup_uri($r->uri);

SecSess/Cookie/X509PIN.pm  view on Meta::CPAN

use strict;

use Apache::SecSess::Cookie;

use vars qw(@ISA $VERSION);

$VERSION = sprintf("%d.%02d", (q$Name: SecSess_Release_0_09 $ =~ /\d+/g));

@ISA = qw(Apache::SecSess::Cookie);

## validate (usually non-cookie) credentials used to authenicate user
sub verifyIdentity {
	my $self = shift;
	my($r) = @_;
	my $log = $r->log;
	my($subr, $email, $uid, %params, $pin, %args, $url, $form, $msg);

    $log->debug(ref($self), "->verifyIdentity():");

	## resolve user ID from certificate DN email
	$subr = $r->lookup_uri($r->uri);

SecSess/Cookie/X509PIN.pm  view on Meta::CPAN

			fill_form => 'true'
		}
	}

	## extract user ID, password and other data from POST
	%params = $r->content;
	$pin = $params{pin};
	%args = $r->args;
	$url = $args{url};

	## validate PIN code
	$msg = $self->{dbo}->validate_stored_token($uid, $pin, 'pin');
	unless ($msg eq 'OK') {
		$form = $self->authenURL;
		$form .= "?msg=$msg";
		$form .= "&url=$url" if $url;
		return {
			message => "Auth error code: '$msg'",
			uri => $form
		};
	}

SecSess/DBI.pm  view on Meta::CPAN

	$uasth->execute($uid, $authid);
	
	# process query output
	($token) = $uasth->fetchrow_array;
	$uasth->finish;

	return $self->dbunquote($token);
}

## valid a user/password against database
sub validate_user_pass {
	my $self = shift;
	my($uid, $pw) = @_;

	## this little extra step is necessary for crypt() to work
	unless ($uid && $pw) { return 'empty'; }
	my $pwhash = $self->get_pwhash($uid);

	return $self->validate_stored_token($uid, crypt($pw, $pwhash), 'unixpw');
}

## validate a general stored token (eg, password, PIN, etc)
sub validate_stored_token {
	my $self = shift;
	my($uid, $token, $authid) = @_;
	my($status);

	unless ($uid) { return 'empty'; } # empty uid argument
	$status = $self->get_user_status($uid);
	unless ($status eq 'enabled') { return $status; } # disabled or unknown
	unless ($token) { return 'empty'; } # empty token argument
	unless ($token eq $self->get_stored_token($uid, $authid)) {
		$self->note_auth_failure($uid, $authid);

SecSess/URL.pm  view on Meta::CPAN

    $log->debug(ref($self), "->verifyIdentity():");

	## extract ciphertext from URL
	%args = $r->args;
	$ctxt = $args{$self->authRealm};
	unless ($ctxt) { return 'No URL credentials found.'; }

	return $self->{wrapper}->unwraphash($ctxt);
}

## validate (usually non-url) credentials used to authenicate user
sub verifyIdentity { my $self = shift; return undef }

## issue credentials
sub issueCredentials {
	my $self = shift;
	my($r) = @_;
	my $log = $r->log;
	my($uid, $realm, $ctxt, %args, $requrl, $idx, @chains, $chain, $url, $sep);
	my($backurl);

SecSess/URL/Cookie.pm  view on Meta::CPAN

use Apache::SecSess;
use Apache::SecSess::URL;
use Apache::SecSess::Wrapper;

use vars qw(@ISA $VERSION);

$VERSION = sprintf("%d.%02d", (q$Name: SecSess_Release_0_09 $ =~ /\d+/g));

@ISA = qw(Apache::SecSess::URL);

## validate credentials used to first authenicate user
sub verifyIdentity { 
	my $self = shift;
	my($r) = @_;
	my $log = $r->log;
	my($realm, $ckyhead, %ckys, @tags, $max, $url, $ckycred);

    $log->debug(ref($self), "->verifyIdentity():");

	## extract strongest cookie with appropriate name/tag pair
	$realm = $self->authRealm;

SecSess/URL/Cookie.pm  view on Meta::CPAN

		);
		return {
			message => "No cookie found, redirecting to '$url'",
			uri => $url
		};
	}

	## cookie found, but must be verified
	$log->debug(sprintf("Found Cookie: %s:%s=%s", $realm, $max, $ckys{$max}));
	$ckycred = $self->{wrapper}->unwraphash($ckys{$max});
	return $self->validateCredentials($r, $ckycred);
}

1;

__END__
What are you looking at?

db/testdb  view on Meta::CPAN


@uids = ('bob', 'guest');

for $uid (@uids) {
	printf("groups(%s): ('%s')\n", $uid, 
		join("','", $dbo->get_groups($uid))
	); 
	printf("%s is valid: %d\n", $uid, $dbo->is_valid_user($uid)); 
	printf("%s is super: %d\n", $uid, $dbo->is_super_user($uid)); 
	printf("%s is admin: %d\n", $uid, $dbo->is_administrator($uid)); 
	printf("verified = '%s'\n", $dbo->validate_user_pass($uid, 'sekret'));
}

## invalidate guest
$uid = 'guest';
printf("verified = '%s'\n", $dbo->validate_user_pass($uid, 'sekret'));
printf("verified = '%s'\n", $dbo->validate_user_pass($uid, 'sekret'));
printf("verified = '%s'\n", $dbo->validate_user_pass($uid, 'sekret'));
printf("status(%s) = %s\n", $uid, $dbo->get_user_status($uid));
printf("verified = '%s'\n", $dbo->validate_user_pass($uid, 'johnanon'));

printf("re-enabling user '%s'\n", $uid);
$dbo->enable_user($uid);
printf("status(%s) = %s\n", $uid, $dbo->get_user_status($uid));

## see if it works for multivalued auths
$uid = 'bob';
printf("verified = '%s'\n", $dbo->validate_user_pass($uid, 'secret'));
printf("verified = '%s'\n", $dbo->validate_user_pass($uid, 'secret'));
printf("verified = '%s'\n", $dbo->validate_user_pass($uid, 'secret'));
printf("verified = '%s'\n", $dbo->validate_user_pass($uid, 'secret'));
printf("status(%s) = %s\n", $uid, $dbo->get_user_status($uid));
printf("re-enabling user '%s'\n", $uid);
$dbo->enable_user($uid);
printf("status(%s) = %s\n", $uid, $dbo->get_user_status($uid));

## resolve X509 emails to uids
for $uid (@uids) {
	$email = $dbo->get_stored_token($uid, 'x509email');
	next unless $email;
	printf("uid('%s') = '%s'\n", $email, $dbo->x509email_to_uid($email));

rfc/rfc2109.txt  view on Meta::CPAN

   response headers, depending on circumstances:

   * To suppress caching of the Set-Cookie header: Cache-control: no-
     cache="set-cookie".

   and one of the following:

   * To suppress caching of a private document in shared caches: Cache-
     control: private.

   * To allow caching of a document and require that it be validated
     before returning it to the client: Cache-control: must-revalidate.

   * To allow caching of a document, but to require that proxy caches
     (not user agent caches) validate it before returning it to the
     client: Cache-control: proxy-revalidate.

   * To allow caching of a document and request that it be validated
     before returning it to the client (by "pre-expiring" it):
     Cache-control: max-age=0.  Not all caches will revalidate the
     document in every case.

   HTTP/1.1 servers must send Expires: old-date (where old-date is a
   date long in the past) on responses containing Set-Cookie response
   headers unless they know for certain (by out of band means) that
   there are no downsteam HTTP/1.0 proxies.  HTTP/1.1 servers may send
   other Cache-Control directives that permit caching by HTTP/1.1
   proxies in addition to the Expires: old-date directive; the Cache-
   Control directive will override the Expires: old-date for HTTP/1.1
   proxies.

rfc/rfc2965.txt  view on Meta::CPAN


         Cache-control: private



Kristol & Montulli          Standards Track                     [Page 7]

RFC 2965            HTTP State Management Mechanism         October 2000


      *  To allow caching of a document and require that it be validated
         before returning it to the client:

         Cache-Control: must-revalidate, max-age=0

      *  To allow caching of a document, but to require that proxy
         caches (not user agent caches) validate it before returning it
         to the client:

         Cache-Control: proxy-revalidate, max-age=0

      *  To allow caching of a document and request that it be validated
         before returning it to the client (by "pre-expiring" it):

         Cache-control: max-age=0

         Not all caches will revalidate the document in every case.

   HTTP/1.1 servers MUST send Expires: old-date (where old-date is a
   date long in the past) on responses containing Set-Cookie2 response
   headers unless they know for certain (by out of band means) that
   there are no HTTP/1.0 proxies in the response chain.  HTTP/1.1
   servers MAY send other Cache-Control directives that permit caching
   by HTTP/1.1 proxies in addition to the Expires: old-date directive;
   the Cache-Control directive will override the Expires: old-date for
   HTTP/1.1 proxies.



( run in 0.671 second using v1.01-cache-2.11-cpan-a5abf4f5562 )