keystone/keystone/auth/plugins/mapped.py

98 lines
4.0 KiB
Python

# 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.
from six.moves.urllib import parse
from keystone import auth
from keystone.common import dependency
from keystone.contrib import federation
from keystone.contrib.federation import utils
from keystone.openstack.common import jsonutils
@dependency.requires('federation_api', 'identity_api', 'token_api')
class Mapped(auth.AuthMethodHandler):
def authenticate(self, context, auth_payload, auth_context):
"""Authenticate mapped user and return an authentication context.
:param context: keystone's request context
:param auth_payload: the content of the authentication for a
given method
:param auth_context: user authentication context, a dictionary
shared by all plugins.
In addition to ``user_id`` in ``auth_context``, this plugin sets
``group_ids``, ``OS-FEDERATION:identity_provider`` and
``OS-FEDERATION:protocol``
"""
if 'id' in auth_payload:
fields = self._handle_scoped_token(auth_payload)
else:
fields = self._handle_unscoped_token(context, auth_payload)
auth_context.update(fields)
def _handle_scoped_token(self, auth_payload):
token_ref = self.token_api.get_token(auth_payload['id'])
utils.validate_expiration(token_ref)
_federation = token_ref['user'][federation.FEDERATION]
identity_provider = _federation['identity_provider']['id']
protocol = _federation['protocol']['id']
group_ids = [group['id'] for group in _federation['groups']]
mapping = self.federation_api.get_mapping_from_idp_and_protocol(
identity_provider, protocol)
utils.validate_groups(group_ids, mapping['id'], self.identity_api)
return {
'user_id': token_ref['user_id'],
'group_ids': group_ids,
federation.IDENTITY_PROVIDER: identity_provider,
federation.PROTOCOL: protocol
}
def _handle_unscoped_token(self, context, auth_payload):
user_id, assertion = self._extract_assertion_data(context)
if user_id:
assertion['user_id'] = user_id
identity_provider = auth_payload['identity_provider']
protocol = auth_payload['protocol']
mapped_properties = self._apply_mapping_filter(identity_provider,
protocol,
assertion)
if not user_id:
user_id = parse.quote(mapped_properties['name'])
return {
'user_id': user_id,
'group_ids': mapped_properties['group_ids'],
federation.IDENTITY_PROVIDER: identity_provider,
federation.PROTOCOL: protocol
}
def _extract_assertion_data(self, context):
assertion = dict(utils.get_assertion_params_from_env(context))
user_id = context['environment'].get('REMOTE_USER')
return user_id, assertion
def _apply_mapping_filter(self, identity_provider, protocol, assertion):
mapping = self.federation_api.get_mapping_from_idp_and_protocol(
identity_provider, protocol)
rules = jsonutils.loads(mapping['rules'])
rule_processor = utils.RuleProcessor(rules)
mapped_properties = rule_processor.process(assertion)
utils.validate_groups(mapped_properties['group_ids'],
mapping['id'], self.identity_api)
return mapped_properties