summaryrefslogtreecommitdiffstats
path: root/apps/oauth2/lib/Controller/OauthApiController.php
diff options
context:
space:
mode:
Diffstat (limited to 'apps/oauth2/lib/Controller/OauthApiController.php')
-rw-r--r--apps/oauth2/lib/Controller/OauthApiController.php110
1 files changed, 97 insertions, 13 deletions
diff --git a/apps/oauth2/lib/Controller/OauthApiController.php b/apps/oauth2/lib/Controller/OauthApiController.php
index b97d85ae3e6..8c96a3feee1 100644
--- a/apps/oauth2/lib/Controller/OauthApiController.php
+++ b/apps/oauth2/lib/Controller/OauthApiController.php
@@ -21,10 +21,17 @@
namespace OCA\OAuth2\Controller;
-use OC\Authentication\Token\DefaultTokenMapper;
+use OC\Authentication\Exceptions\InvalidTokenException;
+use OC\Authentication\Token\ExpiredTokenException;
+use OC\Authentication\Token\IProvider as TokenProvider;
use OCA\OAuth2\Db\AccessTokenMapper;
+use OCA\OAuth2\Db\ClientMapper;
+use OCA\OAuth2\Exceptions\AccessTokenNotFoundException;
+use OCA\OAuth2\Exceptions\ClientNotFoundException;
use OCP\AppFramework\Controller;
+use OCP\AppFramework\Http;
use OCP\AppFramework\Http\JSONResponse;
+use OCP\AppFramework\Utility\ITimeFactory;
use OCP\IRequest;
use OCP\Security\ICrypto;
use OCP\Security\ISecureRandom;
@@ -32,56 +39,133 @@ use OCP\Security\ISecureRandom;
class OauthApiController extends Controller {
/** @var AccessTokenMapper */
private $accessTokenMapper;
+ /** @var ClientMapper */
+ private $clientMapper;
/** @var ICrypto */
private $crypto;
- /** @var DefaultTokenMapper */
- private $defaultTokenMapper;
+ /** @var TokenProvider */
+ private $tokenProvider;
/** @var ISecureRandom */
private $secureRandom;
+ /** @var ITimeFactory */
+ private $time;
/**
* @param string $appName
* @param IRequest $request
* @param ICrypto $crypto
* @param AccessTokenMapper $accessTokenMapper
- * @param DefaultTokenMapper $defaultTokenMapper
+ * @param ClientMapper $clientMapper
+ * @param TokenProvider $tokenProvider
* @param ISecureRandom $secureRandom
+ * @param ITimeFactory $time
*/
public function __construct($appName,
IRequest $request,
ICrypto $crypto,
AccessTokenMapper $accessTokenMapper,
- DefaultTokenMapper $defaultTokenMapper,
- ISecureRandom $secureRandom) {
+ ClientMapper $clientMapper,
+ TokenProvider $tokenProvider,
+ ISecureRandom $secureRandom,
+ ITimeFactory $time) {
parent::__construct($appName, $request);
$this->crypto = $crypto;
$this->accessTokenMapper = $accessTokenMapper;
- $this->defaultTokenMapper = $defaultTokenMapper;
+ $this->clientMapper = $clientMapper;
+ $this->tokenProvider = $tokenProvider;
$this->secureRandom = $secureRandom;
+ $this->time = $time;
}
/**
* @PublicPage
* @NoCSRFRequired
*
+ * @param string $grant_type
* @param string $code
+ * @param string $refresh_token
+ * @param string $client_id
+ * @param string $client_secret
* @return JSONResponse
*/
- public function getToken($code) {
- $accessToken = $this->accessTokenMapper->getByCode($code);
+ public function getToken($grant_type, $code, $refresh_token, $client_id, $client_secret) {
+
+ // We only handle two types
+ if ($grant_type !== 'authorization_code' && $grant_type !== 'refresh_token') {
+ return new JSONResponse([
+ 'error' => 'invalid_grant',
+ ], Http::STATUS_BAD_REQUEST);
+ }
+
+ // We handle the initial and refresh tokens the same way
+ if ($grant_type === 'refresh_token' ) {
+ $code = $refresh_token;
+ }
+
+ try {
+ $accessToken = $this->accessTokenMapper->getByCode($code);
+ } catch (AccessTokenNotFoundException $e) {
+ return new JSONResponse([
+ 'error' => 'invalid_request',
+ ], Http::STATUS_BAD_REQUEST);
+ }
+
+ try {
+ $client = $this->clientMapper->getByUid($accessToken->getClientId());
+ } catch (ClientNotFoundException $e) {
+ return new JSONResponse([
+ 'error' => 'invalid_request',
+ ], Http::STATUS_BAD_REQUEST);
+ }
+
+ // The client id and secret must match. Else we don't provide an access token!
+ if ($client->getClientIdentifier() !== $client_id || $client->getSecret() !== $client_secret) {
+ return new JSONResponse([
+ 'error' => 'invalid_client',
+ ], Http::STATUS_BAD_REQUEST);
+ }
+
$decryptedToken = $this->crypto->decrypt($accessToken->getEncryptedToken(), $code);
- $newCode = $this->secureRandom->generate(128);
+
+ // Obtain the appToken assoicated
+ try {
+ $appToken = $this->tokenProvider->getTokenById($accessToken->getTokenId());
+ } catch (ExpiredTokenException $e) {
+ $appToken = $e->getToken();
+ } catch (InvalidTokenException $e) {
+ //We can't do anything...
+ $this->accessTokenMapper->delete($accessToken);
+ return new JSONResponse([
+ 'error' => 'invalid_request',
+ ], Http::STATUS_BAD_REQUEST);
+ }
+
+ // Rotate the apptoken (so the old one becomes invalid basically)
+ $newToken = $this->secureRandom->generate(72, ISecureRandom::CHAR_UPPER.ISecureRandom::CHAR_LOWER.ISecureRandom::CHAR_DIGITS);
+
+ $appToken = $this->tokenProvider->rotate(
+ $appToken,
+ $decryptedToken,
+ $newToken
+ );
+
+ // Expiration is in 1 hour again
+ $appToken->setExpires($this->time->getTime() + 3600);
+ $this->tokenProvider->updateToken($appToken);
+
+ // Generate a new refresh token and encrypt the new apptoken in the DB
+ $newCode = $this->secureRandom->generate(128, ISecureRandom::CHAR_UPPER.ISecureRandom::CHAR_LOWER.ISecureRandom::CHAR_DIGITS);
$accessToken->setHashedCode(hash('sha512', $newCode));
- $accessToken->setEncryptedToken($this->crypto->encrypt($decryptedToken, $newCode));
+ $accessToken->setEncryptedToken($this->crypto->encrypt($newToken, $newCode));
$this->accessTokenMapper->update($accessToken);
return new JSONResponse(
[
- 'access_token' => $decryptedToken,
+ 'access_token' => $newToken,
'token_type' => 'Bearer',
'expires_in' => 3600,
'refresh_token' => $newCode,
- 'user_id' => $this->defaultTokenMapper->getTokenById($accessToken->getTokenId())->getUID(),
+ 'user_id' => $appToken->getUID(),
]
);
}