codekingpro/portable-devtools
114k
1import base642from urllib.parse import quote3from authlib.common.urls import add_params_to_qs, add_params_to_uri4from authlib.common.encoding import to_bytes, to_native5from .rfc6749 import OAuth2Token6from .rfc6750 import add_bearer_token7 8 9def encode_client_secret_basic(client, method, uri, headers, body):10 text = f'{quote(client.client_id)}:{quote(client.client_secret)}'11 auth = to_native(base64.b64encode(to_bytes(text, 'latin1')))12 headers['Authorization'] = f'Basic {auth}'13 return uri, headers, body14 15 16def encode_client_secret_post(client, method, uri, headers, body):17 body = add_params_to_qs(body or '', [18 ('client_id', client.client_id),19 ('client_secret', client.client_secret or '')20 ])21 if 'Content-Length' in headers:22 headers['Content-Length'] = str(len(body))23 return uri, headers, body24 25 26def encode_none(client, method, uri, headers, body):27 if method == 'GET':28 uri = add_params_to_uri(uri, [('client_id', client.client_id)])29 return uri, headers, body30 body = add_params_to_qs(body, [('client_id', client.client_id)])31 if 'Content-Length' in headers:32 headers['Content-Length'] = str(len(body))33 return uri, headers, body34 35 36class ClientAuth:37 """Attaches OAuth Client Information to HTTP requests.38 39 :param client_id: Client ID, which you get from client registration.40 :param client_secret: Client Secret, which you get from registration.41 :param auth_method: Client auth method for token endpoint. The supported42 methods for now:43 44 * client_secret_basic (default)45 * client_secret_post46 * none47 """48 DEFAULT_AUTH_METHODS = {49 'client_secret_basic': encode_client_secret_basic,50 'client_secret_post': encode_client_secret_post,51 'none': encode_none,52 }53 54 def __init__(self, client_id, client_secret, auth_method=None):55 if auth_method is None:56 auth_method = 'client_secret_basic'57 58 self.client_id = client_id59 self.client_secret = client_secret60 61 if auth_method in self.DEFAULT_AUTH_METHODS:62 auth_method = self.DEFAULT_AUTH_METHODS[auth_method]63 64 self.auth_method = auth_method65 66 def prepare(self, method, uri, headers, body):67 return self.auth_method(self, method, uri, headers, body)68 69 70class TokenAuth:71 """Attach token information to HTTP requests.72 73 :param token: A dict or OAuth2Token instance of an OAuth 2.0 token74 :param token_placement: The placement of the token, default is ``header``,75 available choices:76 77 * header (default)78 * body79 * uri80 """81 DEFAULT_TOKEN_TYPE = 'bearer'82 SIGN_METHODS = {83 'bearer': add_bearer_token84 }85 86 def __init__(self, token, token_placement='header', client=None):87 self.token = OAuth2Token.from_dict(token)88 self.token_placement = token_placement89 self.client = client90 self.hooks = set()91 92 def set_token(self, token):93 self.token = OAuth2Token.from_dict(token)94 95 def prepare(self, uri, headers, body):96 token_type = self.token.get('token_type', self.DEFAULT_TOKEN_TYPE)97 sign = self.SIGN_METHODS[token_type.lower()]98 uri, headers, body = sign(99 self.token['access_token'],100 uri, headers, body,101 self.token_placement)102 103 for hook in self.hooks:104 uri, headers, body = hook(uri, headers, body)105 106 return uri, headers, body107 