Mercurial > pub > Impl
view Lib/IMPL/Web/Handler/SecureCookie.pm @ 396:6f2a494579cb
sync
author | sergey |
---|---|
date | Mon, 24 Feb 2014 01:55:46 +0400 |
parents | 69a1f1508696 |
children |
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::Principal', 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, _security => PROP_RW, _cookies => PROP_RW ] }; sub CTOR { my ($this) = @_; $this->salt('DeadBeef') unless $this->salt; } sub ValidateCookie { my ($this,$sid,$cookie,$sign) = @_; return 1 if $sid and $cookie and $sign and $sign eq md5_hex($this->salt,$sid,$cookie,$this->salt); return 0; } sub AuthCookie { my ($this,$sid,$cookie,$sign, $context) = @_; if (eval { $context->auth->isa(AuthSimple) }) { my ($result,$challenge) = $context->auth->DoAuth($cookie); return $result; } return AUTH_FAIL; } sub Invoke { my ($this,$action,$nextHandler) = @_; return unless $nextHandler; my $context; $this->_security($action->security); my $sid = $action->cookie('sid',qr/(\w+)/); my $cookie = $action->cookie('sdata',qr/(\w+)/); my $sign = $action->cookie('sign',qw/(\w+)/); if ( $this->ValidateCookie($sid,$cookie,$sign) ) { # TODO: add a DeferredProxy to deffer a request to a data source if ( $context = $this->_security->sessions->GetById($sid) ) { if ( eval { $context->auth->isa(AuthSimple) } ) { my ($result,$challenge) = $context->auth->DoAuth($cookie); $context->authority($this); if ($result == AUTH_FAIL) { $context = undef; } } else { undef $context; } } } $context ||= SecurityContext->new(principal => User->nobody, authority => $this); my $httpResponse = eval { $context->Impersonate($nextHandler,$action); }; my $e = $@; die $e if $e; die OperationException->new("A HttpResponse instance is expected") unless ref $httpResponse && eval { $httpResponse->isa(HttpResponse) }; return $this->_WriteResponse($httpResponse); } sub InitSession { my ($this,$user,$roles,$auth,$challenge) = @_; my ($status,$answer); if ($auth) { ($status,$answer) = $auth->DoAuth($challenge); } else { $status = AUTH_SUCCESS; } die OperationException->new("This provider doesn't support multiround auth") if ($status == AUTH_INCOMPLETE || $answer); if ($status == AUTH_SUCCESS) { my $sid = GenSSID(); my $cookie = GenSSID(); $this->_cookies({ sid => $sid, sdata => $cookie }); my $context = $this->_security->sessions->Create({ sessionId => $sid, principal => $user, auth => AuthSimple->Create(password => $cookie), authority => $this, rolesAssigned => $roles }); $context->Apply(); } return $status; } sub CloseSession { my ($this) = @_; if(my $session = SecurityContext->current) { $this->_cookies({ sid => undef, sdata => undef }) } } sub _WriteResponse { my ($this,$response) = @_; if (my $data = $this->_cookies) { my $sign = $data->{sid} && 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<InitSession($user,$roles,$auth,$challenge)> Инициирует сессию, поскольку данный модуль отвечает за взаимодействие с клиентом при проверки аутентификации, ему передаются данные аутентификации для продолжения обмена данными с клиентом. Если создается новая сессия, по инициативе веб-приложения, то C<$auth> должно быть пусто. =cut