diff options
author | Lukas Reschke <lukas@statuscode.ch> | 2017-05-04 23:46:59 +0200 |
---|---|---|
committer | Lukas Reschke <lukas@statuscode.ch> | 2017-05-18 20:49:03 +0200 |
commit | 5f71805c35d04e585ea6d4227254b11204413dfd (patch) | |
tree | e2de66eb03b7127ff542393089013cda526df781 /core | |
parent | 879e11e7d1d9802647ade392f4ae317952bc6f8f (diff) | |
download | nextcloud-server-5f71805c35d04e585ea6d4227254b11204413dfd.tar.gz nextcloud-server-5f71805c35d04e585ea6d4227254b11204413dfd.zip |
Add basic implementation for OAuth 2.0 Authorization Code Flow
Signed-off-by: Lukas Reschke <lukas@statuscode.ch>
Diffstat (limited to 'core')
-rw-r--r-- | core/Controller/ClientFlowLoginController.php | 92 | ||||
-rw-r--r-- | core/templates/loginflow/authpicker.php | 2 | ||||
-rw-r--r-- | core/templates/loginflow/redirect.php | 2 |
3 files changed, 75 insertions, 21 deletions
diff --git a/core/Controller/ClientFlowLoginController.php b/core/Controller/ClientFlowLoginController.php index 8c2c121d5b2..45287f3048c 100644 --- a/core/Controller/ClientFlowLoginController.php +++ b/core/Controller/ClientFlowLoginController.php @@ -25,6 +25,9 @@ use OC\Authentication\Exceptions\InvalidTokenException; use OC\Authentication\Exceptions\PasswordlessTokenException; use OC\Authentication\Token\IProvider; use OC\Authentication\Token\IToken; +use OCA\OAuth2\Db\AccessToken; +use OCA\OAuth2\Db\AccessTokenMapper; +use OCA\OAuth2\Db\ClientMapper; use OCP\AppFramework\Controller; use OCP\AppFramework\Http; use OCP\AppFramework\Http\Response; @@ -35,6 +38,7 @@ use OCP\IRequest; use OCP\ISession; use OCP\IURLGenerator; use OCP\IUserSession; +use OCP\Security\ICrypto; use OCP\Security\ISecureRandom; use OCP\Session\Exceptions\SessionNotAvailableException; @@ -53,6 +57,12 @@ class ClientFlowLoginController extends Controller { private $random; /** @var IURLGenerator */ private $urlGenerator; + /** @var ClientMapper */ + private $clientMapper; + /** @var AccessTokenMapper */ + private $accessTokenMapper; + /** @var ICrypto */ + private $crypto; const stateName = 'client.flow.state.token'; @@ -66,6 +76,9 @@ class ClientFlowLoginController extends Controller { * @param IProvider $tokenProvider * @param ISecureRandom $random * @param IURLGenerator $urlGenerator + * @param ClientMapper $clientMapper + * @param AccessTokenMapper $accessTokenMapper + * @param ICrypto $crypto */ public function __construct($appName, IRequest $request, @@ -75,7 +88,10 @@ class ClientFlowLoginController extends Controller { ISession $session, IProvider $tokenProvider, ISecureRandom $random, - IURLGenerator $urlGenerator) { + IURLGenerator $urlGenerator, + ClientMapper $clientMapper, + AccessTokenMapper $accessTokenMapper, + ICrypto $crypto) { parent::__construct($appName, $request); $this->userSession = $userSession; $this->l10n = $l10n; @@ -84,6 +100,9 @@ class ClientFlowLoginController extends Controller { $this->tokenProvider = $tokenProvider; $this->random = $random; $this->urlGenerator = $urlGenerator; + $this->clientMapper = $clientMapper; + $this->accessTokenMapper = $accessTokenMapper; + $this->crypto = $crypto; } /** @@ -126,31 +145,31 @@ class ClientFlowLoginController extends Controller { * @NoCSRFRequired * @UseSession * + * @param string $clientIdentifier + * * @return TemplateResponse */ - public function showAuthPickerPage() { - if($this->userSession->isLoggedIn()) { - return new TemplateResponse( - $this->appName, - '403', - [ - 'file' => $this->l10n->t('Auth flow can only be started unauthenticated.'), - ], - 'guest' - ); - } - + public function showAuthPickerPage($clientIdentifier = '', + $oauthState = '') { $stateToken = $this->random->generate( 64, ISecureRandom::CHAR_LOWER.ISecureRandom::CHAR_UPPER.ISecureRandom::CHAR_DIGITS ); $this->session->set(self::stateName, $stateToken); + $clientName = $this->getClientName(); + if($clientIdentifier !== '') { + $client = $this->clientMapper->getByIdentifier($clientIdentifier); + $clientName = $client->getName(); + } + return new TemplateResponse( $this->appName, 'loginflow/authpicker', [ - 'client' => $this->getClientName(), + 'client' => $clientName, + 'clientIdentifier' => $clientIdentifier, + 'oauthState' => $oauthState, 'instanceName' => $this->defaults->getName(), 'urlGenerator' => $this->urlGenerator, 'stateToken' => $stateToken, @@ -166,9 +185,13 @@ class ClientFlowLoginController extends Controller { * @UseSession * * @param string $stateToken + * @param string $clientIdentifier + * @param string $oauthState * @return TemplateResponse */ - public function redirectPage($stateToken = '') { + public function redirectPage($stateToken = '', + $clientIdentifier = '', + $oauthState = '') { if(!$this->isValidToken($stateToken)) { return $this->stateTokenForbiddenResponse(); } @@ -179,6 +202,8 @@ class ClientFlowLoginController extends Controller { [ 'urlGenerator' => $this->urlGenerator, 'stateToken' => $stateToken, + 'clientIdentifier' => $clientIdentifier, + 'oauthState' => $oauthState, ], 'empty' ); @@ -189,9 +214,15 @@ class ClientFlowLoginController extends Controller { * @UseSession * * @param string $stateToken + * @param string $clientIdentifier + * @param string $state + * @param string $oauthState * @return Http\RedirectResponse|Response */ - public function generateAppPassword($stateToken) { + public function generateAppPassword($stateToken, + $clientIdentifier = '', + $state = '', + $oauthState = '') { if(!$this->isValidToken($stateToken)) { $this->session->remove(self::stateName); return $this->stateTokenForbiddenResponse(); @@ -222,9 +253,10 @@ class ClientFlowLoginController extends Controller { } $token = $this->random->generate(72); - $this->tokenProvider->generateToken( + $uid = $this->userSession->getUser()->getUID(); + $generatedToken = $this->tokenProvider->generateToken( $token, - $this->userSession->getUser()->getUID(), + $uid, $loginName, $password, $this->getClientName(), @@ -232,7 +264,27 @@ class ClientFlowLoginController extends Controller { IToken::DO_NOT_REMEMBER ); - return new Http\RedirectResponse('nc://login/server:' . $this->request->getServerHost() . '&user:' . urlencode($loginName) . '&password:' . urlencode($token)); - } + if($clientIdentifier !== '') { + $client = $this->clientMapper->getByIdentifier($clientIdentifier); + + $code = $this->random->generate(128); + $accessToken = new AccessToken(); + $accessToken->setClientId($client->getId()); + $accessToken->setEncryptedToken($this->crypto->encrypt($token, $code)); + $accessToken->setHashedCode(hash('sha512', $code)); + $accessToken->setTokenId($generatedToken->getId()); + $this->accessTokenMapper->insert($accessToken); + + $redirectUri = sprintf( + '%s?state=%s&code=%s', + $client->getRedirectUri(), + urlencode($oauthState), + urlencode($code) + ); + } else { + $redirectUri = 'nc://login/server:' . $this->request->getServerHost() . '&user:' . urlencode($loginName) . '&password:' . urlencode($token); + } + return new Http\RedirectResponse($redirectUri); + } } diff --git a/core/templates/loginflow/authpicker.php b/core/templates/loginflow/authpicker.php index c5eb6cb316d..127a1156a68 100644 --- a/core/templates/loginflow/authpicker.php +++ b/core/templates/loginflow/authpicker.php @@ -35,7 +35,7 @@ $urlGenerator = $_['urlGenerator']; <br/> <p id="redirect-link"> - <a href="<?php p($urlGenerator->linkToRouteAbsolute('core.ClientFlowLogin.redirectPage', ['stateToken' => $_['stateToken']])) ?>"> + <a href="<?php p($urlGenerator->linkToRouteAbsolute('core.ClientFlowLogin.redirectPage', ['stateToken' => $_['stateToken'], 'clientIdentifier' => $_['clientIdentifier'], 'oauthState' => $_['oauthState']])) ?>"> <input type="submit" class="login primary icon-confirm-white" value="<?php p('Grant access') ?>"> </a> </p> diff --git a/core/templates/loginflow/redirect.php b/core/templates/loginflow/redirect.php index 7ef0184f61f..1c6e105b88d 100644 --- a/core/templates/loginflow/redirect.php +++ b/core/templates/loginflow/redirect.php @@ -31,7 +31,9 @@ $urlGenerator = $_['urlGenerator']; </div> <form method="POST" action="<?php p($urlGenerator->linkToRouteAbsolute('core.ClientFlowLogin.generateAppPassword')) ?>"> + <input type="hidden" name="clientIdentifier" value="<?php p($_['clientIdentifier']) ?>" /> <input type="hidden" name="requesttoken" value="<?php p($_['requesttoken']) ?>" /> <input type="hidden" name="stateToken" value="<?php p($_['stateToken']) ?>" /> + <input type="hidden" name="oauthState" value="<?php p($_['oauthState']) ?>" /> <input id="submit-redirect-form" type="submit" class="hidden "/> </form> |