1""" 
    2oauthlib.oauth2.rfc6749.grant_types 
    3~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
    4""" 
    5import json 
    6import logging 
    7 
    8from .. import errors 
    9from .base import GrantTypeBase 
    10 
    11log = logging.getLogger(__name__) 
    12 
    13 
    14class ClientCredentialsGrant(GrantTypeBase): 
    15 
    16    """`Client Credentials Grant`_ 
    17 
    18    The client can request an access token using only its client 
    19    credentials (or other supported means of authentication) when the 
    20    client is requesting access to the protected resources under its 
    21    control, or those of another resource owner that have been previously 
    22    arranged with the authorization server (the method of which is beyond 
    23    the scope of this specification). 
    24 
    25    The client credentials grant type MUST only be used by confidential 
    26    clients:: 
    27 
    28        +---------+                                  +---------------+ 
    29        :         :                                  :               : 
    30        :         :>-- A - Client Authentication --->: Authorization : 
    31        : Client  :                                  :     Server    : 
    32        :         :<-- B ---- Access Token ---------<:               : 
    33        :         :                                  :               : 
    34        +---------+                                  +---------------+ 
    35 
    36    Figure 6: Client Credentials Flow 
    37 
    38    The flow illustrated in Figure 6 includes the following steps: 
    39 
    40    (A)  The client authenticates with the authorization server and 
    41            requests an access token from the token endpoint. 
    42 
    43    (B)  The authorization server authenticates the client, and if valid, 
    44            issues an access token. 
    45 
    46    .. _`Client Credentials Grant`: https://tools.ietf.org/html/rfc6749#section-4.4 
    47    """ 
    48 
    49    def create_token_response(self, request, token_handler): 
    50        """Return token or error in JSON format. 
    51 
    52        :param request: OAuthlib request. 
    53        :type request: oauthlib.common.Request 
    54        :param token_handler: A token handler instance, for example of type 
    55                              oauthlib.oauth2.BearerToken. 
    56 
    57        If the access token request is valid and authorized, the 
    58        authorization server issues an access token as described in 
    59        `Section 5.1`_.  A refresh token SHOULD NOT be included.  If the request 
    60        failed client authentication or is invalid, the authorization server 
    61        returns an error response as described in `Section 5.2`_. 
    62 
    63        .. _`Section 5.1`: https://tools.ietf.org/html/rfc6749#section-5.1 
    64        .. _`Section 5.2`: https://tools.ietf.org/html/rfc6749#section-5.2 
    65        """ 
    66        headers = self._get_default_headers() 
    67        try: 
    68            log.debug('Validating access token request, %r.', request) 
    69            self.validate_token_request(request) 
    70        except errors.OAuth2Error as e: 
    71            log.debug('Client error in token request. %s.', e) 
    72            headers.update(e.headers) 
    73            return headers, e.json, e.status_code 
    74 
    75        token = token_handler.create_token(request, refresh_token=False) 
    76 
    77        for modifier in self._token_modifiers: 
    78            token = modifier(token) 
    79 
    80        self.request_validator.save_token(token, request) 
    81 
    82        log.debug('Issuing token to client id %r (%r), %r.', 
    83                  request.client_id, request.client, token) 
    84        return headers, json.dumps(token), 200 
    85 
    86    def validate_token_request(self, request): 
    87        """ 
    88        :param request: OAuthlib request. 
    89        :type request: oauthlib.common.Request 
    90        """ 
    91        for validator in self.custom_validators.pre_token: 
    92            validator(request) 
    93 
    94        if not getattr(request, 'grant_type', None): 
    95            raise errors.InvalidRequestError('Request is missing grant type.', 
    96                                             request=request) 
    97 
    98        if not request.grant_type == 'client_credentials': 
    99            raise errors.UnsupportedGrantTypeError(request=request) 
    100 
    101        for param in ('grant_type', 'scope'): 
    102            if param in request.duplicate_params: 
    103                raise errors.InvalidRequestError(description='Duplicate %s parameter.' % param, 
    104                                                 request=request) 
    105 
    106        log.debug('Authenticating client, %r.', request) 
    107        if not self.request_validator.authenticate_client(request): 
    108            log.debug('Client authentication failed, %r.', request) 
    109            raise errors.InvalidClientError(request=request) 
    110        elif not hasattr(request.client, 'client_id'): 
    111            raise NotImplementedError('Authenticate client must set the ' 
    112                                      'request.client.client_id attribute ' 
    113                                      'in authenticate_client.') 
    114        # Ensure client is authorized use of this grant type 
    115        self.validate_grant_type(request) 
    116 
    117        request.client_id = request.client_id or request.client.client_id 
    118        log.debug('Authorizing access to client %r.', request.client_id) 
    119        self.validate_scopes(request) 
    120 
    121        for validator in self.custom_validators.post_token: 
    122            validator(request)