1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* Created by PhpStorm. |
4
|
|
|
* User: chenyihong |
5
|
|
|
* Date: 16/8/1 |
6
|
|
|
* Time: 14:52 |
7
|
|
|
*/ |
8
|
|
|
|
9
|
|
|
namespace Leo108\CAS\Http\Controllers; |
10
|
|
|
|
11
|
|
|
use Illuminate\Support\Str; |
12
|
|
|
use Leo108\CAS\Contracts\TicketLocker; |
13
|
|
|
use Leo108\CAS\Repositories\PGTicketRepository; |
14
|
|
|
use Leo108\CAS\Repositories\TicketRepository; |
15
|
|
|
use Leo108\CAS\Exceptions\CAS\CasException; |
16
|
|
|
use Leo108\CAS\Models\Ticket; |
17
|
|
|
use Illuminate\Http\Request; |
18
|
|
|
use Illuminate\Http\Response; |
19
|
|
|
use Leo108\CAS\Responses\JsonAuthenticationFailureResponse; |
20
|
|
|
use Leo108\CAS\Responses\JsonAuthenticationSuccessResponse; |
21
|
|
|
use Leo108\CAS\Responses\JsonProxyFailureResponse; |
22
|
|
|
use Leo108\CAS\Responses\JsonProxySuccessResponse; |
23
|
|
|
use Leo108\CAS\Responses\XmlAuthenticationFailureResponse; |
24
|
|
|
use Leo108\CAS\Responses\XmlAuthenticationSuccessResponse; |
25
|
|
|
use Leo108\CAS\Responses\XmlProxyFailureResponse; |
26
|
|
|
use Leo108\CAS\Responses\XmlProxySuccessResponse; |
27
|
|
|
use Leo108\CAS\Services\PGTCaller; |
28
|
|
|
use Leo108\CAS\Services\TicketGenerator; |
29
|
|
|
use SimpleXMLElement; |
30
|
|
|
|
31
|
|
|
class ValidateController extends Controller |
32
|
|
|
{ |
33
|
|
|
/** |
34
|
|
|
* @var TicketLocker |
35
|
|
|
*/ |
36
|
|
|
protected $ticketLocker; |
37
|
|
|
/** |
38
|
|
|
* @var TicketRepository |
39
|
|
|
*/ |
40
|
|
|
protected $ticketRepository; |
41
|
|
|
|
42
|
|
|
/** |
43
|
|
|
* @var PGTicketRepository |
44
|
|
|
*/ |
45
|
|
|
protected $pgTicketRepository; |
46
|
|
|
|
47
|
|
|
/** |
48
|
|
|
* @var TicketGenerator |
49
|
|
|
*/ |
50
|
|
|
protected $ticketGenerator; |
51
|
|
|
|
52
|
|
|
/** |
53
|
|
|
* @var PGTCaller |
54
|
|
|
*/ |
55
|
|
|
protected $pgtCaller; |
56
|
|
|
|
57
|
|
|
/** |
58
|
|
|
* ValidateController constructor. |
59
|
|
|
* @param TicketLocker $ticketLocker |
60
|
|
|
* @param TicketRepository $ticketRepository |
61
|
|
|
* @param PGTicketRepository $pgTicketRepository |
62
|
|
|
* @param TicketGenerator $ticketGenerator |
63
|
|
|
* @param PGTCaller $pgtCaller |
64
|
|
|
*/ |
65
|
20 |
|
public function __construct( |
66
|
|
|
TicketLocker $ticketLocker, |
67
|
|
|
TicketRepository $ticketRepository, |
68
|
|
|
PGTicketRepository $pgTicketRepository, |
69
|
|
|
TicketGenerator $ticketGenerator, |
70
|
|
|
PGTCaller $pgtCaller |
71
|
|
|
) { |
72
|
20 |
|
$this->ticketLocker = $ticketLocker; |
73
|
20 |
|
$this->ticketRepository = $ticketRepository; |
74
|
20 |
|
$this->pgTicketRepository = $pgTicketRepository; |
75
|
20 |
|
$this->ticketGenerator = $ticketGenerator; |
76
|
20 |
|
$this->pgtCaller = $pgtCaller; |
77
|
20 |
|
} |
78
|
|
|
|
79
|
5 |
|
public function v1ValidateAction(Request $request) |
80
|
|
|
{ |
81
|
5 |
|
$service = $request->get('service', ''); |
82
|
5 |
|
$ticket = $request->get('ticket', ''); |
83
|
5 |
|
if (empty($service) || empty($ticket)) { |
84
|
1 |
|
return new Response('no'); |
85
|
|
|
} |
86
|
|
|
|
87
|
4 |
|
if (!$this->lockTicket($ticket)) { |
88
|
1 |
|
return new Response('no'); |
89
|
|
|
} |
90
|
3 |
|
$record = $this->ticketRepository->getByTicket($ticket); |
91
|
3 |
|
if (!$record || $record->service_url != $service) { |
92
|
2 |
|
$this->unlockTicket($ticket); |
93
|
|
|
|
94
|
2 |
|
return new Response('no'); |
95
|
|
|
} |
96
|
1 |
|
$this->ticketRepository->invalidTicket($record); |
97
|
|
|
|
98
|
1 |
|
$this->unlockTicket($ticket); |
99
|
|
|
|
100
|
1 |
|
return new Response('yes'); |
101
|
|
|
} |
102
|
|
|
|
103
|
1 |
|
public function v2ServiceValidateAction(Request $request) |
104
|
|
|
{ |
105
|
1 |
|
return $this->casValidate($request, true, false); |
106
|
|
|
} |
107
|
|
|
|
108
|
1 |
|
public function v3ServiceValidateAction(Request $request) |
109
|
|
|
{ |
110
|
1 |
|
return $this->casValidate($request, true, false); |
111
|
|
|
} |
112
|
|
|
|
113
|
1 |
|
public function v2ProxyValidateAction(Request $request) |
114
|
|
|
{ |
115
|
1 |
|
return $this->casValidate($request, false, true); |
116
|
|
|
} |
117
|
|
|
|
118
|
1 |
|
public function v3ProxyValidateAction(Request $request) |
119
|
|
|
{ |
120
|
1 |
|
return $this->casValidate($request, true, true); |
121
|
|
|
} |
122
|
|
|
|
123
|
3 |
|
public function proxyAction(Request $request) |
124
|
|
|
{ |
125
|
3 |
|
$pgt = $request->get('pgt', ''); |
126
|
3 |
|
$target = $request->get('targetService', ''); |
127
|
3 |
|
$format = strtoupper($request->get('format', 'XML')); |
128
|
|
|
|
129
|
3 |
|
if (empty($pgt) || empty($target)) { |
130
|
1 |
|
return $this->proxyFailureResponse( |
131
|
1 |
|
CasException::INVALID_REQUEST, |
132
|
1 |
|
'param pgt and targetService can not be empty', |
133
|
1 |
|
$format |
134
|
|
|
); |
135
|
|
|
} |
136
|
|
|
|
137
|
2 |
|
$record = $this->pgTicketRepository->getByTicket($pgt); |
138
|
|
|
try { |
139
|
2 |
|
if (!$record) { |
140
|
1 |
|
throw new CasException(CasException::INVALID_TICKET, 'ticket is not valid'); |
141
|
|
|
} |
142
|
1 |
|
$proxies = $record->proxies; |
143
|
1 |
|
array_unshift($proxies, $record->pgt_url); |
144
|
1 |
|
$ticket = $this->ticketRepository->applyTicket($record->user, $target, $proxies); |
145
|
1 |
|
} catch (CasException $e) { |
146
|
1 |
|
return $this->proxyFailureResponse($e->getCasErrorCode(), $e->getMessage(), $format); |
147
|
|
|
} |
148
|
|
|
|
149
|
1 |
|
return $this->proxySuccessResponse($ticket->ticket, $format); |
150
|
|
|
} |
151
|
|
|
|
152
|
|
|
/** |
153
|
|
|
* @param Request $request |
154
|
|
|
* @param bool $returnAttr |
155
|
|
|
* @param bool $allowProxy |
156
|
|
|
* @return Response |
157
|
|
|
*/ |
158
|
11 |
|
protected function casValidate(Request $request, $returnAttr, $allowProxy) |
159
|
|
|
{ |
160
|
11 |
|
$service = $request->get('service', ''); |
161
|
11 |
|
$ticket = $request->get('ticket', ''); |
162
|
11 |
|
$format = strtoupper($request->get('format', 'XML')); |
163
|
11 |
|
if (empty($service) || empty($ticket)) { |
164
|
1 |
|
return $this->authFailureResponse( |
165
|
1 |
|
CasException::INVALID_REQUEST, |
166
|
1 |
|
'param service and ticket can not be empty', |
167
|
1 |
|
$format |
168
|
|
|
); |
169
|
|
|
} |
170
|
|
|
|
171
|
10 |
|
if (!$this->lockTicket($ticket)) { |
172
|
1 |
|
return $this->authFailureResponse(CasException::INTERNAL_ERROR, 'try to lock ticket failed', $format); |
173
|
|
|
} |
174
|
|
|
|
175
|
9 |
|
$record = $this->ticketRepository->getByTicket($ticket); |
176
|
|
|
try { |
177
|
9 |
|
if (!$record || (!$allowProxy && $record->isProxy())) { |
178
|
2 |
|
throw new CasException(CasException::INVALID_TICKET, 'ticket is not valid'); |
179
|
|
|
} |
180
|
|
|
|
181
|
7 |
|
if ($record->service_url != $service) { |
182
|
7 |
|
throw new CasException(CasException::INVALID_SERVICE, 'service is not valid'); |
183
|
|
|
} |
184
|
3 |
|
} catch (CasException $e) { |
185
|
|
|
//invalid ticket if error occur |
186
|
3 |
|
$record instanceof Ticket && $this->ticketRepository->invalidTicket($record); |
187
|
3 |
|
$this->unlockTicket($ticket); |
188
|
|
|
|
189
|
3 |
|
return $this->authFailureResponse($e->getCasErrorCode(), $e->getMessage(), $format); |
190
|
|
|
} |
191
|
|
|
|
192
|
6 |
|
$proxies = []; |
193
|
6 |
|
if ($record->isProxy()) { |
194
|
2 |
|
$proxies = $record->proxies; |
195
|
|
|
} |
196
|
|
|
|
197
|
6 |
|
$user = $record->user; |
198
|
6 |
|
$this->ticketRepository->invalidTicket($record); |
199
|
6 |
|
$this->unlockTicket($ticket); |
200
|
|
|
|
201
|
|
|
//handle pgt |
202
|
6 |
|
$iou = null; |
203
|
6 |
|
$pgtUrl = $request->get('pgtUrl', ''); |
204
|
6 |
|
if ($pgtUrl) { |
205
|
|
|
try { |
206
|
4 |
|
$pgTicket = $this->pgTicketRepository->applyTicket($user, $pgtUrl, $proxies); |
207
|
3 |
|
$iou = $this->ticketGenerator->generateOne(config('cas.pg_ticket_iou_len', 64), 'PGTIOU-'); |
208
|
3 |
|
if (!$this->pgtCaller->call($pgtUrl, $pgTicket->ticket, $iou)) { |
209
|
3 |
|
$iou = null; |
210
|
|
|
} |
211
|
1 |
|
} catch (CasException $e) { |
212
|
1 |
|
$iou = null; |
213
|
|
|
} |
214
|
|
|
} |
215
|
|
|
|
216
|
6 |
|
$attr = $returnAttr ? $record->user->getCASAttributes() : []; |
217
|
|
|
|
218
|
6 |
|
return $this->authSuccessResponse($record->user->getName(), $format, $attr, $proxies, $iou); |
219
|
|
|
} |
220
|
|
|
|
221
|
|
|
/** |
222
|
|
|
* @param string $username |
223
|
|
|
* @param string $format |
224
|
|
|
* @param array $attributes |
225
|
|
|
* @param array $proxies |
226
|
|
|
* @param string|null $pgt |
227
|
|
|
* @return Response |
228
|
|
|
*/ |
229
|
1 |
|
protected function authSuccessResponse($username, $format, $attributes, $proxies = [], $pgt = null) |
230
|
|
|
{ |
231
|
1 |
|
if (strtoupper($format) === 'JSON') { |
232
|
1 |
|
$resp = app(JsonAuthenticationSuccessResponse::class); |
233
|
|
|
} else { |
234
|
1 |
|
$resp = app(XmlAuthenticationSuccessResponse::class); |
235
|
|
|
} |
236
|
1 |
|
$resp->setUser($username); |
237
|
1 |
|
if (!empty($attributes)) { |
238
|
1 |
|
$resp->setAttributes($attributes); |
239
|
|
|
} |
240
|
1 |
|
if (!empty($proxies)) { |
241
|
1 |
|
$resp->setProxies($proxies); |
242
|
|
|
} |
243
|
|
|
|
244
|
1 |
|
if (is_string($pgt)) { |
245
|
1 |
|
$resp->setProxyGrantingTicket($pgt); |
246
|
|
|
} |
247
|
|
|
|
248
|
1 |
|
return $resp->toResponse(); |
249
|
|
|
} |
250
|
|
|
|
251
|
|
|
/** |
252
|
|
|
* @param string $code |
253
|
|
|
* @param string $description |
254
|
|
|
* @param string $format |
255
|
|
|
* @return Response |
256
|
|
|
*/ |
257
|
1 |
View Code Duplication |
protected function authFailureResponse($code, $description, $format) |
|
|
|
|
258
|
|
|
{ |
259
|
1 |
|
if (strtoupper($format) === 'JSON') { |
260
|
1 |
|
$resp = app(JsonAuthenticationFailureResponse::class); |
261
|
|
|
} else { |
262
|
1 |
|
$resp = app(XmlAuthenticationFailureResponse::class); |
263
|
|
|
} |
264
|
1 |
|
$resp->setFailure($code, $description); |
265
|
|
|
|
266
|
1 |
|
return $resp->toResponse(); |
267
|
|
|
} |
268
|
|
|
|
269
|
|
|
/** |
270
|
|
|
* @param string $ticket |
271
|
|
|
* @param string $format |
272
|
|
|
* @return Response |
273
|
|
|
*/ |
274
|
1 |
|
protected function proxySuccessResponse($ticket, $format) |
275
|
|
|
{ |
276
|
1 |
|
if (strtoupper($format) === 'JSON') { |
277
|
1 |
|
$resp = app(JsonProxySuccessResponse::class); |
278
|
|
|
} else { |
279
|
1 |
|
$resp = app(XmlProxySuccessResponse::class); |
280
|
|
|
} |
281
|
1 |
|
$resp->setProxyTicket($ticket); |
282
|
|
|
|
283
|
1 |
|
return $resp->toResponse(); |
284
|
|
|
} |
285
|
|
|
|
286
|
|
|
/** |
287
|
|
|
* @param string $code |
288
|
|
|
* @param string $description |
289
|
|
|
* @param string $format |
290
|
|
|
* @return Response |
291
|
|
|
*/ |
292
|
1 |
View Code Duplication |
protected function proxyFailureResponse($code, $description, $format) |
|
|
|
|
293
|
|
|
{ |
294
|
1 |
|
if (strtoupper($format) === 'JSON') { |
295
|
1 |
|
$resp = app(JsonProxyFailureResponse::class); |
296
|
|
|
} else { |
297
|
1 |
|
$resp = app(XmlProxyFailureResponse::class); |
298
|
|
|
} |
299
|
1 |
|
$resp->setFailure($code, $description); |
300
|
|
|
|
301
|
1 |
|
return $resp->toResponse(); |
302
|
|
|
} |
303
|
|
|
|
304
|
|
|
/** |
305
|
|
|
* @param string $ticket |
306
|
|
|
* @return bool |
307
|
|
|
*/ |
308
|
1 |
|
protected function lockTicket($ticket) |
309
|
|
|
{ |
310
|
1 |
|
return $this->ticketLocker->acquireLock($ticket, config('cas.lock_timeout')); |
311
|
|
|
} |
312
|
|
|
|
313
|
|
|
/** |
314
|
|
|
* @param string $ticket |
315
|
|
|
* @return bool |
316
|
|
|
*/ |
317
|
1 |
|
protected function unlockTicket($ticket) |
318
|
|
|
{ |
319
|
1 |
|
return $this->ticketLocker->releaseLock($ticket); |
320
|
|
|
} |
321
|
|
|
} |
322
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.