Apache-SecSess

 view release on metacpan or  search on metacpan

SecSess/DBI.pm  view on Meta::CPAN


## is the user ID valid (whether or not enabled)
sub is_valid_user {
	my $self = shift;
	my($uid) = @_;

	unless ($self->get_user_record($uid)) { return 0; }
	return 1;
}

## retrieve user's status field
sub get_user_status {
	my $self = shift;
	my($uid) = @_;

	my $rec = $self->get_user_record($uid);
	unless ($rec) { return 'unknown'; }
	return $rec->{status};
}

## get the full name
sub get_full_name {
	my $self = shift;
	my($uid) = @_;

	my $rec = $self->get_user_record($uid);
	unless ($rec) { return undef; }
	return $rec->{name};
}

## get UNIX-style password hash
sub get_pwhash {
	my $self = shift;
	my($uid) = @_;
	return $self->get_stored_token($uid, 'unixpw');
}

## get stored token 
sub get_stored_token {
	my $self = shift;
	my($uid, $authid) = @_;
	my($uasth, $token);

	# set up DB query statement
	$self->refresh_dbh;
	$uasth = $self->{dbh}->prepare(<<'ENDSQL');
		SELECT token
		FROM userauthen
		WHERE usrid = ? AND authid = ?
ENDSQL
	$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);
		return 'again'; # 'again' means 'wrong' but may be visible in URL
	}
	$self->note_auth_success($uid, $authid);
	return 'OK';
}

## protect against online guessing attacks
sub note_auth_failure {
	my $self = shift;
	my($uid, $authid) = @_;
	my($asth, $maxfail, $uasth, $failcount, $usth);

	## determine if we must count failures at all
	$self->refresh_dbh;
	$asth = $self->{dbh}->prepare(<<'ENDSQL');
		SELECT maxfail
		FROM authens
		WHERE authid = ?
ENDSQL
	$asth->execute($authid);
	$maxfail = $asth->fetchrow_array;
	$asth->finish;
	unless ($maxfail) { return; }

	## get current failure count
	$uasth = $self->{dbh}->prepare(<<'ENDSQL');
		SELECT failcount
		FROM userauthen
		WHERE usrid = ? AND authid = ?
ENDSQL
	$uasth->execute($uid, $authid);
	$failcount = $uasth->fetchrow_array;
	$uasth->finish;

	if (++$failcount <= $maxfail) { # bump count
		$uasth = $self->{dbh}->prepare(<<'ENDSQL');
			UPDATE userauthen
			SET failcount = ?
			WHERE usrid = ? AND authid = ?
ENDSQL
		$uasth->execute($failcount, $uid, $authid);
		$uasth->finish;
		return;
	}

	## warn of impending doom
	warn "Too many login failures, disabling user '$uid'";

	## maximum failure count exceeded, must disable
	$usth = $self->{dbh}->prepare(<<'ENDSQL');



( run in 0.345 second using v1.01-cache-2.11-cpan-39bf76dae61 )