Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bypass Superset keycloak OAUTH login page #2225

Open
oldchurch12 opened this issue Apr 4, 2024 · 1 comment
Open

Bypass Superset keycloak OAUTH login page #2225

oldchurch12 opened this issue Apr 4, 2024 · 1 comment

Comments

@oldchurch12
Copy link

Hi,

I know this has been reported before. I think this is one of the old references : link

The issue is related to all superset version we have in use (2.1.0, 3.1.0 and also 3.1.1). We are deploying superset using helmcharts on kubernetes.

Issue:
We have a superset<-> keycloak integration using OAUTH. When the user logs in superset portal, the user always has to click the only option "SIGN IN WITH KEYCLOAK".

image

I have seen this behaviour documented in the current Flask-AppBuilder docu .

We dont see the value of this additional screen, especially if there is only one option you have to select.

In case there is a required functionality in this screen, let us know and we will forward this to our users.

Our preference is to bypass the screen to provide a low threshold access to the superset portal.

I appreciate feedback!

@gugupy
Copy link
Contributor

gugupy commented Apr 24, 2024

You can achive by extending the AuthOAuthView.login method and add below line start of the login view.

if provider is None:
    providers = [k for k in self.appbuilder.sm.oauth_remotes.keys()]
    if len(providers) == 1:
        provider = providers[0]

or simply provider = "keycloak"

Since you using superset you have to tell the security manager that you have different authoauthview.

class CustomSecurityManager(SupersetSecurityManager):
    authoauthview = SupersetAuthOAuthView

You can add the above script in your helm values file without modifying the code base.

extraSecrets:
  custom_security_manager.py: |-
    import logging
    import os
    import json

    from flask_appbuilder import const as c
    
    from superset.security import SupersetSecurityManager
    from werkzeug.security import generate_password_hash

    import jwt
    from typing import Optional
    from flask import flash, g, redirect, request, session, url_for
    from flask_appbuilder._compat import as_unicode
    from flask_appbuilder.security.utils import generate_random_string
    from flask_appbuilder.views import expose
    from flask_appbuilder.security.views import AuthOAuthView
    from werkzeug.wrappers import Response as WerkzeugResponse

    log = logging.getLogger(__name__)

    class SupersetAuthOAuthView(AuthOAuthView):
        @expose("/login/")
        @expose("/login/<provider>")
        def login(self, provider: Optional[str] = None) -> WerkzeugResponse:
           if provider is None:
               providers = [k for k in self.appbuilder.sm.oauth_remotes.keys()]
               if len(providers) == 1:
                   provider = providers[0]
            log.debug("Provider: %s", provider)
            if g.user is not None and g.user.is_authenticated:
                log.debug("Already authenticated %s", g.user)
                return redirect(self.appbuilder.get_url_for_index)

            if provider is None:
                return self.render_template(
                    self.login_template,
                    providers=self.appbuilder.sm.oauth_providers,
                    title=self.title,
                    appbuilder=self.appbuilder,
                )

            log.debug("Going to call authorize for: %s", provider)
            random_state = generate_random_string()
            state = jwt.encode(
                request.args.to_dict(flat=False), random_state, algorithm="HS256"
            )
            session["oauth_state"] = random_state
            try:
                if provider == "twitter":
                    return self.appbuilder.sm.oauth_remotes[provider].authorize_redirect(
                        redirect_uri=url_for(
                            ".oauth_authorized",
                            provider=provider,
                            _external=True,
                            state=state,
                        )
                    )
                else:
                    return self.appbuilder.sm.oauth_remotes[provider].authorize_redirect(
                        redirect_uri=url_for(
                            ".oauth_authorized", provider=provider, _external=True
                        ),
                        state=state.decode("ascii") if isinstance(state, bytes) else state,
                    )
            except Exception as e:
                log.error("Error on OAuth authorize: %s", e)
                flash(as_unicode(self.invalid_login_message), "warning")
                return redirect(self.appbuilder.get_url_for_index)

    class CustomSecurityManager(SupersetSecurityManager):
        authoauthview = SupersetAuthOAuthView
configOverrides:
  enable_oauth: |
    from custom_security_manager import CustomSecurityManager
    CUSTOM_SECURITY_MANAGER = CustomSecurityManager

I hope this helps you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants