add support for v3 swift auth

Signed-off-by: Robin Appelman <robin@icewind.nl>
This commit is contained in:
Robin Appelman 2018-02-14 15:08:52 +01:00
parent 4d380d21b5
commit 31dd6d6aae
No known key found for this signature in database
GPG Key ID: 42B69D8A64526EFB
6 changed files with 94 additions and 15 deletions

View File

@ -36,7 +36,8 @@ use \OCA\Files_External\Lib\Config\IBackendProvider;
use \OCA\Files_External\Lib\Config\IAuthMechanismProvider; use \OCA\Files_External\Lib\Config\IAuthMechanismProvider;
use OCA\Files_External\Lib\Auth\AmazonS3\AccessKey; use OCA\Files_External\Lib\Auth\AmazonS3\AccessKey;
use OCA\Files_External\Lib\Auth\OpenStack\Rackspace; use OCA\Files_External\Lib\Auth\OpenStack\Rackspace;
use OCA\Files_External\Lib\Auth\OpenStack\OpenStack; use OCA\Files_External\Lib\Auth\OpenStack\OpenStackV2;
use OCA\Files_External\Lib\Auth\OpenStack\OpenStackV3;
use OCA\Files_External\Lib\Auth\PublicKey\RSA; use OCA\Files_External\Lib\Auth\PublicKey\RSA;
use OCA\Files_External\Lib\Auth\OAuth2\OAuth2; use OCA\Files_External\Lib\Auth\OAuth2\OAuth2;
use OCA\Files_External\Lib\Auth\OAuth1\OAuth1; use OCA\Files_External\Lib\Auth\OAuth1\OAuth1;
@ -139,7 +140,8 @@ class Application extends App implements IBackendProvider, IAuthMechanismProvide
$container->query(RSA::class), $container->query(RSA::class),
// AuthMechanism::SCHEME_OPENSTACK mechanisms // AuthMechanism::SCHEME_OPENSTACK mechanisms
$container->query(OpenStack::class), $container->query(OpenStackV2::class),
$container->query(OpenStackV3::class),
$container->query(Rackspace::class), $container->query(Rackspace::class),
// Specialized mechanisms // Specialized mechanisms

View File

@ -29,13 +29,13 @@ use \OCA\Files_External\Lib\Auth\AuthMechanism;
/** /**
* OpenStack Keystone authentication * OpenStack Keystone authentication
*/ */
class OpenStack extends AuthMechanism { class OpenStackV2 extends AuthMechanism {
public function __construct(IL10N $l) { public function __construct(IL10N $l) {
$this $this
->setIdentifier('openstack::openstack') ->setIdentifier('openstack::openstack')
->setScheme(self::SCHEME_OPENSTACK) ->setScheme(self::SCHEME_OPENSTACK)
->setText($l->t('OpenStack')) ->setText($l->t('OpenStack v2'))
->addParameters([ ->addParameters([
new DefinitionParameter('user', $l->t('Username')), new DefinitionParameter('user', $l->t('Username')),
(new DefinitionParameter('password', $l->t('Password'))) (new DefinitionParameter('password', $l->t('Password')))

View File

@ -0,0 +1,48 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2018 Robin Appelman <robin@icewind.nl>
*
* @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\Files_External\Lib\Auth\OpenStack;
use \OCP\IL10N;
use \OCA\Files_External\Lib\DefinitionParameter;
use \OCA\Files_External\Lib\Auth\AuthMechanism;
/**
* OpenStack Keystone authentication
*/
class OpenStackV3 extends AuthMechanism {
public function __construct(IL10N $l) {
$this
->setIdentifier('openstack::openstackv3')
->setScheme(self::SCHEME_OPENSTACK)
->setText($l->t('OpenStack v3'))
->addParameters([
new DefinitionParameter('userid', $l->t('User Id')),
(new DefinitionParameter('password', $l->t('Password')))
->setType(DefinitionParameter::VALUE_PASSWORD),
new DefinitionParameter('url', $l->t('Identity endpoint URL'))
])
;
}
}

View File

@ -25,7 +25,8 @@ namespace OCA\Files_External\Lib\Backend;
use \OCP\IL10N; use \OCP\IL10N;
use \OCA\Files_External\Lib\DefinitionParameter; use \OCA\Files_External\Lib\DefinitionParameter;
use \OCA\Files_External\Lib\Auth\AuthMechanism; use \OCA\Files_External\Lib\Auth\AuthMechanism;
use \OCA\Files_External\Lib\Auth\OpenStack\OpenStack; use \OCA\Files_External\Service\BackendService;
use \OCA\Files_External\Lib\Auth\OpenStack\OpenStackV2;
use \OCA\Files_External\Lib\Auth\OpenStack\Rackspace; use \OCA\Files_External\Lib\Auth\OpenStack\Rackspace;
use \OCA\Files_External\Lib\LegacyDependencyCheckPolyfill; use \OCA\Files_External\Lib\LegacyDependencyCheckPolyfill;
@ -33,7 +34,7 @@ class Swift extends Backend {
use LegacyDependencyCheckPolyfill; use LegacyDependencyCheckPolyfill;
public function __construct(IL10N $l, OpenStack $openstackAuth, Rackspace $rackspaceAuth) { public function __construct(IL10N $l, OpenStackV2 $openstackAuth, Rackspace $rackspaceAuth) {
$this $this
->setIdentifier('swift') ->setIdentifier('swift')
->addIdentifierAlias('\OC\Files\Storage\Swift') // legacy compat ->addIdentifierAlias('\OC\Files\Storage\Swift') // legacy compat

View File

@ -156,13 +156,14 @@ class Swift extends \OC\Files\Storage\Common {
public function __construct($params) { public function __construct($params) {
if ((empty($params['key']) and empty($params['password'])) if ((empty($params['key']) and empty($params['password']))
or empty($params['user']) or empty($params['bucket']) or (empty($params['user']) && empty($params['userid'])) or empty($params['bucket'])
or empty($params['region']) or empty($params['region'])
) { ) {
throw new StorageBadConfigException("API Key or password, Username, Bucket and Region have to be configured."); throw new StorageBadConfigException("API Key or password, Username, Bucket and Region have to be configured.");
} }
$this->id = 'swift::' . $params['user'] . md5($params['bucket']); $user = isset($params['user']) ? $params['user'] : $params['userid'];
$this->id = 'swift::' . $user . md5($params['bucket']);
$bucketUrl = new Uri($params['bucket']); $bucketUrl = new Uri($params['bucket']);
if ($bucketUrl->getHost()) { if ($bucketUrl->getHost()) {
@ -180,6 +181,13 @@ class Swift extends \OC\Files\Storage\Common {
$params['autocreate'] = true; $params['autocreate'] = true;
if (isset($params['userid'])) {
$params['user'] = [
'id' => $params['userid'],
'password' => $params['password']
];
}
$this->params = $params; $this->params = $params;
// FIXME: private class... // FIXME: private class...
$this->objectCache = new \OC\Cache\CappedMemoryCache(); $this->objectCache = new \OC\Cache\CappedMemoryCache();

View File

@ -31,8 +31,9 @@ use OCP\Files\StorageAuthException;
use OCP\Files\StorageNotAvailableException; use OCP\Files\StorageNotAvailableException;
use OCP\ICache; use OCP\ICache;
use OpenStack\Common\Error\BadResponseError; use OpenStack\Common\Error\BadResponseError;
use OpenStack\Identity\v2\Models\Token; use OpenStack\Common\Auth\Token;
use OpenStack\Identity\v2\Service; use OpenStack\Identity\v2\Service as IdentityV2Service;
use OpenStack\Identity\v3\Service as IdentityV3Service;
use OpenStack\OpenStack; use OpenStack\OpenStack;
use OpenStack\Common\Transport\Utils as TransportUtils; use OpenStack\Common\Transport\Utils as TransportUtils;
use Psr\Http\Message\RequestInterface; use Psr\Http\Message\RequestInterface;
@ -77,30 +78,49 @@ class SwiftFactory {
// should only be true for tests // should only be true for tests
$this->params['autocreate'] = false; $this->params['autocreate'] = false;
} }
if (!isset($this->params['username']) && isset($this->params['user'])) { if (isset($this->params['user']) && is_array($this->params['user'])) {
$this->params['username'] = $this->params['user']; $userName = $this->params['user']['id'];
} else {
if (!isset($this->params['username']) && isset($this->params['user'])) {
$this->params['username'] = $this->params['user'];
}
$userName = $this->params['username'];
} }
if (!isset($this->params['tenantName']) && isset($this->params['tenant'])) { if (!isset($this->params['tenantName']) && isset($this->params['tenant'])) {
$this->params['tenantName'] = $this->params['tenant']; $this->params['tenantName'] = $this->params['tenant'];
} }
$cacheKey = $this->params['username'] . '@' . $this->params['url'] . '/' . $this->params['bucket']; $cacheKey = $userName . '@' . $this->params['url'] . '/' . $this->params['bucket'];
$token = $this->getCachedToken($cacheKey); $token = $this->getCachedToken($cacheKey);
$hasToken = is_array($token) && (new \DateTimeImmutable($token['expires_at'])) > (new \DateTimeImmutable('now')); $hasToken = is_array($token) && (new \DateTimeImmutable($token['expires_at'])) > (new \DateTimeImmutable('now'));
if ($hasToken) { if ($hasToken) {
$this->params['cachedToken'] = $token; $this->params['cachedToken'] = $token;
} }
$httpClient = new Client([ $httpClient = new Client([
'base_uri' => TransportUtils::normalizeUrl($this->params['url']), 'base_uri' => TransportUtils::normalizeUrl($this->params['url']),
'handler' => HandlerStack::create() 'handler' => HandlerStack::create()
]); ]);
$authService = Service::factory($httpClient); if (isset($this->params['user']) && isset($this->params['user']['id'])) {
return $this->auth(IdentityV3Service::factory($httpClient), $cacheKey);
} else {
return $this->auth(IdentityV2Service::factory($httpClient), $cacheKey);
}
}
/**
* @param IdentityV2Service|IdentityV3Service $authService
* @param string $cacheKey
* @return OpenStack
* @throws StorageAuthException
*/
private function auth($authService, string $cacheKey) {
$this->params['identityService'] = $authService; $this->params['identityService'] = $authService;
$this->params['authUrl'] = $this->params['url']; $this->params['authUrl'] = $this->params['url'];
$client = new OpenStack($this->params); $client = new OpenStack($this->params);
if (!$hasToken) { if (!isset($this->params['cachedToken'])) {
try { try {
$token = $authService->generateToken($this->params); $token = $authService->generateToken($this->params);
$this->cacheToken($token, $cacheKey); $this->cacheToken($token, $cacheKey);