Mercurial > pub > Impl
annotate Lib/IMPL/Web/Handler/SecureCookie.pm @ 339:97628101b765
refactoring: application now holds a security object factory rather than a security object
author | cin |
---|---|
date | Wed, 19 Jun 2013 03:25:44 +0400 |
parents | 63709a4e6da0 |
children | c090d9102a38 |
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, | |
238 | 24 _manager => PROP_RO, |
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; | |
339
97628101b765
refactoring: application now holds a security object factory rather than a security object
cin
parents:
328
diff
changeset
|
60 $this->_manager($action->application->security->new()); |
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 |
69 if ( $context = $this->_manager->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 $this->_manager->Dispose(); |
97628101b765
refactoring: application now holds a security object factory rather than a security object
cin
parents:
328
diff
changeset
|
91 |
97628101b765
refactoring: application now holds a security object factory rather than a security object
cin
parents:
328
diff
changeset
|
92 die $e if $e; |
230 | 93 |
231 | 94 die OperationException->new("A HttpResponse instance is expected") |
95 unless ref $httpResponse && eval { $httpResponse->isa(HttpResponse) }; | |
230 | 96 |
231 | 97 return $this->WriteResponse($httpResponse); |
230 | 98 } |
99 | |
231 | 100 sub InitSession { |
239 | 101 my ($this,$user,$roles,$auth,$challenge) = @_; |
230 | 102 |
254 | 103 my ($status,$answer); |
104 | |
105 if ($auth) { | |
106 ($status,$answer) = $auth->DoAuth($challenge); | |
107 } else { | |
108 $status = AUTH_SUCCESS; | |
109 } | |
239 | 110 |
111 die OperationException->new("This provider doesn't support multiround auth") | |
112 if ($status == AUTH_INCOMPLETE || $answer); | |
230 | 113 |
239 | 114 if ($status == AUTH_SUCCESS) { |
115 my $sid = GenSSID(); | |
116 my $cookie = GenSSID(); | |
117 | |
118 $this->_cookies({ | |
119 sid => $sid, | |
120 sdata => $cookie | |
121 }); | |
122 | |
328 | 123 my $context = $this->_manager->sessions->Create({ |
239 | 124 sessionId => $sid, |
125 principal => $user, | |
126 auth => AuthSimple->Create(password => $cookie), | |
127 authority => $this, | |
128 rolesAssigned => $roles | |
328 | 129 }); |
239 | 130 |
131 $context->Apply(); | |
132 | |
133 } | |
134 | |
135 return $status; | |
136 } | |
230 | 137 |
239 | 138 sub CloseSession { |
139 my ($this) = @_; | |
140 if(my $session = SecurityContext->current) { | |
141 $this->_cookies({ | |
142 sid => undef, | |
143 sdata => undef | |
144 }) | |
145 } | |
196 | 146 } |
147 | |
148 sub WriteResponse { | |
230 | 149 my ($this,$response) = @_; |
150 | |
238 | 151 if (my $data = $this->_cookies) { |
196 | 152 |
239 | 153 my $sign = $data->{sid} && md5_hex( |
230 | 154 $this->salt, |
155 $data->{sid}, | |
156 $data->{sdata}, | |
157 $this->salt | |
158 ); | |
159 | |
160 $response->cookies->{sid} = $data->{sid}; | |
161 $response->cookies->{sdata} = $data->{sdata}; | |
162 $response->cookies->{sign} = $sign; | |
163 } | |
231 | 164 |
165 return $response; | |
196 | 166 } |
167 | |
168 1; | |
169 | |
170 __END__ | |
171 | |
172 =pod | |
173 | |
174 =head1 NAME | |
175 | |
230 | 176 C<IMPL::Web::Handler::SecureCookie> |
196 | 177 |
178 =head1 DESCRIPTION | |
179 | |
180 Возобновляет сессию пользователя на основе информации переданной через Cookie. | |
181 | |
182 Использует механизм подписи информации для проверки верности входных данных перед | |
183 началом каких-либо действий. | |
184 | |
185 Данный обработчик возвращает результат выполнения следдующего обработчика. | |
186 | |
230 | 187 |
188 | |
196 | 189 =head1 MEMBERS |
190 | |
231 | 191 =head2 C<[get,set] salt> |
196 | 192 |
193 Скаляр, использующийся для подписи данных. | |
194 | |
233 | 195 |
254 | 196 =head2 C<InitSession($user,$roles,$auth,$challenge)> |
197 | |
198 Инициирует сессию, поскольку данный модуль отвечает за взаимодействие с клиентом | |
199 при проверки аутентификации, ему передаются данные аутентификации для | |
200 продолжения обмена данными с клиентом. Если создается новая сессия, по | |
201 инициативе веб-приложения, то C<$auth> должно быть пусто. | |
196 | 202 |
203 =cut |