From 470c117644b515f326d2aaa824c16507698a23b0 Mon Sep 17 00:00:00 2001 From: Roland Hedberg Date: Sat, 13 Nov 2021 11:12:30 +0100 Subject: [PATCH] Added add_on documentation. Fixed some minor things. --- doc/source/add_on/dpop.rst | 51 +++++++++++++++ doc/source/add_on/index.rst | 16 +++++ doc/source/add_on/pkce.rst | 62 +++++++++++++++++++ doc/source/add_on/pushed_authorization.rst | 17 +++++ doc/source/index.rst | 2 +- src/oidcrp/oauth2/add_on/dpop.py | 7 +-- .../oauth2/add_on/pushed_authorization.py | 2 +- 7 files changed, 151 insertions(+), 6 deletions(-) create mode 100644 doc/source/add_on/dpop.rst create mode 100644 doc/source/add_on/index.rst create mode 100644 doc/source/add_on/pkce.rst create mode 100644 doc/source/add_on/pushed_authorization.rst diff --git a/doc/source/add_on/dpop.rst b/doc/source/add_on/dpop.rst new file mode 100644 index 0000000..f5dae1b --- /dev/null +++ b/doc/source/add_on/dpop.rst @@ -0,0 +1,51 @@ +.. _dpop: + +************************************ +Demonstration of Proof-of-possession +************************************ + +------------ +Introduction +------------ + +In the traditional mechanism, API access is allowed only if the access +token presented by the client application is valid. However, if a +mechanism of PoP (Proof of Possession) such as DPoP is employed, +the API implementation additionally checks whether the client +application presenting the access token is the valid owner of the +access token (= whether the client application is the same one that +the access token has been issued to). If the client is not the valid +owner of the access token, the API access is rejected. + +The `DPOP Internet draft`_ describes a mechanism for sender-constraining +OAuth 2.0 tokens via a proof-of-possession mechanism on the application +level. This mechanism allows for the detection of replay attacks with +access and refresh tokens. + +------------- +Configuration +------------- + +The only thing you can chose is the signing algorithms. +There are no default algorithms. + +------- +Example +------- + +What you have to do is to add a *dpop* section to an *add_ons* section +in a client configuration. + +.. code:: python + + 'add_ons': { + "dpop": { + "function": "oidcrp.oauth2.add_on.dpop.add_support", + "kwargs": { + "signing_algorithms": ["ES256", "ES512"] + } + } + } + + +.. _DPOP Internet draft: https://datatracker.ietf.org/doc/draft-ietf-oauth-dpop/ \ No newline at end of file diff --git a/doc/source/add_on/index.rst b/doc/source/add_on/index.rst new file mode 100644 index 0000000..570451c --- /dev/null +++ b/doc/source/add_on/index.rst @@ -0,0 +1,16 @@ +OIDCRP add on documentation +=========================== + +.. toctree:: + + dpop.rst + pkce.rst + pushed_authorization.rst + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/doc/source/add_on/pkce.rst b/doc/source/add_on/pkce.rst new file mode 100644 index 0000000..36e85c2 --- /dev/null +++ b/doc/source/add_on/pkce.rst @@ -0,0 +1,62 @@ +.. _pkce: + +*************************** +Proof Key for Code Exchange +*************************** + +------------ +Introduction +------------ + + + +OAuth 2.0 public clients utilizing the Authorization Code Grant are +susceptible to the authorization code interception attack. `RFC7636`_ +describes the attack as well as a technique to mitigate +against the threat through the use of Proof Key for Code Exchange +(PKCE, pronounced "pixy"). + +------------- +Configuration +------------- + +You can set *code_challenge_length* and *code_challenge_method*. +Both have defaults: + +- code_challenge_length: 64 and +- code_challenge_method: S256 + +*S256* is mandatory to implement so there should be good reasons for +not choosing it. To other defined method is *plain*. *plain* should only +be used when you rely on the operating system and transport +security not to disclose the request to an attacker. + +The security model relies on the fact that the code verifier is not +learned or guessed by the attacker. It is vitally important to +adhere to this principle. As such, the code verifier has to be +created in such a manner that it is cryptographically random and has +high entropy that it is not practical for the attacker to guess. + +The client SHOULD create a "code_verifier" with a minimum of 256 bits +of entropy. This can be done by having a suitable random number +generator create a 32-octet sequence. + +code_challenge_length is the length of that sequence. + +------- +Example +------- + +.. code:: python + + "add_ons": { + "pkce": { + "function": "oidcrp.oauth2.add_on.pkce.add_support", + "kwargs": { + "code_challenge_length": 64, + "code_challenge_method": "S256" + } + } + } + +.. _RFC7636: https://datatracker.ietf.org/doc/html/rfc7636 \ No newline at end of file diff --git a/doc/source/add_on/pushed_authorization.rst b/doc/source/add_on/pushed_authorization.rst new file mode 100644 index 0000000..2b65fb8 --- /dev/null +++ b/doc/source/add_on/pushed_authorization.rst @@ -0,0 +1,17 @@ +.. _par: + +******************** +Pushed Authorization +******************** + +------------ +Introduction +------------ + +https://tools.ietf.org/id/draft-lodderstedt-oauth-par-00.html + +The Internet draft defines the pushed authorization request endpoint, +which allows clients to push the payload of an OAuth 2.0 authorization +request to the authorization server via a direct request and provides +them with a request URI that is used as reference to the data in a +subsequent authorization request. \ No newline at end of file diff --git a/doc/source/index.rst b/doc/source/index.rst index 19a435a..e04c75b 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -13,7 +13,7 @@ Welcome to oidcrp's documentation! rp_handler.rst oidcrp.rst - + add_on/index.rst Indices and tables ================== diff --git a/src/oidcrp/oauth2/add_on/dpop.py b/src/oidcrp/oauth2/add_on/dpop.py index 92bd575..13981e1 100644 --- a/src/oidcrp/oauth2/add_on/dpop.py +++ b/src/oidcrp/oauth2/add_on/dpop.py @@ -1,5 +1,4 @@ from typing import Optional -from typing import Union import uuid from cryptojwt.jwk.jwk import key_from_jwk_dict @@ -143,12 +142,12 @@ def dpop_header(service_context: ServiceContext, return headers -def add_support(services, signing_algorithms: Optional[list] = None): +def add_support(services, signing_algorithms): """ Add the necessary pieces to make pushed authorization happen. :param services: A dictionary with all the services the client has access to. - :param signing_algorithms: + :param signing_algorithms: Allowed signing algorithms, there is no default algorithms """ # Access token request should use DPoP header @@ -163,4 +162,4 @@ def add_support(services, signing_algorithms: Optional[list] = None): # The same for userinfo requests _userinfo_service = services.get("userinfo") if _userinfo_service: - _userinfo_service.construct_extra_headers.append(dpop_header) + _userinfo_service.construct_extra_headers.append(dpop_header) \ No newline at end of file diff --git a/src/oidcrp/oauth2/add_on/pushed_authorization.py b/src/oidcrp/oauth2/add_on/pushed_authorization.py index 4378041..4fd1058 100644 --- a/src/oidcrp/oauth2/add_on/pushed_authorization.py +++ b/src/oidcrp/oauth2/add_on/pushed_authorization.py @@ -51,7 +51,7 @@ def push_authorization(request_args, service, **kwargs): def add_support(services, body_format="jws", signing_algorithm="RS256", http_client=None, merge_rule="strict"): """ - Add the necessary pieces to make pushed authorization happen. + Add the necessary pieces to make Demonstration of proof of possession (DPOP). :param merge_rule: :param http_client: