Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
tokens.py351 linesDownload Raw Back to rfc6749
1"""2oauthlib.oauth2.rfc6749.tokens3~~~~~~~~~~~~~~~~~~~~~~~~~~~~~4 5This module contains methods for adding two types of access tokens to requests.6 7- Bearer https://tools.ietf.org/html/rfc67508- MAC https://tools.ietf.org/html/draft-ietf-oauth-v2-http-mac-019"""10import hashlib11import hmac12import warnings13from binascii import b2a_base6414from urllib.parse import urlparse15 16from oauthlib import common17from oauthlib.common import add_params_to_qs, add_params_to_uri18 19from . import utils20 21 22class OAuth2Token(dict):23 24    def __init__(self, params, old_scope=None):25        super().__init__(params)26        self._new_scope = None27        if params.get('scope'):28            self._new_scope = set(utils.scope_to_list(params['scope']))29        if old_scope is not None:30            self._old_scope = set(utils.scope_to_list(old_scope))31            if self._new_scope is None:32                # the rfc says that if the scope hasn't changed, it's optional33                # in params so set the new scope to the old scope34                self._new_scope = self._old_scope35        else:36            self._old_scope = self._new_scope37 38    @property39    def scope_changed(self):40        return self._new_scope != self._old_scope41 42    @property43    def old_scope(self):44        return utils.list_to_scope(self._old_scope)45 46    @property47    def old_scopes(self):48        return list(self._old_scope)49 50    @property51    def scope(self):52        return utils.list_to_scope(self._new_scope)53 54    @property55    def scopes(self):56        return list(self._new_scope)57 58    @property59    def missing_scopes(self):60        return list(self._old_scope - self._new_scope)61 62    @property63    def additional_scopes(self):64        return list(self._new_scope - self._old_scope)65 66 67def prepare_mac_header(token, uri, key, http_method,68                       nonce=None,69                       headers=None,70                       body=None,71                       ext='',72                       hash_algorithm='hmac-sha-1',73                       issue_time=None,74                       draft=0):75    """Add an `MAC Access Authentication`_ signature to headers.76 77    Unlike OAuth 1, this HMAC signature does not require inclusion of the78    request payload/body, neither does it use a combination of client_secret79    and token_secret but rather a mac_key provided together with the access80    token.81 82    Currently two algorithms are supported, "hmac-sha-1" and "hmac-sha-256",83    `extension algorithms`_ are not supported.84 85    Example MAC Authorization header, linebreaks added for clarity86 87    Authorization: MAC id="h480djs93hd8",88                       nonce="1336363200:dj83hs9s",89                       mac="bhCQXTVyfj5cmA9uKkPFx1zeOXM="90 91    .. _`MAC Access Authentication`: https://tools.ietf.org/html/draft-ietf-oauth-v2-http-mac-0192    .. _`extension algorithms`: https://tools.ietf.org/html/draft-ietf-oauth-v2-http-mac-01#section-7.193 94    :param token:95    :param uri: Request URI.96    :param key: MAC given provided by token endpoint.97    :param http_method: HTTP Request method.98    :param nonce:99    :param headers: Request headers as a dictionary.100    :param body:101    :param ext:102    :param hash_algorithm: HMAC algorithm provided by token endpoint.103    :param issue_time: Time when the MAC credentials were issued (datetime).104    :param draft: MAC authentication specification version.105    :return: headers dictionary with the authorization field added.106    """107    http_method = http_method.upper()108    host, port = utils.host_from_uri(uri)109 110    if hash_algorithm.lower() == 'hmac-sha-1':111        h = hashlib.sha1112    elif hash_algorithm.lower() == 'hmac-sha-256':113        h = hashlib.sha256114    else:115        raise ValueError('unknown hash algorithm')116 117    if draft == 0:118        nonce = nonce or '{}:{}'.format(utils.generate_age(issue_time),119                                          common.generate_nonce())120    else:121        ts = common.generate_timestamp()122        nonce = common.generate_nonce()123 124    sch, net, path, par, query, fra = urlparse(uri)125 126    request_uri = path + '?' + query if query else path127 128    # Hash the body/payload129    if body is not None and draft == 0:130        body = body.encode('utf-8')131        bodyhash = b2a_base64(h(body).digest())[:-1].decode('utf-8')132    else:133        bodyhash = ''134 135    # Create the normalized base string136    base = []137    if draft == 0:138        base.append(nonce)139    else:140        base.append(ts)141        base.append(nonce)142    base.append(http_method.upper())143    base.append(request_uri)144    base.append(host)145    base.append(port)146    if draft == 0:147        base.append(bodyhash)148    base.append(ext or '')149    base_string = '\n'.join(base) + '\n'150 151    # hmac struggles with unicode strings - http://bugs.python.org/issue5285152    if isinstance(key, str):153        key = key.encode('utf-8')154    sign = hmac.new(key, base_string.encode('utf-8'), h)155    sign = b2a_base64(sign.digest())[:-1].decode('utf-8')156 157    header = []158    header.append('MAC id="%s"' % token)159    if draft != 0:160        header.append('ts="%s"' % ts)161    header.append('nonce="%s"' % nonce)162    if bodyhash:163        header.append('bodyhash="%s"' % bodyhash)164    if ext:165        header.append('ext="%s"' % ext)166    header.append('mac="%s"' % sign)167 168    headers = headers or {}169    headers['Authorization'] = ', '.join(header)170    return headers171 172 173def prepare_bearer_uri(token, uri):174    """Add a `Bearer Token`_ to the request URI.175    Not recommended, use only if client can't use authorization header or body.176 177    http://www.example.com/path?access_token=h480djs93hd8178 179    .. _`Bearer Token`: https://tools.ietf.org/html/rfc6750180 181    :param token:182    :param uri:183    """184    return add_params_to_uri(uri, [(('access_token', token))])185 186 187def prepare_bearer_headers(token, headers=None):188    """Add a `Bearer Token`_ to the request URI.189    Recommended method of passing bearer tokens.190 191    Authorization: Bearer h480djs93hd8192 193    .. _`Bearer Token`: https://tools.ietf.org/html/rfc6750194 195    :param token:196    :param headers:197    """198    headers = headers or {}199    headers['Authorization'] = 'Bearer %s' % token200    return headers201 202 203def prepare_bearer_body(token, body=''):204    """Add a `Bearer Token`_ to the request body.205 206    access_token=h480djs93hd8207 208    .. _`Bearer Token`: https://tools.ietf.org/html/rfc6750209 210    :param token:211    :param body:212    """213    return add_params_to_qs(body, [(('access_token', token))])214 215 216def random_token_generator(request, refresh_token=False):217    """218    :param request: OAuthlib request.219    :type request: oauthlib.common.Request220    :param refresh_token:221    """222    return common.generate_token()223 224 225def signed_token_generator(private_pem, **kwargs):226    """227    :param private_pem:228    """229    def signed_token_generator(request):230        request.claims = kwargs231        return common.generate_signed_token(private_pem, request)232 233    return signed_token_generator234 235 236def get_token_from_header(request):237    """238    Helper function to extract a token from the request header.239 240    :param request: OAuthlib request.241    :type request: oauthlib.common.Request242    :return: Return the token or None if the Authorization header is malformed.243    """244    token = None245 246    if 'Authorization' in request.headers:247        split_header = request.headers.get('Authorization').split()248        if len(split_header) == 2 and split_header[0].lower() == 'bearer':249            token = split_header[1]250    else:251        token = request.access_token252 253    return token254 255 256class TokenBase:257    __slots__ = ()258 259    def __call__(self, request, refresh_token=False):260        raise NotImplementedError('Subclasses must implement this method.')261 262    def validate_request(self, request):263        """264        :param request: OAuthlib request.265        :type request: oauthlib.common.Request266        """267        raise NotImplementedError('Subclasses must implement this method.')268 269    def estimate_type(self, request):270        """271        :param request: OAuthlib request.272        :type request: oauthlib.common.Request273        """274        raise NotImplementedError('Subclasses must implement this method.')275 276 277class BearerToken(TokenBase):278    __slots__ = (279        'request_validator', 'token_generator',280        'refresh_token_generator', 'expires_in'281    )282 283    def __init__(self, request_validator=None, token_generator=None,284                 expires_in=None, refresh_token_generator=None):285        self.request_validator = request_validator286        self.token_generator = token_generator or random_token_generator287        self.refresh_token_generator = (288            refresh_token_generator or self.token_generator289        )290        self.expires_in = expires_in or 3600291 292    def create_token(self, request, refresh_token=False, **kwargs):293        """294        Create a BearerToken, by default without refresh token.295 296        :param request: OAuthlib request.297        :type request: oauthlib.common.Request298        :param refresh_token:299        """300        if "save_token" in kwargs:301            warnings.warn("`save_token` has been deprecated, it was not called internally."302                          "If you do, call `request_validator.save_token()` instead.",303                          DeprecationWarning)304 305        expires_in = self.expires_in(request) if callable(self.expires_in) else self.expires_in306 307        request.expires_in = expires_in308 309        token = {310            'access_token': self.token_generator(request),311            'expires_in': expires_in,312            'token_type': 'Bearer',313        }314 315        # If provided, include - this is optional in some cases https://tools.ietf.org/html/rfc6749#section-3.3 but316        # there is currently no mechanism to coordinate issuing a token for only a subset of the requested scopes so317        # all tokens issued are for the entire set of requested scopes.318        if request.scopes is not None:319            token['scope'] = ' '.join(request.scopes)320 321        if refresh_token:322            if (request.refresh_token and323                    not self.request_validator.rotate_refresh_token(request)):324                token['refresh_token'] = request.refresh_token325            else:326                token['refresh_token'] = self.refresh_token_generator(request)327 328        token.update(request.extra_credentials or {})329        return OAuth2Token(token)330 331    def validate_request(self, request):332        """333        :param request: OAuthlib request.334        :type request: oauthlib.common.Request335        """336        token = get_token_from_header(request)337        return self.request_validator.validate_bearer_token(338            token, request.scopes, request)339 340    def estimate_type(self, request):341        """342        :param request: OAuthlib request.343        :type request: oauthlib.common.Request344        """345        if request.headers.get('Authorization', '').split(' ')[0].lower() == 'bearer':346            return 9347        elif request.access_token is not None:348            return 5349        else:350            return 0351 
codekingpro/portable-devtools · Team Ai