about summary refs log tree commit diff
path: root/gn_auth/auth/authentication/oauth2/models/oauth2client.py
diff options
context:
space:
mode:
Diffstat (limited to 'gn_auth/auth/authentication/oauth2/models/oauth2client.py')
-rw-r--r--gn_auth/auth/authentication/oauth2/models/oauth2client.py51
1 files changed, 42 insertions, 9 deletions
diff --git a/gn_auth/auth/authentication/oauth2/models/oauth2client.py b/gn_auth/auth/authentication/oauth2/models/oauth2client.py
index 8fac648..dfe5d79 100644
--- a/gn_auth/auth/authentication/oauth2/models/oauth2client.py
+++ b/gn_auth/auth/authentication/oauth2/models/oauth2client.py
@@ -3,15 +3,17 @@ import json
 import logging
 import datetime
 from uuid import UUID
-from dataclasses import dataclass
+from urllib.parse import urlparse
 from functools import cached_property
-from typing import Sequence, Optional
+from dataclasses import asdict, dataclass
+from typing import Any, 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
+from gn_libs.debug import make_peeker
 
 from gn_auth.auth.db import sqlite3 as db
 from gn_auth.auth.errors import NotFoundError
@@ -21,6 +23,10 @@ from gn_auth.auth.authentication.users import (User,
                                                same_password)
 
 
+logger = logging.getLogger(__name__)
+__pk__ = make_peeker(logger)
+
+
 @dataclass(frozen=True)
 class OAuth2Client(ClientMixin):
     """
@@ -62,23 +68,26 @@ class OAuth2Client(ClientMixin):
     def jwks(self) -> KeySet:
         """Return this client's KeySet."""
         jwksuri = self.client_metadata.get("public-jwks-uri")
+        __pk__(f"PUBLIC JWKs link for client {self.client_id}", jwksuri)
         if not bool(jwksuri):
-            logging.debug("No Public JWKs URI set for client!")
+            logger.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"]])
+                           for key in requests.get(
+                                   jwksuri,
+                                   timeout=300,
+                                   allow_redirects=True).json()["jwks"]])
         except requests.ConnectionError as _connerr:
-            logging.debug(
+            logger.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)
+            logger.debug("Could not convert response to JSON", exc_info=True)
         except Exception as _exc:# pylint: disable=[broad-except]
-            logging.debug(
+            logger.debug(
                 "Error retrieving the JWKs for the client.", exc_info=True)
         return KeySet([])
 
@@ -130,7 +139,9 @@ class OAuth2Client(ClientMixin):
         """
         Check whether the given `redirect_uri` is one of the expected ones.
         """
-        return redirect_uri in self.redirect_uris
+        uri = urlparse(redirect_uri)._replace(
+            query="")._replace(fragment="").geturl()
+        return uri in self.redirect_uris
 
     @cached_property
     def response_types(self) -> Sequence[str]:
@@ -289,3 +300,25 @@ def delete_client(
         cursor.execute("DELETE FROM oauth2_tokens WHERE client_id=?", params)
         cursor.execute("DELETE FROM oauth2_clients WHERE client_id=?", params)
         return the_client
+
+
+def update_client_attribute(
+        client: OAuth2Client,# pylint: disable=[redefined-outer-name]
+        attribute: str,
+        value: Any
+) -> OAuth2Client:
+    """Return a new OAuth2Client with the given attribute updated/changed."""
+    attrs = {
+        attr: type(value)
+        for attr, value in asdict(client).items()
+        if attr != "client_id"
+    }
+    assert (
+        attribute in attrs.keys() and isinstance(value, attrs[attribute])), (
+            "Invalid attribute/value provided!")
+    return OAuth2Client(
+        client_id=client.client_id,
+        **{
+            attr: (value if attr==attribute else getattr(client, attr))
+            for attr in attrs
+        })