1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* This file is part of tenside/core-bundle. |
5
|
|
|
* |
6
|
|
|
* (c) Christian Schiffler <[email protected]> |
7
|
|
|
* |
8
|
|
|
* For the full copyright and license information, please view the LICENSE |
9
|
|
|
* file that was distributed with this source code. |
10
|
|
|
* |
11
|
|
|
* This project is provided in good faith and hope to be usable by anyone. |
12
|
|
|
* |
13
|
|
|
* @package tenside/core-bundle |
14
|
|
|
* @author Christian Schiffler <[email protected]> |
15
|
|
|
* @author Yanick Witschi <[email protected]> |
16
|
|
|
* @copyright 2015 Christian Schiffler <[email protected]> |
17
|
|
|
* @license https://github.com/tenside/core-bundle/blob/master/LICENSE MIT |
18
|
|
|
* @link https://github.com/tenside/core-bundle |
19
|
|
|
* @filesource |
20
|
|
|
*/ |
21
|
|
|
|
22
|
|
|
namespace Tenside\CoreBundle\Controller; |
23
|
|
|
|
24
|
|
|
use Nelmio\ApiDocBundle\Annotation\ApiDoc; |
25
|
|
|
use Symfony\Component\HttpFoundation\JsonResponse; |
26
|
|
|
use Symfony\Component\HttpFoundation\Request; |
27
|
|
|
use Tenside\Core\Util\JsonArray; |
28
|
|
|
use Tenside\CoreBundle\Annotation\ApiDescription; |
29
|
|
|
use Tenside\CoreBundle\Security\UserInformationInterface; |
30
|
|
|
|
31
|
|
|
/** |
32
|
|
|
* The main entry point. |
33
|
|
|
*/ |
34
|
|
|
class AuthController extends AbstractController |
35
|
|
|
{ |
36
|
|
|
/** |
37
|
|
|
* Try to validate the user from the request and return a jwt authentication result then. |
38
|
|
|
* |
39
|
|
|
* @param Request $request The request. |
40
|
|
|
* |
41
|
|
|
* @return JsonResponse |
42
|
|
|
* |
43
|
|
|
* @throws \RuntimeException For invalid user classes. |
44
|
|
|
* |
45
|
|
|
* @ApiDoc( |
46
|
|
|
* section="auth", |
47
|
|
|
* statusCodes = { |
48
|
|
|
* 200 = "When everything worked out ok", |
49
|
|
|
* 401 = "When the request was unauthorized." |
50
|
|
|
* }, |
51
|
|
|
* parameters = { |
52
|
|
|
* { |
53
|
|
|
* "name": "ttl", |
54
|
|
|
* "dataType" = "string", |
55
|
|
|
* "format" = "\d+", |
56
|
|
|
* "description" = "The amount of seconds the token shall be valid or -1 for unlimited (default: 3600).", |
57
|
|
|
* "required" = false |
58
|
|
|
* }, |
59
|
|
|
* { |
60
|
|
|
* "name": "username", |
61
|
|
|
* "dataType" = "string", |
62
|
|
|
* "description" = "The username.", |
63
|
|
|
* "required" = true |
64
|
|
|
* }, |
65
|
|
|
* { |
66
|
|
|
* "name": "password", |
67
|
|
|
* "dataType" = "string", |
68
|
|
|
* "description" = "The pssword.", |
69
|
|
|
* "required" = true |
70
|
|
|
* } |
71
|
|
|
* } |
72
|
|
|
* ) |
73
|
|
|
* @ApiDescription( |
74
|
|
|
* response={ |
75
|
|
|
* "status" = { |
76
|
|
|
* "dataType" = "choice", |
77
|
|
|
* "description" = "OK or unauthorized", |
78
|
|
|
* "format" = "['OK', 'unauthorized']", |
79
|
|
|
* }, |
80
|
|
|
* "token" = { |
81
|
|
|
* "dataType" = "string", |
82
|
|
|
* "description" = "The JWT (only if status ok).", |
83
|
|
|
* }, |
84
|
|
|
* "acl" = { |
85
|
|
|
* "actualType" = "collection", |
86
|
|
|
* "subType" = "string", |
87
|
|
|
* "description" = "The roles of the authenticated user.", |
88
|
|
|
* }, |
89
|
|
|
* "username" = { |
90
|
|
|
* "actualType" = "string", |
91
|
|
|
* "description" = "The username of the authenticated user.", |
92
|
|
|
* }, |
93
|
|
|
* }, |
94
|
|
|
* ) |
95
|
|
|
*/ |
96
|
|
|
public function checkAuthAction(Request $request) |
97
|
|
|
{ |
98
|
|
|
$user = $this->getUser(); |
99
|
|
|
|
100
|
|
|
if (null !== $user) { |
101
|
|
|
if (!$user instanceof UserInformationInterface) { |
102
|
|
|
throw new \RuntimeException('Invalid user object'); |
103
|
|
|
} |
104
|
|
|
|
105
|
|
|
$lifetime = $this->determineLifeTime($request); |
106
|
|
|
|
107
|
|
|
$token = $this->get('tenside.jwt_authenticator')->getTokenForData($user, $lifetime); |
108
|
|
|
return new JsonResponse( |
109
|
|
|
[ |
110
|
|
|
'status' => 'OK', |
111
|
|
|
'token' => $token, |
112
|
|
|
'acl' => $user->getRoles(), |
113
|
|
|
'username' => $user->getUsername(), |
114
|
|
|
'ttl' => (null === $lifetime) ? 'unlimited' : date('r', (time() + $lifetime)) |
115
|
|
|
], |
116
|
|
|
JsonResponse::HTTP_OK, |
117
|
|
|
['Authentication' => $token] |
118
|
|
|
); |
119
|
|
|
} |
120
|
|
|
|
121
|
|
|
return new JsonResponse(['status' => 'unauthorized'], JsonResponse::HTTP_UNAUTHORIZED); |
122
|
|
|
} |
123
|
|
|
|
124
|
|
|
/** |
125
|
|
|
* Determine the life time for the token. |
126
|
|
|
* |
127
|
|
|
* This examines the GET parameters if a field "ttl" has been set. |
128
|
|
|
* If not, it examines the JSON post data for a field named ttl. |
129
|
|
|
* |
130
|
|
|
* @param Request $request The request. |
131
|
|
|
* |
132
|
|
|
* @return int|null |
133
|
|
|
*/ |
134
|
|
|
private function determineLifeTime(Request $request) |
135
|
|
|
{ |
136
|
|
|
if ($lifetime = $request->query->getInt('ttl')) { |
137
|
|
|
return $this->revertToNullOnMinusOne($lifetime); |
138
|
|
|
} |
139
|
|
|
|
140
|
|
|
try { |
141
|
|
|
$inputData = new JsonArray($request->getContent()); |
|
|
|
|
142
|
|
|
if ($inputData->has('ttl')) { |
143
|
|
|
return $this->revertToNullOnMinusOne(intval($inputData->get('ttl'))); |
144
|
|
|
} |
145
|
|
|
} catch (\Exception $e) { |
146
|
|
|
// Swallow exception, we need to return a defined result. |
147
|
|
|
} |
148
|
|
|
|
149
|
|
|
return 3600; |
150
|
|
|
} |
151
|
|
|
|
152
|
|
|
/** |
153
|
|
|
* Return the value if it is different than -1, null otherwise. |
154
|
|
|
* |
155
|
|
|
* @param int $lifetime The life time. |
156
|
|
|
* |
157
|
|
|
* @return null|int |
158
|
|
|
*/ |
159
|
|
|
private function revertToNullOnMinusOne($lifetime) |
160
|
|
|
{ |
161
|
|
|
if (-1 === $lifetime) { |
162
|
|
|
return null; |
163
|
|
|
} |
164
|
|
|
|
165
|
|
|
return $lifetime; |
166
|
|
|
} |
167
|
|
|
} |
168
|
|
|
|
This check looks at variables that are passed out again to other methods.
If the outgoing method call has stricter type requirements than the method itself, an issue is raised.
An additional type check may prevent trouble.