Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
metadata.py239 linesDownload Raw Back to endpoints
1"""2oauthlib.oauth2.rfc6749.endpoint.metadata3~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~4 5An implementation of the `OAuth 2.0 Authorization Server Metadata`.6 7.. _`OAuth 2.0 Authorization Server Metadata`: https://tools.ietf.org/html/rfc84148"""9import copy10import json11import logging12 13from .. import grant_types, utils14from .authorization import AuthorizationEndpoint15from .base import BaseEndpoint, catch_errors_and_unavailability16from .introspect import IntrospectEndpoint17from .revocation import RevocationEndpoint18from .token import TokenEndpoint19 20log = logging.getLogger(__name__)21 22 23class MetadataEndpoint(BaseEndpoint):24 25    """OAuth2.0 Authorization Server Metadata endpoint.26 27   This specification generalizes the metadata format defined by28   `OpenID Connect Discovery 1.0` in a way that is compatible29   with OpenID Connect Discovery while being applicable to a wider set30   of OAuth 2.0 use cases.  This is intentionally parallel to the way31   that OAuth 2.0 Dynamic Client Registration Protocol [`RFC7591`_]32   generalized the dynamic client registration mechanisms defined by33   OpenID Connect Dynamic Client Registration 1.034   in a way that is compatible with it.35 36   .. _`OpenID Connect Discovery 1.0`: https://openid.net/specs/openid-connect-discovery-1_0.html37   .. _`RFC7591`: https://tools.ietf.org/html/rfc759138   """39 40    def __init__(self, endpoints, claims={}, raise_errors=True):41        assert isinstance(claims, dict)  # noqa: S10142        for endpoint in endpoints:43            assert isinstance(endpoint, BaseEndpoint)  # noqa: S10144 45        BaseEndpoint.__init__(self)46        self.raise_errors = raise_errors47        self.endpoints = endpoints48        self.initial_claims = claims49        self.claims = self.validate_metadata_server()50 51    @catch_errors_and_unavailability52    def create_metadata_response(self, uri, http_method='GET', body=None,53                                 headers=None):54        """Create metadata response55        """56        headers = {57            'Content-Type': 'application/json',58            'Access-Control-Allow-Origin': '*',59        }60        return headers, json.dumps(self.claims), 20061 62    def validate_metadata(self, array, key, is_required=False, is_list=False, is_url=False, is_issuer=False):63        if not self.raise_errors:64            return65 66        if key not in array:67            if is_required:68                raise ValueError("key {} is a mandatory metadata.".format(key))69 70        elif is_issuer:71            if not utils.is_secure_transport(array[key]):72                raise ValueError("key {}: {} must be an HTTPS URL".format(key, array[key]))73            if "?" in array[key] or "&" in array[key] or "#" in array[key]:74                raise ValueError("key {}: {} must not contain query or fragment components".format(key, array[key]))75 76        elif is_url:77            if not array[key].startswith("http"):78                raise ValueError("key {}: {} must be an URL".format(key, array[key]))79 80        elif is_list:81            if not isinstance(array[key], list):82                raise ValueError("key {}: {} must be an Array".format(key, array[key]))83            for elem in array[key]:84                if not isinstance(elem, str):85                    raise ValueError("array {}: {} must contains only string (not {})".format(key, array[key], elem))86 87    def validate_metadata_token(self, claims, endpoint):88        """89        If the token endpoint is used in the grant type, the value of this90        parameter MUST be the same as the value of the "grant_type"91        parameter passed to the token endpoint defined in the grant type92        definition.93        """94        self._grant_types.extend(endpoint._grant_types.keys())95        claims.setdefault("token_endpoint_auth_methods_supported", ["client_secret_post", "client_secret_basic"])96 97        self.validate_metadata(claims, "token_endpoint_auth_methods_supported", is_list=True)98        self.validate_metadata(claims, "token_endpoint_auth_signing_alg_values_supported", is_list=True)99        self.validate_metadata(claims, "token_endpoint", is_required=True, is_url=True)100 101    def validate_metadata_authorization(self, claims, endpoint):102        claims.setdefault("response_types_supported",103                          list(filter(lambda x: x != "none", endpoint._response_types.keys())))104        claims.setdefault("response_modes_supported", ["query", "fragment"])105 106        # The OAuth2.0 Implicit flow is defined as a "grant type" but it is not107        # using the "token" endpoint, as such, we have to add it explicitly to108        # the list of "grant_types_supported" when enabled.109        if "token" in claims["response_types_supported"]:110            self._grant_types.append("implicit")111 112        self.validate_metadata(claims, "response_types_supported", is_required=True, is_list=True)113        self.validate_metadata(claims, "response_modes_supported", is_list=True)114        if "code" in claims["response_types_supported"]:115            code_grant = endpoint._response_types["code"]116            if not isinstance(code_grant, grant_types.AuthorizationCodeGrant) and hasattr(code_grant, "default_grant"):117                code_grant = code_grant.default_grant118 119            claims.setdefault("code_challenge_methods_supported",120                              list(code_grant._code_challenge_methods.keys()))121            self.validate_metadata(claims, "code_challenge_methods_supported", is_list=True)122        self.validate_metadata(claims, "authorization_endpoint", is_required=True, is_url=True)123 124    def validate_metadata_revocation(self, claims, endpoint):125        claims.setdefault("revocation_endpoint_auth_methods_supported",126                          ["client_secret_post", "client_secret_basic"])127 128        self.validate_metadata(claims, "revocation_endpoint_auth_methods_supported", is_list=True)129        self.validate_metadata(claims, "revocation_endpoint_auth_signing_alg_values_supported", is_list=True)130        self.validate_metadata(claims, "revocation_endpoint", is_required=True, is_url=True)131 132    def validate_metadata_introspection(self, claims, endpoint):133        claims.setdefault("introspection_endpoint_auth_methods_supported",134                          ["client_secret_post", "client_secret_basic"])135 136        self.validate_metadata(claims, "introspection_endpoint_auth_methods_supported", is_list=True)137        self.validate_metadata(claims, "introspection_endpoint_auth_signing_alg_values_supported", is_list=True)138        self.validate_metadata(claims, "introspection_endpoint", is_required=True, is_url=True)139 140    def validate_metadata_server(self):141        """142        Authorization servers can have metadata describing their143        configuration.  The following authorization server metadata values144        are used by this specification. More details can be found in145        `RFC8414 section 2`_ :146 147       issuer148          REQUIRED149 150       authorization_endpoint151          URL of the authorization server's authorization endpoint152          [`RFC6749#Authorization`_].  This is REQUIRED unless no grant types are supported153          that use the authorization endpoint.154 155       token_endpoint156          URL of the authorization server's token endpoint [`RFC6749#Token`_].  This157          is REQUIRED unless only the implicit grant type is supported.158 159       scopes_supported160          RECOMMENDED.161 162       response_types_supported163          REQUIRED.164 165       Other OPTIONAL fields:166          jwks_uri,167          registration_endpoint,168          response_modes_supported169 170       grant_types_supported171          OPTIONAL.  JSON array containing a list of the OAuth 2.0 grant172          type values that this authorization server supports.  The array173          values used are the same as those used with the "grant_types"174          parameter defined by "OAuth 2.0 Dynamic Client Registration175          Protocol" [`RFC7591`_].  If omitted, the default value is176          "["authorization_code", "implicit"]".177 178       token_endpoint_auth_methods_supported179 180       token_endpoint_auth_signing_alg_values_supported181 182       service_documentation183 184       ui_locales_supported185 186       op_policy_uri187 188       op_tos_uri189 190       revocation_endpoint191 192       revocation_endpoint_auth_methods_supported193 194       revocation_endpoint_auth_signing_alg_values_supported195 196       introspection_endpoint197 198       introspection_endpoint_auth_methods_supported199 200       introspection_endpoint_auth_signing_alg_values_supported201 202       code_challenge_methods_supported203 204       Additional authorization server metadata parameters MAY also be used.205       Some are defined by other specifications, such as OpenID Connect206       Discovery 1.0 [`OpenID.Discovery`_].207 208        .. _`RFC8414 section 2`: https://tools.ietf.org/html/rfc8414#section-2209        .. _`RFC6749#Authorization`: https://tools.ietf.org/html/rfc6749#section-3.1210        .. _`RFC6749#Token`: https://tools.ietf.org/html/rfc6749#section-3.2211        .. _`RFC7591`: https://tools.ietf.org/html/rfc7591212        .. _`OpenID.Discovery`: https://openid.net/specs/openid-connect-discovery-1_0.html213        """214        claims = copy.deepcopy(self.initial_claims)215        self.validate_metadata(claims, "issuer", is_required=True, is_issuer=True)216        self.validate_metadata(claims, "jwks_uri", is_url=True)217        self.validate_metadata(claims, "scopes_supported", is_list=True)218        self.validate_metadata(claims, "service_documentation", is_url=True)219        self.validate_metadata(claims, "ui_locales_supported", is_list=True)220        self.validate_metadata(claims, "op_policy_uri", is_url=True)221        self.validate_metadata(claims, "op_tos_uri", is_url=True)222 223        self._grant_types = []224        for endpoint in self.endpoints:225            if isinstance(endpoint, TokenEndpoint):226                self.validate_metadata_token(claims, endpoint)227            if isinstance(endpoint, AuthorizationEndpoint):228                self.validate_metadata_authorization(claims, endpoint)229            if isinstance(endpoint, RevocationEndpoint):230                self.validate_metadata_revocation(claims, endpoint)231            if isinstance(endpoint, IntrospectEndpoint):232                self.validate_metadata_introspection(claims, endpoint)233 234        # "grant_types_supported" is a combination of all OAuth2 grant types235        # allowed in the current provider implementation.236        claims.setdefault("grant_types_supported", self._grant_types)237        self.validate_metadata(claims, "grant_types_supported", is_list=True)238        return claims239