diff options
Diffstat (limited to 'apps/oauth2/lib/Controller/OauthApiController.php')
-rw-r--r-- | apps/oauth2/lib/Controller/OauthApiController.php | 110 |
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(), ] ); } |