在Apache SuperSet中使用KeyCloak(OpenID Connect) [英] Using KeyCloak(OpenID Connect) with Apache SuperSet

查看:297
本文介绍了在Apache SuperSet中使用KeyCloak(OpenID Connect)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我首先使用将OpenID/Keycloak与Superset结合使用,并按说明进行了一切.但是,这是一个过时的帖子,并非所有工作都奏效.我还试图通过将其安装为FAB附加组件来实现自定义安全管理器,以便在我的应用程序中实现它而不必编辑现有的超集代码.

I started with Using OpenID/Keycloak with Superset and did everything as explained. However, it is an old post, and not everything worked. I'm also trying to implement a custom security manager by installing it as a FAB add-on, so as to implement it in my application without having to edit the existing superset code.

我正在运行KeyCloak 4.8.1.Final和Apache SuperSet v 0.28.1

I'm running KeyCloak 4.8.1.Final and Apache SuperSet v 0.28.1

如文章中所述,SuperSet不能很好地与KeyCloak配合使用,因为它使用的是OpenID 2.0,而不是KeyCloak提供的OpenID Connect.

As explained in the post, SuperSet does not play nicely with KeyCloak out of the box because it uses OpenID 2.0 and not OpenID Connect, which is what KeyCloak provides.

第一个区别是,在请求请求 4565 被合并之后,您不能再做:

The first difference is that after pull request 4565 was merged, you can no longer do:

from flask_appbuilder.security.sqla.manager import SecurityManager

相反,您现在必须使用:(根据UPDATING.md文件)

Instead, you now have to use: (as per the UPDATING.md file)

from superset.security import SupersetSecurityManager

在上述文章中,张贴者展示了如何分别创建管理器和查看文件,但没有说明将文件放置在何处.我将管理类和视图类都放在了一个名为manager.py的文件中,并将其放在FAB附加结构中.

In the above mentioned post, the poster shows how to create the manager and view files separately, but don't say where to put it. I placed both the manager and view classes in the same file, named manager.py, and placed it in the FAB add-on structure.

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

CUSTOM_SECURITY_MANAGER = OIDCSecurityManager

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

我在此文件中设置了CUSTOM_SECURITY_MANAGER变量,而不是在superset_config.py中设置.这是因为它在那里时不起作用,也没有加载自定义安全管理器.在阅读烧瓶应用程序构建器中SecurityManager的装饰器以获取最高表现后,我将变量移到了那里/a>.

I have the CUSTOM_SECURITY_MANAGER variable set in this file and not in superset_config.py. This is because it didn't work when it was there, it didn't load the custom security manager. I moved the variable there after reading Decorator for SecurityManager in flask appbuilder for superest.

我的client_secret.json文件如下所示:

{
    "web": {
        "realm_public_key": "<PUBLIC_KEY>",
        "issuer": "https://<DOMAIN>/auth/realms/demo",
        "auth_uri": "https://<DOMAIN>/auth/realms/demo/protocol/openid-connect/auth",
        "client_id": "local",
        "client_secret": "<CLIENT_SECRET>",
        "redirect_urls": [
            "http://localhost:8001/*"
        ],
        "userinfo_uri": "https://<DOMAIN>/auth/realms/demo/protocol/openid-connect/userinfo",
        "token_uri": "https://<DOMAIN>/auth/realms/demo/protocol/openid-connect/token",
        "token_introspection_uri": "https://<DOMAIN>/auth/realms/demo/protocol/openid-connect/token/introspect"
    }
}

  • realm_public_key:我在领域设置">键">活动"中找到了此键,然后在表格的"RS256"行中得到了这个
  • .
  • client_id:本地(我用于本地测试的客户端)
  • client_secret:我是在客户端">本地"(从表中)>凭证">秘密"
  • 处获得此信息的

    • realm_public_key: I got this key at Realm Settings > Keys > Active and then in the table, in the "RS256" row.
    • client_id: local (the client I use for local testing)
    • client_secret: I got this at Clients > local (from the table) > Credentials > Secret
    • 所有的url/uri值都从我之前设置的所有提到的第一篇文章中进行了调整. <DOMAIN>是AWS CloudFront的默认域,因为我在EC2上运行KeyCloak,并且不想麻烦地设置自定义HTTPS域以简单地启动并运行它.

      All the url/uri values are adjusted from the first mentioned post I used to set it all up. The <DOMAIN> is an AWS CloudFront default domain, since I'm running KeyCloak on EC2 and don't want to go through the trouble to setup a custom HTTPS domain for simply getting it up and running.

      然后,最后,我的superset_config.py文件的一部分看起来像这样:

      Then, finally, part of my superset_config.py file looks like this:

      ADDON_MANAGERS = ['fab_addon_keycloak.manager.OIDCSecurityManager']
      AUTH_TYPE = AUTH_OID
      OIDC_CLIENT_SECRETS = '/usr/local/lib/python3.6/site-packages/fab_addon_keycloak/fab_addon_keycloak/client_secret.json'
      OIDC_ID_TOKEN_COOKIE_SECURE = False
      OIDC_REQUIRE_VERIFIED_EMAIL = False
      AUTH_USER_REGISTRATION = True
      AUTH_USER_REGISTRATION_ROLE = 'Gamma'
      OPENID_PROVIDERS = [{
          'name': 'KeyCloak',
          'url': 'https://<DOMAIN>/auth/realms/demo/account'
      }]
      

      在原始文章中,没有提到OPENID_PROVIDERS环境变量,因此我不确定如何在URL中输入什么内容.我把它放在那是因为您在登录KeyCloak上的客户端控制台时将使用该URL.

      In the original post, the OPENID_PROVIDERS environment variable is not mentioned, so I'm not really sure what to put in here for the URL. I put that one since that's the URL you'll hit to login to the client console on KeyCloak.

      当我运行SuperSet时,没有任何错误.我可以看到自定义安全管理器已加载.当我导航到登录屏幕时,我必须选择我的提供者,但是我没有登录表单.我选择KeyCloak,因为显然没有其他选择,然后单击Login.当我单击登录"时,可以看到浏览器的地址栏中加载了某些内容,但没有任何反应.据我了解,应该将我重定向到KeyCloak登录表单,然后在成功登录后再返回到我的应用程序,但是什么也没有发生.我在某处想念东西吗?

      When I run SuperSet I don't get any errors. I can see that the custom security manager loads. When I navigate to the login screen, I have to choose my provider, I don't get a login form. I choose KeyCloak, since there's obviously nothing else, and click Login. When I click Login I can see that something loads in the address bar of the browser, but nothing happens. It's my understanding that I'm supposed to be redirected to the KeyCloak login form, and then back to my application upon successful login, but nothing happens. Am I missing something somewhere?

      修改

      因此,在进行更多挖掘之后,似乎加载了我的自定义视图类,但是该类中的方法不会覆盖默认行为.不知道为什么会这样或如何解决.

      So after some more digging, it seems like my custom view class loads, however the methods in the class do not override the default behavior. Not sure why this is happening or how to fix it.

      推荐答案

      我最终自己弄清楚了.

      我最终得到的解决方案没有使用FAB附加组件,但是您也不必编辑现有的代码/文件.

      The solution I ended up with does not make use of a FAB add-on, but you also don't have to edit existing code/files.

      我已将manager.py文件重命名为security.py,现在看起来像这样:

      I've renamed the manager.py file to security.py, and it now looks like this:

      from flask import redirect, request
      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
      import logging
      
      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))
      
      class OIDCSecurityManager(SupersetSecurityManager):
          authoidview = AuthOIDCView
          def __init__(self,appbuilder):
              super(OIDCSecurityManager, self).__init__(appbuilder)
              if self.auth_type == AUTH_OID:
                  self.oid = OpenIDConnect(self.appbuilder.get_app)
      

      我将security.py文件放在我的superset_config_py文件旁边.

      I place the security.py file next to my superset_config_py file.

      JSON配置文件保持不变.

      The JSON configuration file stays unchanged.

      然后,我将superset_config.py文件更改为包括以下行:

      Then I've changed the superset_config.py file to include the following lines:

      from security import OIDCSecurityManager
      AUTH_TYPE = AUTH_OID
      OIDC_CLIENT_SECRETS = <path_to_configuration_file>
      OIDC_ID_TOKEN_COOKIE_SECURE = False
      OIDC_REQUIRE_VERIFIED_EMAIL = False
      AUTH_USER_REGISTRATION = True
      AUTH_USER_REGISTRATION_ROLE = 'Gamma'
      CUSTOM_SECURITY_MANAGER = OIDCSecurityManager
      

      就是这样.

      现在,当我导航到我的站点时,它会自动转到KeyCloak登录屏幕,成功登录后,我将被重定向回我的应用程序.

      Now when I navigate to my site, it automatically goes to the KeyCloak login screen, and upon successful sign in I am redirected back to my application.

      这篇关于在Apache SuperSet中使用KeyCloak(OpenID Connect)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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