|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
/* |
|
4
|
|
|
* This file is part of the Superdesk Web Publisher Core Bundle. |
|
5
|
|
|
* |
|
6
|
|
|
* Copyright 2016 Sourcefabric z.ú. and contributors. |
|
7
|
|
|
* |
|
8
|
|
|
* For the full copyright and license information, please see the |
|
9
|
|
|
* AUTHORS and LICENSE files distributed with this source code. |
|
10
|
|
|
* |
|
11
|
|
|
* @copyright 2016 Sourcefabric z.ú |
|
12
|
|
|
* @license http://www.superdesk.org/license |
|
13
|
|
|
*/ |
|
14
|
|
|
|
|
15
|
|
|
namespace SWP\Bundle\CoreBundle\Controller; |
|
16
|
|
|
|
|
17
|
|
|
use Doctrine\DBAL\Exception\UniqueConstraintViolationException; |
|
18
|
|
|
use GuzzleHttp; |
|
19
|
|
|
use Nelmio\ApiDocBundle\Annotation\ApiDoc; |
|
20
|
|
|
use Symfony\Component\Routing\Annotation\Route; |
|
21
|
|
|
use SWP\Bundle\CoreBundle\Form\Type\SuperdeskCredentialAuthenticationType; |
|
22
|
|
|
use SWP\Bundle\CoreBundle\Form\Type\UserAuthenticationType; |
|
23
|
|
|
use SWP\Bundle\CoreBundle\Model\ApiKeyInterface; |
|
24
|
|
|
use SWP\Bundle\CoreBundle\Model\UserInterface; |
|
25
|
|
|
use SWP\Component\Common\Response\ResponseContext; |
|
26
|
|
|
use SWP\Component\Common\Response\SingleResourceResponse; |
|
27
|
|
|
use Symfony\Bundle\FrameworkBundle\Controller\Controller; |
|
28
|
|
|
use Symfony\Component\HttpFoundation\Request; |
|
29
|
|
|
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException; |
|
30
|
|
|
|
|
31
|
|
|
class AuthController extends Controller |
|
|
|
|
|
|
32
|
|
|
{ |
|
33
|
|
|
/** |
|
34
|
|
|
* Look for user matching provided credentials. |
|
35
|
|
|
* |
|
36
|
|
|
* @ApiDoc( |
|
37
|
|
|
* resource=true, |
|
38
|
|
|
* description="Look for user matching provided credentials", |
|
39
|
|
|
* statusCodes={ |
|
40
|
|
|
* 200="Returned on success.", |
|
41
|
|
|
* 401="No user found or not authorized." |
|
42
|
|
|
* }, |
|
43
|
|
|
* input="SWP\Bundle\CoreBundle\Form\Type\UserAuthenticationType" |
|
44
|
|
|
* ) |
|
45
|
|
|
* @Route("/api/{version}/auth/", options={"expose"=true}, defaults={"version"="v2"}, methods={"POST"}, name="swp_api_auth") |
|
46
|
2 |
|
*/ |
|
47
|
|
|
public function authenticateAction(Request $request) |
|
48
|
2 |
|
{ |
|
49
|
2 |
|
$form = $this->get('form.factory')->createNamed('', UserAuthenticationType::class, []); |
|
50
|
2 |
|
$form->handleRequest($request); |
|
51
|
2 |
|
if ($form->isSubmitted() && $form->isValid()) { |
|
52
|
|
|
$formData = $form->getData(); |
|
53
|
2 |
|
|
|
54
|
1 |
|
try { |
|
55
|
1 |
|
$user = $this->get('swp.security.user_provider')->loadUserByUsername($formData['username']); |
|
56
|
|
|
} catch (UsernameNotFoundException $e) { |
|
57
|
|
|
$user = null; |
|
58
|
2 |
|
} |
|
59
|
1 |
|
|
|
60
|
1 |
|
if (null !== $user) { |
|
61
|
|
|
if ($this->get('security.password_encoder')->isPasswordValid($user, $formData['password'])) { |
|
62
|
|
|
return $this->returnApiTokenResponse($user, null); |
|
63
|
|
|
} |
|
64
|
|
|
} |
|
65
|
1 |
|
} |
|
66
|
1 |
|
|
|
67
|
|
|
return new SingleResourceResponse([ |
|
68
|
1 |
|
'status' => 401, |
|
69
|
|
|
'message' => 'Unauthorized', |
|
70
|
|
|
], new ResponseContext(401)); |
|
71
|
|
|
} |
|
72
|
|
|
|
|
73
|
|
|
/** |
|
74
|
|
|
* Ask Superdesk server for user with those credentials and tries to authorize. |
|
75
|
|
|
* |
|
76
|
|
|
* @ApiDoc( |
|
77
|
|
|
* resource=true, |
|
78
|
|
|
* description="Authorize using Superdesk credentials", |
|
79
|
|
|
* statusCodes={ |
|
80
|
|
|
* 200="Returned on success.", |
|
81
|
|
|
* 401="No user found or not authorized." |
|
82
|
|
|
* }, |
|
83
|
|
|
* input="SWP\Bundle\CoreBundle\Form\Type\SuperdeskCredentialAuthenticationType" |
|
84
|
|
|
* ) |
|
85
|
|
|
* @Route("/api/{version}/auth/superdesk/", options={"expose"=true}, methods={"POST"}, defaults={"version"="v2"}, name="swp_api_auth_superdesk") |
|
86
|
|
|
*/ |
|
87
|
|
|
public function authenticateWithSuperdeskAction(Request $request) |
|
88
|
|
|
{ |
|
89
|
|
|
$form = $this->get('form.factory')->createNamed('', SuperdeskCredentialAuthenticationType::class, []); |
|
90
|
|
|
$form->handleRequest($request); |
|
91
|
|
|
if ($form->isSubmitted() && $form->isValid()) { |
|
92
|
|
|
$formData = $form->getData(); |
|
93
|
|
|
$authorizedSuperdeskHosts = (array) $this->container->getParameter('superdesk_servers'); |
|
94
|
|
|
$superdeskUser = null; |
|
95
|
|
|
$client = new GuzzleHttp\Client(); |
|
96
|
|
|
|
|
97
|
|
|
foreach ($authorizedSuperdeskHosts as $baseUrl) { |
|
98
|
|
|
try { |
|
99
|
|
|
$apiRequest = new GuzzleHttp\Psr7\Request('GET', sprintf('%s/api/sessions/%s', $baseUrl, $formData['sessionId']), [ |
|
100
|
|
|
'Authorization' => $formData['token'], |
|
101
|
|
|
]); |
|
102
|
|
|
$apiResponse = $client->send($apiRequest); |
|
103
|
|
|
if (200 !== $apiResponse->getStatusCode()) { |
|
104
|
|
|
continue; |
|
105
|
|
|
} |
|
106
|
|
|
|
|
107
|
|
|
$content = json_decode($apiResponse->getBody()->getContents(), true); |
|
108
|
|
|
if (is_array($content) && array_key_exists('user', $content)) { |
|
109
|
|
|
$superdeskUser = $content['user']; |
|
110
|
|
|
|
|
111
|
|
|
break; |
|
112
|
|
|
} |
|
113
|
|
|
} catch (GuzzleHttp\Exception\ClientException $e) { |
|
114
|
|
|
if (200 !== $e->getResponse()->getStatusCode()) { |
|
115
|
|
|
continue; |
|
116
|
|
|
} |
|
117
|
|
|
} |
|
118
|
|
|
} |
|
119
|
|
|
|
|
120
|
|
|
if (null === $superdeskUser) { |
|
121
|
|
|
return new SingleResourceResponse([ |
|
122
|
|
|
'status' => 401, |
|
123
|
|
|
'message' => 'Unauthorized (user not found in Superdesk)', |
|
124
|
|
|
], new ResponseContext(401)); |
|
125
|
|
|
} |
|
126
|
|
|
|
|
127
|
|
|
$userProvider = $this->get('swp.security.user_provider'); |
|
128
|
|
|
$publisherUser = $userProvider->findOneByEmail($superdeskUser['email']); |
|
129
|
|
|
if (null === $publisherUser) { |
|
130
|
|
|
try { |
|
131
|
|
|
$publisherUser = $userProvider->loadUserByUsername($superdeskUser['username']); |
|
132
|
|
|
} catch (UsernameNotFoundException $e) { |
|
133
|
|
|
$publisherUser = null; |
|
134
|
|
|
} |
|
135
|
|
|
} |
|
136
|
|
|
|
|
137
|
1 |
|
if (null === $publisherUser) { |
|
138
|
|
|
$userManager = $this->get('fos_user.user_manager'); |
|
139
|
1 |
|
/** @var UserInterface $publisherUser */ |
|
140
|
1 |
|
$publisherUser = $userManager->createUser(); |
|
141
|
1 |
|
$publisherUser->setUsername($superdeskUser['username']); |
|
142
|
|
|
$publisherUser->setEmail($superdeskUser['email']); |
|
143
|
|
|
$publisherUser->setRoles(['ROLE_INTERNAL_API']); |
|
144
|
|
|
$publisherUser->setFirstName(\array_key_exists('first_name', $superdeskUser) ? $superdeskUser['first_name'] : 'Anon.'); |
|
145
|
|
|
$publisherUser->setLastName(\array_key_exists('last_name', $superdeskUser) ? $superdeskUser['last_name'] : ''); |
|
146
|
|
|
$publisherUser->setPlainPassword(password_hash(random_bytes(36), PASSWORD_BCRYPT)); |
|
147
|
|
|
$publisherUser->setEnabled(true); |
|
148
|
1 |
|
$userManager->updateUser($publisherUser); |
|
149
|
1 |
|
} |
|
150
|
1 |
|
|
|
151
|
|
|
if (null !== $publisherUser) { |
|
152
|
|
|
return $this->returnApiTokenResponse($publisherUser, str_replace('Basic ', '', $formData['token'])); |
|
153
|
1 |
|
} |
|
154
|
|
|
} |
|
155
|
1 |
|
|
|
156
|
1 |
|
return new SingleResourceResponse([ |
|
157
|
|
|
'status' => 401, |
|
158
|
1 |
|
'message' => 'Unauthorized', |
|
159
|
|
|
], new ResponseContext(401)); |
|
160
|
|
|
} |
|
161
|
|
|
|
|
162
|
|
|
/** |
|
163
|
|
|
* @param UserInterface $user |
|
164
|
|
|
* @param string $token |
|
165
|
|
|
* |
|
166
|
|
|
* @return SingleResourceResponse |
|
167
|
|
|
*/ |
|
168
|
|
|
private function returnApiTokenResponse(UserInterface $user, $token) |
|
169
|
|
|
{ |
|
170
|
|
|
/** @var ApiKeyInterface $apiKey */ |
|
171
|
|
|
$apiKey = $this->generateOrGetApiKey($user, $token); |
|
172
|
|
|
|
|
173
|
|
|
return new SingleResourceResponse([ |
|
174
|
|
|
'token' => [ |
|
175
|
|
|
'api_key' => $apiKey->getApiKey(), |
|
176
|
|
|
'valid_to' => $apiKey->getValidTo(), |
|
177
|
|
|
], |
|
178
|
|
|
'user' => $user, |
|
179
|
|
|
]); |
|
180
|
|
|
} |
|
181
|
|
|
|
|
182
|
|
|
private function generateOrGetApiKey(UserInterface $user, $token) |
|
183
|
|
|
{ |
|
184
|
|
|
$apiKey = null; |
|
185
|
|
|
$apiKeyRepository = $this->get('swp.repository.api_key'); |
|
186
|
|
|
if (null !== $token) { |
|
187
|
|
|
$apiKey = $apiKeyRepository->getValidToken($token)->getQuery()->getOneOrNullResult(); |
|
188
|
|
|
} else { |
|
189
|
|
|
$validKeys = $apiKeyRepository->getValidTokenForUser($user)->getQuery()->getResult(); |
|
190
|
|
|
if (count($validKeys) > 0) { |
|
191
|
|
|
$apiKey = reset($validKeys); |
|
192
|
|
|
} |
|
193
|
|
|
} |
|
194
|
|
|
|
|
195
|
|
|
if (null === $apiKey) { |
|
196
|
|
|
$apiKey = $this->get('swp.factory.api_key')->create($user, $token); |
|
197
|
|
|
|
|
198
|
|
|
try { |
|
199
|
|
|
$apiKeyRepository->add($apiKey); |
|
200
|
|
|
} catch (UniqueConstraintViolationException $e) { |
|
201
|
|
|
return $this->generateOrGetApiKey($user, $token); |
|
202
|
|
|
} |
|
203
|
|
|
} |
|
204
|
|
|
|
|
205
|
|
|
return $apiKey; |
|
206
|
|
|
} |
|
207
|
|
|
} |
|
208
|
|
|
|
This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.