将OpenID/Keycloak与Superset结合使用 [英] Using OpenID/Keycloak with Superset

查看:163
本文介绍了将OpenID/Keycloak与Superset结合使用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用keycloak在我们的Superset环境中对我的用户进行身份验证.

I want to use keycloak to authenticate my users in our Superset environment.

Superset正在使用flask-openid,如flask-security中所述:

Superset is using flask-openid, as implemented in flask-security:

  • http://flask-appbuilder.readthedocs.io/en/latest/_modules/flask_appbuilder/security/manager.html
  • https://pythonhosted.org/Flask-OpenID/

要启用与常规身份验证(数据库)不同的用户身份验证,您需要在superset_config.py文件中覆盖AUTH_TYPE参数.您还需要提供对您的openid-connect领域的引用,并启用用户注册.据我了解,它看起来应该像这样:

To enable a different user authentication than the regular one (database), you need to override the AUTH_TYPE parameter in your superset_config.py file. You will also need to provide a reference to your openid-connect realm and enable user registration. As I understand, it should look something like this:

from flask_appbuilder.security.manager import AUTH_OID
AUTH_TYPE = AUTH_OID
OPENID_PROVIDERS = [
    { 'name':'keycloak', 'url':'http://localhost:8080/auth/realms/superset' }
]
AUTH_USER_REGISTRATION = True
AUTH_USER_REGISTRATION_ROLE = 'Gamma'

使用此配置,登录页面将更改为提示,用户可以在其中选择所需的OpenID提供程序(在我们的情况下为密钥斗篷).我们还有两个按钮,一个用于登录(针对现有用户),另一个用于注册为新用户.

With this configuration, the login page changes to a prompt where the user can select the desired OpenID provider (in our case keycloak). We also have two buttons, one to sign in (for existing users) and one to register as a new user.

我希望这些按钮中的任何一个都可以将我带到我的密钥库登录页面.但是,这不会发生.相反,我被重定向回了 登录页面.

I would expect that either of these buttons would take me to my keycloak login page. However, this does not happen. Instead, I am redirected right back to the login page.

在我按下注册按钮的情况下,我收到一条消息,提示目前无法注册,请稍后再试".当我按下登录按钮时,没有消息显示.超级集日志显示加载登录页面的请求,但不显示对密钥斗篷的请求.我已经使用Google OpenID提供程序尝试了同样的方法,效果很好.

In the case where I press the registration button, I get a message that says 'Not possible to register you at the moment, try again later'. When I press the sign in button, no message is displayed. The Superset logs show the request that loads the login page, but no requests to keycloak. I have tried the same using the Google OpenID provider, which works just fine.

由于我没有看到对密钥斗篷的请求,因此使我认为我在某个地方缺少配置设置,或者使用的设置错误.您能帮我弄清楚我应该使用哪些设置吗?

Since I am seeing no requests to keycloak, this makes me think that I am either missing a configuration setting somewhere, or that I am using the wrong settings. Could you please help me figure out which settings I should be using?

推荐答案

更新03-02-2020

@sjmeyer编写了适用于Superset 0.28.1及更高版本的更新指南.我自己还没有尝试过,但是感谢@nawazxy确认此解决方案有效.

Update 03-02-2020

@s.j.meyer has written an updated guide which works with Superset 0.28.1 and up. I haven't tried it myself, but thanks @nawazxy for confirming this solution works.

我设法解决了自己的问题.主要问题是由我对超集使用的flask-openid插件的错误假设引起的.该插件实际上支持 OpenID 2.x ,但不支持OpenID-Connect(由密钥斗篷).

I managed to solve my own question. The main problem was caused by a wrong assumption I made regarding the flask-openid plugin that superset is using. This plugin actually supports OpenID 2.x, but not OpenID-Connect (which is the version implemented by Keycloak).

作为一种解决方法,我决定切换到 flask-oidc 插件.切换到新的身份验证提供程序实际上需要进行一些挖掘工作.要集成插件,我必须遵循以下步骤:

As a workaround, I decided to switch to the flask-oidc plugin. Switching to a new authentication provider actually requires some digging work. To integrate the plugin, I had to follow these steps:

不幸的是,flask-oidc不支持Keycloak生成的配置格式.相反,您的配置应如下所示:

Unfortunately, flask-oidc does not support the configuration format generated by Keycloak. Instead, your configuration should look something like this:

{
    "web": {
        "realm_public_key": "<YOUR_REALM_PUBLIC_KEY>",
        "issuer": "http://<YOUR_DOMAIN>/auth/realms/<YOUR_REALM_ID>",
        "auth_uri": "http://<YOUR_DOMAIN>/auth/realms/<YOUR_REALM_ID>/protocol/openid-connect/auth",
        "client_id": "<YOUR_CLIENT_ID>",
        "client_secret": "<YOUR_SECRET_KEY>",
        "redirect_urls": [
            "http://<YOUR_DOMAIN>/*"
        ],
        "userinfo_uri": "http://<YOUR_DOMAIN>/auth/realms/<YOUR_REALM_ID>/protocol/openid-connect/userinfo",
        "token_uri": "http://<YOUR_DOMAIN>/auth/realms/<YOUR_REALM_ID>/protocol/openid-connect/token",
        "token_introspection_uri": "http://<YOUR_DOMAIN>/auth/realms/<YOUR_REALM_ID>/protocol/openid-connect/token/introspect"
    }
}

Flask-oidc希望该配置位于文件中.我已经将我的存储在client_secret.json中.您可以在superset_config.py中配置配置文件的路径.

Flask-oidc expects the configuration to be in a file. I have stored mine in client_secret.json. You can configure the path to the configuration file in your superset_config.py.

首先,您需要确保使用flask-openid来停止烧瓶,而使用flask-oidc来开始烧瓶.为此,您将需要创建自己的安全管理器,该管理器将flask-oidc配置为其身份验证提供程序.我已经实现了我的安全管理器,如下所示:

Firstly, you will want to make sure that flask stops using flask-openid ad starts using flask-oidc instead. To do so, you will need to create your own security manager that configures flask-oidc as its authentication provider. I have implemented my security manager like this:

from flask_appbuilder.security.manager import AUTH_OID
from flask_appbuilder.security.sqla.manager import SecurityManager
from flask_oidc import OpenIDConnect

class OIDCSecurityManager(SecurityManager):

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

要在Superset中启用OpenID,以前必须将身份验证类型设置为AUTH_OID.我的安全管理器仍然执行超类的所有行为,但是用OpenIDConnect对象覆盖oid属性.此外,它用自定义视图替换默认的OpenID身份验证视图.我已经实现了我的这样的

To enable OpenID in Superset, you would previously have had to set the authentication type to AUTH_OID. My security manager still executes all the behaviour of the super class, but overrides the oid attribute with the OpenIDConnect object. Further, it replaces the default OpenID authentication view with a custom one. I have implemented mine like this:

from flask_appbuilder.security.views import AuthOIDView
from flask_login import login_user
from urllib import quote

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))

我的视图覆盖了/login和/logout端点上的行为.登录时,将运行handle_login方法.它要求用户由OIDC提供程序进行身份验证.在我们的情况下,这意味着用户将首先被重定向到Keycloak进行登录.

My view overrides the behaviours at the /login and /logout endpoints. On login, the handle_login method is run. It requires the user to be authenticated by the OIDC provider. In our case, this means the user will first be redirected to Keycloak to log in.

在身份验证时,用户将被重定向回Superset.接下来,我们查询是否可以识别用户.如果没有,我们将基于他们的OIDC用户信息创建用户.最后,我们将用户登录到Superset,然后将其重定向到登录页面.

On authentication, the user is redirected back to Superset. Next, we look up whether we recognize the user. If not, we create the user based on their OIDC user info. Finally, we log the user into Superset and redirect them to the landing page.

注销后,我们将使这些cookie无效

On logout, we will need to invalidate these cookies:

  1. 超集会话
  2. OIDC令牌
  3. Keycloak设置的cookie

默认情况下,Superset只处理第一个.扩展的登出方法可以照顾到所有这三点.

By default, Superset will only take care of the first. The extended logout method takes care of all three points.

最后,我们需要在superset_config.py中添加一些参数.这是我配置我的方式:

Finally, we need to add some parameters to our superset_config.py. This is how I've configured mine:

'''
AUTHENTICATION
'''
AUTH_TYPE = AUTH_OID
OIDC_CLIENT_SECRETS = 'client_secret.json'
OIDC_ID_TOKEN_COOKIE_SECURE = False
OIDC_REQUIRE_VERIFIED_EMAIL = False
CUSTOM_SECURITY_MANAGER = OIDCSecurityManager
AUTH_USER_REGISTRATION = True
AUTH_USER_REGISTRATION_ROLE = 'Gamma'

这篇关于将OpenID/Keycloak与Superset结合使用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆