Mercurial > pub > Impl
annotate Lib/IMPL/Web/Handler/SecureCookie.pm @ 398:38cb0b80e88e
minor changes
| author | sergey | 
|---|---|
| date | Thu, 08 May 2014 03:53:17 +0400 | 
| parents | 69a1f1508696 | 
| children | 
| rev | line source | 
|---|---|
| 230 | 1 package IMPL::Web::Handler::SecureCookie; | 
| 196 | 2 use strict; | 
| 3 | |
| 230 | 4 | 
| 196 | 5 use Digest::MD5 qw(md5_hex); | 
| 230 | 6 use IMPL::Const qw(:prop); | 
| 7 use IMPL::Security::Auth qw(:Const GenSSID); | |
| 8 use IMPL::declare { | |
| 9 require => { | |
| 10 SecurityContext => 'IMPL::Security::Context', | |
| 238 | 11 User => 'IMPL::Security::Principal', | 
| 230 | 12 AuthSimple => 'IMPL::Security::Auth::Simple', | 
| 231 | 13 Exception => 'IMPL::Exception', | 
| 14 OperationException => '-IMPL::InvalidOperationException', | |
| 15 HttpResponse => '-IMPL::Web::HttpResponse' | |
| 230 | 16 }, | 
| 17 base => { | |
| 18 'IMPL::Object' => undef, | |
| 19 'IMPL::Object::Autofill' => '@_', | |
| 20 'IMPL::Object::Serializable' => undef | |
| 21 }, | |
| 22 props => [ | |
| 23 salt => PROP_RO, | |
| 371 | 24 _security => PROP_RW, | 
| 230 | 25 _cookies => PROP_RW | 
| 26 ] | |
| 27 }; | |
| 196 | 28 | 
| 29 sub CTOR { | |
| 30 my ($this) = @_; | |
| 31 | |
| 32 $this->salt('DeadBeef') unless $this->salt; | |
| 33 } | |
| 34 | |
| 262 | 35 sub ValidateCookie { | 
| 36 my ($this,$sid,$cookie,$sign) = @_; | |
| 37 | |
| 38 return 1 if $sid and $cookie and $sign and $sign eq md5_hex($this->salt,$sid,$cookie,$this->salt); | |
| 39 | |
| 40 return 0; | |
| 41 } | |
| 42 | |
| 263 | 43 sub AuthCookie { | 
| 44 my ($this,$sid,$cookie,$sign, $context) = @_; | |
| 45 | |
| 46 if (eval { $context->auth->isa(AuthSimple) }) { | |
| 47 my ($result,$challenge) = $context->auth->DoAuth($cookie); | |
| 48 return $result; | |
| 49 } | |
| 50 | |
| 51 return AUTH_FAIL; | |
| 52 } | |
| 53 | |
| 230 | 54 sub Invoke { | 
| 196 | 55 my ($this,$action,$nextHandler) = @_; | 
| 56 | |
| 230 | 57 return unless $nextHandler; | 
| 58 | |
| 59 my $context; | |
| 357 | 60 $this->_security($action->security); | 
| 196 | 61 | 
| 230 | 62 | 
| 63 my $sid = $action->cookie('sid',qr/(\w+)/); | |
| 64 my $cookie = $action->cookie('sdata',qr/(\w+)/); | |
| 239 | 65 my $sign = $action->cookie('sign',qw/(\w+)/); | 
| 196 | 66 | 
| 262 | 67 if ( $this->ValidateCookie($sid,$cookie,$sign) ) { | 
| 328 | 68 # TODO: add a DeferredProxy to deffer a request to a data source | 
| 357 | 69 if ( $context = $this->_security->sessions->GetById($sid) ) { | 
| 230 | 70 if ( eval { $context->auth->isa(AuthSimple) } ) { | 
| 71 my ($result,$challenge) = $context->auth->DoAuth($cookie); | |
| 239 | 72 | 
| 73 $context->authority($this); | |
| 74 | |
| 230 | 75 if ($result == AUTH_FAIL) { | 
| 76 $context = undef; | |
| 77 } | |
| 239 | 78 } else { | 
| 79 undef $context; | |
| 196 | 80 } | 
| 81 } | |
| 230 | 82 | 
| 196 | 83 } | 
| 230 | 84 | 
| 231 | 85 $context ||= SecurityContext->new(principal => User->nobody, authority => $this); | 
| 230 | 86 | 
| 
339
 
97628101b765
refactoring: application now holds a security object factory rather than a security object
 
cin 
parents: 
328 
diff
changeset
 | 
87 my $httpResponse = eval { $context->Impersonate($nextHandler,$action); }; | 
| 
 
97628101b765
refactoring: application now holds a security object factory rather than a security object
 
cin 
parents: 
328 
diff
changeset
 | 
88 my $e = $@; | 
| 
 
97628101b765
refactoring: application now holds a security object factory rather than a security object
 
cin 
parents: 
328 
diff
changeset
 | 
89 | 
| 
 
97628101b765
refactoring: application now holds a security object factory rather than a security object
 
cin 
parents: 
328 
diff
changeset
 | 
90 die $e if $e; | 
| 230 | 91 | 
| 231 | 92 die OperationException->new("A HttpResponse instance is expected") | 
| 93 unless ref $httpResponse && eval { $httpResponse->isa(HttpResponse) }; | |
| 230 | 94 | 
| 393 | 95 return $this->_WriteResponse($httpResponse); | 
| 230 | 96 } | 
| 97 | |
| 231 | 98 sub InitSession { | 
| 239 | 99 my ($this,$user,$roles,$auth,$challenge) = @_; | 
| 230 | 100 | 
| 254 | 101 my ($status,$answer); | 
| 102 | |
| 103 if ($auth) { | |
| 104 ($status,$answer) = $auth->DoAuth($challenge); | |
| 105 } else { | |
| 106 $status = AUTH_SUCCESS; | |
| 107 } | |
| 239 | 108 | 
| 109 die OperationException->new("This provider doesn't support multiround auth") | |
| 110 if ($status == AUTH_INCOMPLETE || $answer); | |
| 230 | 111 | 
| 239 | 112 if ($status == AUTH_SUCCESS) { | 
| 113 my $sid = GenSSID(); | |
| 114 my $cookie = GenSSID(); | |
| 115 | |
| 116 $this->_cookies({ | |
| 117 sid => $sid, | |
| 118 sdata => $cookie | |
| 119 }); | |
| 120 | |
| 357 | 121 my $context = $this->_security->sessions->Create({ | 
| 239 | 122 sessionId => $sid, | 
| 123 principal => $user, | |
| 124 auth => AuthSimple->Create(password => $cookie), | |
| 125 authority => $this, | |
| 126 rolesAssigned => $roles | |
| 328 | 127 }); | 
| 239 | 128 | 
| 129 $context->Apply(); | |
| 130 | |
| 131 } | |
| 132 | |
| 133 return $status; | |
| 134 } | |
| 230 | 135 | 
| 239 | 136 sub CloseSession { | 
| 137 my ($this) = @_; | |
| 138 if(my $session = SecurityContext->current) { | |
| 139 $this->_cookies({ | |
| 140 sid => undef, | |
| 141 sdata => undef | |
| 142 }) | |
| 143 } | |
| 196 | 144 } | 
| 145 | |
| 393 | 146 sub _WriteResponse { | 
| 230 | 147 my ($this,$response) = @_; | 
| 148 | |
| 238 | 149 if (my $data = $this->_cookies) { | 
| 196 | 150 | 
| 239 | 151 my $sign = $data->{sid} && md5_hex( | 
| 230 | 152 $this->salt, | 
| 153 $data->{sid}, | |
| 154 $data->{sdata}, | |
| 155 $this->salt | |
| 156 ); | |
| 157 | |
| 158 $response->cookies->{sid} = $data->{sid}; | |
| 159 $response->cookies->{sdata} = $data->{sdata}; | |
| 160 $response->cookies->{sign} = $sign; | |
| 161 } | |
| 231 | 162 | 
| 163 return $response; | |
| 196 | 164 } | 
| 165 | |
| 166 1; | |
| 167 | |
| 168 __END__ | |
| 169 | |
| 170 =pod | |
| 171 | |
| 172 =head1 NAME | |
| 173 | |
| 230 | 174 C<IMPL::Web::Handler::SecureCookie> | 
| 196 | 175 | 
| 176 =head1 DESCRIPTION | |
| 177 | |
| 178 Возобновляет сессию пользователя на основе информации переданной через Cookie. | |
| 179 | |
| 180 Использует механизм подписи информации для проверки верности входных данных перед | |
| 181 началом каких-либо действий. | |
| 182 | |
| 183 Данный обработчик возвращает результат выполнения следдующего обработчика. | |
| 184 | |
| 230 | 185 | 
| 186 | |
| 196 | 187 =head1 MEMBERS | 
| 188 | |
| 231 | 189 =head2 C<[get,set] salt> | 
| 196 | 190 | 
| 191 Скаляр, использующийся для подписи данных. | |
| 192 | |
| 233 | 193 | 
| 254 | 194 =head2 C<InitSession($user,$roles,$auth,$challenge)> | 
| 195 | |
| 196 Инициирует сессию, поскольку данный модуль отвечает за взаимодействие с клиентом | |
| 197 при проверки аутентификации, ему передаются данные аутентификации для | |
| 198 продолжения обмена данными с клиентом. Если создается новая сессия, по | |
| 199 инициативе веб-приложения, то C<$auth> должно быть пусто. | |
| 196 | 200 | 
| 201 =cut | 
