1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
|
"""authlib.oauth2.rfc6749.authenticate_client.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Registry of client authentication methods, with 3 built-in methods:
1. client_secret_basic
2. client_secret_post
3. none
The "client_secret_basic" method is used a lot in examples of `RFC6749`_,
but the concept of naming are introduced in `RFC7591`_.
.. _`RFC6749`: https://tools.ietf.org/html/rfc6749
.. _`RFC7591`: https://tools.ietf.org/html/rfc7591
"""
import logging
from .errors import InvalidClientError
from .util import extract_basic_authorization
log = logging.getLogger(__name__)
__all__ = ["ClientAuthentication"]
class ClientAuthentication:
def __init__(self, query_client):
self.query_client = query_client
self._methods = {
"none": authenticate_none,
"client_secret_basic": authenticate_client_secret_basic,
"client_secret_post": authenticate_client_secret_post,
}
def register(self, method, func):
self._methods[method] = func
def authenticate(self, request, methods, endpoint):
for method in methods:
func = self._methods[method]
client = func(self.query_client, request)
if client and client.check_endpoint_auth_method(method, endpoint):
request.auth_method = method
return client
if "client_secret_basic" in methods:
raise InvalidClientError(
status_code=401,
description=f"The client cannot authenticate with methods: {methods}",
)
raise InvalidClientError(
description=f"The client cannot authenticate with methods: {methods}",
)
def __call__(self, request, methods, endpoint="token"):
return self.authenticate(request, methods, endpoint)
def authenticate_client_secret_basic(query_client, request):
"""Authenticate client by ``client_secret_basic`` method. The client
uses HTTP Basic for authentication.
"""
client_id, client_secret = extract_basic_authorization(request.headers)
if client_id and client_secret:
client = _validate_client(query_client, client_id, 401)
if client.check_client_secret(client_secret):
log.debug(f'Authenticate {client_id} via "client_secret_basic" success')
return client
log.debug(f'Authenticate {client_id} via "client_secret_basic" failed')
def authenticate_client_secret_post(query_client, request):
"""Authenticate client by ``client_secret_post`` method. The client
uses POST parameters for authentication.
"""
data = request.form
client_id = data.get("client_id")
client_secret = data.get("client_secret")
if client_id and client_secret:
client = _validate_client(query_client, client_id)
if client.check_client_secret(client_secret):
log.debug(f'Authenticate {client_id} via "client_secret_post" success')
return client
log.debug(f'Authenticate {client_id} via "client_secret_post" failed')
def authenticate_none(query_client, request):
"""Authenticate public client by ``none`` method. The client
does not have a client secret.
"""
client_id = request.payload.client_id
if client_id and not request.payload.data.get("client_secret"):
client = _validate_client(query_client, client_id)
log.debug(f'Authenticate {client_id} via "none" success')
return client
log.debug(f'Authenticate {client_id} via "none" failed')
def _validate_client(query_client, client_id, status_code=400):
if client_id is None:
raise InvalidClientError(
status_code=status_code,
description="Missing 'client_id' parameter.",
)
client = query_client(client_id)
if not client:
raise InvalidClientError(
status_code=status_code,
description="The client does not exist on this server.",
)
return client
|