Repository: google/timesketch

Issue:
Allow OIDC API clients to consume OAuth tokens from several clients
Allow OIDC API clients to consume OAuth tokens from several clients, this will allow Timsketch admins to add additional CLIENT_IDs to the config file and allow users to authenticate to the APIs using valid Token issued using these clients.



Discussion:

Resolving patch:
diff --git a/timesketch/views/auth.py b/timesketch/views/auth.py
--- a/timesketch/views/auth.py
+++ b/timesketch/views/auth.py
@@ -60,19 +60,21 @@
     "openid",
     "https://www.googleapis.com/auth/userinfo.profile",
 ]
+_GOOGLE_OIDC_CLIENTS = []
 
 
 @auth_views.route("/login/", methods=["GET", "POST"])
 def login():
     """Handler for the login page view.
 
-    There are three ways of authentication.
-    1) Google Cloud Identity-Aware Proxy.
-    2) If Single Sign On (SSO) is enabled in the configuration and the
+    There are four ways of authentication.
+    1) Google OpenID connect.
+    2) Google Cloud Identity-Aware Proxy.
+    3) If Single Sign On (SSO) is enabled in the configuration and the
        environment variable is present, e.g. REMOTE_USER then the system will
        get or create the user object and setup a session for the user.
-    3) Local authentication is used if SSO login is not enabled. This will
-       authenticate the user against the local user database.
+    4) Local authentication is used if SSO login is not enabled. This will
+       authenticate the user against the local user database
 
     Returns:
         Redirect if authentication is successful or template with context
@@ -192,13 +194,27 @@ def validate_api_token():
     id_token = request.args.get("id_token")
     if not id_token:
         return abort(HTTP_STATUS_CODE_UNAUTHORIZED, "No ID token supplied.")
-
-    client_id = current_app.config.get("GOOGLE_OIDC_API_CLIENT_ID")
-    if not client_id:
-        return abort(
-            HTTP_STATUS_CODE_BAD_REQUEST,
-            "No OIDC API client ID defined in the configuration file.",
-        )
+    if not _GOOGLE_OIDC_CLIENTS:
+        client_ids = set()
+        primary_client_id = current_app.config.get("GOOGLE_OIDC_CLIENT_ID")
+        if primary_client_id:
+            client_ids.add(primary_client_id)
+        else:
+            current_app.logger.warning(
+                "GOOGLE_OIDC_CLIENT_ID is not set in config file.")
+        additional_client_ids = current_app.config.get(
+            "ALLOWED_GOOGLE_OIDC_API_CLIENT_IDS",[])
+        if additional_client_ids:
+            client_ids.update(additional_client_ids)
+        else:
+            current_app.logger.warning(
+                "ALLOWED_GOOGLE_OIDC_API_CLIENT_IDS is not set in config file.")
+        _GOOGLE_OIDC_CLIENTS = list(client_ids)
+        if not _GOOGLE_OIDC_CLIENTS:
+            return abort(
+                HTTP_STATUS_CODE_BAD_REQUEST,
+                "No OIDC API client ID defined in the configuration file.",
+            )
 
     # Authenticating session, see more details here:
     # https://www.oauth.com/oauth2-servers/signing-in-with-google/\
@@ -259,7 +275,7 @@ def validate_api_token():
         )
 
     read_client_id = token_json.get("aud", "")
-    if read_client_id != client_id:
+    if read_client_id not in _GOOGLE_OIDC_CLIENTS:
         return abort(
             HTTP_STATUS_CODE_UNAUTHORIZED,
             "Client ID {0:s} does not match server configuration for "


Test patch: