From 8064ef05cdda49a493d2765d6bac3d191a7f4b8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Thu, 8 Apr 2021 18:18:46 +0200 Subject: [PATCH] NXPY-215: Add support for the JSON Web Token authentication --- CHANGELOG.rst | 3 ++- examples/authentication.rst | 13 +++++++++++++ nuxeo/auth/__init__.py | 3 ++- nuxeo/auth/jwt.py | 39 +++++++++++++++++++++++++++++++++++++ tests/test_auth.py | 15 +++++++++++++- 5 files changed, 70 insertions(+), 3 deletions(-) create mode 100644 nuxeo/auth/jwt.py diff --git a/CHANGELOG.rst b/CHANGELOG.rst index c8f4969f..fbba4ad4 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -8,11 +8,12 @@ Release date: ``2021-0x-xx`` - `NXPY-213 `__: Handle incomplete serialized HTTP error - `NXPY-214 `__: Add a code coverage GitHub Action on PRs +- `NXPY-215 `__: Add support for the JSON Web Token authentication Technical changes ----------------- -- +- Added nuxeo/auth/jwt.py 5.0.0 ----- diff --git a/examples/authentication.rst b/examples/authentication.rst index 9ffcae0f..41b8234b 100644 --- a/examples/authentication.rst +++ b/examples/authentication.rst @@ -13,6 +13,19 @@ Basic Authentication server = Nuxeo(host=host, auth=auth) +JSON Web Token Authentication +============================= + +.. code:: python + + from nuxeo.auth import JWTAuth + from nuxeo.client import Nuxeo + + host = "https:///nuxeo/" + auth = JWTAuth("token") + server = Nuxeo(host=host, auth=auth) + + Portal SSO Authentication ========================= diff --git a/nuxeo/auth/__init__.py b/nuxeo/auth/__init__.py index 16b3ebb5..3ecc2376 100644 --- a/nuxeo/auth/__init__.py +++ b/nuxeo/auth/__init__.py @@ -1,7 +1,8 @@ # coding: utf-8 from __future__ import unicode_literals +from .jwt import JWTAuth from .portal_sso import PortalSSOAuth from .token import TokenAuth -__all__ = ("PortalSSOAuth", "TokenAuth") +__all__ = ("JWTAuth", "PortalSSOAuth", "TokenAuth") diff --git a/nuxeo/auth/jwt.py b/nuxeo/auth/jwt.py new file mode 100644 index 00000000..6ef354bb --- /dev/null +++ b/nuxeo/auth/jwt.py @@ -0,0 +1,39 @@ +# coding: utf-8 +from __future__ import unicode_literals + +from ..compat import get_bytes +from .base import AuthBase + +try: + from typing import TYPE_CHECKING + + if TYPE_CHECKING: + from typing import Text + from requests import Request +except ImportError: + pass + + +class JWTAuth(AuthBase): + """ Attaches JSON Web Token Authentication to the given Request object. """ + + __slots__ = ("token",) + + AUTHORIZATION = get_bytes("Authorization") + + def __init__(self, token): + # type: (Text) -> None + self.token = token + + def __eq__(self, other): + # type: (object) -> bool + return self.token == getattr(other, "token", None) + + def __ne__(self, other): + # type: (object) -> bool + return not self == other + + def __call__(self, r): + # type: (Request) -> Request + r.headers[self.AUTHORIZATION] = "Bearer " + self.token + return r diff --git a/tests/test_auth.py b/tests/test_auth.py index 38d08ad9..30f6e509 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -4,7 +4,7 @@ import pytest from requests import Request -from nuxeo.auth import PortalSSOAuth, TokenAuth +from nuxeo.auth import JWTAuth, PortalSSOAuth, TokenAuth from nuxeo.auth.utils import make_portal_sso_token from nuxeo.compat import text from nuxeo.exceptions import NuxeoError @@ -13,6 +13,19 @@ skip_logging = True +def test_jwt(): + auth = JWTAuth("") + req = Request("GET", "https://httpbin.org/get", auth=auth) + prepared = req.prepare() + assert prepared.headers[auth.AUTHORIZATION] == "Bearer " + + +def test_jwt_equality(): + auth1 = JWTAuth("secure secret") + auth2 = JWTAuth("other secret") + assert auth1 != auth2 + + def test_make_portal_sso_token(): timestamp = 1324572561000 random = "qwertyuiop"