aboutsummaryrefslogtreecommitdiff
path: root/gn_auth/auth/authentication/oauth2/models
diff options
context:
space:
mode:
Diffstat (limited to 'gn_auth/auth/authentication/oauth2/models')
-rw-r--r--gn_auth/auth/authentication/oauth2/models/jwt_bearer_token.py15
-rw-r--r--gn_auth/auth/authentication/oauth2/models/jwtrefreshtoken.py12
-rw-r--r--gn_auth/auth/authentication/oauth2/models/oauth2client.py38
3 files changed, 47 insertions, 18 deletions
diff --git a/gn_auth/auth/authentication/oauth2/models/jwt_bearer_token.py b/gn_auth/auth/authentication/oauth2/models/jwt_bearer_token.py
new file mode 100644
index 0000000..2606ac6
--- /dev/null
+++ b/gn_auth/auth/authentication/oauth2/models/jwt_bearer_token.py
@@ -0,0 +1,15 @@
+"""Implement model for JWTBearerToken"""
+import uuid
+
+from authlib.oauth2.rfc7523 import JWTBearerToken as _JWTBearerToken
+
+from gn_auth.auth.db.sqlite3 import with_db_connection
+from gn_auth.auth.authentication.users import user_by_id
+
+class JWTBearerToken(_JWTBearerToken):
+ """Overrides default JWTBearerToken class."""
+
+ def __init__(self, payload, header, options=None, params=None):
+ super().__init__(payload, header, options, params)
+ self.user = with_db_connection(
+ lambda conn:user_by_id(conn, uuid.UUID(payload["sub"])))
diff --git a/gn_auth/auth/authentication/oauth2/models/jwtrefreshtoken.py b/gn_auth/auth/authentication/oauth2/models/jwtrefreshtoken.py
index 31c9147..46515c8 100644
--- a/gn_auth/auth/authentication/oauth2/models/jwtrefreshtoken.py
+++ b/gn_auth/auth/authentication/oauth2/models/jwtrefreshtoken.py
@@ -142,7 +142,7 @@ def link_child_token(conn: db.DbConnection, parenttoken: str, childtoken: str):
"WHERE token=:parenttoken"),
{"parenttoken": parent.token, "childtoken": childtoken})
- def __check_child__(parent):
+ def __check_child__(parent):#pylint: disable=[unused-variable]
with db.cursor(conn) as cursor:
cursor.execute(
("SELECT * FROM jwt_refresh_tokens WHERE token=:parenttoken"),
@@ -154,15 +154,17 @@ def link_child_token(conn: db.DbConnection, parenttoken: str, childtoken: str):
"activity detected.")
return Right(parent)
- def __revoke_and_raise_error__(_error_msg_):
+ def __revoke_and_raise_error__(_error_msg_):#pylint: disable=[unused-variable]
load_refresh_token(conn, parenttoken).then(
lambda _tok: revoke_refresh_token(conn, _tok))
raise InvalidGrantError(_error_msg_)
+ def __handle_not_found__(_error_msg_):
+ raise InvalidGrantError(_error_msg_)
+
load_refresh_token(conn, parenttoken).maybe(
- Left("Token not found"), Right).then(
- __check_child__).either(__revoke_and_raise_error__,
- __link_to_child__)
+ Left("Token not found"), Right).either(
+ __handle_not_found__, __link_to_child__)
def is_refresh_token_valid(token: JWTRefreshToken, client: OAuth2Client) -> bool:
diff --git a/gn_auth/auth/authentication/oauth2/models/oauth2client.py b/gn_auth/auth/authentication/oauth2/models/oauth2client.py
index d31faf6..8fac648 100644
--- a/gn_auth/auth/authentication/oauth2/models/oauth2client.py
+++ b/gn_auth/auth/authentication/oauth2/models/oauth2client.py
@@ -1,13 +1,14 @@
"""OAuth2 Client model."""
import json
+import logging
import datetime
-from pathlib import Path
-
from uuid import UUID
from dataclasses import dataclass
from functools import cached_property
from typing import Sequence, Optional
+import requests
+from requests.exceptions import JSONDecodeError
from authlib.jose import KeySet, JsonWebKey
from authlib.oauth2.rfc6749 import ClientMixin
from pymonad.maybe import Just, Maybe, Nothing
@@ -57,16 +58,30 @@ class OAuth2Client(ClientMixin):
"""
return self.client_metadata.get("client_type", "public")
- @cached_property
+
def jwks(self) -> KeySet:
"""Return this client's KeySet."""
- def __parse_key__(keypath: Path) -> JsonWebKey:
- with open(keypath) as _key:# pylint: disable=[unspecified-encoding]
- return JsonWebKey.import_key(_key.read())
+ jwksuri = self.client_metadata.get("public-jwks-uri")
+ if not bool(jwksuri):
+ logging.debug("No Public JWKs URI set for client!")
+ return KeySet([])
+ try:
+ ## IMPORTANT: This can cause a deadlock if the client is working in
+ ## single-threaded mode, i.e. can only serve one request
+ ## at a time.
+ return KeySet([JsonWebKey.import_key(key)
+ for key in requests.get(jwksuri).json()["jwks"]])
+ except requests.ConnectionError as _connerr:
+ logging.debug(
+ "Could not connect to provided URI: %s", jwksuri, exc_info=True)
+ except JSONDecodeError as _jsonerr:
+ logging.debug(
+ "Could not convert response to JSON", exc_info=True)
+ except Exception as _exc:# pylint: disable=[broad-except]
+ logging.debug(
+ "Error retrieving the JWKs for the client.", exc_info=True)
+ return KeySet([])
- return KeySet([
- __parse_key__(Path(pth))
- for pth in self.client_metadata.get("public_keys", [])])
def check_endpoint_auth_method(self, method: str, endpoint: str) -> bool:
"""
@@ -77,12 +92,9 @@ class OAuth2Client(ClientMixin):
* client_secret_post: Client uses the HTTP POST parameters
* client_secret_basic: Client uses HTTP Basic
"""
- if endpoint == "token":
+ if endpoint in ("token", "revoke", "introspection"):
return (method in self.token_endpoint_auth_method
and method == "client_secret_post")
- if endpoint in ("introspection", "revoke"):
- return (method in self.token_endpoint_auth_method
- and method == "client_secret_basic")
return False
@cached_property