summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorLukas Reschke <lukas@statuscode.ch>2017-05-04 23:46:59 +0200
committerLukas Reschke <lukas@statuscode.ch>2017-05-18 20:49:03 +0200
commit5f71805c35d04e585ea6d4227254b11204413dfd (patch)
treee2de66eb03b7127ff542393089013cda526df781 /core
parent879e11e7d1d9802647ade392f4ae317952bc6f8f (diff)
downloadnextcloud-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.php92
-rw-r--r--core/templates/loginflow/authpicker.php2
-rw-r--r--core/templates/loginflow/redirect.php2
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>