Apache Superset与Jumpcloud OIDC集成OAuth错误求助
Apache Superset与Jumpcloud OIDC集成问题排查
问题背景
使用Helm部署Apache Superset,尝试通过OIDC协议与Jumpcloud集成以实现身份验证,过程中出现两类错误,请求协助排查。
两端配置信息
Jumpcloud端配置
login url - https://superset.dev/login redirect url - https://superset.dev/oauth-authorized/jumpcloud
Superset端配置
from superset.security import SupersetSecurityManager from superset.security.manager import SupersetSecurityManager from superset.security.manager import SupersetSecurityManager from flask_appbuilder.security.manager import AUTH_OAUTH import json import logging from base64 import b64decode AUTH_TYPE = AUTH_OAUTH AUTH_USER_REGISTRATION = False ENABLE_PROXY_FIX = True PROXY_FIX_CONFIG = {"x_for": 1, "x_proto": 1, "x_host": 1, "x_port": 0, "x_prefix": 1} OAUTH_PROVIDERS = [ { 'name': 'jumpcloud', 'icon': 'fa-address-card', 'remote_app': { 'client_id': 'abc', 'client_secret': 'xyz', 'client_kwargs': { 'scope': 'openid' # Scope for the Authorization }, 'server_metadata_url': 'https://oauth.id.jumpcloud.com/.well-known/openid-configuration', 'api_base_url':'https://oauth.id.jumpcloud.com/', 'access_token_url':'https://oauth.id.jumpcloud.com/oauth2/token', 'authorize_url':'https://oauth.id.jumpcloud.com/oauth2/auth', 'jwks_uri':'https://oauth.id.jumpcloud.com/.well-known/jwks.json', 'userinfo_uri': 'https://oauth.id.jumpcloud.com/userinfo' } } ] class CustomSsoSecurityManager(SupersetSecurityManager): def oauth_user_info(self, provider, response=None): print(provider) if provider == "jumpcloud": id_token = self.appbuilder.sm.oauth_remotes[provider].token logging.debug(f"ID Token: {id_token}") user_groups = get_user_group(id_token) me = self.appbuilder.sm.oauth_remotes[provider].userinfo() role_map = { "admin": "Admin" } roles = [role_map[key] for key in user_groups if key in role_map] user_payload = { "name": me["preferred_username"], "email": me["email"], "id": me["email"], "username": me["email"].split("@")[0], "first_name": me["given_name"], "last_name": me["family_name"], } if len(roles) > 0: user_payload["role"] = roles[0] return user_payload def auth_user_oauth(self, userinfo): if "username" in userinfo: user = self.find_user(username=userinfo["username"]) elif "email" in userinfo: user = self.find_user(email=userinfo["email"]) else: user = False logging.error("User info does not have username or email {0}".format(userinfo)) if not user and not self.auth_user_registration: logging.debug("user does not exist on the DB and not self user registration, go away") return None if not user: if userinfo.get("role"): default_role = self.find_role(userinfo["role"]) else: aur = self.auth_user_registration_role default_role = self.find_role(aur) user = self.add_user( username=userinfo["username"], first_name=userinfo.get("first_name", ""), last_name=userinfo.get("last_name", ""), email=userinfo.get("email", ""), role=default_role, ) logging.debug("Adding user with role={} ".format(default_role)) if not user: logging.error("Error creating a new OAuth user %s" % userinfo["username"]) return None else: logging.debug("Success!") logging.debug("final user before update ={}".format(user)) self.update_user_auth_stat(user) return user CUSTOM_SECURITY_MANAGER = CustomSsoSecurityManager
遇到的错误
错误1
DEBUG:urllib3.connectionpool:https://oauth.id.jumpcloud.com:443 "POST /oauth2/token HTTP/1.1" 200 None ERROR:flask_appbuilder.security.views:Error returning OAuth user info: 'oauth_token'
错误2
[ERROR] Error handling request Traceback (most recent call last): File "/usr/local/lib/python3.8/site-packages/gunicorn/workers/gthread.py", line 326, in handle_request resp.write_file(respiter) File "/usr/local/lib/python3.8/site-packages/gunicorn/http/wsgi.py", line 385, in write_file if not self.sendfile(respiter): File "/usr/local/lib/python3.8/site-packages/gunicorn/http/wsgi.py", line 375, in sendfile self.sock.sendfile(respiter.filelike, count=nbytes) File "/usr/local/lib/python3.8/socket.py", line 482, in sendfile return self._sendfile_use_sendfile(file, offset, count) File "/usr/local/lib/python3.8/socket.py", line 346, in _sendfile_use_sendfile self._check_sendfile_params(file, offset, count) File "/usr/local/lib/python3.8/socket.py", line 460, in _check_sendfile_params raise ValueError( ValueError: count must be a positive integer (got 0)
排查与修复建议
解决
oauth_token错误- 调整token获取方式:
oauth_user_info方法中应使用传入的response参数获取token,替换id_token = self.appbuilder.sm.oauth_remotes[provider].token为id_token = response.get('id_token'),避免调用未初始化的token对象。 - 补充
get_user_group函数:当前代码未定义该函数,需实现解析id_token群组信息的逻辑,否则会触发运行时错误。 - 扩展OAuth Scope:仅
openid权限不足以获取完整用户信息,修改client_kwargs中的scope为openid profile email groups。
- 调整token获取方式:
修复gunicorn响应错误
- 该错误是OAuth认证失败导致响应体为空的连锁问题,解决第一个错误后大概率会自动消失。若仍存在,可在Helm配置中添加
GUNICORN_CMD_ARGS: "--disable-sendfile"禁用sendfile功能。
- 该错误是OAuth认证失败导致响应体为空的连锁问题,解决第一个错误后大概率会自动消失。若仍存在,可在Helm配置中添加
优化OAuth配置
- 已配置
server_metadata_url,可删除重复的access_token_url、authorize_url、jwks_uri,让系统自动从元数据中读取,避免配置冲突。 - 验证Jumpcloud端redirect url与Superset回调路径完全一致,包括协议、域名和路径。
- 已配置
内容的提问来源于stack exchange,提问作者surya
相关产品推荐
相关产品推荐

