view Lib/Security/Auth.pm @ 103:c289ed9662ca

Schema beta 2 More strict validation, support for inflating a simple nodes and properties
author wizard
date Fri, 07 May 2010 18:17:40 +0400
parents 16ada169ca75
children
line wrap: on
line source

package Security::Auth;
use strict;
use Common;
use Security;
use DateTime;
use Digest::MD5 qw(md5_hex);
our @ISA = qw(Object);

our $Package;
our $DataSource;

srand time;

BEGIN {
    DeclareProperty DS => ACCESS_READ;
    DeclareProperty SecPackage => ACCESS_READ;
}

{
    my $i = 0;
    sub GenSSID() {
        return md5_hex(time,rand,$i++);
    }
}

sub CTOR {
    my ($this,%args) = @_;
    $this->{$DS} = $args{'DS'} or die new Exception('A data source is required');
    $this->{$SecPackage} = $args{'SecPackage'} or die new Exception('A security package is required');
}

sub AuthenticateUser {
    my ($this,$Name,$SecData) = @_;
    
    my $User = $this->{$DS}->FindUser($Name);
    if (not $User or not $User->Active ) {
        return new Security::AuthResult (
            State => Security::AUTH_FAILED,
            AuthModule => $this
        );
    } else {
        
        
        if (my $StoredData = $this->{$DS}->GetUserAuthData($User,$this->{$SecPackage})) {
            my $AuthData = $this->{$SecPackage}->ConstructAuthData($StoredData->AuthData);
            if ((my $status = $AuthData->DoAuth($SecData)) != Security::AUTH_FAILED) {
                $AuthData = $this->{$SecPackage}->NewAuthData(GenSSID);
                return new Security::AuthResult (
                    State => $status,
                    Session => $this->{$DS}->CreateSession(GenSSID,$User,$AuthData),
                    ClientSecData => $AuthData->ClientAuthData,
                    AuthModule => $this
                )
            } else {
                return new Security::AuthResult (
                    State => Security::AUTH_FAILED,
                    AuthModule => $this
                );
            }
        } else {
            # the user isn't allowed to authenticate using this method
            return new Security::AuthResult (
                    State => Security::AUTH_FAILED,
                    AuthModule => $this
            );
        }
    }
}

sub AuthenticateSession {
    my ($this,$SSID,$SecData) = @_;
    
    my $Session = $this->{$DS}->LoadSession($SSID) or return new Security::AuthResult(State => Security::AUTH_FAILED);
    
    my $AuthData = $this->{$SecPackage}->ConstructAuthData($Session->SecData);
    if ((my $status = $AuthData->DoAuth($SecData)) != Security::AUTH_FAILED) {
        $Session->SecData($AuthData->SessionAuthData);
        $Session->LastUsage(DateTime->now());
        return new Security::AuthResult(State => $status, Session => $Session, ClientSecData => $AuthData->ClientAuthData, AuthModule => $this);
    } else {
        $this->{$DS}->CloseSession($Session);
        return new Security::AuthResult(State => Security::AUTH_FAILED, AuthModule => $this);
    }
}

sub CreateUser {
    my ($this,$uname,$description,$active,$secData) = @_;
    
    my $user = $this->{$DS}->CreateUser($uname,$description,$active);
    $this->{$DS}->SetUserAuthData($user,$this->{$SecPackage},$this->{$SecPackage}->NewAuthData($secData));
    
    return $user;
}

sub try_construct {
    my $package = shift;
    return $package->can('construct') ? $package->construct() : $package;
}

sub construct {
    $Package or die new Exception('A security package is reqiured');
    $DataSource or die new Exception('A data source is required');
    eval "require $DataSource;" or die new Exception('Failed to load the data source module',$@) if not ref $DataSource;
    eval "require $Package;" or die new Exception('Failed to load the security package module',$@) if not ref $Package;
    return __PACKAGE__->new(DS => try_construct($DataSource), SecPackage => try_construct($Package));
}

1;