Mercurial > pub > Impl
comparison lib/IMPL/Web/Handler/SecureCookie.pm @ 407:c6e90e02dd17 ref20150831
renamed Lib->lib
author | cin |
---|---|
date | Fri, 04 Sep 2015 19:40:23 +0300 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
406:f23fcb19d3c1 | 407:c6e90e02dd17 |
---|---|
1 package IMPL::Web::Handler::SecureCookie; | |
2 use strict; | |
3 | |
4 | |
5 use Digest::MD5 qw(md5_hex); | |
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', | |
11 User => 'IMPL::Security::Principal', | |
12 AuthSimple => 'IMPL::Security::Auth::Simple', | |
13 Exception => 'IMPL::Exception', | |
14 OperationException => '-IMPL::InvalidOperationException', | |
15 HttpResponse => '-IMPL::Web::HttpResponse' | |
16 }, | |
17 base => { | |
18 'IMPL::Object' => undef, | |
19 'IMPL::Object::Autofill' => '@_', | |
20 'IMPL::Object::Serializable' => undef | |
21 }, | |
22 props => [ | |
23 salt => PROP_RO, | |
24 _security => PROP_RW, | |
25 _cookies => PROP_RW | |
26 ] | |
27 }; | |
28 | |
29 sub CTOR { | |
30 my ($this) = @_; | |
31 | |
32 $this->salt('DeadBeef') unless $this->salt; | |
33 } | |
34 | |
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 | |
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 | |
54 sub Invoke { | |
55 my ($this,$action,$nextHandler) = @_; | |
56 | |
57 return unless $nextHandler; | |
58 | |
59 my $context; | |
60 $this->_security($action->security); | |
61 | |
62 | |
63 my $sid = $action->cookie('sid',qr/(\w+)/); | |
64 my $cookie = $action->cookie('sdata',qr/(\w+)/); | |
65 my $sign = $action->cookie('sign',qw/(\w+)/); | |
66 | |
67 if ( $this->ValidateCookie($sid,$cookie,$sign) ) { | |
68 # TODO: add a DeferredProxy to deffer a request to a data source | |
69 if ( $context = $this->_security->sessions->GetById($sid) ) { | |
70 if ( eval { $context->auth->isa(AuthSimple) } ) { | |
71 my ($result,$challenge) = $context->auth->DoAuth($cookie); | |
72 | |
73 $context->authority($this); | |
74 | |
75 if ($result == AUTH_FAIL) { | |
76 $context = undef; | |
77 } | |
78 } else { | |
79 undef $context; | |
80 } | |
81 } | |
82 | |
83 } | |
84 | |
85 $context ||= SecurityContext->new(principal => User->nobody, authority => $this); | |
86 | |
87 my $httpResponse = eval { $context->Impersonate($nextHandler,$action); }; | |
88 my $e = $@; | |
89 | |
90 die $e if $e; | |
91 | |
92 die OperationException->new("A HttpResponse instance is expected") | |
93 unless ref $httpResponse && eval { $httpResponse->isa(HttpResponse) }; | |
94 | |
95 return $this->_WriteResponse($httpResponse); | |
96 } | |
97 | |
98 sub InitSession { | |
99 my ($this,$user,$roles,$auth,$challenge) = @_; | |
100 | |
101 my ($status,$answer); | |
102 | |
103 if ($auth) { | |
104 ($status,$answer) = $auth->DoAuth($challenge); | |
105 } else { | |
106 $status = AUTH_SUCCESS; | |
107 } | |
108 | |
109 die OperationException->new("This provider doesn't support multiround auth") | |
110 if ($status == AUTH_INCOMPLETE || $answer); | |
111 | |
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 | |
121 my $context = $this->_security->sessions->Create({ | |
122 sessionId => $sid, | |
123 principal => $user, | |
124 auth => AuthSimple->Create(password => $cookie), | |
125 authority => $this, | |
126 rolesAssigned => $roles | |
127 }); | |
128 | |
129 $context->Apply(); | |
130 | |
131 } | |
132 | |
133 return $status; | |
134 } | |
135 | |
136 sub CloseSession { | |
137 my ($this) = @_; | |
138 if(my $session = SecurityContext->current) { | |
139 $this->_cookies({ | |
140 sid => undef, | |
141 sdata => undef | |
142 }) | |
143 } | |
144 } | |
145 | |
146 sub _WriteResponse { | |
147 my ($this,$response) = @_; | |
148 | |
149 if (my $data = $this->_cookies) { | |
150 | |
151 my $sign = $data->{sid} && md5_hex( | |
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 } | |
162 | |
163 return $response; | |
164 } | |
165 | |
166 1; | |
167 | |
168 __END__ | |
169 | |
170 =pod | |
171 | |
172 =head1 NAME | |
173 | |
174 C<IMPL::Web::Handler::SecureCookie> | |
175 | |
176 =head1 DESCRIPTION | |
177 | |
178 Возобновляет сессию пользователя на основе информации переданной через Cookie. | |
179 | |
180 Использует механизм подписи информации для проверки верности входных данных перед | |
181 началом каких-либо действий. | |
182 | |
183 Данный обработчик возвращает результат выполнения следдующего обработчика. | |
184 | |
185 | |
186 | |
187 =head1 MEMBERS | |
188 | |
189 =head2 C<[get,set] salt> | |
190 | |
191 Скаляр, использующийся для подписи данных. | |
192 | |
193 | |
194 =head2 C<InitSession($user,$roles,$auth,$challenge)> | |
195 | |
196 Инициирует сессию, поскольку данный модуль отвечает за взаимодействие с клиентом | |
197 при проверки аутентификации, ему передаются данные аутентификации для | |
198 продолжения обмена данными с клиентом. Если создается новая сессия, по | |
199 инициативе веб-приложения, то C<$auth> должно быть пусто. | |
200 | |
201 =cut |