124 lines
5.0 KiB
Python
124 lines
5.0 KiB
Python
![]() |
"""
|
||
|
oauthlib.oauth2.rfc6749.grant_types
|
||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
"""
|
||
|
import json
|
||
|
import logging
|
||
|
|
||
|
from .. import errors
|
||
|
from .base import GrantTypeBase
|
||
|
|
||
|
log = logging.getLogger(__name__)
|
||
|
|
||
|
|
||
|
class ClientCredentialsGrant(GrantTypeBase):
|
||
|
|
||
|
"""`Client Credentials Grant`_
|
||
|
|
||
|
The client can request an access token using only its client
|
||
|
credentials (or other supported means of authentication) when the
|
||
|
client is requesting access to the protected resources under its
|
||
|
control, or those of another resource owner that have been previously
|
||
|
arranged with the authorization server (the method of which is beyond
|
||
|
the scope of this specification).
|
||
|
|
||
|
The client credentials grant type MUST only be used by confidential
|
||
|
clients::
|
||
|
|
||
|
+---------+ +---------------+
|
||
|
: : : :
|
||
|
: :>-- A - Client Authentication --->: Authorization :
|
||
|
: Client : : Server :
|
||
|
: :<-- B ---- Access Token ---------<: :
|
||
|
: : : :
|
||
|
+---------+ +---------------+
|
||
|
|
||
|
Figure 6: Client Credentials Flow
|
||
|
|
||
|
The flow illustrated in Figure 6 includes the following steps:
|
||
|
|
||
|
(A) The client authenticates with the authorization server and
|
||
|
requests an access token from the token endpoint.
|
||
|
|
||
|
(B) The authorization server authenticates the client, and if valid,
|
||
|
issues an access token.
|
||
|
|
||
|
.. _`Client Credentials Grant`: https://tools.ietf.org/html/rfc6749#section-4.4
|
||
|
"""
|
||
|
|
||
|
def create_token_response(self, request, token_handler):
|
||
|
"""Return token or error in JSON format.
|
||
|
|
||
|
:param request: OAuthlib request.
|
||
|
:type request: oauthlib.common.Request
|
||
|
:param token_handler: A token handler instance, for example of type
|
||
|
oauthlib.oauth2.BearerToken.
|
||
|
|
||
|
If the access token request is valid and authorized, the
|
||
|
authorization server issues an access token as described in
|
||
|
`Section 5.1`_. A refresh token SHOULD NOT be included. If the request
|
||
|
failed client authentication or is invalid, the authorization server
|
||
|
returns an error response as described in `Section 5.2`_.
|
||
|
|
||
|
.. _`Section 5.1`: https://tools.ietf.org/html/rfc6749#section-5.1
|
||
|
.. _`Section 5.2`: https://tools.ietf.org/html/rfc6749#section-5.2
|
||
|
"""
|
||
|
headers = self._get_default_headers()
|
||
|
try:
|
||
|
log.debug('Validating access token request, %r.', request)
|
||
|
self.validate_token_request(request)
|
||
|
except errors.OAuth2Error as e:
|
||
|
log.debug('Client error in token request. %s.', e)
|
||
|
headers.update(e.headers)
|
||
|
return headers, e.json, e.status_code
|
||
|
|
||
|
token = token_handler.create_token(request, refresh_token=False)
|
||
|
|
||
|
for modifier in self._token_modifiers:
|
||
|
token = modifier(token)
|
||
|
|
||
|
self.request_validator.save_token(token, request)
|
||
|
|
||
|
log.debug('Issuing token to client id %r (%r), %r.',
|
||
|
request.client_id, request.client, token)
|
||
|
return headers, json.dumps(token), 200
|
||
|
|
||
|
def validate_token_request(self, request):
|
||
|
"""
|
||
|
:param request: OAuthlib request.
|
||
|
:type request: oauthlib.common.Request
|
||
|
"""
|
||
|
for validator in self.custom_validators.pre_token:
|
||
|
validator(request)
|
||
|
|
||
|
if not getattr(request, 'grant_type', None):
|
||
|
raise errors.InvalidRequestError('Request is missing grant type.',
|
||
|
request=request)
|
||
|
|
||
|
if not request.grant_type == 'client_credentials':
|
||
|
raise errors.UnsupportedGrantTypeError(request=request)
|
||
|
|
||
|
for param in ('grant_type', 'scope'):
|
||
|
if param in request.duplicate_params:
|
||
|
raise errors.InvalidRequestError(description='Duplicate %s parameter.' % param,
|
||
|
request=request)
|
||
|
|
||
|
log.debug('Authenticating client, %r.', request)
|
||
|
if not self.request_validator.authenticate_client(request):
|
||
|
log.debug('Client authentication failed, %r.', request)
|
||
|
raise errors.InvalidClientError(request=request)
|
||
|
else:
|
||
|
if not hasattr(request.client, 'client_id'):
|
||
|
raise NotImplementedError('Authenticate client must set the '
|
||
|
'request.client.client_id attribute '
|
||
|
'in authenticate_client.')
|
||
|
# Ensure client is authorized use of this grant type
|
||
|
self.validate_grant_type(request)
|
||
|
|
||
|
request.client_id = request.client_id or request.client.client_id
|
||
|
log.debug('Authorizing access to client %r.', request.client_id)
|
||
|
self.validate_scopes(request)
|
||
|
|
||
|
for validator in self.custom_validators.post_token:
|
||
|
validator(request)
|