sadpandajoe commented on code in PR #35044: URL: https://github.com/apache/superset/pull/35044#discussion_r3669382829
########## docs/versioned_docs/version-6.0.0/configuration/configuring-superset.mdx: ########## @@ -363,6 +363,121 @@ CUSTOM_SECURITY_MANAGER = CustomSsoSecurityManager ] ``` +### Keycloak-Specific Configuration using Flask-OIDC + +If you are using Keycloak as OpenID Connect 1.0 Provider, the above configuration based on [`Authlib`](https://authlib.org/) might not work. In this case using [`Flask-OIDC`](https://pypi.org/project/flask-oidc/) is a viable option. + +Make sure the pip package [`Flask-OIDC`](https://pypi.org/project/flask-oidc/) is installed on the webserver. This was successfully tested using version 2.2.0. This package requires [`Flask-OpenID`](https://pypi.org/project/Flask-OpenID/) as a dependency. + +The following code defines a new security manager. Add it to a new file named `keycloak_security_manager.py`, placed in the same directory as your `superset_config.py` file. + +```python +from flask_appbuilder.security.manager import AUTH_OID +from superset.security import SupersetSecurityManager +from flask_oidc import OpenIDConnect +from flask_appbuilder.security.views import AuthOIDView +from flask_login import login_user +from urllib.parse import quote +from flask_appbuilder.views import ModelView, SimpleFormView, expose +from flask import ( + redirect, + request +) +import logging + +class OIDCSecurityManager(SupersetSecurityManager): + + def __init__(self, appbuilder): + super(OIDCSecurityManager, self).__init__(appbuilder) + if self.auth_type == AUTH_OID: + self.oid = OpenIDConnect(self.appbuilder.get_app) + self.authoidview = AuthOIDCView + + +class AuthOIDCView(AuthOIDView): + + @expose("/login/", methods=["GET", "POST"]) + def login(self, flag=True): + sm = self.appbuilder.sm + oidc = sm.oid + + @self.appbuilder.sm.oid.require_login + def handle_login(): + user = sm.auth_user_oid(oidc.user_getfield("email")) + + if user is None: + info = oidc.user_getinfo( + ["preferred_username", "given_name", "family_name", "email"] + ) + user = sm.add_user( + info.get("preferred_username"), + info.get("given_name"), + info.get("family_name"), + info.get("email"), + sm.find_role("Gamma"), + ) + + login_user(user, remember=False) + return redirect(self.appbuilder.get_url_for_index) + + return handle_login() + + @expose("/logout/", methods=["GET", "POST"]) + def logout(self): + oidc = self.appbuilder.sm.oid + + oidc.logout() + super(AuthOIDCView, self).logout() + redirect_url = request.url_root.strip("/") + self.appbuilder.get_url_for_login + + return redirect( + oidc.client_secrets.get("issuer") + + "/protocol/openid-connect/logout?redirect_uri=" + + quote(redirect_url) + ) +``` + +Then add to your `superset_config.py` file: + +```python +from keycloak_security_manager import OIDCSecurityManager +from flask_appbuilder.security.manager import AUTH_OID, AUTH_REMOTE_USER, AUTH_DB, AUTH_LDAP, AUTH_OAUTH +import os + +AUTH_TYPE = AUTH_OID +SECRET_KEY: 'SomethingNotEntirelySecret' Review Comment: These configuration examples use annotations instead of assignments (`SECRET_KEY: ...`, and likewise the two OIDC settings below), so copying them leaves all three values unset. Could these use `=` so the documented configuration actually takes effect? -- 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]
