Authentication allow now token and keystone together (#26)
This commit is contained in:
parent
3a458da2cb
commit
1728025721
@ -15,6 +15,7 @@
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
from almanach import config
|
from almanach import config
|
||||||
|
from almanach.auth.mixed_auth import MixedAuthentication
|
||||||
from almanach.auth.keystone_auth import KeystoneAuthentication, KeystoneTokenManagerFactory
|
from almanach.auth.keystone_auth import KeystoneAuthentication, KeystoneTokenManagerFactory
|
||||||
from almanach.auth.private_key_auth import PrivateKeyAuthentication
|
from almanach.auth.private_key_auth import PrivateKeyAuthentication
|
||||||
|
|
||||||
@ -31,6 +32,16 @@ class AuthenticationAdapter(object):
|
|||||||
auth_url=config.keystone_url(),
|
auth_url=config.keystone_url(),
|
||||||
tenant_name=config.keystone_tenant_name()
|
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:
|
else:
|
||||||
logging.info("Loading PrivateKey authentication backend")
|
logging.info("Loading PrivateKey authentication backend")
|
||||||
return PrivateKeyAuthentication(config.auth_private_key())
|
return PrivateKeyAuthentication(config.auth_private_key())
|
||||||
|
32
almanach/auth/mixed_auth.py
Normal file
32
almanach/auth/mixed_auth.py
Normal 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')
|
@ -20,11 +20,11 @@ from hamcrest import instance_of, assert_that
|
|||||||
from almanach import config
|
from almanach import config
|
||||||
from almanach.adapters.auth_adapter import AuthenticationAdapter
|
from almanach.adapters.auth_adapter import AuthenticationAdapter
|
||||||
from almanach.auth.keystone_auth import KeystoneAuthentication
|
from almanach.auth.keystone_auth import KeystoneAuthentication
|
||||||
|
from almanach.auth.mixed_auth import MixedAuthentication
|
||||||
from almanach.auth.private_key_auth import PrivateKeyAuthentication
|
from almanach.auth.private_key_auth import PrivateKeyAuthentication
|
||||||
|
|
||||||
|
|
||||||
class AuthenticationAdapterTest(unittest.TestCase):
|
class AuthenticationAdapterTest(unittest.TestCase):
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
flexmock_teardown()
|
flexmock_teardown()
|
||||||
|
|
||||||
@ -36,3 +36,8 @@ class AuthenticationAdapterTest(unittest.TestCase):
|
|||||||
flexmock(config).should_receive("auth_strategy").and_return("keystone")
|
flexmock(config).should_receive("auth_strategy").and_return("keystone")
|
||||||
adapter = AuthenticationAdapter().factory()
|
adapter = AuthenticationAdapter().factory()
|
||||||
assert_that(adapter, instance_of(KeystoneAuthentication))
|
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))
|
||||||
|
48
tests/auth/test_mixed_auth.py
Normal file
48
tests/auth/test_mixed_auth.py
Normal 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))
|
Loading…
x
Reference in New Issue
Block a user