1<?php
2/**
3 * @author      Alex Bilbie <hello@alexbilbie.com>
4 * @copyright   Copyright (c) Alex Bilbie
5 * @license     http://mit-license.org/
6 *
7 * @link        https://github.com/thephpleague/oauth2-server
8 */
9
10use Defuse\Crypto\Key;
11use League\Event\EmitterAwareInterface;
12use League\Event\EmitterAwareTrait;
13use League\OAuth2\Server\Exception\OAuthServerException;
14use League\OAuth2\Server\Grant\GrantTypeInterface;
15use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
16use League\OAuth2\Server\Repositories\ClientRepositoryInterface;
17use League\OAuth2\Server\Repositories\ScopeRepositoryInterface;
18use League\OAuth2\Server\RequestTypes\AuthorizationRequest;
19use League\OAuth2\Server\ResponseTypes\AbstractResponseType;
20use League\OAuth2\Server\ResponseTypes\BearerTokenResponse;
21use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface;
22use Psr\Http\Message\ResponseInterface;
23use Psr\Http\Message\ServerRequestInterface;
24
25class AuthorizationServer implements EmitterAwareInterface
26{
27	use EmitterAwareTrait;
28
29	/**
30	 * @var GrantTypeInterface[]
31	 */
32	protected $enabledGrantTypes = [];
33
34	/**
35	 * @var DateInterval[]
36	 */
37	protected $grantTypeAccessTokenTTL = [];
38
39	/**
40	 * @var ResponseTypeInterface
41	 */
42	protected $responseType;
43
44	/**
45	 * @var ClientRepositoryInterface
46	 */
47	private $clientRepository;
48
49	/**
50	 * @var AccessTokenRepositoryInterface
51	 */
52	private $accessTokenRepository;
53
54	/**
55	 * @var ScopeRepositoryInterface
56	 */
57	private $scopeRepository;
58
59	/**
60	 * @var string
61	 */
62	private $defaultScope = '';
63
64	/**
65	 * New server instance.
66	 *
67	 * @param ClientRepositoryInterface      $clientRepository
68	 * @param AccessTokenRepositoryInterface $accessTokenRepository
69	 * @param ScopeRepositoryInterface       $scopeRepository
70	 * @param null|ResponseTypeInterface     $responseType
71	 */
72	public function __construct(
73		ClientRepositoryInterface $clientRepository,
74		AccessTokenRepositoryInterface $accessTokenRepository,
75		ScopeRepositoryInterface $scopeRepository,
76		ResponseTypeInterface $responseType = null,
77		$encryptionKey = ''
78	) {
79		$this->clientRepository = $clientRepository;
80		$this->accessTokenRepository = $accessTokenRepository;
81		$this->scopeRepository = $scopeRepository;
82
83		$this->encryptionKey = $encryptionKey;
84
85		if ($responseType === null) {
86			$responseType = new BearerTokenResponse();
87		} else {
88			$responseType = clone $responseType;
89		}
90
91		$this->responseType = $responseType;
92	}
93
94	/**
95	 * Enable a grant type on the server.
96	 *
97	 * @param GrantTypeInterface $grantType
98	 * @param null|DateInterval  $accessTokenTTL
99	 */
100	public function enableGrantType(GrantTypeInterface $grantType, DateInterval $accessTokenTTL = null)
101	{
102		if ($accessTokenTTL instanceof DateInterval === false) {
103			$accessTokenTTL = new DateInterval('PT1H');
104		}
105
106		$grantType->setAccessTokenRepository($this->accessTokenRepository);
107		$grantType->setClientRepository($this->clientRepository);
108		$grantType->setScopeRepository($this->scopeRepository);
109		$grantType->setDefaultScope($this->defaultScope);
110		$grantType->setEmitter($this->getEmitter());
111		$grantType->setEncryptionKey($this->encryptionKey);
112
113		$this->enabledGrantTypes[$grantType->getIdentifier()] = $grantType;
114		$this->grantTypeAccessTokenTTL[$grantType->getIdentifier()] = $accessTokenTTL;
115	}
116
117	/**
118	 * Validate an authorization request
119	 *
120	 * @param ServerRequestInterface $request
121	 *
122	 * @throws OAuthServerException
123	 *
124	 * @return AuthorizationRequest
125	 */
126	public function validateAuthorizationRequest(ServerRequestInterface $request)
127	{
128		foreach ($this->enabledGrantTypes as $grantType) {
129			if ($grantType->canRespondToAuthorizationRequest($request)) {
130				return $grantType->validateAuthorizationRequest($request);
131			}
132		}
133
134		throw OAuthServerException::unsupportedGrantType();
135	}
136
137	/**
138	 * Complete an authorization request
139	 *
140	 * @param AuthorizationRequest $authRequest
141	 * @param ResponseInterface    $response
142	 *
143	 * @return ResponseInterface
144	 */
145	public function completeAuthorizationRequest(AuthorizationRequest $authRequest, ResponseInterface $response)
146	{
147		return $this->enabledGrantTypes[$authRequest->getGrantTypeId()]
148			->completeAuthorizationRequest($authRequest)
149			->generateHttpResponse($response);
150	}
151
152	/**
153	 * Return an access token response.
154	 *
155	 * @param ServerRequestInterface $request
156	 * @param ResponseInterface      $response
157	 *
158	 * @throws OAuthServerException
159	 *
160	 * @return ResponseInterface
161	 */
162	public function respondToAccessTokenRequest(ServerRequestInterface $request, ResponseInterface $response)
163	{
164		foreach ($this->enabledGrantTypes as $grantType) {
165			if (! $grantType->canRespondToAccessTokenRequest($request)) {
166				continue;
167			}
168			$response_type = $this->getResponseType();
169			$grant_identifier = $grantType->getIdentifier();
170			$tokenResponse = $grantType->respondToAccessTokenRequest(
171				$request,
172				$response_type,
173				$this->grantTypeAccessTokenTTL[$grant_identifier]
174			);
175
176			if ($tokenResponse instanceof ResponseTypeInterface) {
177				return $tokenResponse->generateHttpResponse($response);
178			}
179		}
180
181		throw OAuthServerException::unsupportedGrantType();
182	}
183
184	/**
185	 * Get the token type that grants will return in the HTTP response.
186	 *
187	 * @return ResponseTypeInterface
188	 */
189	protected function getResponseType()
190	{
191		$responseType = clone $this->responseType;
192		$responseType->setEncryptionKey($this->encryptionKey);
193
194		return $responseType;
195	}
196
197	/**
198	 * Set the default scope for the authorization server.
199	 *
200	 * @param string $defaultScope
201	 */
202	public function setDefaultScope($defaultScope)
203	{
204		$this->defaultScope = $defaultScope;
205	}
206}
207