codeant-ai-for-open-source[bot] commented on code in PR #38092:
URL: https://github.com/apache/superset/pull/38092#discussion_r2826935644
##########
docs/docs/installation/kubernetes.mdx:
##########
@@ -308,6 +308,122 @@ configOverrides:
AUTH_USER_REGISTRATION_ROLE = "Admin"
```
+:::note
+
+Here another example with groups mapping, logout from Keycloak and PKCE flow.
+You need to create a Secret that contains CLIENT_ID, CLIENT_SECRET and
OIDC_ISSUER.
+
+Your oauth provider must be configured to support PKCE flow.
+For keycloak for example, you need to set 'Proof Key for Code Exchange Code
Challenge Method' to value S256 under:
+Clients -> <your-client-id> -> Advanced -> Advanced settings
+
+:::
+
+```yaml
+extraSecretEnv:
+ CLIENT_ID: my_superset_clientid
+ CLIENT_SECRET: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+ OIDC_ISSUER: https://myoauthprovider.youpi.fr/auth/realms/MYREALM
+
+configOverrides:
+ enable_oauth: |
+ from flask import redirect, request, session
+ from flask_appbuilder import expose
+ from flask_appbuilder.security.manager import AUTH_OAUTH
+ from flask_appbuilder.security.views import AuthOAuthView
+ from superset.security import SupersetSecurityManager
+ import logging
+ import os
+ import requests
+
+ log = logging.getLogger(__name__)
+
+ AUTH_TYPE = AUTH_OAUTH
+ AUTH_USER_REGISTRATION = True
+ AUTH_ROLES_SYNC_AT_LOGIN = True
+ AUTH_USER_REGISTRATION_ROLE = 'Public'
+
+ PROVIDER_NAME = 'keycloak'
+ CLIENT_ID = os.getenv('CLIENT_ID')
+ CLIENT_SECRET = os.getenv('CLIENT_SECRET')
+ OIDC_ISSUER = os.getenv('OIDC_ISSUER')
+ OIDC_BASE_URL = f'{OIDC_ISSUER}/protocol/openid-connect'
+ OIDC_AUTH_URL = f'{OIDC_BASE_URL}/auth'
+ OIDC_METADATA_URL = f'{OIDC_ISSUER}/.well-known/openid-configuration'
+ OIDC_TOKEN_URL = f'{OIDC_BASE_URL}/token'
+ OIDC_USERINFO_URL = f'{OIDC_BASE_URL}/userinfo'
+ OAUTH_PROVIDERS = [
+ {
+ 'name': PROVIDER_NAME,
+ 'token_key': 'access_token',
+ 'icon': 'fa-circle-o',
+ 'remote_app': {
+ 'api_base_url': OIDC_BASE_URL,
+ 'access_token_url': OIDC_TOKEN_URL,
+ 'authorize_url': OIDC_AUTH_URL,
+ 'request_token_url': None,
+ 'server_metadata_url': OIDC_METADATA_URL,
+ 'client_id': CLIENT_ID,
+ 'client_secret': CLIENT_SECRET,
+ 'client_kwargs': {
+ 'scope': 'openid email profile',
+ 'code_challenge_method': 'S256',
+ 'response_type': 'code',
+ },
+ },
+ }
+ ]
+
+ # Make sure you create these groups on Keycloak
+ AUTH_ROLES_MAPPING = {
+ f'{CLIENT_ID}_admin': ['Admin'],
+ f'{CLIENT_ID}_alpha': ['Alpha'],
+ f'{CLIENT_ID}_gamma': ['Gamma'],
+ f'{CLIENT_ID}_public': ['Public'],
+ }
+
+
+ # Custom OAuth view to handle logout redirection to Keycloak
+ class CustomOAuthView(AuthOAuthView):
+ @expose('/logout/', methods=['GET', 'POST'])
+ def logout(self):
+ session.clear()
+ return redirect(
+
f'{OIDC_ISSUER}/protocol/openid-connect/logout?post_logout_redirect_uri={request.url_root.strip("/")}&client_id={CLIENT_ID}'
+ )
+
+
+ class CustomSsoSecurityManager(SupersetSecurityManager):
+ # Override the default OAuth view with our custom one
+ authoauthview = CustomOAuthView
+
+ # Override the method to fetch groups from the token and map them to
Superset roles
+ def get_oauth_user_info(self, provider, response):
+ if provider == 'keycloak':
+ headers = {'Authorization': f"Bearer
{response['access_token']}"}
+ resp = requests.get(OIDC_USERINFO_URL, headers=headers)
+ me = resp.json()
+
+ log.info(f'userinfo: {me}')
+
+ groups = me.get('groups', [])
+ if not groups:
+ groups = ['Public']
+
Review Comment:
**Suggestion:** The default group assigned when no groups are present
(`"Public"`) does not match any key in the roles mapping (which uses names like
`<CLIENT_ID>_public`), so users without a `groups` claim will not get any
mapped roles, likely preventing them from receiving the intended default
"Public" role. [logic error]
<details>
<summary><b>Severity Level:</b> Major ⚠️</summary>
```mdx
- ⚠️ Keycloak-based OAuth example misconfigures default group mapping.
- ⚠️ Users without groups may miss intended Public permissions.
- ⚠️ Role sync from IdP groups behaves inconsistently with docs.
```
</details>
```suggestion
groups = [f'{CLIENT_ID}_public']
```
<details>
<summary><b>Steps of Reproduction ✅ </b></summary>
```mdx
1. Deploy Superset on Kubernetes using the Helm chart and copy the Keycloak
example from
`docs/docs/installation/kubernetes.mdx` under `### Setting up OAuth`,
specifically the
`configOverrides.enable_oauth` block that defines
`CustomSsoSecurityManager.get_oauth_user_info` (around lines 396–424 in the
final file).
2. In Keycloak, configure the client with ID `my_superset_clientid`
(matching `CLIENT_ID`
in the example) and create realm roles / groups such that some user has no
groups (or the
`groups` claim is omitted/empty in the ID/access token / userinfo response).
3. Log in to Superset via the Keycloak OAuth provider (the `keycloak`
provider defined in
`OAUTH_PROVIDERS` in the same config block). Superset invokes
`CustomSsoSecurityManager.get_oauth_user_info('keycloak', response)` which
calls the
snippet at `docs/docs/installation/kubernetes.mdx:410–412` to derive
`groups`.
4. Because `groups` is empty, the code sets `groups = ['Public']`, but
`AUTH_ROLES_MAPPING` (defined earlier in the same config block at lines
~378–383) only
contains keys like `f'{CLIENT_ID}_public'`. As a result, Superset's role
sync logic (in
`superset/security/manager.py`, which reads `AUTH_ROLES_MAPPING`) cannot map
`['Public']`
to any Superset role, so the user does not receive the intended `Public`
role derived from
group mapping. This misalignment demonstrates the logic bug the suggestion
addresses.
```
</details>
<details>
<summary><b>Prompt for AI Agent 🤖 </b></summary>
```mdx
This is a comment left during a code review.
**Path:** docs/docs/installation/kubernetes.mdx
**Line:** 412:412
**Comment:**
*Logic Error: The default group assigned when no groups are present
(`"Public"`) does not match any key in the roles mapping (which uses names like
`<CLIENT_ID>_public`), so users without a `groups` claim will not get any
mapped roles, likely preventing them from receiving the intended default
"Public" role.
Validate the correctness of the flagged issue. If correct, How can I resolve
this? If you propose a fix, implement it and please make it concise.
```
</details>
<a
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38092&comment_hash=00040b1c110b801ce2a53b1fc25d726b52e114cf8a95569d315f725d27ec3527&reaction=like'>👍</a>
| <a
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38092&comment_hash=00040b1c110b801ce2a53b1fc25d726b52e114cf8a95569d315f725d27ec3527&reaction=dislike'>👎</a>
##########
docs/docs/installation/kubernetes.mdx:
##########
@@ -308,6 +308,122 @@ configOverrides:
AUTH_USER_REGISTRATION_ROLE = "Admin"
```
+:::note
+
+Here another example with groups mapping, logout from Keycloak and PKCE flow.
+You need to create a Secret that contains CLIENT_ID, CLIENT_SECRET and
OIDC_ISSUER.
+
+Your oauth provider must be configured to support PKCE flow.
+For keycloak for example, you need to set 'Proof Key for Code Exchange Code
Challenge Method' to value S256 under:
+Clients -> <your-client-id> -> Advanced -> Advanced settings
+
+:::
+
+```yaml
+extraSecretEnv:
+ CLIENT_ID: my_superset_clientid
+ CLIENT_SECRET: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+ OIDC_ISSUER: https://myoauthprovider.youpi.fr/auth/realms/MYREALM
+
+configOverrides:
+ enable_oauth: |
+ from flask import redirect, request, session
+ from flask_appbuilder import expose
+ from flask_appbuilder.security.manager import AUTH_OAUTH
+ from flask_appbuilder.security.views import AuthOAuthView
+ from superset.security import SupersetSecurityManager
+ import logging
+ import os
+ import requests
+
+ log = logging.getLogger(__name__)
+
+ AUTH_TYPE = AUTH_OAUTH
+ AUTH_USER_REGISTRATION = True
+ AUTH_ROLES_SYNC_AT_LOGIN = True
+ AUTH_USER_REGISTRATION_ROLE = 'Public'
+
+ PROVIDER_NAME = 'keycloak'
+ CLIENT_ID = os.getenv('CLIENT_ID')
+ CLIENT_SECRET = os.getenv('CLIENT_SECRET')
+ OIDC_ISSUER = os.getenv('OIDC_ISSUER')
+ OIDC_BASE_URL = f'{OIDC_ISSUER}/protocol/openid-connect'
+ OIDC_AUTH_URL = f'{OIDC_BASE_URL}/auth'
+ OIDC_METADATA_URL = f'{OIDC_ISSUER}/.well-known/openid-configuration'
+ OIDC_TOKEN_URL = f'{OIDC_BASE_URL}/token'
+ OIDC_USERINFO_URL = f'{OIDC_BASE_URL}/userinfo'
+ OAUTH_PROVIDERS = [
+ {
+ 'name': PROVIDER_NAME,
+ 'token_key': 'access_token',
+ 'icon': 'fa-circle-o',
+ 'remote_app': {
+ 'api_base_url': OIDC_BASE_URL,
+ 'access_token_url': OIDC_TOKEN_URL,
+ 'authorize_url': OIDC_AUTH_URL,
+ 'request_token_url': None,
+ 'server_metadata_url': OIDC_METADATA_URL,
+ 'client_id': CLIENT_ID,
+ 'client_secret': CLIENT_SECRET,
+ 'client_kwargs': {
+ 'scope': 'openid email profile',
+ 'code_challenge_method': 'S256',
+ 'response_type': 'code',
+ },
+ },
+ }
+ ]
+
+ # Make sure you create these groups on Keycloak
+ AUTH_ROLES_MAPPING = {
+ f'{CLIENT_ID}_admin': ['Admin'],
+ f'{CLIENT_ID}_alpha': ['Alpha'],
+ f'{CLIENT_ID}_gamma': ['Gamma'],
+ f'{CLIENT_ID}_public': ['Public'],
+ }
+
+
+ # Custom OAuth view to handle logout redirection to Keycloak
+ class CustomOAuthView(AuthOAuthView):
+ @expose('/logout/', methods=['GET', 'POST'])
+ def logout(self):
+ session.clear()
+ return redirect(
+
f'{OIDC_ISSUER}/protocol/openid-connect/logout?post_logout_redirect_uri={request.url_root.strip("/")}&client_id={CLIENT_ID}'
+ )
+
+
+ class CustomSsoSecurityManager(SupersetSecurityManager):
+ # Override the default OAuth view with our custom one
+ authoauthview = CustomOAuthView
+
+ # Override the method to fetch groups from the token and map them to
Superset roles
+ def get_oauth_user_info(self, provider, response):
+ if provider == 'keycloak':
+ headers = {'Authorization': f"Bearer
{response['access_token']}"}
+ resp = requests.get(OIDC_USERINFO_URL, headers=headers)
+ me = resp.json()
+
+ log.info(f'userinfo: {me}')
+
Review Comment:
**Suggestion:** Logging the entire `userinfo` payload at info level will
store personally identifiable information (like emails and full profile data)
in standard logs, which is a security and privacy risk in production
environments. [security]
<details>
<summary><b>Severity Level:</b> Critical 🚨</summary>
```mdx
- ❌ Keycloak OAuth logins leak PII into app logs.
- ⚠️ Centralized logging stores emails and profile attributes.
- ⚠️ Harder to meet privacy and compliance requirements.
```
</details>
```suggestion
log.debug("Received userinfo from OIDC provider for user %s",
me.get("preferred_username"))
```
<details>
<summary><b>Steps of Reproduction ✅ </b></summary>
```mdx
1. Deploy Superset on Kubernetes with the Keycloak `enable_oauth` example
from
`docs/docs/installation/kubernetes.mdx` copied verbatim into
`configOverrides.enable_oauth`, including the `log.info(f'userinfo: {me}')`
line at
approximately line 408.
2. Configure logging for the Superset webserver to use the default INFO log
level (the
standard production setting for many deployments).
3. Have any user authenticate via the configured Keycloak OAuth provider
(`provider` name
`keycloak` as defined in `OAUTH_PROVIDERS` in the same config block). During
login,
Superset calls `CustomSsoSecurityManager.get_oauth_user_info('keycloak',
response)` which
issues the userinfo request and assigns `me = resp.json()`.
4. The line `log.info(f'userinfo: {me}')` at
`docs/docs/installation/kubernetes.mdx:408`
logs the full `userinfo` JSON including email, full name, username, and
groups to the
application logs on every login, making this PII available to anyone with
access to logs
and potentially to log aggregation systems.
```
</details>
<details>
<summary><b>Prompt for AI Agent 🤖 </b></summary>
```mdx
This is a comment left during a code review.
**Path:** docs/docs/installation/kubernetes.mdx
**Line:** 408:408
**Comment:**
*Security: Logging the entire `userinfo` payload at info level will
store personally identifiable information (like emails and full profile data)
in standard logs, which is a security and privacy risk in production
environments.
Validate the correctness of the flagged issue. If correct, How can I resolve
this? If you propose a fix, implement it and please make it concise.
```
</details>
<a
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38092&comment_hash=a05101bd0c458359bba7ea29d786591843ff106325df28fa0c4da01cbcbeca97&reaction=like'>👍</a>
| <a
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38092&comment_hash=a05101bd0c458359bba7ea29d786591843ff106325df28fa0c4da01cbcbeca97&reaction=dislike'>👎</a>
##########
docs/docs/installation/kubernetes.mdx:
##########
@@ -308,6 +308,122 @@ configOverrides:
AUTH_USER_REGISTRATION_ROLE = "Admin"
```
+:::note
+
+Here another example with groups mapping, logout from Keycloak and PKCE flow.
+You need to create a Secret that contains CLIENT_ID, CLIENT_SECRET and
OIDC_ISSUER.
+
+Your oauth provider must be configured to support PKCE flow.
+For keycloak for example, you need to set 'Proof Key for Code Exchange Code
Challenge Method' to value S256 under:
+Clients -> <your-client-id> -> Advanced -> Advanced settings
+
+:::
+
+```yaml
+extraSecretEnv:
+ CLIENT_ID: my_superset_clientid
+ CLIENT_SECRET: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+ OIDC_ISSUER: https://myoauthprovider.youpi.fr/auth/realms/MYREALM
+
+configOverrides:
+ enable_oauth: |
+ from flask import redirect, request, session
+ from flask_appbuilder import expose
+ from flask_appbuilder.security.manager import AUTH_OAUTH
+ from flask_appbuilder.security.views import AuthOAuthView
+ from superset.security import SupersetSecurityManager
+ import logging
+ import os
+ import requests
+
+ log = logging.getLogger(__name__)
+
+ AUTH_TYPE = AUTH_OAUTH
+ AUTH_USER_REGISTRATION = True
+ AUTH_ROLES_SYNC_AT_LOGIN = True
+ AUTH_USER_REGISTRATION_ROLE = 'Public'
+
+ PROVIDER_NAME = 'keycloak'
+ CLIENT_ID = os.getenv('CLIENT_ID')
+ CLIENT_SECRET = os.getenv('CLIENT_SECRET')
+ OIDC_ISSUER = os.getenv('OIDC_ISSUER')
+ OIDC_BASE_URL = f'{OIDC_ISSUER}/protocol/openid-connect'
+ OIDC_AUTH_URL = f'{OIDC_BASE_URL}/auth'
+ OIDC_METADATA_URL = f'{OIDC_ISSUER}/.well-known/openid-configuration'
+ OIDC_TOKEN_URL = f'{OIDC_BASE_URL}/token'
+ OIDC_USERINFO_URL = f'{OIDC_BASE_URL}/userinfo'
+ OAUTH_PROVIDERS = [
+ {
+ 'name': PROVIDER_NAME,
+ 'token_key': 'access_token',
+ 'icon': 'fa-circle-o',
+ 'remote_app': {
+ 'api_base_url': OIDC_BASE_URL,
+ 'access_token_url': OIDC_TOKEN_URL,
+ 'authorize_url': OIDC_AUTH_URL,
+ 'request_token_url': None,
+ 'server_metadata_url': OIDC_METADATA_URL,
+ 'client_id': CLIENT_ID,
+ 'client_secret': CLIENT_SECRET,
+ 'client_kwargs': {
+ 'scope': 'openid email profile',
+ 'code_challenge_method': 'S256',
+ 'response_type': 'code',
+ },
+ },
+ }
+ ]
+
+ # Make sure you create these groups on Keycloak
+ AUTH_ROLES_MAPPING = {
+ f'{CLIENT_ID}_admin': ['Admin'],
+ f'{CLIENT_ID}_alpha': ['Alpha'],
+ f'{CLIENT_ID}_gamma': ['Gamma'],
+ f'{CLIENT_ID}_public': ['Public'],
+ }
+
+
+ # Custom OAuth view to handle logout redirection to Keycloak
+ class CustomOAuthView(AuthOAuthView):
+ @expose('/logout/', methods=['GET', 'POST'])
+ def logout(self):
+ session.clear()
+ return redirect(
+
f'{OIDC_ISSUER}/protocol/openid-connect/logout?post_logout_redirect_uri={request.url_root.strip("/")}&client_id={CLIENT_ID}'
+ )
+
+
+ class CustomSsoSecurityManager(SupersetSecurityManager):
+ # Override the default OAuth view with our custom one
+ authoauthview = CustomOAuthView
+
+ # Override the method to fetch groups from the token and map them to
Superset roles
+ def get_oauth_user_info(self, provider, response):
+ if provider == 'keycloak':
+ headers = {'Authorization': f"Bearer
{response['access_token']}"}
+ resp = requests.get(OIDC_USERINFO_URL, headers=headers)
+ me = resp.json()
Review Comment:
**Suggestion:** The call to the OIDC userinfo endpoint uses `requests.get`
without a timeout, so if the identity provider is slow or unresponsive, login
requests can hang indefinitely and tie up worker processes. [possible bug]
<details>
<summary><b>Severity Level:</b> Major ⚠️</summary>
```mdx
- ❌ Keycloak-based logins can hang during IdP outages.
- ⚠️ Webserver workers may be exhausted under partial outages.
- ⚠️ User authentication reliability reduced during network issues.
```
</details>
```suggestion
resp = requests.get(OIDC_USERINFO_URL, headers=headers,
timeout=5)
```
<details>
<summary><b>Steps of Reproduction ✅ </b></summary>
```mdx
1. Deploy Superset using the Kubernetes Helm chart and copy the Keycloak
OAuth example
from `docs/docs/installation/kubernetes.mdx` into
`configOverrides.enable_oauth`,
including the `requests.get(OIDC_USERINFO_URL, headers=headers)` call in
`CustomSsoSecurityManager.get_oauth_user_info` (around line 405).
2. Configure the `CLIENT_ID`, `CLIENT_SECRET`, and `OIDC_ISSUER` environment
variables as
described in the same example so that `OIDC_USERINFO_URL` points at your IdP
(e.g.,
Keycloak `.../protocol/openid-connect/userinfo`).
3. Simulate an IdP/network issue by making the OIDC userinfo endpoint slow
or unresponsive
(for example, by adding a firewall rule that drops packets to the userinfo
URL, or by
stopping the Keycloak instance while keeping DNS/resolution unchanged).
4. Have a user attempt to log in via the Keycloak OAuth provider. The
Superset webserver
calls `requests.get(OIDC_USERINFO_URL, headers=headers)` at
`docs/docs/installation/kubernetes.mdx:405` with no timeout, causing the
request (and
therefore the login HTTP request) to hang until the underlying HTTP stack or
webserver
kills the worker, tying up resources and degrading availability.
```
</details>
<details>
<summary><b>Prompt for AI Agent 🤖 </b></summary>
```mdx
This is a comment left during a code review.
**Path:** docs/docs/installation/kubernetes.mdx
**Line:** 405:405
**Comment:**
*Possible Bug: The call to the OIDC userinfo endpoint uses
`requests.get` without a timeout, so if the identity provider is slow or
unresponsive, login requests can hang indefinitely and tie up worker processes.
Validate the correctness of the flagged issue. If correct, How can I resolve
this? If you propose a fix, implement it and please make it concise.
```
</details>
<a
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38092&comment_hash=f26999d3e2048e7b35e6b8b097e2abc127a752993c889c4086d8ecad89d15bf0&reaction=like'>👍</a>
| <a
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38092&comment_hash=f26999d3e2048e7b35e6b8b097e2abc127a752993c889c4086d8ecad89d15bf0&reaction=dislike'>👎</a>
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]