Authentication allow now token and keystone together (#26)

This commit is contained in:
Marx314 2016-07-14 13:05:23 -04:00 committed by Sebastien Delisle
parent 3a458da2cb
commit 1728025721
4 changed files with 97 additions and 1 deletions

View File

@ -15,6 +15,7 @@
import logging
from almanach import config
from almanach.auth.mixed_auth import MixedAuthentication
from almanach.auth.keystone_auth import KeystoneAuthentication, KeystoneTokenManagerFactory
from almanach.auth.private_key_auth import PrivateKeyAuthentication
@ -31,6 +32,16 @@ class AuthenticationAdapter(object):
auth_url=config.keystone_url(),
tenant_name=config.keystone_tenant_name()
))
elif all(auth_method in config.auth_strategy() for auth_method in ['token', 'keystone']):
logging.info("Loading Keystone authentication backend")
auths = [PrivateKeyAuthentication(config.auth_private_key()),
KeystoneAuthentication(KeystoneTokenManagerFactory(
username=config.keystone_username(),
password=config.keystone_password(),
auth_url=config.keystone_url(),
tenant_name=config.keystone_tenant_name()
))]
return MixedAuthentication(auths)
else:
logging.info("Loading PrivateKey authentication backend")
return PrivateKeyAuthentication(config.auth_private_key())

View File

@ -0,0 +1,32 @@
# Copyright 2016 Internap.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import logging
from almanach.auth.base_auth import BaseAuth
from almanach.common.exceptions.authentication_failure_exception import AuthenticationFailureException
class MixedAuthentication(BaseAuth):
def __init__(self, authentication_methods):
self.authentication_methods = authentication_methods
def validate(self, token):
for method in self.authentication_methods:
try:
valid = method.validate(token)
if valid:
logging.debug('Validated token with auth {0}'.format(method.__class__))
return True
except AuthenticationFailureException:
logging.debug('Failed to validate with auth {0}'.format(method.__class__))
raise AuthenticationFailureException('No valid auth method matching token')

View File

@ -20,11 +20,11 @@ from hamcrest import instance_of, assert_that
from almanach import config
from almanach.adapters.auth_adapter import AuthenticationAdapter
from almanach.auth.keystone_auth import KeystoneAuthentication
from almanach.auth.mixed_auth import MixedAuthentication
from almanach.auth.private_key_auth import PrivateKeyAuthentication
class AuthenticationAdapterTest(unittest.TestCase):
def tearDown(self):
flexmock_teardown()
@ -36,3 +36,8 @@ class AuthenticationAdapterTest(unittest.TestCase):
flexmock(config).should_receive("auth_strategy").and_return("keystone")
adapter = AuthenticationAdapter().factory()
assert_that(adapter, instance_of(KeystoneAuthentication))
def test_get_mixed_auth_backend(self):
flexmock(config).should_receive("auth_strategy").and_return("token,keystone")
adapter = AuthenticationAdapter().factory()
assert_that(adapter, instance_of(MixedAuthentication))

View File

@ -0,0 +1,48 @@
# Copyright 2016 Internap.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import unittest
from flexmock import flexmock, flexmock_teardown
from hamcrest import raises, assert_that, calling, equal_to
from almanach.auth.mixed_auth import MixedAuthentication
from almanach.common.exceptions.authentication_failure_exception import AuthenticationFailureException
class MixedAuthenticationTest(unittest.TestCase):
def setUp(self):
self.auth_one = flexmock()
self.auth_two = flexmock()
self.auth_backend = MixedAuthentication([self.auth_one, self.auth_two])
def tearDown(self):
flexmock_teardown()
def test_with_token_valid_with_auth_one(self):
token = "my token"
self.auth_one.should_receive("validate").and_return(True)
assert_that(self.auth_backend.validate(token), equal_to(True))
def test_with_token_valid_with_auth_two(self):
token = "my token"
self.auth_one.should_receive("validate").and_raise(AuthenticationFailureException)
self.auth_two.should_receive("validate").and_return(True)
assert_that(self.auth_backend.validate(token), equal_to(True))
def test_with_token_valid_with_auth_twos(self):
token = "bad token"
self.auth_one.should_receive("validate").and_raise(AuthenticationFailureException)
self.auth_two.should_receive("validate").and_raise(AuthenticationFailureException)
assert_that(calling(self.auth_backend.validate).with_args(token), raises(AuthenticationFailureException))