1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace AdvancedLearning\Oauth2Server\Services; |
4
|
|
|
|
5
|
|
|
|
6
|
|
|
use AdvancedLearning\Oauth2Server\Exceptions\AuthenticationException; |
7
|
|
|
use AdvancedLearning\Oauth2Server\Repositories\AccessTokenRepository; |
8
|
|
|
use GuzzleHttp\Psr7\Response; |
9
|
|
|
use League\OAuth2\Server\Exception\OAuthServerException; |
10
|
|
|
use League\OAuth2\Server\ResourceServer; |
11
|
|
|
use Robbie\Psr7\HttpRequestAdapter; |
12
|
|
|
use Robbie\Psr7\HttpResponseAdapter; |
13
|
|
|
use SilverStripe\Control\HTTPRequest; |
14
|
|
|
use SilverStripe\Core\Environment; |
15
|
|
|
|
16
|
|
|
class AuthenticationService implements Authenticator |
17
|
|
|
{ |
18
|
|
|
protected $server; |
19
|
|
|
|
20
|
|
|
/** |
21
|
|
|
* AuthenticationService constructor. |
22
|
|
|
* |
23
|
|
|
* @param ResourceServer|null $server Optional resource server. |
24
|
|
|
*/ |
25
|
|
|
public function __construct(ResourceServer $server = null) |
26
|
|
|
{ |
27
|
|
|
$this->server = $server ?: $this->createServer(); |
28
|
|
|
} |
29
|
|
|
|
30
|
|
|
/** |
31
|
|
|
* Authenticate the request. Returns modified request (probably not as SS doesn't support |
32
|
|
|
* request attributes). |
33
|
|
|
* |
34
|
|
|
* @param HTTPRequest $request The SilverStripe request object to be authenticated. |
35
|
|
|
* |
36
|
|
|
* @return HTTPRequest |
37
|
|
|
* @throws AuthenticationException |
38
|
|
|
*/ |
39
|
|
|
public function authenticate(HTTPRequest $request): HTTPRequest |
40
|
|
|
{ |
41
|
|
|
$requestAdapter = new HttpRequestAdapter(); |
42
|
|
|
$responseAdapter = new HttpResponseAdapter(); |
43
|
|
|
|
44
|
|
|
// missing vars (cli) |
45
|
|
|
$this->addMissingServerVariables($requestAdapter); |
46
|
|
|
|
47
|
|
|
// store session as it doesn't get converted |
48
|
|
|
$session = $request->getSession(); |
49
|
|
|
$routeParams = $request->params(); |
50
|
|
|
|
51
|
|
|
$server = $this->getServer(); |
52
|
|
|
$psrRequest = $requestAdapter->toPsr7($request); |
53
|
|
|
$psrResponse = new Response(); |
54
|
|
|
|
55
|
|
|
try { |
56
|
|
|
$psrRequest = $server->validateAuthenticatedRequest($psrRequest); |
57
|
|
|
} catch (OAuthServerException $exception) { |
58
|
|
|
// convert to authentication exception |
59
|
|
|
throw new AuthenticationException( |
60
|
|
|
$exception->getMessage(), |
61
|
|
|
$exception->getCode(), |
62
|
|
|
$responseAdapter->fromPsr7($exception->generateHttpResponse($psrResponse)) |
|
|
|
|
63
|
|
|
); |
64
|
|
|
} catch (\Exception $exception) { |
65
|
|
|
// convert to authentication exception |
66
|
|
|
throw new AuthenticationException( |
67
|
|
|
$exception->getMessage(), |
68
|
|
|
$exception->getCode(), |
69
|
|
|
$responseAdapter->fromPsr7( |
|
|
|
|
70
|
|
|
(new OAuthServerException($exception->getMessage(), 0, 'unknown_error', 500)) |
71
|
|
|
->generateHttpResponse($psrResponse) |
72
|
|
|
) |
73
|
|
|
); |
74
|
|
|
} |
75
|
|
|
$request = $requestAdapter->fromPsr7($psrRequest); |
76
|
|
|
|
77
|
|
|
// add session back |
78
|
|
|
$request->setSession($session); |
|
|
|
|
79
|
|
|
$request->setRouteParams($routeParams); |
|
|
|
|
80
|
|
|
|
81
|
|
|
// add the request attributes as custom auth headers |
82
|
|
|
foreach ($psrRequest->getAttributes() as $attribute => $value) { |
83
|
|
|
$request->addHeader($attribute, $value); |
84
|
|
|
} |
85
|
|
|
|
86
|
|
|
return $request; |
87
|
|
|
} |
88
|
|
|
|
89
|
|
|
/** |
90
|
|
|
* Override the default ResourceServer. |
91
|
|
|
* |
92
|
|
|
* @param ResourceServer $v The new ResourceServer to use. |
93
|
|
|
* |
94
|
|
|
* @return $this |
95
|
|
|
*/ |
96
|
|
|
public function setServer(ResourceServer $v): Authenticator |
97
|
|
|
{ |
98
|
|
|
$this->server = $v; |
99
|
|
|
return $this; |
100
|
|
|
} |
101
|
|
|
|
102
|
|
|
/** |
103
|
|
|
* Get the ResourceServer. |
104
|
|
|
* |
105
|
|
|
* @return ResourceServer |
106
|
|
|
*/ |
107
|
|
|
public function getServer(): ResourceServer |
108
|
|
|
{ |
109
|
|
|
return $this->server; |
110
|
|
|
} |
111
|
|
|
|
112
|
|
|
/** |
113
|
|
|
* Create a default ResourceServer. Used if one isn't provided. |
114
|
|
|
* |
115
|
|
|
* @return ResourceServer |
116
|
|
|
*/ |
117
|
|
|
protected function createServer(): ResourceServer |
118
|
|
|
{ |
119
|
|
|
// Init our repositories |
120
|
|
|
$accessTokenRepository = new AccessTokenRepository(); // instance of AccessTokenRepositoryInterface |
121
|
|
|
|
122
|
|
|
// Path to authorization server's public key |
123
|
|
|
$publicKeyPath = Environment::getEnv('OAUTH_PUBLIC_KEY_PATH'); |
124
|
|
|
|
125
|
|
|
// Setup the authorization server |
126
|
|
|
return new ResourceServer( |
127
|
|
|
$accessTokenRepository, |
128
|
|
|
$publicKeyPath |
129
|
|
|
); |
130
|
|
|
} |
131
|
|
|
|
132
|
|
|
/** |
133
|
|
|
* Cli is missing some $_SERVER variables. |
134
|
|
|
* |
135
|
|
|
* @param HttpRequestAdapter $adapter |
136
|
|
|
*/ |
137
|
|
|
protected function addMissingServerVariables(HttpRequestAdapter $adapter) |
138
|
|
|
{ |
139
|
|
|
$vars = $adapter->getServerVars() ?: []; |
140
|
|
|
$defaults = [ |
141
|
|
|
'SERVER_PORT' => 80, |
142
|
|
|
'HTTP_HOST' => Environment::getEnv('SS_BASE_URL') |
143
|
|
|
]; |
144
|
|
|
|
145
|
|
|
foreach ($defaults as $key => $value) { |
146
|
|
|
if (empty($vars[$key])) { |
147
|
|
|
$vars[$key] = $value; |
148
|
|
|
} |
149
|
|
|
} |
150
|
|
|
|
151
|
|
|
$adapter->setServerVars($vars); |
152
|
|
|
} |
153
|
|
|
} |
154
|
|
|
|
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.