微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Apache SuperSet 中的 OpenID 代码身份验证 - 不是 keycloak

如何解决Apache SuperSet 中的 OpenID 代码身份验证 - 不是 keycloak

我一直在尝试为 SuperSet 设置 OpenID 身份验证。我见过很多 Oauth 的配置,但没有看到 OpenID 的配置。

我尝试了以下配置:

from formshare_sso_security_manager import FormShareSsoSecurityManager
from flask_appbuilder.security.manager import AUTH_OID
...
AUTH_TYPE = AUTH_OID


OPENID_PROVIDERS = [
    {
        'name': 'FormShare','icon': 'fa-google','token_key': 'access_token','remote_app': {
            'client_id': '501cE2ow7V4J','client_secret': '060a450db0474b7db20afeda22a671b6','api_base_url': 'https://qlands.ngrok.io/','client_kwargs':{
              'scope': 'profile'
            },'request_token_url': None,'access_token_url': 'https://qlands.ngrok.io/openid_token','authorize_url': 'https://qlands.ngrok.io/openid_authentication'
        }
    }
]

formshare_sso_security_manager.py 的内容是:

from superset.security import SupersetSecurityManager

class FormShareSsoSecurityManager(SupersetSecurityManager):
    def oauth_user_info(self,provider,response=None):
        logging.debug("Oauth2 provider: {0}.".format(provider))
        if provider == 'FormShare':
            me = self.appbuilder.sm.oauth_remotes[provider].get('openid_userinfo').data
            logging.debug("user_data: {0}".format(me))
            return { 'name' : me['name'],'email' : me['email'],'id' : me['user_name'],'username' : me['user_name'],'first_name':'','last_name':''} 

但是我在 Superset 登录中得到以下图像:

enter image description here

如果我点击提供者,什么也没有发生,但界面会要求我提供 OpenID ID 作为输入。如果我输入经过身份验证的用户 ID,例如“carlos”超级集日志:

"GET /login/?next=http://qlands.eu.ngrok.io/login/ HTTP/1.1" 200 -
2021-05-18 09:53:17,871:WARNING:superset.views.base:404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.

我想我的配置基于 OAuth 但 OpenID 不同?我在 keycloak 上看到过一篇帖子,但我的 OpenID 服务器是一个简单的实现,它使用了 PyOphttps://oidcdebugger.com/

测试

我希望 superset 对 https://qlands.ngrok.io/openid_authentication 执行 GET 以对用户进行身份验证,作为回报,服务器将为 superset 提供一个代码,用于将其交换为令牌并使用令牌获取用户信息。

我还尝试了以下 OAUTH 配置,这使我在身份验证过程中取得了进展:

OAUTH_PROVIDERS = [
    {   'name':'FormShare','token_key':'access_token',# Name of the token in the response of access_token_url
        'icon':'fa-address-card',# Icon for the provider
        'remote_app': {
            'client_id':'501cE2ow7V4J',# Client Id (Identify Superset application)
            'client_secret':'060a450db0474b7db20afeda22a671b6',# Secret for this Client Id (Identify Superset application)
            'client_kwargs':{
                'scope': 'openid profile'               # Scope for the Authorization
            },'access_token_method':'POST',# HTTP Method to call access_token_url
            'access_token_params':{},'access_token_headers':{    # Additional headers for calls to access_token_url
                'Authorization': 'Basic Base64EncodedClientIdAndSecret'
            },'base_url':'https://qlands.ngrok.io','access_token_url':'https://qlands.ngrok.io/openid_token','authorize_url':'https://qlands.ngrok.io/openid_authentication'
        }
    }
]

Superset 提供了以下输出

2021-05-19 15:08:29,869:DEBUG:authlib.integrations.base_client.base_app:Saving authorize data: {'redirect_uri': 'http://qlands.eu.ngrok.io/oauth-authorized/FormShare','nonce': 'V3k0XaaVFL6pBqGbjGNt','url': 'https://qlands.ngrok.io/openid_authentication?response_type=code&client_id=501cE2ow7V4J&redirect_uri=http%3A%2F%2Fqlands.eu.ngrok.io%2Foauth-authorized%2FFormShare&scope=openid+profile&state=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuZXh0IjpbIiJdfQ.NTWe_SlU7cdUrf4WrQFRxasVKdcIpm98sMOoXkMg2No&nonce=V3k0XaaVFL6pBqGbjGNt','state': 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuZXh0IjpbIiJdfQ.NTWe_SlU7cdUrf4WrQFRxasVKdcIpm98sMOoXkMg2No'}
2021-05-19 15:08:29,872:INFO:werkzeug:127.0.0.1 - - [19/May/2021 15:08:29] "GET /login/FormShare?next= HTTP/1.1" 302 -
2021-05-19 15:08:30,636:DEBUG:authlib.integrations.base_client.base_app:Retrieve temporary data: {'code': '89cb4c27ed4f42268c59ab170a932aa1','state': 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuZXh0IjpbIiJdfQ.NTWe_SlU7cdUrf4WrQFRxasVKdcIpm98sMOoXkMg2No','redirect_uri': 'http://qlands.eu.ngrok.io/oauth-authorized/FormShare'}
2021-05-19 15:08:30,641:DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): qlands.ngrok.io:443
2021-05-19 15:08:30,929:DEBUG:urllib3.connectionpool:https://qlands.ngrok.io:443 "POST /openid_token HTTP/1.1" 200 1140
Oauth2 provider: FormShare.
2021-05-19 15:08:30,938:INFO:werkzeug:127.0.0.1 - - [19/May/2021 15:08:30] "GET /oauth-authorized/FormShare?code=89cb4c27ed4f42268c59ab170a932aa1&state=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuZXh0IjpbIiJdfQ.NTWe_SlU7cdUrf4WrQFRxasVKdcIpm98sMOoXkMg2No HTTP/1.1" 302 -
2021-05-19 15:08:31,310:INFO:werkzeug:127.0.0.1 - - [19/May/2021 15:08:31] "GET /login/ HTTP/1.1" 200 -

Superset 提出以下请求

[3]GET /login/                     200 OK                                                                                                                        
[2]GET /oauth-authorized/FormShare 302 FOUND                                                                                                                     
[1]GET /login/FormShare            302 FOUND  

以及 Supeset 向 OpenID 服务器发出的以下请求:

[2]POST /openid_token             200 OK                                                                                                                         
[1]GET  /openid_authentication    303 See Other

但是这个过程让我回到登录的消息:

登录无效。请重试。

感谢任何提示

解决方法

经过反复试验,我设法使用我的 OpenID 服务器配置了 SuperSet,但使用了 OAUTH。我使用了以下配置:

from formshare_sso_security_manager import FormShareSsoSecurityManager
from flask_appbuilder.security.manager import AUTH_OAUTH
...
CUSTOM_SECURITY_MANAGER = FormShareSsoSecurityManager
AUTH_TYPE = AUTH_OAUTH


OAUTH_PROVIDERS = [
    {
        "name": "FormShare","token_key": "access_token",# Name of the token in the response of access_token_url
        "icon": "fa-address-card",# Icon for the provider
        "remote_app": {
            "client_id": "501cE2ow7V4J",# Client Id (Identify Superset application)
            "client_secret": "060a450db0474b7db20afeda22a671b6",# Secret for this Client Id (Identify Superset application)
            "client_kwargs": {"scope": "openid profile"},# Scope for the Authorization
            "access_token_method": "POST",# HTTP Method to call access_token_url
            "access_token_params": {
                "redirect_uri": "http://qlands.eu.ngrok.io/oauth-authorized/FormShare"
            },"access_token_headers": {  # Additional headers for calls to access_token_url
                "Authorization": "Basic Base64EncodedClientIdAndSecret"
            },"base_url": "https://qlands.ngrok.io","access_token_url": "https://qlands.ngrok.io/openid_token","authorize_url": "https://qlands.ngrok.io/openid_authentication",},}
]

自定义管理器代码为:

class FormShareSsoSecurityManager(SupersetSecurityManager):
    def oauth_user_info(self,provider,response=None):
        if provider == "FormShare":
            access_token = response["access_token"]
            headers = {"Authorization": "Bearer {}".format(access_token)}
            response = requests.get("https://qlands.ngrok.io/openid_userinfo",headers=headers)
            user_data = response.json()
            return {
                "name": user_data["name"],"email": user_data["email"],"id": user_data["user_name"],"username": user_data["user_name"],"first_name": user_data["name"],"last_name": user_data["name"],}

自定义安全管理器使用 Python 请求来获取用户信息,因为 Superset documentation 中指示的以下代码不起作用:

me = self.appbuilder.sm.oauth_remotes[provider].get('openid_userinfo').data

要使 OpenID 集成工作,您需要在 superset_config.py 文件中设置 AUTH_USER_REGISTRATION = True,这对 OpenID 没有意义。因此,如果您有 AUTH_USER_REGISTRATION = False,则需要修改管理器以自定义函数 auth_user_oauth():

class FormShareSsoSecurityManager(SupersetSecurityManager):
    def oauth_user_info(self,}

    def auth_user_oauth(self,userinfo):
        ...

flask_appbuilder/security/manager.py 中的原始内容类似,但在 OpenID 客户端对用户进行身份验证后自动注册一次。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?