Browse Source
Merge pull request #4704 from nextcloud/add-oauth-code-flow-support
Merge pull request #4704 from nextcloud/add-oauth-code-flow-support
Add oauth code flow supportpull/4949/head
committed by
GitHub
46 changed files with 1969 additions and 50 deletions
-
1.gitignore
-
3apps/dav/appinfo/v1/publicwebdav.php
-
10apps/dav/appinfo/v1/webdav.php
-
1apps/dav/lib/Connector/Sabre/Auth.php
-
80apps/dav/lib/Connector/Sabre/BearerAuth.php
-
7apps/dav/lib/Connector/Sabre/ServerFactory.php
-
8apps/dav/lib/Server.php
-
88apps/dav/tests/unit/Connector/Sabre/BearerAuthTest.php
-
3apps/dav/tests/unit/Connector/Sabre/RequestTest/RequestTestCase.php
-
100apps/oauth2/appinfo/database.xml
-
18apps/oauth2/appinfo/info.xml
-
45apps/oauth2/appinfo/routes.php
-
5apps/oauth2/css/setting-admin.css
-
15apps/oauth2/js/setting-admin.js
-
79apps/oauth2/lib/Controller/LoginRedirectorController.php
-
88apps/oauth2/lib/Controller/OauthApiController.php
-
100apps/oauth2/lib/Controller/SettingsController.php
-
53apps/oauth2/lib/Db/AccessToken.php
-
70apps/oauth2/lib/Db/AccessTokenMapper.php
-
53apps/oauth2/lib/Db/Client.php
-
89apps/oauth2/lib/Db/ClientMapper.php
-
24apps/oauth2/lib/Exceptions/AccessTokenNotFoundException.php
-
24apps/oauth2/lib/Exceptions/ClientNotFoundException.php
-
66apps/oauth2/lib/Settings/Admin.php
-
76apps/oauth2/templates/admin.php
-
91apps/oauth2/tests/Controller/LoginRedirectorControllerTest.php
-
106apps/oauth2/tests/Controller/OauthApiControllerTest.php
-
139apps/oauth2/tests/Controller/SettingsControllerTest.php
-
70apps/oauth2/tests/Db/AccessTokenMapperTest.php
-
79apps/oauth2/tests/Db/ClientMapperTest.php
-
66apps/oauth2/tests/Settings/AdminTest.php
-
8build/integration/features/auth.feature
-
4build/integration/features/bootstrap/Auth.php
-
1build/integration/features/provisioning-v1.feature
-
4build/integration/features/webdav-related.feature
-
101core/Controller/ClientFlowLoginController.php
-
2core/css/login/authpicker.css
-
4core/templates/loginflow/authpicker.php
-
2core/templates/loginflow/redirect.php
-
12lib/private/Authentication/Token/DefaultTokenMapper.php
-
4lib/private/User/Session.php
-
2settings/personal.php
-
200tests/Core/Controller/ClientFlowLoginControllerTest.php
-
15tests/lib/Authentication/Token/DefaultTokenMapperTest.php
-
2tests/lib/User/SessionTest.php
-
1tests/phpunit-autotest.xml
@ -0,0 +1,80 @@ |
|||
<?php |
|||
/** |
|||
* @copyright Copyright (c) 2017 Lukas Reschke <lukas@statuscode.ch> |
|||
* |
|||
* @license GNU AGPL version 3 or any later version |
|||
* |
|||
* This program is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU Affero General Public License as |
|||
* published by the Free Software Foundation, either version 3 of the |
|||
* License, or (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU Affero General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU Affero General Public License |
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
|||
* |
|||
*/ |
|||
|
|||
namespace OCA\DAV\Connector\Sabre; |
|||
|
|||
use OCP\IRequest; |
|||
use OCP\ISession; |
|||
use OCP\IUserSession; |
|||
use Sabre\DAV\Auth\Backend\AbstractBearer; |
|||
|
|||
class BearerAuth extends AbstractBearer { |
|||
/** @var IUserSession */ |
|||
private $userSession; |
|||
/** @var ISession */ |
|||
private $session; |
|||
/** @var IRequest */ |
|||
private $request; |
|||
/** @var string */ |
|||
private $principalPrefix; |
|||
|
|||
/** |
|||
* @param IUserSession $userSession |
|||
* @param ISession $session |
|||
* @param string $principalPrefix |
|||
* @param IRequest $request |
|||
*/ |
|||
public function __construct(IUserSession $userSession, |
|||
ISession $session, |
|||
IRequest $request, |
|||
$principalPrefix = 'principals/users/') { |
|||
$this->userSession = $userSession; |
|||
$this->session = $session; |
|||
$this->request = $request; |
|||
$this->principalPrefix = $principalPrefix; |
|||
|
|||
// setup realm
|
|||
$defaults = new \OCP\Defaults(); |
|||
$this->realm = $defaults->getName(); |
|||
} |
|||
|
|||
private function setupUserFs($userId) { |
|||
\OC_Util::setupFS($userId); |
|||
$this->session->close(); |
|||
return $this->principalPrefix . $userId; |
|||
} |
|||
|
|||
/** |
|||
* {@inheritdoc} |
|||
*/ |
|||
public function validateBearerToken($bearerToken) { |
|||
\OC_Util::setupFS(); |
|||
|
|||
if(!$this->userSession->isLoggedIn()) { |
|||
$this->userSession->tryTokenLogin($this->request); |
|||
} |
|||
if($this->userSession->isLoggedIn()) { |
|||
return $this->setupUserFs($this->userSession->getUser()->getUID()); |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
} |
|||
@ -0,0 +1,88 @@ |
|||
<?php |
|||
/** |
|||
* @copyright Copyright (c) 2017 Lukas Reschke <lukas@statuscode.ch> |
|||
* |
|||
* @license GNU AGPL version 3 or any later version |
|||
* |
|||
* This program is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU Affero General Public License as |
|||
* published by the Free Software Foundation, either version 3 of the |
|||
* License, or (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU Affero General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU Affero General Public License |
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
|||
* |
|||
*/ |
|||
|
|||
namespace OCA\DAV\Tests\unit\Connector\Sabre; |
|||
|
|||
use OC\Authentication\TwoFactorAuth\Manager; |
|||
use OC\Security\Bruteforce\Throttler; |
|||
use OC\User\Session; |
|||
use OCA\DAV\Connector\Sabre\BearerAuth; |
|||
use OCP\IRequest; |
|||
use OCP\ISession; |
|||
use OCP\IUser; |
|||
use OCP\IUserSession; |
|||
use Sabre\HTTP\RequestInterface; |
|||
use Sabre\HTTP\ResponseInterface; |
|||
use Test\TestCase; |
|||
|
|||
/** |
|||
* @group DB |
|||
*/ |
|||
class BearerAuthTest extends TestCase { |
|||
/** @var IUserSession|\PHPUnit_Framework_MockObject_MockObject */ |
|||
private $userSession; |
|||
/** @var ISession|\PHPUnit_Framework_MockObject_MockObject */ |
|||
private $session; |
|||
/** @var IRequest|\PHPUnit_Framework_MockObject_MockObject */ |
|||
private $request; |
|||
/** @var BearerAuth */ |
|||
private $bearerAuth; |
|||
|
|||
public function setUp() { |
|||
parent::setUp(); |
|||
|
|||
$this->userSession = $this->createMock(\OC\User\Session::class); |
|||
$this->session = $this->createMock(ISession::class); |
|||
$this->request = $this->createMock(IRequest::class); |
|||
|
|||
$this->bearerAuth = new BearerAuth( |
|||
$this->userSession, |
|||
$this->session, |
|||
$this->request |
|||
); |
|||
} |
|||
|
|||
public function testValidateBearerTokenNotLoggedIn() { |
|||
$this->assertFalse($this->bearerAuth->validateBearerToken('Token')); |
|||
} |
|||
|
|||
public function testValidateBearerToken() { |
|||
$this->userSession |
|||
->expects($this->at(0)) |
|||
->method('isLoggedIn') |
|||
->willReturn(false); |
|||
$this->userSession |
|||
->expects($this->at(2)) |
|||
->method('isLoggedIn') |
|||
->willReturn(true); |
|||
$user = $this->createMock(IUser::class); |
|||
$user |
|||
->expects($this->once()) |
|||
->method('getUID') |
|||
->willReturn('admin'); |
|||
$this->userSession |
|||
->expects($this->once()) |
|||
->method('getUser') |
|||
->willReturn($user); |
|||
|
|||
$this->assertSame('principals/users/admin', $this->bearerAuth->validateBearerToken('Token')); |
|||
} |
|||
} |
|||
@ -0,0 +1,100 @@ |
|||
<?xml version="1.0" encoding="ISO-8859-1" ?> |
|||
<database xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://apps.nextcloud.com/schema/apps/database.xsd"> |
|||
<name>*dbname*</name> |
|||
<create>true</create> |
|||
<overwrite>false</overwrite> |
|||
<charset>utf8</charset> |
|||
<table> |
|||
<name>*dbprefix*oauth2_clients</name> |
|||
<declaration> |
|||
<field> |
|||
<name>id</name> |
|||
<type>integer</type> |
|||
<notnull>true</notnull> |
|||
<autoincrement>true</autoincrement> |
|||
<unsigned>true</unsigned> |
|||
<primary>true</primary> |
|||
</field> |
|||
<field> |
|||
<name>name</name> |
|||
<type>text</type> |
|||
<notnull>true</notnull> |
|||
<length>64</length> |
|||
</field> |
|||
<field> |
|||
<name>redirect_uri</name> |
|||
<type>text</type> |
|||
<notnull>true</notnull> |
|||
<length>2000</length> |
|||
</field> |
|||
<field> |
|||
<name>client_identifier</name> |
|||
<type>text</type> |
|||
<notnull>true</notnull> |
|||
<length>64</length> |
|||
</field> |
|||
<field> |
|||
<name>secret</name> |
|||
<type>text</type> |
|||
<notnull>true</notnull> |
|||
<length>64</length> |
|||
</field> |
|||
<index> |
|||
<name>oauth2_client_id_idx</name> |
|||
<unique>false</unique> |
|||
<field> |
|||
<name>client_identifier</name> |
|||
</field> |
|||
</index> |
|||
</declaration> |
|||
</table> |
|||
<table> |
|||
<name>*dbprefix*oauth2_access_tokens</name> |
|||
<declaration> |
|||
<field> |
|||
<name>id</name> |
|||
<type>integer</type> |
|||
<notnull>true</notnull> |
|||
<autoincrement>true</autoincrement> |
|||
<unsigned>true</unsigned> |
|||
<primary>true</primary> |
|||
</field> |
|||
<field> |
|||
<name>token_id</name> |
|||
<type>integer</type> |
|||
<notnull>true</notnull> |
|||
</field> |
|||
<field> |
|||
<name>client_id</name> |
|||
<type>integer</type> |
|||
<notnull>true</notnull> |
|||
</field> |
|||
<field> |
|||
<name>hashed_code</name> |
|||
<type>text</type> |
|||
<notnull>true</notnull> |
|||
<length>128</length> |
|||
</field> |
|||
<field> |
|||
<name>encrypted_token</name> |
|||
<type>text</type> |
|||
<notnull>true</notnull> |
|||
<length>786</length> |
|||
</field> |
|||
<index> |
|||
<name>oauth2_access_hash_idx</name> |
|||
<unique>true</unique> |
|||
<field> |
|||
<name>hashed_code</name> |
|||
</field> |
|||
</index> |
|||
<index> |
|||
<name>oauth2_access_client_id_idx</name> |
|||
<unique>false</unique> |
|||
<field> |
|||
<name>client_id</name> |
|||
</field> |
|||
</index> |
|||
</declaration> |
|||
</table> |
|||
</database> |
|||
@ -0,0 +1,18 @@ |
|||
<?xml version="1.0"?> |
|||
<info xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://apps.nextcloud.com/schema/apps/info.xsd"> |
|||
<id>oauth2</id> |
|||
<name>OAuth 2.0</name> |
|||
<description>The OAuth2 app allows administrators to configure the built-in authentication workflow to also allow OAuth2 compatible authentication from other web applications.</description> |
|||
<licence>agpl</licence> |
|||
<author>Lukas Reschke</author> |
|||
<namespace>OAuth2</namespace> |
|||
<version>1.0.5</version> |
|||
<default_enable/> |
|||
<types> |
|||
<authentication/> |
|||
</types> |
|||
|
|||
<settings> |
|||
<admin>OCA\OAuth2\Settings\Admin</admin> |
|||
</settings> |
|||
</info> |
|||
@ -0,0 +1,45 @@ |
|||
<?php |
|||
/** |
|||
* @copyright Copyright (c) 2017 Lukas Reschke <lukas@statuscode.ch> |
|||
* |
|||
* @license GNU AGPL version 3 or any later version |
|||
* |
|||
* This program is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU Affero General Public License as |
|||
* published by the Free Software Foundation, either version 3 of the |
|||
* License, or (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU Affero General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU Affero General Public License |
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
|||
* |
|||
*/ |
|||
|
|||
return [ |
|||
'routes' => [ |
|||
[ |
|||
'name' => 'Settings#addClient', |
|||
'url' => '/settings', |
|||
'verb' => 'POST', |
|||
], |
|||
[ |
|||
'name' => 'Settings#deleteClient', |
|||
'url' => '/clients/{id}/delete', |
|||
'verb' => 'POST' |
|||
], |
|||
[ |
|||
'name' => 'LoginRedirector#authorize', |
|||
'url' => '/authorize', |
|||
'verb' => 'GET', |
|||
], |
|||
[ |
|||
'name' => 'OauthApi#getToken', |
|||
'url' => '/api/v1/token', |
|||
'verb' => 'POST' |
|||
], |
|||
], |
|||
]; |
|||
@ -0,0 +1,5 @@ |
|||
.show-oauth-credentials { |
|||
padding-left: 10px; |
|||
opacity: 0.3; |
|||
cursor: pointer; |
|||
} |
|||
@ -0,0 +1,15 @@ |
|||
$(document).ready(function () { |
|||
|
|||
$('.show-oauth-credentials').click(function() { |
|||
var row = $(this).parent(); |
|||
var code = $(row).find('code'); |
|||
if(code.text() === '****') { |
|||
code.text(row.data('value')); |
|||
$(this).css('opacity', 0.9); |
|||
} else { |
|||
code.text('****'); |
|||
$(this).css('opacity', 0.3); |
|||
} |
|||
}) |
|||
|
|||
}); |
|||
@ -0,0 +1,79 @@ |
|||
<?php |
|||
/** |
|||
* @copyright Copyright (c) 2017 Lukas Reschke <lukas@statuscode.ch> |
|||
* |
|||
* @license GNU AGPL version 3 or any later version |
|||
* |
|||
* This program is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU Affero General Public License as |
|||
* published by the Free Software Foundation, either version 3 of the |
|||
* License, or (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU Affero General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU Affero General Public License |
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
|||
* |
|||
*/ |
|||
|
|||
namespace OCA\OAuth2\Controller; |
|||
|
|||
use OCA\OAuth2\Db\ClientMapper; |
|||
use OCP\AppFramework\Controller; |
|||
use OCP\AppFramework\Http\RedirectResponse; |
|||
use OCP\IRequest; |
|||
use OCP\ISession; |
|||
use OCP\IURLGenerator; |
|||
|
|||
class LoginRedirectorController extends Controller { |
|||
/** @var IURLGenerator */ |
|||
private $urlGenerator; |
|||
/** @var ClientMapper */ |
|||
private $clientMapper; |
|||
/** @var ISession */ |
|||
private $session; |
|||
|
|||
/** |
|||
* @param string $appName |
|||
* @param IRequest $request |
|||
* @param IURLGenerator $urlGenerator |
|||
* @param ClientMapper $clientMapper |
|||
* @param ISession $session |
|||
*/ |
|||
public function __construct($appName, |
|||
IRequest $request, |
|||
IURLGenerator $urlGenerator, |
|||
ClientMapper $clientMapper, |
|||
ISession $session) { |
|||
parent::__construct($appName, $request); |
|||
$this->urlGenerator = $urlGenerator; |
|||
$this->clientMapper = $clientMapper; |
|||
$this->session = $session; |
|||
} |
|||
|
|||
/** |
|||
* @PublicPage |
|||
* @NoCSRFRequired |
|||
* @UseSession |
|||
* |
|||
* @param string $client_id |
|||
* @param string $state |
|||
* @return RedirectResponse |
|||
*/ |
|||
public function authorize($client_id, |
|||
$state) { |
|||
$client = $this->clientMapper->getByIdentifier($client_id); |
|||
$this->session->set('oauth.state', $state); |
|||
|
|||
$targetUrl = $this->urlGenerator->linkToRouteAbsolute( |
|||
'core.ClientFlowLogin.showAuthPickerPage', |
|||
[ |
|||
'clientIdentifier' => $client->getClientIdentifier(), |
|||
] |
|||
); |
|||
return new RedirectResponse($targetUrl); |
|||
} |
|||
} |
|||
@ -0,0 +1,88 @@ |
|||
<?php |
|||
/** |
|||
* @copyright Copyright (c) 2017 Lukas Reschke <lukas@statuscode.ch> |
|||
* |
|||
* @license GNU AGPL version 3 or any later version |
|||
* |
|||
* This program is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU Affero General Public License as |
|||
* published by the Free Software Foundation, either version 3 of the |
|||
* License, or (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU Affero General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU Affero General Public License |
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
|||
* |
|||
*/ |
|||
|
|||
namespace OCA\OAuth2\Controller; |
|||
|
|||
use OC\Authentication\Token\DefaultTokenMapper; |
|||
use OCA\OAuth2\Db\AccessTokenMapper; |
|||
use OCP\AppFramework\Controller; |
|||
use OCP\AppFramework\Http\JSONResponse; |
|||
use OCP\IRequest; |
|||
use OCP\Security\ICrypto; |
|||
use OCP\Security\ISecureRandom; |
|||
|
|||
class OauthApiController extends Controller { |
|||
/** @var AccessTokenMapper */ |
|||
private $accessTokenMapper; |
|||
/** @var ICrypto */ |
|||
private $crypto; |
|||
/** @var DefaultTokenMapper */ |
|||
private $defaultTokenMapper; |
|||
/** @var ISecureRandom */ |
|||
private $secureRandom; |
|||
|
|||
/** |
|||
* @param string $appName |
|||
* @param IRequest $request |
|||
* @param ICrypto $crypto |
|||
* @param AccessTokenMapper $accessTokenMapper |
|||
* @param DefaultTokenMapper $defaultTokenMapper |
|||
* @param ISecureRandom $secureRandom |
|||
*/ |
|||
public function __construct($appName, |
|||
IRequest $request, |
|||
ICrypto $crypto, |
|||
AccessTokenMapper $accessTokenMapper, |
|||
DefaultTokenMapper $defaultTokenMapper, |
|||
ISecureRandom $secureRandom) { |
|||
parent::__construct($appName, $request); |
|||
$this->crypto = $crypto; |
|||
$this->accessTokenMapper = $accessTokenMapper; |
|||
$this->defaultTokenMapper = $defaultTokenMapper; |
|||
$this->secureRandom = $secureRandom; |
|||
} |
|||
|
|||
/** |
|||
* @PublicPage |
|||
* @NoCSRFRequired |
|||
* |
|||
* @param string $code |
|||
* @return JSONResponse |
|||
*/ |
|||
public function getToken($code) { |
|||
$accessToken = $this->accessTokenMapper->getByCode($code); |
|||
$decryptedToken = $this->crypto->decrypt($accessToken->getEncryptedToken(), $code); |
|||
$newCode = $this->secureRandom->generate(128); |
|||
$accessToken->setHashedCode(hash('sha512', $newCode)); |
|||
$accessToken->setEncryptedToken($this->crypto->encrypt($decryptedToken, $newCode)); |
|||
$this->accessTokenMapper->update($accessToken); |
|||
|
|||
return new JSONResponse( |
|||
[ |
|||
'access_token' => $decryptedToken, |
|||
'token_type' => 'Bearer', |
|||
'expires_in' => 3600, |
|||
'refresh_token' => $newCode, |
|||
'user_id' => $this->defaultTokenMapper->getTokenById($accessToken->getTokenId())->getUID(), |
|||
] |
|||
); |
|||
} |
|||
} |
|||
@ -0,0 +1,100 @@ |
|||
<?php |
|||
/** |
|||
* @copyright Copyright (c) 2017 Lukas Reschke <lukas@statuscode.ch> |
|||
* |
|||
* @license GNU AGPL version 3 or any later version |
|||
* |
|||
* This program is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU Affero General Public License as |
|||
* published by the Free Software Foundation, either version 3 of the |
|||
* License, or (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU Affero General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU Affero General Public License |
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
|||
* |
|||
*/ |
|||
|
|||
namespace OCA\OAuth2\Controller; |
|||
|
|||
use OC\Authentication\Token\DefaultTokenMapper; |
|||
use OCA\OAuth2\Db\AccessTokenMapper; |
|||
use OCA\OAuth2\Db\Client; |
|||
use OCA\OAuth2\Db\ClientMapper; |
|||
use OCP\AppFramework\Controller; |
|||
use OCP\AppFramework\Http\RedirectResponse; |
|||
use OCP\IRequest; |
|||
use OCP\IURLGenerator; |
|||
use OCP\Security\ISecureRandom; |
|||
|
|||
class SettingsController extends Controller { |
|||
/** @var IURLGenerator */ |
|||
private $urlGenerator; |
|||
/** @var ClientMapper */ |
|||
private $clientMapper; |
|||
/** @var ISecureRandom */ |
|||
private $secureRandom; |
|||
/** @var AccessTokenMapper */ |
|||
private $accessTokenMapper; |
|||
/** @var DefaultTokenMapper */ |
|||
private $defaultTokenMapper; |
|||
|
|||
const validChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; |
|||
|
|||
/** |
|||
* @param string $appName |
|||
* @param IRequest $request |
|||
* @param IURLGenerator $urlGenerator |
|||
* @param ClientMapper $clientMapper |
|||
* @param ISecureRandom $secureRandom |
|||
* @param AccessTokenMapper $accessTokenMapper |
|||
* @param DefaultTokenMapper $defaultTokenMapper |
|||
*/ |
|||
public function __construct($appName, |
|||
IRequest $request, |
|||
IURLGenerator $urlGenerator, |
|||
ClientMapper $clientMapper, |
|||
ISecureRandom $secureRandom, |
|||
AccessTokenMapper $accessTokenMapper, |
|||
DefaultTokenMapper $defaultTokenMapper |
|||
) { |
|||
parent::__construct($appName, $request); |
|||
$this->urlGenerator = $urlGenerator; |
|||
$this->secureRandom = $secureRandom; |
|||
$this->clientMapper = $clientMapper; |
|||
$this->accessTokenMapper = $accessTokenMapper; |
|||
$this->defaultTokenMapper = $defaultTokenMapper; |
|||
} |
|||
|
|||
/** |
|||
* @param string $name |
|||
* @param string $redirectUri |
|||
* @return RedirectResponse |
|||
*/ |
|||
public function addClient($name, |
|||
$redirectUri) { |
|||
$client = new Client(); |
|||
$client->setName($name); |
|||
$client->setRedirectUri($redirectUri); |
|||
$client->setSecret($this->secureRandom->generate(64, self::validChars)); |
|||
$client->setClientIdentifier($this->secureRandom->generate(64, self::validChars)); |
|||
$this->clientMapper->insert($client); |
|||
return new RedirectResponse($this->urlGenerator->getAbsoluteURL('/index.php/settings/admin/security')); |
|||
} |
|||
|
|||
/** |
|||
* @param int $id |
|||
* @return RedirectResponse |
|||
*/ |
|||
public function deleteClient($id) { |
|||
$client = $this->clientMapper->getByUid($id); |
|||
$this->accessTokenMapper->deleteByClientId($id); |
|||
$this->defaultTokenMapper->deleteByName($client->getName()); |
|||
$this->clientMapper->delete($client); |
|||
return new RedirectResponse($this->urlGenerator->getAbsoluteURL('/index.php/settings/admin/security')); |
|||
} |
|||
} |
|||
@ -0,0 +1,53 @@ |
|||
<?php |
|||
/** |
|||
* @copyright Copyright (c) 2017 Lukas Reschke <lukas@statuscode.ch> |
|||
* |
|||
* @license GNU AGPL version 3 or any later version |
|||
* |
|||
* This program is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU Affero General Public License as |
|||
* published by the Free Software Foundation, either version 3 of the |
|||
* License, or (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU Affero General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU Affero General Public License |
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
|||
* |
|||
*/ |
|||
|
|||
namespace OCA\OAuth2\Db; |
|||
|
|||
use OCP\AppFramework\Db\Entity; |
|||
|
|||
/** |
|||
* @method int getTokenId() |
|||
* @method void setTokenId(int $identifier) |
|||
* @method int getClientId() |
|||
* @method void setClientId(int $identifier) |
|||
* @method string getEncryptedToken() |
|||
* @method void setEncryptedToken(string $token) |
|||
* @method string getHashedCode() |
|||
* @method void setHashedCode(string $token) |
|||
*/ |
|||
class AccessToken extends Entity { |
|||
/** @var int */ |
|||
protected $tokenId; |
|||
/** @var int */ |
|||
protected $clientId; |
|||
/** @var string */ |
|||
protected $hashedCode; |
|||
/** @var string */ |
|||
protected $encryptedToken; |
|||
|
|||
public function __construct() { |
|||
$this->addType('id', 'int'); |
|||
$this->addType('token_id', 'int'); |
|||
$this->addType('client_id', 'int'); |
|||
$this->addType('hashed_code', 'string'); |
|||
$this->addType('encrypted_token', 'string'); |
|||
} |
|||
} |
|||
@ -0,0 +1,70 @@ |
|||
<?php |
|||
/** |
|||
* @copyright Copyright (c) 2017 Lukas Reschke <lukas@statuscode.ch> |
|||
* |
|||
* @license GNU AGPL version 3 or any later version |
|||
* |
|||
* This program is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU Affero General Public License as |
|||
* published by the Free Software Foundation, either version 3 of the |
|||
* License, or (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU Affero General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU Affero General Public License |
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
|||
* |
|||
*/ |
|||
|
|||
namespace OCA\OAuth2\Db; |
|||
|
|||
use OCA\OAuth2\Exceptions\AccessTokenNotFoundException; |
|||
use OCP\AppFramework\Db\Mapper; |
|||
use OCP\DB\QueryBuilder\IQueryBuilder; |
|||
use OCP\IDBConnection; |
|||
|
|||
class AccessTokenMapper extends Mapper { |
|||
|
|||
/** |
|||
* @param IDBConnection $db |
|||
*/ |
|||
public function __construct(IDBConnection $db) { |
|||
parent::__construct($db, 'oauth2_access_tokens'); |
|||
} |
|||
|
|||
/** |
|||
* @param string $code |
|||
* @return AccessToken |
|||
* @throws AccessTokenNotFoundException |
|||
*/ |
|||
public function getByCode($code) { |
|||
$qb = $this->db->getQueryBuilder(); |
|||
$qb |
|||
->select('*') |
|||
->from($this->tableName) |
|||
->where($qb->expr()->eq('hashed_code', $qb->createNamedParameter(hash('sha512', $code)))); |
|||
$result = $qb->execute(); |
|||
$row = $result->fetch(); |
|||
$result->closeCursor(); |
|||
if($row === false) { |
|||
throw new AccessTokenNotFoundException(); |
|||
} |
|||
return AccessToken::fromRow($row); |
|||
} |
|||
|
|||
/** |
|||
* delete all access token from a given client |
|||
* |
|||
* @param int $id |
|||
*/ |
|||
public function deleteByClientId($id) { |
|||
$qb = $this->db->getQueryBuilder(); |
|||
$qb |
|||
->delete($this->tableName) |
|||
->where($qb->expr()->eq('client_id', $qb->createNamedParameter($id, IQueryBuilder::PARAM_INT))); |
|||
$qb->execute(); |
|||
} |
|||
} |
|||
@ -0,0 +1,53 @@ |
|||
<?php |
|||
/** |
|||
* @copyright Copyright (c) 2017 Lukas Reschke <lukas@statuscode.ch> |
|||
* |
|||
* @license GNU AGPL version 3 or any later version |
|||
* |
|||
* This program is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU Affero General Public License as |
|||
* published by the Free Software Foundation, either version 3 of the |
|||
* License, or (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU Affero General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU Affero General Public License |
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
|||
* |
|||
*/ |
|||
|
|||
namespace OCA\OAuth2\Db; |
|||
|
|||
use OCP\AppFramework\Db\Entity; |
|||
|
|||
/** |
|||
* @method string getClientIdentifier() |
|||
* @method void setClientIdentifier(string $identifier) |
|||
* @method string getSecret() |
|||
* @method void setSecret(string $secret) |
|||
* @method string getRedirectUri() |
|||
* @method void setRedirectUri(string $redirectUri) |
|||
* @method string getName() |
|||
* @method void setName(string $name) |
|||
*/ |
|||
class Client extends Entity { |
|||
/** @var string */ |
|||
protected $name; |
|||
/** @var string */ |
|||
protected $redirectUri; |
|||
/** @var string */ |
|||
protected $clientIdentifier; |
|||
/** @var string */ |
|||
protected $secret; |
|||
|
|||
public function __construct() { |
|||
$this->addType('id', 'int'); |
|||
$this->addType('name', 'string'); |
|||
$this->addType('redirect_uri', 'string'); |
|||
$this->addType('client_identifier', 'string'); |
|||
$this->addType('secret', 'string'); |
|||
} |
|||
} |
|||
@ -0,0 +1,89 @@ |
|||
<?php |
|||
/** |
|||
* @copyright Copyright (c) 2017 Lukas Reschke <lukas@statuscode.ch> |
|||
* |
|||
* @license GNU AGPL version 3 or any later version |
|||
* |
|||
* This program is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU Affero General Public License as |
|||
* published by the Free Software Foundation, either version 3 of the |
|||
* License, or (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU Affero General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU Affero General Public License |
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
|||
* |
|||
*/ |
|||
|
|||
namespace OCA\OAuth2\Db; |
|||
|
|||
use OCA\OAuth2\Exceptions\ClientNotFoundException; |
|||
use OCP\AppFramework\Db\Mapper; |
|||
use OCP\DB\QueryBuilder\IQueryBuilder; |
|||
use OCP\IDBConnection; |
|||
|
|||
class ClientMapper extends Mapper { |
|||
|
|||
/** |
|||
* @param IDBConnection $db |
|||
*/ |
|||
public function __construct(IDBConnection $db) { |
|||
parent::__construct($db, 'oauth2_clients'); |
|||
} |
|||
|
|||
/** |
|||
* @param string $clientIdentifier |
|||
* @return Client |
|||
* @throws ClientNotFoundException |
|||
*/ |
|||
public function getByIdentifier($clientIdentifier) { |
|||
$qb = $this->db->getQueryBuilder(); |
|||
$qb |
|||
->select('*') |
|||
->from($this->tableName) |
|||
->where($qb->expr()->eq('client_identifier', $qb->createNamedParameter($clientIdentifier))); |
|||
$result = $qb->execute(); |
|||
$row = $result->fetch(); |
|||
$result->closeCursor(); |
|||
if($row === false) { |
|||
throw new ClientNotFoundException(); |
|||
} |
|||
return Client::fromRow($row); |
|||
} |
|||
|
|||
/** |
|||
* @param string $uid internal uid of the client |
|||
* @return Client |
|||
* @throws ClientNotFoundException |
|||
*/ |
|||
public function getByUid($uid) { |
|||
$qb = $this->db->getQueryBuilder(); |
|||
$qb |
|||
->select('*') |
|||
->from($this->tableName) |
|||
->where($qb->expr()->eq('id', $qb->createNamedParameter($uid, IQueryBuilder::PARAM_INT))); |
|||
$result = $qb->execute(); |
|||
$row = $result->fetch(); |
|||
$result->closeCursor(); |
|||
if($row === false) { |
|||
throw new ClientNotFoundException(); |
|||
} |
|||
return Client::fromRow($row); |
|||
} |
|||
|
|||
/** |
|||
* @return Client[] |
|||
*/ |
|||
public function getClients() { |
|||
$qb = $this->db->getQueryBuilder(); |
|||
$qb |
|||
->select('*') |
|||
->from($this->tableName); |
|||
|
|||
return $this->findEntities($qb->getSQL()); |
|||
} |
|||
} |
|||
@ -0,0 +1,24 @@ |
|||
<?php |
|||
/** |
|||
* @copyright Copyright (c) 2017 Lukas Reschke <lukas@statuscode.ch> |
|||
* |
|||
* @license GNU AGPL version 3 or any later version |
|||
* |
|||
* This program is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU Affero General Public License as |
|||
* published by the Free Software Foundation, either version 3 of the |
|||
* License, or (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU Affero General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU Affero General Public License |
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
|||
* |
|||
*/ |
|||
|
|||
namespace OCA\OAuth2\Exceptions; |
|||
|
|||
class AccessTokenNotFoundException extends \Exception {} |
|||
@ -0,0 +1,24 @@ |
|||
<?php |
|||
/** |
|||
* @copyright Copyright (c) 2017 Lukas Reschke <lukas@statuscode.ch> |
|||
* |
|||
* @license GNU AGPL version 3 or any later version |
|||
* |
|||
* This program is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU Affero General Public License as |
|||
* published by the Free Software Foundation, either version 3 of the |
|||
* License, or (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU Affero General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU Affero General Public License |
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
|||
* |
|||
*/ |
|||
|
|||
namespace OCA\OAuth2\Exceptions; |
|||
|
|||
class ClientNotFoundException extends \Exception {} |
|||
@ -0,0 +1,66 @@ |
|||
<?php |
|||
/** |
|||
* @copyright Copyright (c) 2017 Lukas Reschke <lukas@statuscode.ch> |
|||
* |
|||
* @license GNU AGPL version 3 or any later version |
|||
* |
|||
* This program is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU Affero General Public License as |
|||
* published by the Free Software Foundation, either version 3 of the |
|||
* License, or (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU Affero General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU Affero General Public License |
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
|||
* |
|||
*/ |
|||
|
|||
namespace OCA\OAuth2\Settings; |
|||
|
|||
use OCA\OAuth2\Db\ClientMapper; |
|||
use OCP\AppFramework\Http\TemplateResponse; |
|||
use OCP\Settings\ISettings; |
|||
|
|||
class Admin implements ISettings { |
|||
/** @var ClientMapper */ |
|||
private $clientMapper; |
|||
|
|||
/** |
|||
* @param ClientMapper $clientMapper |
|||
*/ |
|||
public function __construct(ClientMapper $clientMapper) { |
|||
$this->clientMapper = $clientMapper; |
|||
} |
|||
|
|||
/** |
|||
* @return TemplateResponse |
|||
*/ |
|||
public function getForm() { |
|||
return new TemplateResponse( |
|||
'oauth2', |
|||
'admin', |
|||
[ |
|||
'clients' => $this->clientMapper->getClients(), |
|||
], |
|||
'' |
|||
); |
|||
} |
|||
|
|||
/** |
|||
* {@inheritdoc} |
|||
*/ |
|||
public function getSection() { |
|||
return 'security'; |
|||
} |
|||
|
|||
/** |
|||
* {@inheritdoc} |
|||
*/ |
|||
public function getPriority() { |
|||
return 0; |
|||
} |
|||
} |
|||
@ -0,0 +1,76 @@ |
|||
<?php |
|||
/** |
|||
* @copyright Copyright (c) 2017 Lukas Reschke <lukas@statuscode.ch> |
|||
* |
|||
* @license GNU AGPL version 3 or any later version |
|||
* |
|||
* This program is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU Affero General Public License as |
|||
* published by the Free Software Foundation, either version 3 of the |
|||
* License, or (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU Affero General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU Affero General Public License |
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
|||
* |
|||
*/ |
|||
|
|||
$urlGenerator = \OC::$server->getURLGenerator(); |
|||
$themingDefaults = \OC::$server->getThemingDefaults(); |
|||
|
|||
script('oauth2', 'setting-admin'); |
|||
style('oauth2', 'setting-admin'); |
|||
|
|||
/** @var array $_ */ |
|||
/** @var \OCA\OAuth2\Db\Client[] $clients */ |
|||
$clients = $_['clients']; |
|||
?>
|
|||
|
|||
<div id="oauth2" class="section"> |
|||
<h2><?php p($l->t('OAuth 2.0 clients')); ?></h2>
|
|||
<p class="settings-hint"><?php p($l->t('OAuth 2.0 allows external services to request access to your %s.', [$themingDefaults->getName()])); ?></p>
|
|||
|
|||
<table class="grid"> |
|||
<thead> |
|||
<tr> |
|||
<th id="headerName" scope="col"><?php p($l->t('Name')); ?></th>
|
|||
<th id="headerRedirectUri" scope="col"><?php p($l->t('Redirection URI')); ?></th>
|
|||
<th id="headerClientIdentifier" scope="col"><?php p($l->t('Client Identifier')); ?></th>
|
|||
<th id="headerSecret" scope="col"><?php p($l->t('Secret')); ?></th>
|
|||
<th id="headerRemove"> </th> |
|||
</tr> |
|||
</thead> |
|||
<tbody> |
|||
<?php |
|||
$imageUrl = $urlGenerator->imagePath('core', 'actions/toggle.svg'); |
|||
foreach ($clients as $client) { |
|||
?>
|
|||
<tr> |
|||
<td><?php p($client->getName()); ?></td>
|
|||
<td><?php p($client->getRedirectUri()); ?></td>
|
|||
<td><code><?php p($client->getClientIdentifier()); ?></code></td>
|
|||
<td data-value="<?php p($client->getSecret()); ?>"><code>****</code><img class='show-oauth-credentials' src="<?php p($imageUrl); ?>"/></td> |
|||
<td> |
|||
<form id="form-inline" class="delete" action="<?php p($urlGenerator->linkToRoute('oauth2.Settings.deleteClient', ['id' => $client->getId()])); ?>" method="POST"> |
|||
<input type="hidden" name="requesttoken" value="<?php p($_['requesttoken']) ?>" /> |
|||
<input type="submit" class="button icon-delete" value=""> |
|||
</form> |
|||
</td> |
|||
</tr> |
|||
<?php } ?>
|
|||
</tbody> |
|||
</table> |
|||
|
|||
<br/> |
|||
<h3><?php p($l->t('Add client')); ?></h3>
|
|||
<form action="<?php p($urlGenerator->linkToRoute('oauth2.Settings.addClient')); ?>" method="POST"> |
|||
<input type="text" id="name" name="name" placeholder="<?php p($l->t('Name')); ?>"> |
|||
<input type="url" id="redirectUri" name="redirectUri" placeholder="<?php p($l->t('Redirection URI')); ?>"> |
|||
<input type="hidden" name="requesttoken" value="<?php p($_['requesttoken']) ?>" /> |
|||
<input type="submit" class="button" value="<?php p($l->t('Add')); ?>"> |
|||
</form> |
|||
</div> |
|||
@ -0,0 +1,91 @@ |
|||
<?php |
|||
/** |
|||
* @copyright Copyright (c) 2017 Lukas Reschke <lukas@statuscode.ch> |
|||
* |
|||
* @license GNU AGPL version 3 or any later version |
|||
* |
|||
* This program is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU Affero General Public License as |
|||
* published by the Free Software Foundation, either version 3 of the |
|||
* License, or (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU Affero General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU Affero General Public License |
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
|||
* |
|||
*/ |
|||
|
|||
namespace OCA\OAuth2\Tests\Controller; |
|||
|
|||
use OCA\Files_Sharing\Tests\TestCase; |
|||
use OCA\OAuth2\Controller\LoginRedirectorController; |
|||
use OCA\OAuth2\Db\Client; |
|||
use OCA\OAuth2\Db\ClientMapper; |
|||
use OCP\AppFramework\Http\RedirectResponse; |
|||
use OCP\IRequest; |
|||
use OCP\ISession; |
|||
use OCP\IURLGenerator; |
|||
|
|||
/** |
|||
* @group DB |
|||
*/ |
|||
class LoginRedirectorControllerTest extends TestCase { |
|||
/** @var IRequest|\PHPUnit_Framework_MockObject_MockObject */ |
|||
private $request; |
|||
/** @var IURLGenerator|\PHPUnit_Framework_MockObject_MockObject */ |
|||
private $urlGenerator; |
|||
/** @var ClientMapper|\PHPUnit_Framework_MockObject_MockObject */ |
|||
private $clientMapper; |
|||
/** @var ISession|\PHPUnit_Framework_MockObject_MockObject */ |
|||
private $session; |
|||
/** @var LoginRedirectorController */ |
|||
private $loginRedirectorController; |
|||
|
|||
public function setUp() { |
|||
parent::setUp(); |
|||
|
|||
$this->request = $this->createMock(IRequest::class); |
|||
$this->urlGenerator = $this->createMock(IURLGenerator::class); |
|||
$this->clientMapper = $this->createMock(ClientMapper::class); |
|||
$this->session = $this->createMock(ISession::class); |
|||
|
|||
$this->loginRedirectorController = new LoginRedirectorController( |
|||
'oauth2', |
|||
$this->request, |
|||
$this->urlGenerator, |
|||
$this->clientMapper, |
|||
$this->session |
|||
); |
|||
} |
|||
|
|||
public function testAuthorize() { |
|||
$client = new Client(); |
|||
$client->setClientIdentifier('MyClientIdentifier'); |
|||
$this->clientMapper |
|||
->expects($this->once()) |
|||
->method('getByIdentifier') |
|||
->with('MyClientId') |
|||
->willReturn($client); |
|||
$this->session |
|||
->expects($this->once()) |
|||
->method('set') |
|||
->with('oauth.state', 'MyState'); |
|||
$this->urlGenerator |
|||
->expects($this->once()) |
|||
->method('linkToRouteAbsolute') |
|||
->with( |
|||
'core.ClientFlowLogin.showAuthPickerPage', |
|||
[ |
|||
'clientIdentifier' => 'MyClientIdentifier', |
|||
] |
|||
) |
|||
->willReturn('https://example.com/?clientIdentifier=foo'); |
|||
|
|||
$expected = new RedirectResponse('https://example.com/?clientIdentifier=foo'); |
|||
$this->assertEquals($expected, $this->loginRedirectorController->authorize('MyClientId', 'MyState')); |
|||
} |
|||
} |
|||
@ -0,0 +1,106 @@ |
|||
<?php |
|||
/** |
|||
* @copyright Copyright (c) 2017 Lukas Reschke <lukas@statuscode.ch> |
|||
* |
|||
* @license GNU AGPL version 3 or any later version |
|||
* |
|||
* This program is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU Affero General Public License as |
|||
* published by the Free Software Foundation, either version 3 of the |
|||
* License, or (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU Affero General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU Affero General Public License |
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
|||
* |
|||
*/ |
|||
|
|||
namespace OCA\OAuth2\Tests\Controller; |
|||
|
|||
use OC\Authentication\Token\DefaultToken; |
|||
use OC\Authentication\Token\DefaultTokenMapper; |
|||
use OCA\OAuth2\Controller\OauthApiController; |
|||
use OCA\OAuth2\Db\AccessToken; |
|||
use OCA\OAuth2\Db\AccessTokenMapper; |
|||
use OCP\AppFramework\Http\JSONResponse; |
|||
use OCP\IRequest; |
|||
use OCP\Security\ICrypto; |
|||
use OCP\Security\ISecureRandom; |
|||
use Test\TestCase; |
|||
|
|||
class OauthApiControllerTest extends TestCase { |
|||
/** @var IRequest|\PHPUnit_Framework_MockObject_MockObject */ |
|||
private $request; |
|||
/** @var ICrypto|\PHPUnit_Framework_MockObject_MockObject */ |
|||
private $crypto; |
|||
/** @var AccessTokenMapper|\PHPUnit_Framework_MockObject_MockObject */ |
|||
private $accessTokenMapper; |
|||
/** @var DefaultTokenMapper|\PHPUnit_Framework_MockObject_MockObject */ |
|||
private $defaultTokenMapper; |
|||
/** @var ISecureRandom|\PHPUnit_Framework_MockObject_MockObject */ |
|||
private $secureRandom; |
|||
/** @var OauthApiController */ |
|||
private $oauthApiController; |
|||
|
|||
public function setUp() { |
|||
parent::setUp(); |
|||
|
|||
$this->request = $this->createMock(IRequest::class); |
|||
$this->crypto = $this->createMock(ICrypto::class); |
|||
$this->accessTokenMapper = $this->createMock(AccessTokenMapper::class); |
|||
$this->defaultTokenMapper = $this->createMock(DefaultTokenMapper::class); |
|||
$this->secureRandom = $this->createMock(ISecureRandom::class); |
|||
|
|||
$this->oauthApiController = new OauthApiController( |
|||
'oauth2', |
|||
$this->request, |
|||
$this->crypto, |
|||
$this->accessTokenMapper, |
|||
$this->defaultTokenMapper, |
|||
$this->secureRandom |
|||
); |
|||
} |
|||
|
|||
public function testGetToken() { |
|||
$accessToken = new AccessToken(); |
|||
$accessToken->setEncryptedToken('MyEncryptedToken'); |
|||
$accessToken->setTokenId(123); |
|||
$this->accessTokenMapper |
|||
->expects($this->once()) |
|||
->method('getByCode') |
|||
->willReturn($accessToken); |
|||
$this->crypto |
|||
->expects($this->once()) |
|||
->method('decrypt') |
|||
->with('MyEncryptedToken', 'MySecretCode') |
|||
->willReturn('MyDecryptedToken'); |
|||
$this->secureRandom |
|||
->expects($this->once()) |
|||
->method('generate') |
|||
->with(128) |
|||
->willReturn('NewToken'); |
|||
$token = new DefaultToken(); |
|||
$token->setUid('JohnDoe'); |
|||
$this->defaultTokenMapper |
|||
->expects($this->once()) |
|||
->method('getTokenById') |
|||
->with(123) |
|||
->willReturn($token); |
|||
|
|||
$expected = new JSONResponse( |
|||
[ |
|||
'access_token' => 'MyDecryptedToken', |
|||
'token_type' => 'Bearer', |
|||
'expires_in' => 3600, |
|||
'refresh_token' => 'NewToken', |
|||
'user_id' => 'JohnDoe', |
|||
] |
|||
); |
|||
$this->assertEquals($expected, $this->oauthApiController->getToken('MySecretCode')); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,139 @@ |
|||
<?php |
|||
/** |
|||
* @copyright Copyright (c) 2017 Lukas Reschke <lukas@statuscode.ch> |
|||
* |
|||
* @license GNU AGPL version 3 or any later version |
|||
* |
|||
* This program is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU Affero General Public License as |
|||
* published by the Free Software Foundation, either version 3 of the |
|||
* License, or (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU Affero General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU Affero General Public License |
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
|||
* |
|||
*/ |
|||
|
|||
namespace OCA\OAuth2\Tests\Controller; |
|||
|
|||
use OC\Authentication\Token\DefaultTokenMapper; |
|||
use OCA\OAuth2\Controller\SettingsController; |
|||
use OCA\OAuth2\Db\AccessTokenMapper; |
|||
use OCA\OAuth2\Db\Client; |
|||
use OCA\OAuth2\Db\ClientMapper; |
|||
use OCP\AppFramework\Http\RedirectResponse; |
|||
use OCP\IRequest; |
|||
use OCP\IURLGenerator; |
|||
use OCP\Security\ISecureRandom; |
|||
use Test\TestCase; |
|||
|
|||
class SettingsControllerTest extends TestCase { |
|||
/** @var IRequest|\PHPUnit_Framework_MockObject_MockObject */ |
|||
private $request; |
|||
/** @var IURLGenerator|\PHPUnit_Framework_MockObject_MockObject */ |
|||
private $urlGenerator; |
|||
/** @var ClientMapper|\PHPUnit_Framework_MockObject_MockObject */ |
|||
private $clientMapper; |
|||
/** @var ISecureRandom|\PHPUnit_Framework_MockObject_MockObject */ |
|||
private $secureRandom; |
|||
/** @var AccessTokenMapper|\PHPUnit_Framework_MockObject_MockObject */ |
|||
private $accessTokenMapper; |
|||
/** @var DefaultTokenMapper|\PHPUnit_Framework_MockObject_MockObject */ |
|||
private $defaultTokenMapper; |
|||
/** @var SettingsController */ |
|||
private $settingsController; |
|||
|
|||
public function setUp() { |
|||
parent::setUp(); |
|||
|
|||
$this->request = $this->createMock(IRequest::class); |
|||
$this->urlGenerator = $this->createMock(IURLGenerator::class); |
|||
$this->clientMapper = $this->createMock(ClientMapper::class); |
|||
$this->secureRandom = $this->createMock(ISecureRandom::class); |
|||
$this->accessTokenMapper = $this->createMock(AccessTokenMapper::class); |
|||
$this->defaultTokenMapper = $this->createMock(DefaultTokenMapper::class); |
|||
|
|||
$this->settingsController = new SettingsController( |
|||
'oauth2', |
|||
$this->request, |
|||
$this->urlGenerator, |
|||
$this->clientMapper, |
|||
$this->secureRandom, |
|||
$this->accessTokenMapper, |
|||
$this->defaultTokenMapper |
|||
); |
|||
} |
|||
|
|||
public function testAddClient() { |
|||
$this->secureRandom |
|||
->expects($this->at(0)) |
|||
->method('generate') |
|||
->with(64, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789') |
|||
->willReturn('MySecret'); |
|||
$this->secureRandom |
|||
->expects($this->at(1)) |
|||
->method('generate') |
|||
->with(64, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789') |
|||
->willReturn('MyClientIdentifier'); |
|||
|
|||
$client = new Client(); |
|||
$client->setName('My Client Name'); |
|||
$client->setRedirectUri('https://example.com/'); |
|||
$client->setSecret('MySecret'); |
|||
$client->setClientIdentifier('MyClientIdentifier'); |
|||
|
|||
$this->clientMapper |
|||
->expects($this->once()) |
|||
->method('insert') |
|||
->with($client); |
|||
|
|||
$this->urlGenerator |
|||
->expects($this->once()) |
|||
->method('getAbsoluteURL') |
|||
->with('/index.php/settings/admin/security') |
|||
->willReturn('https://example.com/index.php/settings/admin/security'); |
|||
|
|||
$expected = new RedirectResponse('https://example.com/index.php/settings/admin/security'); |
|||
$this->assertEquals($expected, $this->settingsController->addClient('My Client Name', 'https://example.com/')); |
|||
} |
|||
|
|||
public function testDeleteClient() { |
|||
$client = new Client(); |
|||
$client->setName('My Client Name'); |
|||
$client->setRedirectUri('https://example.com/'); |
|||
$client->setSecret('MySecret'); |
|||
$client->setClientIdentifier('MyClientIdentifier'); |
|||
|
|||
$this->clientMapper |
|||
->expects($this->at(0)) |
|||
->method('getByUid') |
|||
->with(123) |
|||
->willReturn($client); |
|||
$this->accessTokenMapper |
|||
->expects($this->once()) |
|||
->method('deleteByClientId') |
|||
->with(123); |
|||
$this->defaultTokenMapper |
|||
->expects($this->once()) |
|||
->method('deleteByName') |
|||
->with('My Client Name'); |
|||
$this->clientMapper |
|||
->expects($this->at(1)) |
|||
->method('delete') |
|||
->with($client); |
|||
|
|||
$this->urlGenerator |
|||
->expects($this->once()) |
|||
->method('getAbsoluteURL') |
|||
->with('/index.php/settings/admin/security') |
|||
->willReturn('https://example.com/index.php/settings/admin/security'); |
|||
|
|||
$expected = new RedirectResponse('https://example.com/index.php/settings/admin/security'); |
|||
$this->assertEquals($expected, $this->settingsController->deleteClient(123)); |
|||
} |
|||
} |
|||
@ -0,0 +1,70 @@ |
|||
<?php |
|||
/** |
|||
* @copyright Copyright (c) 2017 Lukas Reschke <lukas@statuscode.ch> |
|||
* |
|||
* @license GNU AGPL version 3 or any later version |
|||
* |
|||
* This program is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU Affero General Public License as |
|||
* published by the Free Software Foundation, either version 3 of the |
|||
* License, or (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU Affero General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU Affero General Public License |
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
|||
* |
|||
*/ |
|||
|
|||
namespace OCA\OAuth2\Tests\Db; |
|||
|
|||
use OCA\OAuth2\Db\AccessToken; |
|||
use OCA\OAuth2\Db\AccessTokenMapper; |
|||
use Test\TestCase; |
|||
|
|||
/** |
|||
* @group DB |
|||
*/ |
|||
class AccessTokenMapperTest extends TestCase { |
|||
/** @var AccessTokenMapper */ |
|||
private $accessTokenMapper; |
|||
|
|||
public function setUp() { |
|||
parent::setUp(); |
|||
$this->accessTokenMapper = new AccessTokenMapper(\OC::$server->getDatabaseConnection()); |
|||
} |
|||
|
|||
public function testGetByCode() { |
|||
$this->accessTokenMapper->deleteByClientId(1234); |
|||
$token = new AccessToken(); |
|||
$token->setClientId(1234); |
|||
$token->setTokenId((string)time()); |
|||
$token->setEncryptedToken('MyEncryptedToken'); |
|||
$token->setHashedCode(hash('sha512', 'MyAwesomeToken')); |
|||
$this->accessTokenMapper->insert($token); |
|||
$token->resetUpdatedFields(); |
|||
|
|||
$result = $this->accessTokenMapper->getByCode('MyAwesomeToken'); |
|||
$this->assertEquals($token, $result); |
|||
$this->accessTokenMapper->delete($token); |
|||
} |
|||
|
|||
/** |
|||
* @expectedException \OCA\OAuth2\Exceptions\AccessTokenNotFoundException |
|||
*/ |
|||
public function testDeleteByClientId() { |
|||
$this->accessTokenMapper->deleteByClientId(1234); |
|||
$token = new AccessToken(); |
|||
$token->setClientId(1234); |
|||
$token->setTokenId((string)time()); |
|||
$token->setEncryptedToken('MyEncryptedToken'); |
|||
$token->setHashedCode(hash('sha512', 'MyAwesomeToken')); |
|||
$this->accessTokenMapper->insert($token); |
|||
$token->resetUpdatedFields(); |
|||
$this->accessTokenMapper->deleteByClientId(1234); |
|||
$this->accessTokenMapper->getByCode('MyAwesomeToken'); |
|||
} |
|||
} |
|||
@ -0,0 +1,79 @@ |
|||
<?php |
|||
/** |
|||
* @copyright Copyright (c) 2017 Lukas Reschke <lukas@statuscode.ch> |
|||
* |
|||
* @license GNU AGPL version 3 or any later version |
|||
* |
|||
* This program is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU Affero General Public License as |
|||
* published by the Free Software Foundation, either version 3 of the |
|||
* License, or (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU Affero General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU Affero General Public License |
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
|||
* |
|||
*/ |
|||
|
|||
namespace OCA\OAuth2\Tests\Db; |
|||
|
|||
use OCA\OAuth2\Db\Client; |
|||
use OCA\OAuth2\Db\ClientMapper; |
|||
use Test\TestCase; |
|||
|
|||
/** |
|||
* @group DB |
|||
*/ |
|||
class ClientMapperTest extends TestCase { |
|||
/** @var ClientMapper */ |
|||
private $clientMapper; |
|||
|
|||
public function setUp() { |
|||
parent::setUp(); |
|||
$this->clientMapper = new ClientMapper(\OC::$server->getDatabaseConnection()); |
|||
} |
|||
|
|||
public function testGetByIdentifier() { |
|||
$client = new Client(); |
|||
$client->setClientIdentifier('MyAwesomeClientIdentifier'); |
|||
$client->setName('Client Name'); |
|||
$client->setRedirectUri('https://example.com/'); |
|||
$client->setSecret('TotallyNotSecret'); |
|||
$this->clientMapper->insert($client); |
|||
$client->resetUpdatedFields(); |
|||
$this->assertEquals($client, $this->clientMapper->getByIdentifier('MyAwesomeClientIdentifier')); |
|||
} |
|||
|
|||
/** |
|||
* @expectedException \OCA\OAuth2\Exceptions\ClientNotFoundException |
|||
*/ |
|||
public function testGetByIdentifierNotExisting() { |
|||
$this->clientMapper->getByIdentifier('MyTotallyNotExistingClient'); |
|||
} |
|||
|
|||
public function testGetByUid() { |
|||
$client = new Client(); |
|||
$client->setClientIdentifier('MyNewClient'); |
|||
$client->setName('Client Name'); |
|||
$client->setRedirectUri('https://example.com/'); |
|||
$client->setSecret('TotallyNotSecret'); |
|||
$this->clientMapper->insert($client); |
|||
$client->resetUpdatedFields(); |
|||
$this->assertEquals($client, $this->clientMapper->getByUid($client->getId())); |
|||
} |
|||
|
|||
/** |
|||
* @expectedException \OCA\OAuth2\Exceptions\ClientNotFoundException |
|||
*/ |
|||
public function testGetByUidNotExisting() { |
|||
$this->clientMapper->getByUid(1234); |
|||
} |
|||
|
|||
public function testGetClients() { |
|||
$this->assertSame('array', gettype($this->clientMapper->getClients())); |
|||
} |
|||
} |
|||
@ -0,0 +1,66 @@ |
|||
<?php |
|||
/** |
|||
* @copyright Copyright (c) 2017 Lukas Reschke <lukas@statuscode.ch> |
|||
* |
|||
* @license GNU AGPL version 3 or any later version |
|||
* |
|||
* This program is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU Affero General Public License as |
|||
* published by the Free Software Foundation, either version 3 of the |
|||
* License, or (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU Affero General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU Affero General Public License |
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
|||
* |
|||
*/ |
|||
|
|||
namespace OCA\OAuth2\Tests\Settings; |
|||
|
|||
use OCA\OAuth2\Db\ClientMapper; |
|||
use OCA\OAuth2\Settings\Admin; |
|||
use OCP\AppFramework\Http\TemplateResponse; |
|||
use Test\TestCase; |
|||
|
|||
class AdminTest extends TestCase { |
|||
/** @var ClientMapper|\PHPUnit_Framework_MockObject_MockObject */ |
|||
private $clientMapper; |
|||
/** @var Admin|\PHPUnit_Framework_MockObject_MockObject */ |
|||
private $admin; |
|||
|
|||
public function setUp() { |
|||
parent::setUp(); |
|||
|
|||
$this->clientMapper = $this->createMock(ClientMapper::class); |
|||
$this->admin = new Admin($this->clientMapper); |
|||
} |
|||
|
|||
public function testGetForm() { |
|||
$this->clientMapper |
|||
->expects($this->once()) |
|||
->method('getClients') |
|||
->willReturn(['MyClients']); |
|||
|
|||
$expected = new TemplateResponse( |
|||
'oauth2', |
|||
'admin', |
|||
[ |
|||
'clients' => ['MyClients'], |
|||
], |
|||
'' |
|||
); |
|||
$this->assertEquals($expected, $this->admin->getForm()); |
|||
} |
|||
|
|||
public function testGetSection() { |
|||
$this->assertSame('security', $this->admin->getSection()); |
|||
} |
|||
|
|||
public function testGetPriority() { |
|||
$this->assertSame(0, $this->admin->getPriority()); |
|||
} |
|||
} |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue