text: import logging
  from datetime import timedelta
  from hashlib import md5, sha256
  
  try:
      from urllib import urlencode
  
      from urlparse import parse_qs, urlsplit, urlunsplit
  except ImportError:
      from urllib.parse import urlsplit, parse_qs, urlunsplit, urlencode
  
  from uuid import uuid4
  
  from django.utils import timezone
  
  from oidc_provider import settings
  from oidc_provider.lib.claims import StandardScopeClaims
  from oidc_provider.lib.errors import AuthorizeError, ClientIdError, RedirectUriError
  from oidc_provider.lib.utils.common import get_browser_state_or_default
  from oidc_provider.lib.utils.token import (
      create_code,
      create_id_token,
      create_token,
      encode_id_token,
  )
  from oidc_provider.models import Client, UserConsent
  
  logger = logging.getLogger(__name__)
  
  
  class AuthorizeEndpoint(object):
      _allowed_prompt_params = {"none", "login", "consent", "select_account"}
      client_class = Client
  
      def __init__(self, request):
          self.request = request
          self.params = {}
  
          self._extract_params()
  
          # Determine which flow to use.
          if self.params["response_type"] in ["code"]:
              self.grant_type = "authorization_code"
          elif self.params["response_type"] in ["id_token", "id_token token", "token"]:
              self.grant_type = "implicit"
          elif self.params["response_type"] in [
              "code token",
              "code id_token",
              "code id_token token",
          ]:
              self.grant_type = "hybrid"
          else:
              self.grant_type = None
  
          # Determine if it's an OpenID Authentication request (or OAuth2).
          self.is_authentication = "openid" in self.params["scope"]
  
      def _extract_params(self):
          """
          Get all the params used by the Authorization Code Flow
          (and also for the Implicit and Hybrid).
  
          See: http://openid.net/specs/openid-connect-core-1_0.html#AuthRequest
          """
          # Because in this endpoint we handle both GET
          # and POST request.
          query_dict = (
              self.request.POST if self.request.method == "POST" else self.request.GET
          )
  
          self.params["client_id"] = query_dict.get("client_id", "")
          self.params["redirect_uri"] = query_dict.get("redirect_uri", "")
          self.params["response_type"] = query_dict.get("response_type", "")
          self.params["scope"] = query_dict.get("scope", "").split()
          self.params["state"] = query_dict.get("state", "")
          self.params["nonce"] = query_dict.get("nonce", "")
  
          self.params["prompt"] = self._allowed_prompt_params.intersection(
              set(query_dict.get("prompt", "").split())
          )
  
          self.params["code_challenge"] = query_dict.get("code_challenge", "")
          self.params["code_challenge_method"] = query_dict.get(
              "code_challenge_method", ""
          )
  
      def validate_params(self):
          # Client validation.
          try:
              self.client = self.client_class.objects.get(
                  client_id=self.params["client_id"]
              )
          except Client.DoesNotExist:
              logger.debug(
                  "[Authorize] Invalid client identifier: %s", self.params["client_id"]
              )
              raise ClientIdError()
  
          # Redirect URI validation.
          if self.is_authentication and not self.params["redirect_uri"]:
              logger.debug("[Authorize] Missing redirect uri.")
              raise RedirectUriError()
          if not (self.params["redirect_uri"] in self.client.redirect_uris):
              logger.debug(
                  "[Authorize] Invalid redirect uri: %s", self.params["redirect_uri"]
              )
              raise RedirectUriError()
  
          # Grant type validation.
          if not self.grant_type:
              logger.debug(
                  "[Authorize] Invalid response type: %s", self.params["response_type"]
              )
              raise AuthorizeError(
                  self.params["redirect_uri"],
                  "unsupported_response_type",
                  self.grant_type,
              )
  
          if not self.is_authentication and (
              self.grant_type == "hybrid"
              or self.params["response_type"] in ["id_token", "id_token token"]
          ):
              logger.debug("[Authorize] Missing openid scope.")
              raise AuthorizeError(
                  self.params["redirect_uri"], "invalid_scope", self.grant_type
              )
  
          # Nonce parameter validation.
          if (
              self.is_authentication
              and self.grant_type == "implicit"
              and not self.params["nonce"]
          ):
              raise AuthorizeError(
                  self.params["redirect_uri"], "invalid_request", self.grant_type
              )
  
          # Response type parameter validation.
          if (
              self.is_authentication
              and self.params["response_type"] not in self.client.response_type_values()
          ):
              raise AuthorizeError(
                  self.params["redirect_uri"], "invalid_request", self.grant_type
              )
  
          # PKCE validation of the transformation method.
          if self.params["code_challenge"]:
              if not (self.params["code_challenge_method"] in ["plain", "S256"]):
                  raise AuthorizeError(
                      self.params["redirect_uri"], "invalid_request", self.grant_type
                  )
  
      def create_response_uri(self):
          uri = urlsplit(self.params["redirect_uri"])
          query_params = parse_qs(uri.query)
          query_fragment = {}
  
          try:
              if self.grant_type in ["authorization_code", "hybrid"]:
                  code = create_code(
                      user=self.request.user,
                      client=self.client,
                      scope=self.params["scope"],
                      nonce=self.params["nonce"],
                      is_authentication=self.is_authentication,
                      code_challenge=self.params["code_challenge"],
                      code_challenge_method=self.params["code_challenge_method"],
                  )
                  code.save()
  
              if self.grant_type == "authorization_code":
                  query_params["code"] = code.code
                  query_params["state"] = (
                      self.params["state"] if self.params["state"] else ""
                  )
              elif self.grant_type in ["implicit", "hybrid"]:
                  token = create_token(
                      user=self.request.user,
                      client=self.client,
                      scope=self.params["scope"],
                  )
  
                  # Check if response_type must include access_token in the response.
                  if self.params["response_type"] in [
                      "id_token token",
                      "token",
                      "code token",
                      "code id_token token",
                  ]:
                      query_fragment["access_token"] = token.access_token
  
                  # We don't need id_token if it's an OAuth2 request.
                  if self.is_authentication:
                      kwargs = {
                          "token": token,
                          "user": self.request.user,
                          "aud": self.client.client_id,
                          "nonce": self.params["nonce"],
                          "request": self.request,
                          "scope": self.params["scope"],
                      }
                      # Include at_hash when access_token is being returned.
                      if "access_token" in query_fragment:
                          kwargs["at_hash"] = token.at_hash
                      id_token_dic = create_id_token(**kwargs)
  
                      # Check if response_type must include id_token in the response.
                      if self.params["response_type"] in [
                          "id_token",
                          "id_token token",
                          "code id_token",
                          "code id_token token",
                      ]:
                          query_fragment["id_token"] = encode_id_token(
                              id_token_dic, self.client
                          )
                  else:
                      id_token_dic = {}
  
                  # Store the token.
                  token.id_token = id_token_dic
                  token.save()
  
                  # Code parameter must be present if it's Hybrid Flow.
                  if self.grant_type == "hybrid":
                      query_fragment["code"] = code.code
  
                  query_fragment["token_type"] = "bearer"
  
                  query_fragment["expires_in"] = settings.get("OIDC_TOKEN_EXPIRE")
  
                  query_fragment["state"] = (
                      self.params["state"] if self.params["state"] else ""
                  )
  
              if settings.get("OIDC_SESSION_MANAGEMENT_ENABLE"):
                  # Generate client origin URI from the redirect_uri param.
                  redirect_uri_parsed = urlsplit(self.params["redirect_uri"])
                  client_origin = "{0}://{1}".format(
                      redirect_uri_parsed.scheme, redirect_uri_parsed.netloc
                  )
  
                  # Create random salt.
                  salt = md5(uuid4().hex.encode()).hexdigest()
  
                  # The generation of suitable Session State values is based
                  # on a salted cryptographic hash of Client ID, origin URL,
                  # and OP browser state.
                  session_state = "{client_id} {origin} {browser_state} {salt}".format(
                      client_id=self.client.client_id,
                      origin=client_origin,
                      browser_state=get_browser_state_or_default(self.request),
                      salt=salt,
                  )
                  session_state = sha256(session_state.encode("utf-8")).hexdigest()
                  session_state += "." + salt
                  if self.grant_type == "authorization_code":
                      query_params["session_state"] = session_state
                  elif self.grant_type in ["implicit", "hybrid"]:
                      query_fragment["session_state"] = session_state
  
          except Exception as error:
              logger.exception(
                  "[Authorize] Error when trying to create response uri: %s", error
              )
              raise AuthorizeError(
                  self.params["redirect_uri"], "server_error", self.grant_type
              )
  
          uri = uri._replace(
              query=urlencode(query_params, doseq=True),
              fragment=uri.fragment + urlencode(query_fragment, doseq=True),
          )
  
          return urlunsplit(uri)
  
      def set_client_user_consent(self):
          """
          Save the user consent given to a specific client.
  
          Return None.
          """
          date_given = timezone.now()
          expires_at = date_given + timedelta(
              days=settings.get("OIDC_SKIP_CONSENT_EXPIRE")
          )
  
          uc, created = UserConsent.objects.get_or_create(
              user=self.request.user,
              client=self.client,
              defaults={
                  "expires_at": expires_at,
                  "date_given": date_given,
              },
          )
          uc.scope = self.params["scope"]
  
          # Rewrite expires_at and date_given if object already exists.
          if not created:
              uc.expires_at = expires_at
              uc.date_given = date_given
  
          uc.save()
  
      def client_has_user_consent(self):
          """
          Check if already exists user consent for some client.
  
          Return bool.
          """
          value = False
          try:
              uc = UserConsent.objects.get(user=self.request.user, client=self.client)
              if (set(self.params["scope"]).issubset(uc.scope)) and not (
                  uc.has_expired()
              ):
                  value = True
          except UserConsent.DoesNotExist:
              pass
  
          return value
  
      def get_scopes_information(self):
          """
          Return a list with the description of all the scopes requested.
          """
          scopes = StandardScopeClaims.get_scopes_info(self.params["scope"])
          if settings.get("OIDC_EXTRA_SCOPE_CLAIMS"):
              scopes_extra = settings.get(
                  "OIDC_EXTRA_SCOPE_CLAIMS", import_str=True
              ).get_scopes_info(self.params["scope"])
              for index_extra, scope_extra in enumerate(scopes_extra):
                  for index, scope in enumerate(scopes[:]):
                      if scope_extra["scope"] == scope["scope"]:
                          del scopes[index]
          else:
              scopes_extra = []
  
          return scopes + scopes_extra
  