Merge "Validate identity providers during token validation"

This commit is contained in:
Zuul 2018-02-07 03:46:56 +00:00 committed by Gerrit Code Review
commit 26ecbc2dae
7 changed files with 57 additions and 10 deletions

View File

@ -22,6 +22,7 @@ import keystone.conf
from keystone import exception
from keystone.federation import utils
from keystone.i18n import _
from keystone import notifications
# This is a general cache region for service providers.
@ -77,6 +78,18 @@ class Manager(manager.Manager):
self._cleanup_idp_domain(idp['domain_id'])
raise
def delete_idp(self, idp_id):
self.driver.delete_idp(idp_id)
# NOTE(lbragstad): If an identity provider is removed from the system,
# then we need to invalidate the token cache. Otherwise it will be
# possible for federated tokens to be considered valid after a service
# provider removes a federated identity provider resource. The `idp_id`
# isn't actually used when invalidating the token cache but we have to
# pass something.
notifications.Audit.internal(
notifications.INVALIDATE_TOKEN_CACHE_DELETED_IDP, idp_id
)
def _cleanup_idp_domain(self, domain_id):
domain = {'enabled': False}
PROVIDERS.resource_api.update_domain(domain_id, domain)

View File

@ -79,6 +79,7 @@ CONF = keystone.conf.CONF
INVALIDATE_USER_TOKEN_PERSISTENCE = 'invalidate_user_tokens'
INVALIDATE_USER_PROJECT_TOKEN_PERSISTENCE = 'invalidate_user_project_tokens'
INVALIDATE_USER_OAUTH_CONSUMER_TOKENS = 'invalidate_user_consumer_tokens'
INVALIDATE_TOKEN_CACHE_DELETED_IDP = 'invalidate_token_cache_from_deleted_idp'
class Audit(object):

View File

@ -44,7 +44,6 @@ from keystone.tests.unit import federation_fixtures
from keystone.tests.unit import ksfixtures
from keystone.tests.unit import mapping_fixtures
from keystone.tests.unit import test_v3
from keystone.tests.unit import utils
from keystone.token.providers import common as token_common
@ -2097,9 +2096,7 @@ class FederatedTokenTests(test_v3.RestfulTestCase, FederatedSetupMixin):
self.TOKEN_SCOPE_PROJECT_EMPLOYEE_FROM_CUSTOMER,
expected_status=http_client.FORBIDDEN)
@utils.wip('This will fail because of bug #1291157. The token should be '
'invalid after deleting the identity provider.')
def test_validate_token_after_deleting_idp_fails(self):
def test_validate_token_after_deleting_idp_raises_not_found(self):
token = self.v3_create_token(
self.TOKEN_SCOPE_PROJECT_EMPLOYEE_FROM_ADMIN
)
@ -2110,13 +2107,14 @@ class FederatedTokenTests(test_v3.RestfulTestCase, FederatedSetupMixin):
headers = {
'X-Subject-Token': token_id
}
# FIXME(lbragstad): This should raise a 401 Unauthorized exception
# since the identity provider is gone.
# NOTE(lbragstad): This raises a 404 NOT FOUND because the identity
# provider is no longer present. We raise 404 NOT FOUND when we
# validate a token and a project or domain no longer exists.
self.get(
'/auth/tokens/',
token=token_id,
headers=headers,
expected_status=http_client.UNAUTHORIZED
expected_status=http_client.NOT_FOUND
)
def test_scope_to_bad_project(self):

View File

@ -139,13 +139,19 @@ class TestValidate(unit.TestCase):
method_names = ['mapped']
group_ids = [uuid.uuid4().hex, ]
identity_provider = uuid.uuid4().hex
idp_id = uuid.uuid4().hex
idp_ref = {
'id': idp_id,
'description': uuid.uuid4().hex,
'enabled': True
}
self.federation_api.create_idp(idp_id, idp_ref)
protocol = uuid.uuid4().hex
auth_context_params = {
'user_id': user_ref['id'],
'user_name': user_ref['name'],
'group_ids': group_ids,
federation_constants.IDENTITY_PROVIDER: identity_provider,
federation_constants.IDENTITY_PROVIDER: idp_id,
federation_constants.PROTOCOL: protocol,
}
auth_context = auth.core.AuthContext(**auth_context_params)
@ -161,7 +167,7 @@ class TestValidate(unit.TestCase):
'name': CONF.federation.federated_domain_name, },
federation_constants.FEDERATION: {
'groups': [{'id': group_id} for group_id in group_ids],
'identity_provider': {'id': identity_provider, },
'identity_provider': {'id': idp_id, },
'protocol': {'id': protocol, },
},
}

View File

@ -91,6 +91,8 @@ class Manager(manager.Manager):
self._delete_user_project_tokens_callback],
[notifications.INVALIDATE_USER_OAUTH_CONSUMER_TOKENS,
self._delete_user_oauth_consumer_tokens_callback],
[notifications.INVALIDATE_TOKEN_CACHE_DELETED_IDP,
self._invalidate_token_cache_from_deleted_idp_callback],
]
}
@ -329,3 +331,16 @@ class Manager(manager.Manager):
if CONF.token.cache_on_issue:
# NOTE(amakarov): preserving behavior
TOKENS_REGION.invalidate()
def _invalidate_token_cache_from_deleted_idp_callback(self,
service,
resource_type,
operation, payload):
"""Callback to invalidate the token cache after deleting an idp.
While this callback doesn't use the information about the deleted
identity provider to invalidate the cache, the method name and payload
are emitted when logging at the DEBUG level.
"""
TOKENS_REGION.invalidate()

View File

@ -462,6 +462,12 @@ class V3TokenDataHelper(provider_api.ProviderAPIMixin, object):
if service_providers:
token_data['service_providers'] = service_providers
def _validate_identity_provider(self, token_data):
federated_info = token_data['user'].get('OS-FEDERATION')
if federated_info:
idp_id = federated_info['identity_provider']['id']
PROVIDERS.federation_api.get_idp(idp_id)
def _populate_token_dates(self, token_data, expires=None, issued_at=None):
if not expires:
expires = default_expire_time()
@ -518,6 +524,7 @@ class V3TokenDataHelper(provider_api.ProviderAPIMixin, object):
token_data, user_id, system, domain_id, project_id, trust
)
self._populate_service_providers(token_data)
self._validate_identity_provider(token_data)
self._populate_token_dates(token_data, expires=expires,
issued_at=issued_at)
self._populate_oauth_section(token_data, access_token)

View File

@ -0,0 +1,7 @@
---
fixes:
- |
[`bug 1291157 <https://bugs.launchpad.net/keystone/+bug/1291157>`_]
Identity provider information is now validated in during token validation.
If an identity provider is removed from a keystone service provider, tokens
associated to that identity provider will be considered invalid.