<commit_before>"""
A consent module for the satosa proxy
"""
import hashlib
import json
import logging
from base64 import urlsafe_b64encode

import requests
from jwkest.jwk import RSAKey
from jwkest.jwk import rsa_load
from jwkest.jws import JWS
from requests.exceptions import ConnectionError

import satosa.logging_util as lu
from satosa.internal import InternalData
from satosa.micro_services.base import ResponseMicroService
from satosa.response import Redirect


logger = logging.getLogger(__name__)

STATE_KEY = "CONSENT"


class UnexpectedResponseError(Exception):
    pass


class Consent(ResponseMicroService):
    """
    Module for handling consent. Uses an external consent service
    """

    def __init__(self, config, internal_attributes, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.name = "consent"
        self.api_url = config["api_url"]
        self.redirect_url = config["redirect_url"]
        self.locked_attr = None
        if "user_id_to_attr" in internal_attributes:
            self.locked_attr = internal_attributes["user_id_to_attr"]

        self.signing_key = RSAKey(key=rsa_load(config["sign_key"]), use="sig", alg="RS256")
        self.endpoint = "/handle_consent"
        logger.info("Consent flow is active")

    def _handle_consent_response(self, context):
        """
        Endpoint for handling consent service response
        :type context: satosa.context.Context
        :rtype: satosa.response.Response

        :param context: response context
        :return: response
        """
        consent_state = context.state[STATE_KEY]
        saved_resp = consent_state["internal_resp"]
        internal_response = InternalData.from_dict(saved_resp)

        hash_id = self._get_consent_id(internal_response.requester, internal_response.subject_id,
                                       internal_response.attributes)

        try:
            consent_attributes = self._verify_consent(hash_id)
        except ConnectionError as e:
            msg = "Consent service is not reachable, no consent given."
            logline = lu.LOG_FMT.format(id=lu.get_session_id(context.state), message=msg)
            logger.error(logline)
            # Send an internal_response without any attributes
            consent_attributes = None

        if consent_attributes is None:
            msg = "Consent was NOT given"
            logline = lu.LOG_FMT.format(id=lu.get_session_id(context.state), message=msg)
            logger.info(logline)
            # If consent was not given, then don't send any attributes
            consent_attributes = []
        else:
            msg = "Consent was given"
            logline = lu.LOG_FMT.format(id=lu.get_session_id(context.state), message=msg)
            logger.info(logline)

        internal_response.attributes = self._filter_attributes(internal_response.attributes, consent_attributes)
        return self._end_consent(context, internal_response)

    def _approve_new_consent(self, context, internal_response, id_hash):
        context.state[STATE_KEY]["internal_resp"] = internal_response.to_dict()

        consent_args = {
            "attr": internal_response.attributes,
            "id": id_hash,
            "redirect_endpoint": "%s/consent%s" % (self.base_url, self.endpoint),
            "requester_name": internal_response.requester_name,
        }
        if self.locked_attr:
            consent_args["locked_attrs"] = [self.locked_attr]
        if 'requester_logo' in context.state[STATE_KEY]:
             consent_args["requester_logo"] = context.state[STATE_KEY]['requester_logo']
        try:
            ticket = self._consent_registration(consent_args)
        except (ConnectionError, UnexpectedResponseError) as e:
            msg = "Consent request failed, no consent given: {}".format(str(e))
            logline = lu.LOG_FMT.format(id=lu.get_session_id(context.state), message=msg)
            logger.error(logline)
            # Send an internal_response without any attributes
            internal_response.attributes = {}
            return self._end_consent(context, internal_response)

        consent_redirect = "%s/%s" % (self.redirect_url, ticket)<commit_msg>Add the Requester ID to the Consent Call<commit_after>"""
A consent module for the satosa proxy
"""
import hashlib
import json
import logging
from base64 import urlsafe_b64encode

import requests
from jwkest.jwk import RSAKey
from jwkest.jwk import rsa_load
from jwkest.jws import JWS
from requests.exceptions import ConnectionError

import satosa.logging_util as lu
from satosa.internal import InternalData
from satosa.micro_services.base import ResponseMicroService
from satosa.response import Redirect


logger = logging.getLogger(__name__)

STATE_KEY = "CONSENT"


class UnexpectedResponseError(Exception):
    pass


class Consent(ResponseMicroService):
    """
    Module for handling consent. Uses an external consent service
    """

    def __init__(self, config, internal_attributes, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.name = "consent"
        self.api_url = config["api_url"]
        self.redirect_url = config["redirect_url"]
        self.locked_attr = None
        if "user_id_to_attr" in internal_attributes:
            self.locked_attr = internal_attributes["user_id_to_attr"]

        self.signing_key = RSAKey(key=rsa_load(config["sign_key"]), use="sig", alg="RS256")
        self.endpoint = "/handle_consent"
        logger.info("Consent flow is active")

    def _handle_consent_response(self, context):
        """
        Endpoint for handling consent service response
        :type context: satosa.context.Context
        :rtype: satosa.response.Response

        :param context: response context
        :return: response
        """
        consent_state = context.state[STATE_KEY]
        saved_resp = consent_state["internal_resp"]
        internal_response = InternalData.from_dict(saved_resp)

        hash_id = self._get_consent_id(internal_response.requester, internal_response.subject_id,
                                       internal_response.attributes)

        try:
            consent_attributes = self._verify_consent(hash_id)
        except ConnectionError as e:
            msg = "Consent service is not reachable, no consent given."
            logline = lu.LOG_FMT.format(id=lu.get_session_id(context.state), message=msg)
            logger.error(logline)
            # Send an internal_response without any attributes
            consent_attributes = None

        if consent_attributes is None:
            msg = "Consent was NOT given"
            logline = lu.LOG_FMT.format(id=lu.get_session_id(context.state), message=msg)
            logger.info(logline)
            # If consent was not given, then don't send any attributes
            consent_attributes = []
        else:
            msg = "Consent was given"
            logline = lu.LOG_FMT.format(id=lu.get_session_id(context.state), message=msg)
            logger.info(logline)

        internal_response.attributes = self._filter_attributes(internal_response.attributes, consent_attributes)
        return self._end_consent(context, internal_response)

    def _approve_new_consent(self, context, internal_response, id_hash):
        context.state[STATE_KEY]["internal_resp"] = internal_response.to_dict()

        consent_args = {
            "attr": internal_response.attributes,
            "id": id_hash,
            "redirect_endpoint": "%s/consent%s" % (self.base_url, self.endpoint),
            "requester": internal_response.requester,
            "requester_name": internal_response.requester_name,
        }
        if self.locked_attr:
            consent_args["locked_attrs"] = [self.locked_attr]
        if 'requester_logo' in context.state[STATE_KEY]:
             consent_args["requester_logo"] = context.state[STATE_KEY]['requester_logo']
        try:
            ticket = self._consent_registration(consent_args)
        except (ConnectionError, UnexpectedResponseError) as e:
            msg = "Consent request failed, no consent given: {}".format(str(e))
            logline = lu.LOG_FMT.format(id=lu.get_session_id(context.state), message=msg)
            logger.error(logline)
            # Send an internal_response without any attributes
            internal_response.attributes = {}
            return self._end_consent(context, internal_response)

        consent_redirect = "%s/%s" % (self.redirect_url, ticket)
{'fraction_non_alphanumeric': 0.08842576239255857, 'fraction_numerical': 0.0016484163428705993, 'mean_word_length': 2.905287356321839, 'pattern_counts': {'":': 9, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4135567', 'n_tokens_mistral': 2385, 'n_tokens_neox': 2346, 'n_words': 530}