Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
endpoint.py171 linesDownload Raw Back to rfc8628
1from authlib.consts import default_json_headers2from authlib.common.security import generate_token3from authlib.common.urls import add_params_to_uri4 5 6class DeviceAuthorizationEndpoint:7    """This OAuth 2.0 [RFC6749] protocol extension enables OAuth clients to8    request user authorization from applications on devices that have9    limited input capabilities or lack a suitable browser.  Such devices10    include smart TVs, media consoles, picture frames, and printers,11    which lack an easy input method or a suitable browser required for12    traditional OAuth interactions. Here is the authorization flow::13 14        +----------+                                +----------------+15        |          |>---(A)-- Client Identifier --->|                |16        |          |                                |                |17        |          |<---(B)-- Device Code,      ---<|                |18        |          |          User Code,            |                |19        |  Device  |          & Verification URI    |                |20        |  Client  |                                |                |21        |          |  [polling]                     |                |22        |          |>---(E)-- Device Code       --->|                |23        |          |          & Client Identifier   |                |24        |          |                                |  Authorization |25        |          |<---(F)-- Access Token      ---<|     Server     |26        +----------+   (& Optional Refresh Token)   |                |27              v                                     |                |28              :                                     |                |29             (C) User Code & Verification URI       |                |30              :                                     |                |31              v                                     |                |32        +----------+                                |                |33        | End User |                                |                |34        |    at    |<---(D)-- End user reviews  --->|                |35        |  Browser |          authorization request |                |36        +----------+                                +----------------+37 38    This DeviceAuthorizationEndpoint is the implementation of step (A) and (B).39 40    (A) The client requests access from the authorization server and41        includes its client identifier in the request.42 43    (B) The authorization server issues a device code and an end-user44        code and provides the end-user verification URI.45    """46 47    ENDPOINT_NAME = 'device_authorization'48    CLIENT_AUTH_METHODS = ['client_secret_basic', 'client_secret_post', 'none']49 50    #: customize "user_code" type, string or digital51    USER_CODE_TYPE = 'string'52 53    #: The lifetime in seconds of the "device_code" and "user_code"54    EXPIRES_IN = 180055 56    #: The minimum amount of time in seconds that the client SHOULD57    #: wait between polling requests to the token endpoint.58    INTERVAL = 559 60    def __init__(self, server):61        self.server = server62 63    def __call__(self, request):64        # make it callable for authorization server65        # ``create_endpoint_response``66        return self.create_endpoint_response(request)67 68    def create_endpoint_request(self, request):69        return self.server.create_oauth2_request(request)70 71    def authenticate_client(self, request):72        """client_id is REQUIRED **if the client is not** authenticating with the73        authorization server as described in Section 3.2.1. of [RFC6749].74 75        This means the endpoint support "none" authentication method. In this case,76        this endpoint's auth methods are:77 78        - client_secret_basic79        - client_secret_post80        - none81 82        Developers change the value of ``CLIENT_AUTH_METHODS`` in subclass. For83        instance::84 85            class MyDeviceAuthorizationEndpoint(DeviceAuthorizationEndpoint):86                # only support ``client_secret_basic`` auth method87                CLIENT_AUTH_METHODS = ['client_secret_basic']88        """89        client = self.server.authenticate_client(90            request, self.CLIENT_AUTH_METHODS, self.ENDPOINT_NAME)91        request.client = client92        return client93 94    def create_endpoint_response(self, request):95        # https://tools.ietf.org/html/rfc8628#section-3.196 97        self.authenticate_client(request)98        self.server.validate_requested_scope(request.scope)99 100        device_code = self.generate_device_code()101        user_code = self.generate_user_code()102        verification_uri = self.get_verification_uri()103        verification_uri_complete = add_params_to_uri(104            verification_uri, [('user_code', user_code)])105 106        data = {107            'device_code': device_code,108            'user_code': user_code,109            'verification_uri': verification_uri,110            'verification_uri_complete': verification_uri_complete,111            'expires_in': self.EXPIRES_IN,112            'interval': self.INTERVAL,113        }114 115        self.save_device_credential(request.client_id, request.scope, data)116        return 200, data, default_json_headers117 118    def generate_user_code(self):119        """A method to generate ``user_code`` value for device authorization120        endpoint. This method will generate a random string like MQNA-JPOZ.121        Developers can rewrite this  method to create their own ``user_code``.122        """123        # https://tools.ietf.org/html/rfc8628#section-6.1124        if self.USER_CODE_TYPE == 'digital':125            return create_digital_user_code()126        return create_string_user_code()127 128    def generate_device_code(self):129        """A method to generate ``device_code`` value for device authorization130        endpoint. This method will generate a random string of 42 characters.131        Developers can rewrite this method to create their own ``device_code``.132        """133        return generate_token(42)134 135    def get_verification_uri(self):136        """Define the ``verification_uri`` of device authorization endpoint.137        Developers MUST implement this method in subclass::138 139            def get_verification_uri(self):140                return 'https://your-company.com/active'141        """142        raise NotImplementedError()143 144    def save_device_credential(self, client_id, scope, data):145        """Save device token into database for later use. Developers MUST146        implement this method in subclass::147 148            def save_device_credential(self, client_id, scope, data):149                item = DeviceCredential(150                    client_id=client_id,151                    scope=scope,152                    **data153                )154                item.save()155        """156        raise NotImplementedError()157 158 159def create_string_user_code():160    base = 'BCDFGHJKLMNPQRSTVWXZ'161    return '-'.join([generate_token(4, base), generate_token(4, base)])162 163 164def create_digital_user_code():165    base = '0123456789'166    return '-'.join([167        generate_token(3, base),168        generate_token(3, base),169        generate_token(3, base),170    ])171 
codekingpro/portable-devtools · Team Ai