def handle_scoped_token(context, auth_payload, auth_context, token_ref, federation_api, identity_api, token_provider_api): utils.validate_expiration(token_ref) token_audit_id = token_ref.audit_id identity_provider = token_ref.federation_idp_id protocol = token_ref.federation_protocol_id user_id = token_ref.user_id group_ids = token_ref.federation_group_ids send_notification = functools.partial( notifications.send_saml_audit_notification, 'authenticate', context, user_id, group_ids, identity_provider, protocol, token_audit_id) utils.assert_enabled_identity_provider(federation_api, identity_provider) try: mapping = federation_api.get_mapping_from_idp_and_protocol( identity_provider, protocol) utils.validate_groups(group_ids, mapping['id'], identity_api) except Exception: # NOTE(topol): Diaper defense to catch any exception, so we can # send off failed authentication notification, raise the exception # after sending the notification send_notification(taxonomy.OUTCOME_FAILURE) raise else: send_notification(taxonomy.OUTCOME_SUCCESS) auth_context['user_id'] = user_id auth_context['group_ids'] = group_ids auth_context[federation_constants.IDENTITY_PROVIDER] = identity_provider auth_context[federation_constants.PROTOCOL] = protocol
def handle_unscoped_token(context, auth_payload, auth_context, resource_api, federation_api, identity_api): def is_ephemeral_user(mapped_properties): return mapped_properties["user"]["type"] == utils.UserType.EPHEMERAL def build_ephemeral_user_context(auth_context, user, mapped_properties, identity_provider, protocol): auth_context["user_id"] = user["id"] auth_context["group_ids"] = mapped_properties["group_ids"] auth_context[federation_constants.IDENTITY_PROVIDER] = identity_provider auth_context[federation_constants.PROTOCOL] = protocol def build_local_user_context(auth_context, mapped_properties): user_info = auth_plugins.UserAuthInfo.create(mapped_properties, METHOD_NAME) auth_context["user_id"] = user_info.user_id assertion = extract_assertion_data(context) identity_provider = auth_payload["identity_provider"] protocol = auth_payload["protocol"] utils.assert_enabled_identity_provider(federation_api, identity_provider) group_ids = None # NOTE(topol): The user is coming in from an IdP with a SAML assertion # instead of from a token, so we set token_id to None token_id = None # NOTE(marek-denis): This variable is set to None and there is a # possibility that it will be used in the CADF notification. This means # operation will not be mapped to any user (even ephemeral). user_id = None try: mapped_properties, mapping_id = apply_mapping_filter( identity_provider, protocol, assertion, resource_api, federation_api, identity_api ) if is_ephemeral_user(mapped_properties): user = setup_username(context, mapped_properties) user_id = user["id"] group_ids = mapped_properties["group_ids"] utils.validate_groups_cardinality(group_ids, mapping_id) build_ephemeral_user_context(auth_context, user, mapped_properties, identity_provider, protocol) else: build_local_user_context(auth_context, mapped_properties) except Exception: # NOTE(topol): Diaper defense to catch any exception, so we can # send off failed authentication notification, raise the exception # after sending the notification outcome = taxonomy.OUTCOME_FAILURE notifications.send_saml_audit_notification( "authenticate", context, user_id, group_ids, identity_provider, protocol, token_id, outcome ) raise else: outcome = taxonomy.OUTCOME_SUCCESS notifications.send_saml_audit_notification( "authenticate", context, user_id, group_ids, identity_provider, protocol, token_id, outcome )
def handle_scoped_token(token, federation_api, identity_api): response_data = {} utils.validate_expiration(token) token_audit_id = token.audit_id identity_provider = token.identity_provider_id protocol = token.protocol_id user_id = token.user_id group_ids = [] for group_dict in token.federated_groups: group_ids.append(group_dict['id']) send_notification = functools.partial( notifications.send_saml_audit_notification, 'authenticate', user_id, group_ids, identity_provider, protocol, token_audit_id) utils.assert_enabled_identity_provider(federation_api, identity_provider) try: mapping = federation_api.get_mapping_from_idp_and_protocol( identity_provider, protocol) utils.validate_mapped_group_ids(group_ids, mapping['id'], identity_api) except Exception: # NOTE(topol): Diaper defense to catch any exception, so we can # send off failed authentication notification, raise the exception # after sending the notification send_notification(taxonomy.OUTCOME_FAILURE) raise else: send_notification(taxonomy.OUTCOME_SUCCESS) response_data['user_id'] = user_id response_data['group_ids'] = group_ids response_data[federation_constants.IDENTITY_PROVIDER] = identity_provider response_data[federation_constants.PROTOCOL] = protocol return response_data
def handle_unscoped_token(context, auth_payload, auth_context, resource_api, federation_api, identity_api): def is_ephemeral_user(mapped_properties): return mapped_properties['user']['type'] == utils.UserType.EPHEMERAL def build_ephemeral_user_context(auth_context, user, mapped_properties, identity_provider, protocol): auth_context['user_id'] = user['id'] auth_context['group_ids'] = mapped_properties['group_ids'] auth_context[federation_constants.IDENTITY_PROVIDER] = ( identity_provider) auth_context[federation_constants.PROTOCOL] = protocol def build_local_user_context(auth_context, mapped_properties): user_info = auth_plugins.UserAuthInfo.create(mapped_properties, METHOD_NAME) auth_context['user_id'] = user_info.user_id assertion = extract_assertion_data(context) identity_provider = auth_payload['identity_provider'] protocol = auth_payload['protocol'] utils.assert_enabled_identity_provider(federation_api, identity_provider) group_ids = None # NOTE(topol): The user is coming in from an IdP with a SAML assertion # instead of from a token, so we set token_id to None token_id = None # NOTE(marek-denis): This variable is set to None and there is a # possibility that it will be used in the CADF notification. This means # operation will not be mapped to any user (even ephemeral). user_id = None try: try: mapped_properties, mapping_id = apply_mapping_filter( identity_provider, protocol, assertion, resource_api, federation_api, identity_api) except exception.ValidationError as e: # if mapping is either invalid or yield no valid identity, # it is considered a failed authentication raise exception.Unauthorized(e) if is_ephemeral_user(mapped_properties): unique_id, display_name = ( get_user_unique_id_and_display_name(context, mapped_properties) ) user = identity_api.shadow_federated_user(identity_provider, protocol, unique_id, display_name) user_id = user['id'] group_ids = mapped_properties['group_ids'] utils.validate_groups_cardinality(group_ids, mapping_id) build_ephemeral_user_context(auth_context, user, mapped_properties, identity_provider, protocol) else: build_local_user_context(auth_context, mapped_properties) except Exception: # NOTE(topol): Diaper defense to catch any exception, so we can # send off failed authentication notification, raise the exception # after sending the notification outcome = taxonomy.OUTCOME_FAILURE notifications.send_saml_audit_notification('authenticate', context, user_id, group_ids, identity_provider, protocol, token_id, outcome) raise else: outcome = taxonomy.OUTCOME_SUCCESS notifications.send_saml_audit_notification('authenticate', context, user_id, group_ids, identity_provider, protocol, token_id, outcome)
def handle_unscoped_token(request, auth_payload, resource_api, federation_api, identity_api, assignment_api, role_api): def validate_shadow_mapping(shadow_projects, existing_roles, idp_domain_id, idp_id): # Validate that the roles in the shadow mapping actually exist. If # they don't we should bail early before creating anything. for shadow_project in shadow_projects: for shadow_role in shadow_project['roles']: # The role in the project mapping must exist in order for it to # be useful. if shadow_role['name'] not in existing_roles: LOG.error( 'Role %s was specified in the mapping but does ' 'not exist. All roles specified in a mapping must ' 'exist before assignment.', shadow_role['name']) # NOTE(lbragstad): The RoleNotFound exception usually # expects a role_id as the parameter, but in this case we # only have a name so we'll pass that instead. raise exception.RoleNotFound(shadow_role['name']) role = existing_roles[shadow_role['name']] if (role['domain_id'] is not None and role['domain_id'] != idp_domain_id): LOG.error( 'Role %(role)s is a domain-specific role and ' 'cannot be assigned within %(domain)s.', { 'role': shadow_role['name'], 'domain': idp_domain_id }) raise exception.DomainSpecificRoleNotWithinIdPDomain( role_name=shadow_role['name'], identity_provider=idp_id) def create_projects_from_mapping(shadow_projects, idp_domain_id, existing_roles, user, assignment_api, resource_api): for shadow_project in shadow_projects: try: # Check and see if the project already exists and if it # does not, try to create it. project = resource_api.get_project_by_name( shadow_project['name'], idp_domain_id) except exception.ProjectNotFound: LOG.info( 'Project %(project_name)s does not exist. It will be ' 'automatically provisioning for user %(user_id)s.', { 'project_name': shadow_project['name'], 'user_id': user['id'] }) project_ref = { 'id': uuid.uuid4().hex, 'name': shadow_project['name'], 'domain_id': idp_domain_id } project = resource_api.create_project(project_ref['id'], project_ref) shadow_roles = shadow_project['roles'] for shadow_role in shadow_roles: assignment_api.create_grant( existing_roles[shadow_role['name']]['id'], user_id=user['id'], project_id=project['id']) def is_ephemeral_user(mapped_properties): return mapped_properties['user']['type'] == utils.UserType.EPHEMERAL def build_ephemeral_user_context(user, mapped_properties, identity_provider, protocol): resp = {} resp['user_id'] = user['id'] resp['group_ids'] = mapped_properties['group_ids'] resp[federation_constants.IDENTITY_PROVIDER] = identity_provider resp[federation_constants.PROTOCOL] = protocol return resp def build_local_user_context(mapped_properties): resp = {} user_info = auth_plugins.UserAuthInfo.create(mapped_properties, METHOD_NAME) resp['user_id'] = user_info.user_id return resp assertion = extract_assertion_data(request) try: identity_provider = auth_payload['identity_provider'] except KeyError: raise exception.ValidationError(attribute='identity_provider', target='mapped') try: protocol = auth_payload['protocol'] except KeyError: raise exception.ValidationError(attribute='protocol', target='mapped') utils.assert_enabled_identity_provider(federation_api, identity_provider) group_ids = None # NOTE(topol): The user is coming in from an IdP with a SAML assertion # instead of from a token, so we set token_id to None token_id = None # NOTE(marek-denis): This variable is set to None and there is a # possibility that it will be used in the CADF notification. This means # operation will not be mapped to any user (even ephemeral). user_id = None try: try: mapped_properties, mapping_id = apply_mapping_filter( identity_provider, protocol, assertion, resource_api, federation_api, identity_api) except exception.ValidationError as e: # if mapping is either invalid or yield no valid identity, # it is considered a failed authentication raise exception.Unauthorized(e) if is_ephemeral_user(mapped_properties): unique_id, display_name = (get_user_unique_id_and_display_name( request, mapped_properties)) user = identity_api.shadow_federated_user(identity_provider, protocol, unique_id, display_name) if 'projects' in mapped_properties: idp_domain_id = federation_api.get_idp( identity_provider)['domain_id'] existing_roles = { role['name']: role for role in role_api.list_roles() } # NOTE(lbragstad): If we are dealing with a shadow mapping, # then we need to make sure we validate all pieces of the # mapping and what it's saying to create. If there is something # wrong with how the mapping is, we should bail early before we # create anything. validate_shadow_mapping(mapped_properties['projects'], existing_roles, idp_domain_id, identity_provider) create_projects_from_mapping(mapped_properties['projects'], idp_domain_id, existing_roles, user, assignment_api, resource_api) user_id = user['id'] group_ids = mapped_properties['group_ids'] response_data = build_ephemeral_user_context( user, mapped_properties, identity_provider, protocol) else: response_data = build_local_user_context(mapped_properties) except Exception: # NOTE(topol): Diaper defense to catch any exception, so we can # send off failed authentication notification, raise the exception # after sending the notification outcome = taxonomy.OUTCOME_FAILURE notifications.send_saml_audit_notification('authenticate', request, user_id, group_ids, identity_provider, protocol, token_id, outcome) raise else: outcome = taxonomy.OUTCOME_SUCCESS notifications.send_saml_audit_notification('authenticate', request, user_id, group_ids, identity_provider, protocol, token_id, outcome) return response_data
def handle_unscoped_token(auth_payload, resource_api, federation_api, identity_api, assignment_api, role_api): def validate_shadow_mapping(shadow_projects, existing_roles, idp_domain_id, idp_id): # Validate that the roles in the shadow mapping actually exist. If # they don't we should bail early before creating anything. for shadow_project in shadow_projects: for shadow_role in shadow_project['roles']: # The role in the project mapping must exist in order for it to # be useful. if shadow_role['name'] not in existing_roles: LOG.error( 'Role %s was specified in the mapping but does ' 'not exist. All roles specified in a mapping must ' 'exist before assignment.', shadow_role['name'] ) # NOTE(lbragstad): The RoleNotFound exception usually # expects a role_id as the parameter, but in this case we # only have a name so we'll pass that instead. raise exception.RoleNotFound(shadow_role['name']) role = existing_roles[shadow_role['name']] if (role['domain_id'] is not None and role['domain_id'] != idp_domain_id): LOG.error( 'Role %(role)s is a domain-specific role and ' 'cannot be assigned within %(domain)s.', {'role': shadow_role['name'], 'domain': idp_domain_id} ) raise exception.DomainSpecificRoleNotWithinIdPDomain( role_name=shadow_role['name'], identity_provider=idp_id ) def create_projects_from_mapping(shadow_projects, idp_domain_id, existing_roles, user, assignment_api, resource_api): for shadow_project in shadow_projects: try: # Check and see if the project already exists and if it # does not, try to create it. project = resource_api.get_project_by_name( shadow_project['name'], idp_domain_id ) except exception.ProjectNotFound: LOG.info( 'Project %(project_name)s does not exist. It will be ' 'automatically provisioning for user %(user_id)s.', {'project_name': shadow_project['name'], 'user_id': user['id']} ) project_ref = { 'id': uuid.uuid4().hex, 'name': shadow_project['name'], 'domain_id': idp_domain_id } project = resource_api.create_project( project_ref['id'], project_ref ) shadow_roles = shadow_project['roles'] for shadow_role in shadow_roles: assignment_api.create_grant( existing_roles[shadow_role['name']]['id'], user_id=user['id'], project_id=project['id'] ) def is_ephemeral_user(mapped_properties): return mapped_properties['user']['type'] == utils.UserType.EPHEMERAL def build_ephemeral_user_context(user, mapped_properties, identity_provider, protocol): resp = {} resp['user_id'] = user['id'] resp['group_ids'] = mapped_properties['group_ids'] resp[federation_constants.IDENTITY_PROVIDER] = identity_provider resp[federation_constants.PROTOCOL] = protocol return resp def build_local_user_context(mapped_properties): resp = {} user_info = auth_plugins.UserAuthInfo.create(mapped_properties, METHOD_NAME) resp['user_id'] = user_info.user_id return resp assertion = extract_assertion_data() try: identity_provider = auth_payload['identity_provider'] except KeyError: raise exception.ValidationError( attribute='identity_provider', target='mapped') try: protocol = auth_payload['protocol'] except KeyError: raise exception.ValidationError( attribute='protocol', target='mapped') utils.assert_enabled_identity_provider(federation_api, identity_provider) group_ids = None # NOTE(topol): The user is coming in from an IdP with a SAML assertion # instead of from a token, so we set token_id to None token_id = None # NOTE(marek-denis): This variable is set to None and there is a # possibility that it will be used in the CADF notification. This means # operation will not be mapped to any user (even ephemeral). user_id = None try: try: mapped_properties, mapping_id = apply_mapping_filter( identity_provider, protocol, assertion, resource_api, federation_api, identity_api) except exception.ValidationError as e: # if mapping is either invalid or yield no valid identity, # it is considered a failed authentication raise exception.Unauthorized(e) if is_ephemeral_user(mapped_properties): unique_id, display_name = ( get_user_unique_id_and_display_name(mapped_properties) ) email = mapped_properties['user'].get('email') user = identity_api.shadow_federated_user(identity_provider, protocol, unique_id, display_name, email) if 'projects' in mapped_properties: idp_domain_id = federation_api.get_idp( identity_provider )['domain_id'] existing_roles = { role['name']: role for role in role_api.list_roles() } # NOTE(lbragstad): If we are dealing with a shadow mapping, # then we need to make sure we validate all pieces of the # mapping and what it's saying to create. If there is something # wrong with how the mapping is, we should bail early before we # create anything. validate_shadow_mapping( mapped_properties['projects'], existing_roles, idp_domain_id, identity_provider ) create_projects_from_mapping( mapped_properties['projects'], idp_domain_id, existing_roles, user, assignment_api, resource_api ) user_id = user['id'] group_ids = mapped_properties['group_ids'] response_data = build_ephemeral_user_context( user, mapped_properties, identity_provider, protocol) else: response_data = build_local_user_context(mapped_properties) except Exception: # NOTE(topol): Diaper defense to catch any exception, so we can # send off failed authentication notification, raise the exception # after sending the notification outcome = taxonomy.OUTCOME_FAILURE notifications.send_saml_audit_notification('authenticate', user_id, group_ids, identity_provider, protocol, token_id, outcome) raise else: outcome = taxonomy.OUTCOME_SUCCESS notifications.send_saml_audit_notification('authenticate', user_id, group_ids, identity_provider, protocol, token_id, outcome) return response_data