view Lib/IMPL/Web/Handler/SecureCookie.pm @ 234:2530d1bb9638

sync
author sergey
date Thu, 11 Oct 2012 20:11:45 +0400
parents 3cebcf6fdb9b
children b8c724f6de36
line wrap: on
line source

package IMPL::Web::Handler::SecureCookie;
use strict;


use Digest::MD5 qw(md5_hex);
use IMPL::Const qw(:prop);
use IMPL::Security::Auth qw(:Const GenSSID);
use IMPL::declare {
    require => {
        SecurityContext => 'IMPL::Security::Context',
        User => 'IMPL::Security::User',
        AuthSimple => 'IMPL::Security::Auth::Simple',
        Exception => 'IMPL::Exception',
        OperationException => '-IMPL::InvalidOperationException',
        HttpResponse => '-IMPL::Web::HttpResponse'
    },
    base => {
        'IMPL::Object' => undef,
        'IMPL::Object::Autofill' => '@_',
        'IMPL::Object::Serializable' => undef
    },
    props => [  
        salt => PROP_RO,
        manager => PROP_RO,
        _cookies => PROP_RW
    ]
};

sub CTOR {
    my ($this) = @_;
    
    $this->salt('DeadBeef') unless $this->salt;
}

sub Invoke {
    my ($this,$action,$nextHandler) = @_;
    
    return unless $nextHandler;
    
    my $context;
    
        
    my $sid = $action->cookie('sid',qr/(\w+)/); 
    my $cookie = $action->cookie('sdata',qr/(\w+)/);
    my $sign = $action->cookie('sign',qw/(\w+)/); 
    
    if (
        $sid and
        $cookie and
        $sign and
        $sign eq md5_hex(
            $this->salt,
            $sid,
            $cookie,
            $this->salt
        )
    ) {
        # TODO: add a DefferedProxy to deffer a request to a data source
        if ( $context = $this->manager->GetSession($sid) ) {
        
            if ( eval { $context->auth->isa(AuthSimple) } ) {
                my ($result,$challenge) = $context->auth->DoAuth($cookie);
                
                $action->manager->SaveSession($context);
                
                if ($result == AUTH_FAIL) {
                    $context = undef;
                }
            }
        }
        
    }
    
    $context ||= SecurityContext->new(principal => User->nobody, authority => $this);
    
    my $httpResponse = $context->Impersonate($nextHandler);
    
    die OperationException->new("A HttpResponse instance is expected")
        unless ref $httpResponse && eval { $httpResponse->isa(HttpResponse) };
    
    return $this->WriteResponse($httpResponse);
}

sub InitSession {
    my ($this,$user,$auth,$roles) = @_;
    
    my $sid = GenSSID();
    my $cookie = GenSSID();
    
    $this->_cookies({
        sid => $sid,
        sdata => $cookie
    })

    my $context = $this->$manager->CreateSession(
        sessionId => $sid,
        principal => $user,
        auth => AuthSimple->Create(password => $cookie),
        authority => $this,
        assignedRoles => $roles
    );
    
    $context->Apply();
    
    return $context;
}

sub WriteResponse {
    my ($this,$response) = @_;
    
    if (my $data $this->_cookies) {

        my $sign = md5_hex(
            $this->salt,
            $data->{sid},
            $data->{sdata},
            $this->salt
        );
        
        $response->cookies->{sid} = $data->{sid};
        $response->cookies->{sdata} = $data->{sdata};
        $response->cookies->{sign} = $sign;
    }
    
    return $response;
}

1;

__END__

=pod

=head1 NAME

C<IMPL::Web::Handler::SecureCookie>

=head1 DESCRIPTION

Возобновляет сессию пользователя на основе информации переданной через Cookie.

Использует механизм подписи информации для проверки верности входных данных перед
началом каких-либо действий.

Данный обработчик возвращает результат выполнения следдующего обработчика.



=head1 MEMBERS

=head2 C<[get,set] salt>

Скаляр, использующийся для подписи данных.

=head2 C<[get,set] manager>

Реализация менеджера безопасности, отвечающая за реализацию взаимодействия с
моделью безопасности. 

=head2 C<InitSession($user,$auth,$roles)>

=cut