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

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)