1""" 
    2oauthlib.oauth2.rfc6749.grant_types 
    3~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
    4""" 
    5import logging 
    6 
    7from oauthlib import common 
    8 
    9from .. import errors 
    10from .base import GrantTypeBase 
    11 
    12log = logging.getLogger(__name__) 
    13 
    14 
    15class ImplicitGrant(GrantTypeBase): 
    16 
    17    """`Implicit Grant`_ 
    18 
    19    The implicit grant type is used to obtain access tokens (it does not 
    20    support the issuance of refresh tokens) and is optimized for public 
    21    clients known to operate a particular redirection URI.  These clients 
    22    are typically implemented in a browser using a scripting language 
    23    such as JavaScript. 
    24 
    25    Unlike the authorization code grant type, in which the client makes 
    26    separate requests for authorization and for an access token, the 
    27    client receives the access token as the result of the authorization 
    28    request. 
    29 
    30    The implicit grant type does not include client authentication, and 
    31    relies on the presence of the resource owner and the registration of 
    32    the redirection URI.  Because the access token is encoded into the 
    33    redirection URI, it may be exposed to the resource owner and other 
    34    applications residing on the same device:: 
    35 
    36        +----------+ 
    37        | Resource | 
    38        |  Owner   | 
    39        |          | 
    40        +----------+ 
    41             ^ 
    42             | 
    43            (B) 
    44        +----|-----+          Client Identifier     +---------------+ 
    45        |         -+----(A)-- & Redirection URI --->|               | 
    46        |  User-   |                                | Authorization | 
    47        |  Agent  -|----(B)-- User authenticates -->|     Server    | 
    48        |          |                                |               | 
    49        |          |<---(C)--- Redirection URI ----<|               | 
    50        |          |          with Access Token     +---------------+ 
    51        |          |            in Fragment 
    52        |          |                                +---------------+ 
    53        |          |----(D)--- Redirection URI ---->|   Web-Hosted  | 
    54        |          |          without Fragment      |     Client    | 
    55        |          |                                |    Resource   | 
    56        |     (F)  |<---(E)------- Script ---------<|               | 
    57        |          |                                +---------------+ 
    58        +-|--------+ 
    59          |    | 
    60         (A)  (G) Access Token 
    61          |    | 
    62          ^    v 
    63        +---------+ 
    64        |         | 
    65        |  Client | 
    66        |         | 
    67        +---------+ 
    68 
    69   Note: The lines illustrating steps (A) and (B) are broken into two 
    70   parts as they pass through the user-agent. 
    71 
    72   Figure 4: Implicit Grant Flow 
    73 
    74   The flow illustrated in Figure 4 includes the following steps: 
    75 
    76   (A)  The client initiates the flow by directing the resource owner's 
    77        user-agent to the authorization endpoint.  The client includes 
    78        its client identifier, requested scope, local state, and a 
    79        redirection URI to which the authorization server will send the 
    80        user-agent back once access is granted (or denied). 
    81 
    82   (B)  The authorization server authenticates the resource owner (via 
    83        the user-agent) and establishes whether the resource owner 
    84        grants or denies the client's access request. 
    85 
    86   (C)  Assuming the resource owner grants access, the authorization 
    87        server redirects the user-agent back to the client using the 
    88        redirection URI provided earlier.  The redirection URI includes 
    89        the access token in the URI fragment. 
    90 
    91   (D)  The user-agent follows the redirection instructions by making a 
    92        request to the web-hosted client resource (which does not 
    93        include the fragment per [RFC2616]).  The user-agent retains the 
    94        fragment information locally. 
    95 
    96   (E)  The web-hosted client resource returns a web page (typically an 
    97        HTML document with an embedded script) capable of accessing the 
    98        full redirection URI including the fragment retained by the 
    99        user-agent, and extracting the access token (and other 
    100        parameters) contained in the fragment. 
    101 
    102   (F)  The user-agent executes the script provided by the web-hosted 
    103        client resource locally, which extracts the access token. 
    104 
    105   (G)  The user-agent passes the access token to the client. 
    106 
    107    See `Section 10.3`_ and `Section 10.16`_ for important security considerations 
    108    when using the implicit grant. 
    109 
    110    .. _`Implicit Grant`: https://tools.ietf.org/html/rfc6749#section-4.2 
    111    .. _`Section 10.3`: https://tools.ietf.org/html/rfc6749#section-10.3 
    112    .. _`Section 10.16`: https://tools.ietf.org/html/rfc6749#section-10.16 
    113    """ 
    114 
    115    response_types = ['token'] 
    116    grant_allows_refresh_token = False 
    117 
    118    def create_authorization_response(self, request, token_handler): 
    119        """Create an authorization response. 
    120 
    121        :param request: OAuthlib request. 
    122        :type request: oauthlib.common.Request 
    123        :param token_handler: A token handler instance, for example of type 
    124                              oauthlib.oauth2.BearerToken. 
    125 
    126        The client constructs the request URI by adding the following 
    127        parameters to the query component of the authorization endpoint URI 
    128        using the "application/x-www-form-urlencoded" format, per `Appendix B`_: 
    129 
    130        response_type 
    131                REQUIRED.  Value MUST be set to "token" for standard OAuth2 implicit flow 
    132                           or "id_token token" or just "id_token" for OIDC implicit flow 
    133 
    134        client_id 
    135                REQUIRED.  The client identifier as described in `Section 2.2`_. 
    136 
    137        redirect_uri 
    138                OPTIONAL.  As described in `Section 3.1.2`_. 
    139 
    140        scope 
    141                OPTIONAL.  The scope of the access request as described by 
    142                `Section 3.3`_. 
    143 
    144        state 
    145                RECOMMENDED.  An opaque value used by the client to maintain 
    146                state between the request and callback.  The authorization 
    147                server includes this value when redirecting the user-agent back 
    148                to the client.  The parameter SHOULD be used for preventing 
    149                cross-site request forgery as described in `Section 10.12`_. 
    150 
    151        The authorization server validates the request to ensure that all 
    152        required parameters are present and valid.  The authorization server 
    153        MUST verify that the redirection URI to which it will redirect the 
    154        access token matches a redirection URI registered by the client as 
    155        described in `Section 3.1.2`_. 
    156 
    157        .. _`Section 2.2`: https://tools.ietf.org/html/rfc6749#section-2.2 
    158        .. _`Section 3.1.2`: https://tools.ietf.org/html/rfc6749#section-3.1.2 
    159        .. _`Section 3.3`: https://tools.ietf.org/html/rfc6749#section-3.3 
    160        .. _`Section 10.12`: https://tools.ietf.org/html/rfc6749#section-10.12 
    161        .. _`Appendix B`: https://tools.ietf.org/html/rfc6749#appendix-B 
    162        """ 
    163        return self.create_token_response(request, token_handler) 
    164 
    165    def create_token_response(self, request, token_handler): 
    166        """Return token or error embedded in the URI fragment. 
    167 
    168        :param request: OAuthlib request. 
    169        :type request: oauthlib.common.Request 
    170        :param token_handler: A token handler instance, for example of type 
    171                              oauthlib.oauth2.BearerToken. 
    172 
    173        If the resource owner grants the access request, the authorization 
    174        server issues an access token and delivers it to the client by adding 
    175        the following parameters to the fragment component of the redirection 
    176        URI using the "application/x-www-form-urlencoded" format, per 
    177        `Appendix B`_: 
    178 
    179        access_token 
    180                REQUIRED.  The access token issued by the authorization server. 
    181 
    182        token_type 
    183                REQUIRED.  The type of the token issued as described in 
    184                `Section 7.1`_.  Value is case insensitive. 
    185 
    186        expires_in 
    187                RECOMMENDED.  The lifetime in seconds of the access token.  For 
    188                example, the value "3600" denotes that the access token will 
    189                expire in one hour from the time the response was generated. 
    190                If omitted, the authorization server SHOULD provide the 
    191                expiration time via other means or document the default value. 
    192 
    193        scope 
    194                OPTIONAL, if identical to the scope requested by the client; 
    195                otherwise, REQUIRED.  The scope of the access token as 
    196                described by `Section 3.3`_. 
    197 
    198        state 
    199                REQUIRED if the "state" parameter was present in the client 
    200                authorization request.  The exact value received from the 
    201                client. 
    202 
    203        The authorization server MUST NOT issue a refresh token. 
    204 
    205        .. _`Appendix B`: https://tools.ietf.org/html/rfc6749#appendix-B 
    206        .. _`Section 3.3`: https://tools.ietf.org/html/rfc6749#section-3.3 
    207        .. _`Section 7.1`: https://tools.ietf.org/html/rfc6749#section-7.1 
    208        """ 
    209        try: 
    210            self.validate_token_request(request) 
    211 
    212        # If the request fails due to a missing, invalid, or mismatching 
    213        # redirection URI, or if the client identifier is missing or invalid, 
    214        # the authorization server SHOULD inform the resource owner of the 
    215        # error and MUST NOT automatically redirect the user-agent to the 
    216        # invalid redirection URI. 
    217        except errors.FatalClientError as e: 
    218            log.debug('Fatal client error during validation of %r. %r.', 
    219                      request, e) 
    220            raise 
    221 
    222        # If the resource owner denies the access request or if the request 
    223        # fails for reasons other than a missing or invalid redirection URI, 
    224        # the authorization server informs the client by adding the following 
    225        # parameters to the fragment component of the redirection URI using the 
    226        # "application/x-www-form-urlencoded" format, per Appendix B: 
    227        # https://tools.ietf.org/html/rfc6749#appendix-B 
    228        except errors.OAuth2Error as e: 
    229            log.debug('Client error during validation of %r. %r.', request, e) 
    230            return {'Location': common.add_params_to_uri(request.redirect_uri, e.twotuples, 
    231                                                         fragment=True)}, None, 302 
    232 
    233        # In OIDC implicit flow it is possible to have a request_type that does not include the access_token! 
    234        # "id_token token" - return the access token and the id token 
    235        # "id_token" - don't return the access token 
    236        token = token_handler.create_token(request, refresh_token=False) if 'token' in request.response_type.split() else {} 
    237 
    238        if request.state is not None: 
    239            token['state'] = request.state 
    240 
    241        for modifier in self._token_modifiers: 
    242            token = modifier(token, token_handler, request) 
    243 
    244        # In OIDC implicit flow it is possible to have a request_type that does 
    245        # not include the access_token! In this case there is no need to save a token. 
    246        if "token" in request.response_type.split(): 
    247            self.request_validator.save_token(token, request) 
    248 
    249        return self.prepare_authorization_response( 
    250            request, token, {}, None, 302) 
    251 
    252    def validate_authorization_request(self, request): 
    253        """ 
    254        :param request: OAuthlib request. 
    255        :type request: oauthlib.common.Request 
    256        """ 
    257        return self.validate_token_request(request) 
    258 
    259    def validate_token_request(self, request): 
    260        """Check the token request for normal and fatal errors. 
    261 
    262        :param request: OAuthlib request. 
    263        :type request: oauthlib.common.Request 
    264 
    265        This method is very similar to validate_authorization_request in 
    266        the AuthorizationCodeGrant but differ in a few subtle areas. 
    267 
    268        A normal error could be a missing response_type parameter or the client 
    269        attempting to access scope it is not allowed to ask authorization for. 
    270        Normal errors can safely be included in the redirection URI and 
    271        sent back to the client. 
    272 
    273        Fatal errors occur when the client_id or redirect_uri is invalid or 
    274        missing. These must be caught by the provider and handled, how this 
    275        is done is outside of the scope of OAuthLib but showing an error 
    276        page describing the issue is a good idea. 
    277        """ 
    278 
    279        # First check for fatal errors 
    280 
    281        # If the request fails due to a missing, invalid, or mismatching 
    282        # redirection URI, or if the client identifier is missing or invalid, 
    283        # the authorization server SHOULD inform the resource owner of the 
    284        # error and MUST NOT automatically redirect the user-agent to the 
    285        # invalid redirection URI. 
    286 
    287        # First check duplicate parameters 
    288        for param in ('client_id', 'response_type', 'redirect_uri', 'scope', 'state'): 
    289            try: 
    290                duplicate_params = request.duplicate_params 
    291            except ValueError: 
    292                raise errors.InvalidRequestFatalError(description='Unable to parse query string', request=request) 
    293            if param in duplicate_params: 
    294                raise errors.InvalidRequestFatalError(description='Duplicate %s parameter.' % param, request=request) 
    295 
    296        # REQUIRED. The client identifier as described in Section 2.2. 
    297        # https://tools.ietf.org/html/rfc6749#section-2.2 
    298        if not request.client_id: 
    299            raise errors.MissingClientIdError(request=request) 
    300 
    301        if not self.request_validator.validate_client_id(request.client_id, request): 
    302            raise errors.InvalidClientIdError(request=request) 
    303 
    304        # OPTIONAL. As described in Section 3.1.2. 
    305        # https://tools.ietf.org/html/rfc6749#section-3.1.2 
    306        self._handle_redirects(request) 
    307 
    308        # Then check for normal errors. 
    309 
    310        request_info = self._run_custom_validators(request, 
    311                                                   self.custom_validators.all_pre) 
    312 
    313        # If the resource owner denies the access request or if the request 
    314        # fails for reasons other than a missing or invalid redirection URI, 
    315        # the authorization server informs the client by adding the following 
    316        # parameters to the fragment component of the redirection URI using the 
    317        # "application/x-www-form-urlencoded" format, per Appendix B. 
    318        # https://tools.ietf.org/html/rfc6749#appendix-B 
    319 
    320        # Note that the correct parameters to be added are automatically 
    321        # populated through the use of specific exceptions 
    322 
    323        # REQUIRED. 
    324        if request.response_type is None: 
    325            raise errors.MissingResponseTypeError(request=request) 
    326        # Value MUST be one of our registered types: "token" by default or if using OIDC "id_token" or "id_token token" 
    327        elif not set(request.response_type.split()).issubset(self.response_types): 
    328            raise errors.UnsupportedResponseTypeError(request=request) 
    329 
    330        log.debug('Validating use of response_type token for client %r (%r).', 
    331                  request.client_id, request.client) 
    332        if not self.request_validator.validate_response_type(request.client_id, 
    333                                                             request.response_type, 
    334                                                             request.client, request): 
    335 
    336            log.debug('Client %s is not authorized to use response_type %s.', 
    337                      request.client_id, request.response_type) 
    338            raise errors.UnauthorizedClientError(request=request) 
    339 
    340        # OPTIONAL. The scope of the access request as described by Section 3.3 
    341        # https://tools.ietf.org/html/rfc6749#section-3.3 
    342        self.validate_scopes(request) 
    343 
    344        request_info.update({ 
    345            'client_id': request.client_id, 
    346            'redirect_uri': request.redirect_uri, 
    347            'response_type': request.response_type, 
    348            'state': request.state, 
    349            'request': request, 
    350        }) 
    351 
    352        request_info = self._run_custom_validators( 
    353            request, 
    354            self.custom_validators.all_post, 
    355            request_info 
    356        ) 
    357 
    358        return request.scopes, request_info 
    359 
    360    def _run_custom_validators(self, 
    361                               request, 
    362                               validations, 
    363                               request_info=None): 
    364        # Make a copy so we don't modify the existing request_info dict 
    365        request_info = {} if request_info is None else request_info.copy() 
    366        # For implicit grant, auth_validators and token_validators are 
    367        # basically equivalent since the token is returned from the 
    368        # authorization endpoint. 
    369        for validator in validations: 
    370            result = validator(request) 
    371            if result is not None: 
    372                request_info.update(result) 
    373        return request_info