diff --git a/plaid/auth_oidc.py b/plaid/auth_oidc.py index 19a424a8f0050..f4c332a05d7f3 100644 --- a/plaid/auth_oidc.py +++ b/plaid/auth_oidc.py @@ -25,7 +25,7 @@ def login(self, flag:bool=True) -> Response: def authorize(self) -> Response: oauth = self.appbuilder.sm.oauth token = oauth.plaid.authorize_access_token() - userinfo = oauth.plaid.parse_id_token(token) + userinfo = oauth.plaid.parse_id_token(token, None) log.info(f"Fetched user info from token: {userinfo}") user_email = userinfo['email'].lower() if user_email.endswith('tartansolutions.com') or user_email.endswith('plaidcloud.com'): diff --git a/plaid/security.py b/plaid/security.py index 9c458e8c2d902..d82d46a53399c 100644 --- a/plaid/security.py +++ b/plaid/security.py @@ -13,7 +13,7 @@ from flask import session from flask_login import logout_user from flask_appbuilder import Model -from flask_appbuilder.security.manager import AUTH_OID +from flask_appbuilder.security.manager import AUTH_OID, AUTH_OAUTH from authlib.integrations.flask_client import OAuth from requests.exceptions import HTTPError @@ -44,12 +44,11 @@ class PlaidSecurityManager(SupersetSecurityManager): """ def __init__(self, appbuilder): - super(PlaidSecurityManager, self).__init__(appbuilder) - # engine = self.get_session.get_bind(mapper=None, clause=None) - # metadata = MetaData(bind=engine, reflect=True) - # self.plaiduser_user = metadata.tables['plaiduser_user'] + app = appbuilder.get_app + # app.config['AUTH_TYPE'] = AUTH_OAUTH + super().__init__(appbuilder) if self.auth_type == AUTH_OID: - self.oidc_params = self.appbuilder.app.config.get("OIDC_PARAMS") + self.oidc_params = app.config.get("OIDC_PARAMS") self.oauth = OAuth(app=appbuilder.get_app) self.oauth.register( 'plaid', @@ -64,8 +63,34 @@ def __init__(self, appbuilder): self.authoidview = AuthOIDCView + def oauth_user_info(self, provider, response=None): + # logging.debug("Oauth2 provider: {0}.".format(provider)) + if provider == 'plaid-keycloak': + me = self.appbuilder.sm.oauth_remotes[provider].get( + "openid-connect/userinfo" + ) + me.raise_for_status() + data = me.json() + log.debug("User info from Keycloak: %s", data) + + user_email = me['email'].lower() + role_keys = ["superset-plaid", "superset-gamma"] + if user_email.endswith('tartansolutions.com') or user_email.endswith('plaidcloud.com'): + role_keys.append("superset-admin") + + # possibly use AUTH_ROLES_MAPPING and AUTH_ROLES_SYNC_AT_LOGIN = True, with roles given in Keycloak + # https://github.com/apache/superset/blob/ff903486a851760e108b2e841e6a17348b3a9523/docs/src/pages/docs/installation/configuring.mdx + + return { + "username": data.get("preferred_username", ""), + "first_name": data.get("given_name", ""), + "last_name": data.get("family_name", ""), + "email": data.get("email", ""), + "role_keys": role_keys # data.get("groups", []), + } + def sync_role_definitions(self): - """PlaidSecurityManager contructor. + """PlaidSecurityManager constructor. Establishes a Plaid role (and Public, if configured to do so) after invoking the super constructor. @@ -110,12 +135,12 @@ def get_rpc(self) -> SimpleRPC: base_url = f"http://{self.appbuilder.app.config.get('PLAID_RPC')}" rpc_url = urljoin(base_url, "json-rpc/") - if 'workspace' in session: - temp_token = f"{session['token']['access_token']}_ws{session['workspace']}" + if self.auth_type == AUTH_OAUTH: + rpc_token, secret = session['oauth'] else: - temp_token = session['token']['access_token'] + rpc_token = session['token']['access_token'] - rpc = SimpleRPC(session['token']['access_token'], uri=rpc_url, verify_ssl=False) + rpc = SimpleRPC(rpc_token, uri=rpc_url, verify_ssl=False) try: rpc.identity.me.scopes() # Just checking authentication diff --git a/requirements/base.txt b/requirements/base.txt index d81bb06b088a5..94b8ae89348f9 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -25,7 +25,7 @@ attrs==23.2.0 # referencing # requests-cache # trio -authlib==0.13 +authlib==1.3.0 # via apache-superset babel==2.14.0 # via flask-babel diff --git a/setup.py b/setup.py index 3251ab1fe9cb1..6813368844f01 100644 --- a/setup.py +++ b/setup.py @@ -73,7 +73,7 @@ def get_git_sha() -> str: ], }, install_requires=[ - "Authlib==0.13", + "Authlib==1.3.0", "backoff>=1.8.0", "celery>=5.2.2, <6.0.0", "click>=8.0.3",