def _apply_filter(self, context, attributes, provider, requester): filter_allow = get_dict_defaults(self.attribute_allow, provider, requester) satosa_logging( logger, logging.DEBUG, "{} filter_allow: {}".format(self.logprefix, filter_allow), context.state) filter_deny = get_dict_defaults(self.attribute_deny, provider, requester) satosa_logging( logger, logging.DEBUG, "{} filter_deny: {}".format(self.logprefix, filter_deny), context.state) allow = self._filter_attributes(attributes, filter_allow) satosa_logging(logger, logging.DEBUG, "{} allow: {}".format(self.logprefix, allow), context.state) deny = self._filter_attributes(attributes, filter_deny) satosa_logging(logger, logging.DEBUG, "{} deny: {}".format(self.logprefix, deny), context.state) # Remove Denies (values) from Allows (values) for a, v in deny.items(): for r in v: if a in allow and r in allow[a]: allow[a].remove(r) result = {a: v for a, v in allow.items() if len(v)} satosa_logging(logger, logging.DEBUG, "{} result: {}".format(self.logprefix, result), context.state) return result
def construct_requested_authn_context(self, entity_id): if not self.acr_mapping: return None acr_entry = util.get_dict_defaults(self.acr_mapping, entity_id) if not acr_entry: return None if type(acr_entry) is not dict: acr_entry = { "class_ref": acr_entry, "comparison": self.VALUE_ACR_COMPARISON_DEFAULT, } authn_context = requested_authn_context( acr_entry['class_ref'], comparison=acr_entry.get( 'comparison', self.VALUE_ACR_COMPARISON_DEFAULT)) return authn_context
def _handle_authn_response(self, context, internal_response, idp): """ See super class satosa.frontends.base.FrontendModule :type context: satosa.context.Context :type internal_response: satosa.internal.InternalData :type idp: saml.server.Server :param context: The current context :param internal_response: The internal response :param idp: The saml frontend idp server :return: A saml response """ request_state = self.load_state(context.state) resp_args = request_state["resp_args"] sp_entity_id = resp_args["sp_entity_id"] internal_response.attributes = self._filter_attributes( idp, internal_response, context) ava = self.converter.from_internal( self.attribute_profile, internal_response.attributes) auth_info = {} if self.acr_mapping: auth_info["class_ref"] = self.acr_mapping.get( internal_response.auth_info.issuer, self.acr_mapping[""]) else: auth_info["class_ref"] = internal_response.auth_info.auth_class_ref auth_info["authn_auth"] = internal_response.auth_info.issuer if self.custom_attribute_release: custom_release = util.get_dict_defaults( self.custom_attribute_release, internal_response.auth_info.issuer, sp_entity_id) attributes_to_remove = custom_release.get("exclude", []) for k in attributes_to_remove: ava.pop(k, None) nameid_value = internal_response.subject_id nameid_format = subject_type_to_saml_nameid_format( internal_response.subject_type ) # If the backend did not receive a SAML <NameID> and so # name_id is set to None then do not create a NameID instance. # Instead pass None as the name name_id to the IdP server # instance and it will use its configured policy to construct # a <NameID>, with the default to create a transient <NameID>. name_id = None if not nameid_value else NameID( text=nameid_value, format=nameid_format, sp_name_qualifier=None, name_qualifier=None, ) msg = "returning attributes {}".format(json.dumps(ava)) logline = lu.LOG_FMT.format(id=lu.get_session_id(context.state), message=msg) logger.debug(logline) idp_conf = self.idp_config.get('service', {}).get('idp', {}) policies = idp_conf.get('policy', {}) sp_policy = policies.get('default', {}) sp_policy.update(policies.get(sp_entity_id, {})) sign_assertion = sp_policy.get('sign_assertion', False) sign_response = sp_policy.get('sign_response', True) encrypt_assertion = sp_policy.get('encrypt_assertion', False) encrypted_advice_attributes = sp_policy.get('encrypted_advice_attributes', False) signing_algorithm = idp_conf.get('signing_algorithm') digest_algorithm = idp_conf.get('digest_algorithm') sign_alg_attr = sp_policy.get('sign_alg', 'SIG_RSA_SHA256') digest_alg_attr = sp_policy.get('digest_alg', 'DIGEST_SHA256') # Construct arguments for method create_authn_response # on IdP Server instance args = { # Add the SP details **resp_args, # AuthnResponse data 'identity': ava, 'name_id': name_id, 'authn': auth_info, 'sign_response': sign_response, 'sign_assertion': sign_assertion, 'encrypt_assertion': encrypt_assertion, 'encrypted_advice_attributes': encrypted_advice_attributes, } args['sign_alg'] = signing_algorithm if not args['sign_alg']: try: args['sign_alg'] = getattr(xmldsig, sign_alg_attr) except AttributeError as e: msg = "Unsupported sign algorithm {}".format(sign_alg) logline = lu.LOG_FMT.format(id=lu.get_session_id(context.state), message=msg) logger.error(logline) raise Exception(msg) from e msg = "signing with algorithm {}".format(args['sign_alg']) logline = lu.LOG_FMT.format(id=lu.get_session_id(context.state), message=msg) logger.debug(logline) args['digest_alg'] = digest_algorithm if not args['digest_alg']: try: args['digest_alg'] = getattr(xmldsig, digest_alg_attr) except AttributeError as e: msg = "Unsupported digest algorithm {}".format(digest_alg) logline = lu.LOG_FMT.format(id=lu.get_session_id(context.state), message=msg) logger.error(logline) raise Exception(msg) from e msg = "using digest algorithm {}".format(args['digest_alg']) logline = lu.LOG_FMT.format(id=lu.get_session_id(context.state), message=msg) logger.debug(logline) if sign_alg_attr or digest_alg_attr: msg = ( "sign_alg and digest_alg are deprecated; " "instead, use signing_algorithm and digest_algorithm " "under the service/idp configuration path " "(not under policy/default)." ) logline = lu.LOG_FMT.format(id=lu.get_session_id(context.state), message=msg) logger.warning(msg) resp = idp.create_authn_response(**args) http_args = idp.apply_binding( resp_args["binding"], str(resp), resp_args["destination"], request_state["relay_state"], response=True) # Set the common domain cookie _saml_idp if so configured. if self.config.get('common_domain_cookie'): self._set_common_domain_cookie(internal_response, http_args, context) del context.state[self.name] return make_saml_response(resp_args["binding"], http_args)
def _handle_authn_response(self, context, internal_response, idp): """ See super class satosa.frontends.base.FrontendModule :type context: satosa.context.Context :type internal_response: satosa.internal.InternalData :type idp: saml.server.Server :param context: The current context :param internal_response: The internal response :param idp: The saml frontend idp server :return: A saml response """ request_state = self.load_state(context.state) resp_args = request_state["resp_args"] sp_entity_id = resp_args["sp_entity_id"] internal_response.attributes = self._filter_attributes( idp, internal_response, context) ava = self.converter.from_internal(self.attribute_profile, internal_response.attributes) auth_info = {} if self.acr_mapping: auth_info["class_ref"] = self.acr_mapping.get( internal_response.auth_info.issuer, self.acr_mapping[""]) else: auth_info["class_ref"] = internal_response.auth_info.auth_class_ref auth_info["authn_auth"] = internal_response.auth_info.issuer if self.custom_attribute_release: custom_release = util.get_dict_defaults( self.custom_attribute_release, internal_response.auth_info.issuer, sp_entity_id) attributes_to_remove = custom_release.get("exclude", []) for k in attributes_to_remove: ava.pop(k, None) nameid_value = internal_response.subject_id nameid_format = subject_type_to_saml_nameid_format( internal_response.subject_type) # If the backend did not receive a SAML <NameID> and so # name_id is set to None then do not create a NameID instance. # Instead pass None as the name name_id to the IdP server # instance and it will use its configured policy to construct # a <NameID>, with the default to create a transient <NameID>. name_id = None if not nameid_value else NameID( text=nameid_value, format=nameid_format, sp_name_qualifier=None, name_qualifier=None, ) dbgmsg = "returning attributes %s" % json.dumps(ava) satosa_logging(logger, logging.DEBUG, dbgmsg, context.state) policies = self.idp_config.get('service', {}).get('idp', {}).get('policy', {}) sp_policy = policies.get('default', {}) sp_policy.update(policies.get(sp_entity_id, {})) sign_assertion = sp_policy.get('sign_assertion', False) sign_response = sp_policy.get('sign_response', True) sign_alg = sp_policy.get('sign_alg', 'SIG_RSA_SHA256') digest_alg = sp_policy.get('digest_alg', 'DIGEST_SHA256') # Construct arguments for method create_authn_response # on IdP Server instance args = { 'identity': ava, 'name_id': name_id, 'authn': auth_info, 'sign_response': sign_response, 'sign_assertion': sign_assertion, } # Add the SP details args.update(**resp_args) try: args['sign_alg'] = getattr(xmldsig, sign_alg) except AttributeError as e: errmsg = "Unsupported sign algorithm %s" % sign_alg satosa_logging(logger, logging.ERROR, errmsg, context.state) raise Exception(errmsg) from e else: dbgmsg = "signing with algorithm %s" % args['sign_alg'] satosa_logging(logger, logging.DEBUG, dbgmsg, context.state) try: args['digest_alg'] = getattr(xmldsig, digest_alg) except AttributeError as e: errmsg = "Unsupported digest algorithm %s" % digest_alg satosa_logging(logger, logging.ERROR, errmsg, context.state) raise Exception(errmsg) from e else: dbgmsg = "using digest algorithm %s" % args['digest_alg'] satosa_logging(logger, logging.DEBUG, dbgmsg, context.state) resp = idp.create_authn_response(**args) http_args = idp.apply_binding(resp_args["binding"], str(resp), resp_args["destination"], request_state["relay_state"], response=True) # Set the common domain cookie _saml_idp if so configured. if self.config.get('common_domain_cookie'): self._set_common_domain_cookie(internal_response, http_args, context) del context.state[self.name] return make_saml_response(resp_args["binding"], http_args)
def _handle_authn_response(self, context, internal_response, idp): """ See super class satosa.frontends.base.FrontendModule :type context: satosa.context.Context :type internal_response: satosa.internal.InternalData :type idp: saml.server.Server :param context: The current context :param internal_response: The internal response :param idp: The saml frontend idp server :return: A saml response """ request_state = self.load_state(context.state) resp_args = request_state["resp_args"] sp_entity_id = resp_args["sp_entity_id"] internal_response.attributes = self._filter_attributes( idp, internal_response, context) ava = self.converter.from_internal( self.attribute_profile, internal_response.attributes) auth_info = {} if self.acr_mapping: auth_info["class_ref"] = self.acr_mapping.get( internal_response.auth_info.issuer, self.acr_mapping[""]) else: auth_info["class_ref"] = internal_response.auth_info.auth_class_ref auth_info["authn_auth"] = internal_response.auth_info.issuer if self.custom_attribute_release: custom_release = util.get_dict_defaults( self.custom_attribute_release, internal_response.auth_info.issuer, sp_entity_id) attributes_to_remove = custom_release.get("exclude", []) for k in attributes_to_remove: ava.pop(k, None) nameid_value = internal_response.subject_id nameid_format = subject_type_to_saml_nameid_format( internal_response.subject_type ) # If the backend did not receive a SAML <NameID> and so # name_id is set to None then do not create a NameID instance. # Instead pass None as the name name_id to the IdP server # instance and it will use its configured policy to construct # a <NameID>, with the default to create a transient <NameID>. name_id = None if not nameid_value else NameID( text=nameid_value, format=nameid_format, sp_name_qualifier=None, name_qualifier=None, ) dbgmsg = "returning attributes %s" % json.dumps(ava) satosa_logging(logger, logging.DEBUG, dbgmsg, context.state) policies = self.idp_config.get( 'service', {}).get('idp', {}).get('policy', {}) sp_policy = policies.get('default', {}) sp_policy.update(policies.get(sp_entity_id, {})) sign_assertion = sp_policy.get('sign_assertion', False) sign_response = sp_policy.get('sign_response', True) sign_alg = sp_policy.get('sign_alg', 'SIG_RSA_SHA256') digest_alg = sp_policy.get('digest_alg', 'DIGEST_SHA256') # Construct arguments for method create_authn_response # on IdP Server instance args = { 'identity' : ava, 'name_id' : name_id, 'authn' : auth_info, 'sign_response' : sign_response, 'sign_assertion': sign_assertion, } # Add the SP details args.update(**resp_args) try: args['sign_alg'] = getattr(xmldsig, sign_alg) except AttributeError as e: errmsg = "Unsupported sign algorithm %s" % sign_alg satosa_logging(logger, logging.ERROR, errmsg, context.state) raise Exception(errmsg) from e else: dbgmsg = "signing with algorithm %s" % args['sign_alg'] satosa_logging(logger, logging.DEBUG, dbgmsg, context.state) try: args['digest_alg'] = getattr(xmldsig, digest_alg) except AttributeError as e: errmsg = "Unsupported digest algorithm %s" % digest_alg satosa_logging(logger, logging.ERROR, errmsg, context.state) raise Exception(errmsg) from e else: dbgmsg = "using digest algorithm %s" % args['digest_alg'] satosa_logging(logger, logging.DEBUG, dbgmsg, context.state) resp = idp.create_authn_response(**args) http_args = idp.apply_binding( resp_args["binding"], str(resp), resp_args["destination"], request_state["relay_state"], response=True) # Set the common domain cookie _saml_idp if so configured. if self.config.get('common_domain_cookie'): self._set_common_domain_cookie(internal_response, http_args, context) del context.state[self.name] return make_saml_response(resp_args["binding"], http_args)