Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/phabricator
Path: blob/master/src/applications/oauthserver/controller/PhabricatorOAuthServerTokenController.php
12242 views
1
<?php
2
3
final class PhabricatorOAuthServerTokenController
4
extends PhabricatorOAuthServerController {
5
6
public function shouldRequireLogin() {
7
return false;
8
}
9
10
public function shouldAllowRestrictedParameter($parameter_name) {
11
if ($parameter_name == 'code') {
12
return true;
13
}
14
return parent::shouldAllowRestrictedParameter($parameter_name);
15
}
16
17
public function handleRequest(AphrontRequest $request) {
18
$grant_type = $request->getStr('grant_type');
19
$code = $request->getStr('code');
20
$redirect_uri = $request->getStr('redirect_uri');
21
$response = new PhabricatorOAuthResponse();
22
$server = new PhabricatorOAuthServer();
23
24
$client_id_parameter = $request->getStr('client_id');
25
$client_id_header = idx($_SERVER, 'PHP_AUTH_USER');
26
if (strlen($client_id_parameter) && strlen($client_id_header)) {
27
if ($client_id_parameter !== $client_id_header) {
28
throw new Exception(
29
pht(
30
'Request included a client_id parameter and an "Authorization" '.
31
'header with a username, but the values "%s" and "%s") disagree. '.
32
'The values must match.',
33
$client_id_parameter,
34
$client_id_header));
35
}
36
}
37
38
$client_secret_parameter = $request->getStr('client_secret');
39
$client_secret_header = idx($_SERVER, 'PHP_AUTH_PW');
40
if (strlen($client_secret_parameter)) {
41
// If the `client_secret` parameter is present, prefer parameters.
42
$client_phid = $client_id_parameter;
43
$client_secret = $client_secret_parameter;
44
} else {
45
// Otherwise, read values from the "Authorization" header.
46
$client_phid = $client_id_header;
47
$client_secret = $client_secret_header;
48
}
49
50
if ($grant_type != 'authorization_code') {
51
$response->setError('unsupported_grant_type');
52
$response->setErrorDescription(
53
pht(
54
'Only %s %s is supported.',
55
'grant_type',
56
'authorization_code'));
57
return $response;
58
}
59
60
if (!$code) {
61
$response->setError('invalid_request');
62
$response->setErrorDescription(pht('Required parameter code missing.'));
63
return $response;
64
}
65
66
if (!$client_phid) {
67
$response->setError('invalid_request');
68
$response->setErrorDescription(
69
pht(
70
'Required parameter %s missing.',
71
'client_id'));
72
return $response;
73
}
74
75
if (!$client_secret) {
76
$response->setError('invalid_request');
77
$response->setErrorDescription(
78
pht(
79
'Required parameter %s missing.',
80
'client_secret'));
81
return $response;
82
}
83
84
// one giant try / catch around all the exciting database stuff so we
85
// can return a 'server_error' response if something goes wrong!
86
try {
87
$auth_code = id(new PhabricatorOAuthServerAuthorizationCode())
88
->loadOneWhere('code = %s',
89
$code);
90
if (!$auth_code) {
91
$response->setError('invalid_grant');
92
$response->setErrorDescription(
93
pht(
94
'Authorization code %s not found.',
95
$code));
96
return $response;
97
}
98
99
// if we have an auth code redirect URI, there must be a redirect_uri
100
// in the request and it must match the auth code redirect uri *exactly*
101
$auth_code_redirect_uri = $auth_code->getRedirectURI();
102
if ($auth_code_redirect_uri) {
103
$auth_code_redirect_uri = new PhutilURI($auth_code_redirect_uri);
104
$redirect_uri = new PhutilURI($redirect_uri);
105
if (!$redirect_uri->getDomain() ||
106
$redirect_uri != $auth_code_redirect_uri) {
107
$response->setError('invalid_grant');
108
$response->setErrorDescription(
109
pht(
110
'Redirect URI in request must exactly match redirect URI '.
111
'from authorization code.'));
112
return $response;
113
}
114
} else if ($redirect_uri) {
115
$response->setError('invalid_grant');
116
$response->setErrorDescription(
117
pht(
118
'Redirect URI in request and no redirect URI in authorization '.
119
'code. The two must exactly match.'));
120
return $response;
121
}
122
123
$client = id(new PhabricatorOAuthServerClient())
124
->loadOneWhere('phid = %s', $client_phid);
125
if (!$client) {
126
$response->setError('invalid_client');
127
$response->setErrorDescription(
128
pht(
129
'Client with %s %s not found.',
130
'client_id',
131
$client_phid));
132
return $response;
133
}
134
135
if ($client->getIsDisabled()) {
136
$response->setError('invalid_client');
137
$response->setErrorDescription(
138
pht(
139
'OAuth application "%s" has been disabled.',
140
$client->getName()));
141
142
return $response;
143
}
144
145
$server->setClient($client);
146
147
$user_phid = $auth_code->getUserPHID();
148
$user = id(new PhabricatorUser())
149
->loadOneWhere('phid = %s', $user_phid);
150
if (!$user) {
151
$response->setError('invalid_grant');
152
$response->setErrorDescription(
153
pht(
154
'User with PHID %s not found.',
155
$user_phid));
156
return $response;
157
}
158
$server->setUser($user);
159
160
$test_code = new PhabricatorOAuthServerAuthorizationCode();
161
$test_code->setClientSecret($client_secret);
162
$test_code->setClientPHID($client_phid);
163
$is_good_code = $server->validateAuthorizationCode(
164
$auth_code,
165
$test_code);
166
if (!$is_good_code) {
167
$response->setError('invalid_grant');
168
$response->setErrorDescription(
169
pht(
170
'Invalid authorization code %s.',
171
$code));
172
return $response;
173
}
174
175
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
176
$access_token = $server->generateAccessToken();
177
$auth_code->delete();
178
unset($unguarded);
179
$result = array(
180
'access_token' => $access_token->getToken(),
181
'token_type' => 'Bearer',
182
);
183
return $response->setContent($result);
184
} catch (Exception $e) {
185
$response->setError('server_error');
186
$response->setErrorDescription(
187
pht(
188
'The authorization server encountered an unexpected condition '.
189
'which prevented it from fulfilling the request.'));
190
return $response;
191
}
192
}
193
194
}
195
196