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

Apache Superset & Keycloak integration #29539

Open
3 tasks done
kormpakis opened this issue Jul 10, 2024 · 5 comments
Open
3 tasks done

Apache Superset & Keycloak integration #29539

kormpakis opened this issue Jul 10, 2024 · 5 comments
Labels
authentication:sso Single Sign On authentication Related to authentication

Comments

@kormpakis
Copy link

Bug description

I am currently working on configuring OAuth authentication between Keycloak and Apache Superset. I am encountering an issue where, after entering the credentials on the Keycloak page, I am redirected back to Superset with the message: "The request to sign in was denied."

How to reproduce the bug

Below are the configurations I have used: Keycloak Configuration (Version 23.0.3)

Keycloak Client Settings
Valid Redirect URIs: http://localhost:8089/oauth-authorized/keycloak
Web Origins: http://localhost:8089/%5C*

Apache Superset Configuration (superset_config.py):

AUTH_TYPE = AUTH_OAUTH
LOGOUT_REDIRECT_URL = 'https://{my_keycloak_domain}/realms/{my_realm_name}/protocol/openid-connect/logout'
AUTH_USER_REGISTRATION = TrueAUTH_USER_REGISTRATION_ROLE = 'Gamma'

OAuth provider configuration for Keycloak in superset_config.py

OAUTH_PROVIDERS = [
{
'name': 'keycloak',
'icon': 'fa-key',
'token_key': 'access_token', # Keycloak uses 'access_token' for the access token
'remote_app': {
'client_id': 'test',
'client_secret': 'dElzstUQqUgQshK23IWWjmNuoe9GgIo8',
'api_base_url': 'https://{my_keycloak_domain}/auth/',
'client_kwargs': {
'scope': 'openid profile email',
},
'base_url': 'https://{my_keycloak_domain}/realms/{my_realm_name}/protocol/openid-connect/auth',
'request_token_url': None,
'access_token_url': 'https://{my_keycloak_domain}/realms/{my_realm_name}/protocol/openid-connect/token',
'authorize_url': 'https://{my_keycloak_domain}/realms/{my_realm_name}/protocol/openid-connect/auth',
},
}
]

Issue Description
After entering the credentials in the Keycloak login page, the redirection to Superset results in the following message: "The request to sign in was denied."

Screenshots/recordings

No response

Superset version

master / latest-dev

Python version

I don't know

Node version

I don't know

Browser

Not applicable

Additional context

I am unsure what might be causing this error and would greatly appreciate your assistance in identifying and resolving the issue.

Has anyone had any similar issues?

I tried various configurations and similar issues for several days now with no result.
It seems to be connected in the first place (it redirects to Keycloak sign-in page and comes back to Superset when correct credentials are provided) but it stucks in the final step.

Please help me and let's create a clear and working configuration, since the official docs are not so helpful...

Checklist

  • I have searched Superset docs and Slack and didn't find a solution to my problem.
  • I have searched the GitHub issue tracker and didn't find a similar bug report.
  • I have checked Superset's logs for errors and if I found a relevant Python stacktrace, I included it here as text in the "additional context" section.
@dosubot dosubot bot added authentication Related to authentication authentication:sso Single Sign On labels Jul 10, 2024
Copy link

dosubot bot commented Jul 10, 2024

To resolve the issue where, after entering credentials on the Keycloak page, you are redirected back to Apache Superset with the message: "The request to sign in was denied," you need to ensure that the OAuth2 flow is correctly configured and that the necessary permissions are granted.

Here are some steps you can take to troubleshoot and resolve the issue:

  1. Check Redirect URI: Ensure that the redirect_uri configured in Keycloak matches the one expected by Superset. The redirect_uri should be correctly set in both Keycloak and Superset configurations.

  2. Verify OAuth2 Configuration: Make sure that the OAuth2 client configuration in Keycloak is correct. This includes the client ID, client secret, and the allowed redirect URIs.

  3. Inspect Browser Console and Network Logs: Look at the browser console and network logs to see if there are any errors or warnings that can provide more details about why the sign-in request was denied.

  4. Check Superset Logs: Review the Superset logs for any error messages or warnings related to the OAuth2 authentication process. This can provide more insight into what might be going wrong.

  5. Ensure Correct Permissions: Verify that the user has the necessary permissions in Keycloak to access the application.

  6. Cross-Origin Requests: Ensure that cross-origin requests are properly handled and that the event.origin and event.source checks in the handleMessage function are correctly validating the message source.

Here is the relevant part of the code that handles the OAuth2 redirect and message validation:

const handleMessage = (event: MessageEvent) => {
  const redirectUrl = new URL(extra.redirect_uri);
  if (
    event.origin === redirectUrl.origin &&
    event.data.tabId === extra.tab_id &&
    event.source === oAuthTab.current
  ) {
    if (source === 'sqllab' && query) {
      dispatch(reRunQuery(query));
    } else if (source === 'explore' && chartId) {
      dispatch(triggerQuery(true, chartId));
    } else if (source === 'dashboard') {
      dispatch(onRefresh(chartList, true, 0, dashboardId));
    }
  }
};

Ensure that the redirect_uri, tab_id, and event.origin are correctly set and match the expected values. This validation is crucial for the OAuth2 flow to succeed [1].

Additionally, review the specific error messages or logs generated by Superset when the OAuth2 authentication fails. The relevant error messages are:

  1. OAuth2RedirectError:

    SupersetError(
        message="You don't have permission to access the data.",
        error_type=SupersetErrorType.OAUTH2_REDIRECT,
        level=ErrorLevel.WARNING,
        extra={"url": url, "tab_id": tab_id, "redirect_uri": redirect_uri},
    )
  2. OAuth2Error:

    SupersetError(
        message="Something went wrong while doing OAuth2",
        error_type=SupersetErrorType.OAUTH2_REDIRECT_ERROR,
        level=ErrorLevel.ERROR,
        extra={"error": error},
    )
    <sup>[[2]](https://github.com/apache/superset/blob/master/superset/exceptions.py)</sup><sup>[[3]](https://github.com/apache/superset/blob/master/superset/errors.py)</sup>

By following these steps and ensuring that the configurations are correct, you should be able to resolve the issue and successfully authenticate using Keycloak with Apache Superset.

To continue talking to Dosu, mention @dosu.

@kormpakis
Copy link
Author

To resolve the issue where, after entering credentials on the Keycloak page, you are redirected back to Apache Superset with the message: "The request to sign in was denied," you need to ensure that the OAuth2 flow is correctly configured and that the necessary permissions are granted.

Here are some steps you can take to troubleshoot and resolve the issue:

  1. Check Redirect URI: Ensure that the redirect_uri configured in Keycloak matches the one expected by Superset. The redirect_uri should be correctly set in both Keycloak and Superset configurations.
  2. Verify OAuth2 Configuration: Make sure that the OAuth2 client configuration in Keycloak is correct. This includes the client ID, client secret, and the allowed redirect URIs.
  3. Inspect Browser Console and Network Logs: Look at the browser console and network logs to see if there are any errors or warnings that can provide more details about why the sign-in request was denied.
  4. Check Superset Logs: Review the Superset logs for any error messages or warnings related to the OAuth2 authentication process. This can provide more insight into what might be going wrong.
  5. Ensure Correct Permissions: Verify that the user has the necessary permissions in Keycloak to access the application.
  6. Cross-Origin Requests: Ensure that cross-origin requests are properly handled and that the event.origin and event.source checks in the handleMessage function are correctly validating the message source.

Here is the relevant part of the code that handles the OAuth2 redirect and message validation:

const handleMessage = (event: MessageEvent) => {
  const redirectUrl = new URL(extra.redirect_uri);
  if (
    event.origin === redirectUrl.origin &&
    event.data.tabId === extra.tab_id &&
    event.source === oAuthTab.current
  ) {
    if (source === 'sqllab' && query) {
      dispatch(reRunQuery(query));
    } else if (source === 'explore' && chartId) {
      dispatch(triggerQuery(true, chartId));
    } else if (source === 'dashboard') {
      dispatch(onRefresh(chartList, true, 0, dashboardId));
    }
  }
};

Ensure that the redirect_uri, tab_id, and event.origin are correctly set and match the expected values. This validation is crucial for the OAuth2 flow to succeed [1].

Additionally, review the specific error messages or logs generated by Superset when the OAuth2 authentication fails. The relevant error messages are:

  1. OAuth2RedirectError:
    SupersetError(
        message="You don't have permission to access the data.",
        error_type=SupersetErrorType.OAUTH2_REDIRECT,
        level=ErrorLevel.WARNING,
        extra={"url": url, "tab_id": tab_id, "redirect_uri": redirect_uri},
    )
  2. OAuth2Error:
    SupersetError(
        message="Something went wrong while doing OAuth2",
        error_type=SupersetErrorType.OAUTH2_REDIRECT_ERROR,
        level=ErrorLevel.ERROR,
        extra={"error": error},
    )
    <sup>[[2]](https://github.com/apache/superset/blob/master/superset/exceptions.py)</sup><sup>[[3]](https://github.com/apache/superset/blob/master/superset/errors.py)</sup>

By following these steps and ensuring that the configurations are correct, you should be able to resolve the issue and successfully authenticate using Keycloak with Apache Superset.

To continue talking to Dosu, mention @dosu.

This is like a ChatGPT reply, lol.

Copy link

dosubot bot commented Jul 10, 2024

To resolve the issue where, after entering credentials on the Keycloak page, you are redirected back to Apache Superset with the message: "The request to sign in was denied," you need to ensure that the OAuth2 flow is correctly configured and that the necessary permissions are granted.

Here are some steps you can take to troubleshoot and resolve the issue:

  1. Check Redirect URI: Ensure that the redirect_uri configured in Keycloak matches the one expected by Superset. The redirect_uri should be correctly set in both Keycloak and Superset configurations.

  2. Verify OAuth2 Configuration: Make sure that the OAuth2 client configuration in Keycloak is correct. This includes the client ID, client secret, and the allowed redirect URIs.

  3. Inspect Browser Console and Network Logs: Look at the browser console and network logs to see if there are any errors or warnings that can provide more details about why the sign-in request was denied.

  4. Check Superset Logs: Review the Superset logs for any error messages or warnings related to the OAuth2 authentication process. This can provide more insight into what might be going wrong.

  5. Ensure Correct Permissions: Verify that the user has the necessary permissions in Keycloak to access the application.

  6. Cross-Origin Requests: Ensure that cross-origin requests are properly handled and that the event.origin and event.source checks in the handleMessage function are correctly validating the message source.

Here is the relevant part of the code that handles the OAuth2 redirect and message validation:

const handleMessage = (event: MessageEvent) => {
  const redirectUrl = new URL(extra.redirect_uri);
  if (
    event.origin === redirectUrl.origin &&
    event.data.tabId === extra.tab_id &&
    event.source === oAuthTab.current
  ) {
    if (source === 'sqllab' && query) {
      dispatch(reRunQuery(query));
    } else if (source === 'explore' && chartId) {
      dispatch(triggerQuery(true, chartId));
    } else if (source === 'dashboard') {
      dispatch(onRefresh(chartList, true, 0, dashboardId));
    }
  }
};

Ensure that the redirect_uri, tab_id, and event.origin are correctly set and match the expected values. This validation is crucial for the OAuth2 flow to succeed [1].

Additionally, review the specific error messages or logs generated by Superset when the OAuth2 authentication fails. The relevant error messages are:

  1. OAuth2RedirectError:

    SupersetError(
        message="You don't have permission to access the data.",
        error_type=SupersetErrorType.OAUTH2_REDIRECT,
        level=ErrorLevel.WARNING,
        extra={"url": url, "tab_id": tab_id, "redirect_uri": redirect_uri},
    )
  2. OAuth2Error:

    SupersetError(
        message="Something went wrong while doing OAuth2",
        error_type=SupersetErrorType.OAUTH2_REDIRECT_ERROR,
        level=ErrorLevel.ERROR,
        extra={"error": error},
    )
    <sup>[[2]](https://github.com/apache/superset/blob/master/superset/exceptions.py)</sup><sup>[[3]](https://github.com/apache/superset/blob/master/superset/errors.py)</sup>

By following these steps and ensuring that the configurations are correct, you should be able to resolve the issue and successfully authenticate using Keycloak with Apache Superset.

To continue talking to Dosu, mention @dosu.

@sfirke
Copy link
Member

sfirke commented Jul 10, 2024

Great timing @kormpakis -- can you please take a look at this pending addition to the documentation about how to set up Keycloak auth: #29487

@PedroMartinSteenstrup
Copy link

PedroMartinSteenstrup commented Jul 18, 2024

just FYI, you can make sure everything is well set up in Keycloak itself, and then just refer to the well-known endpoint.
Start with allowing all origins and redirects, to make sure your code work, then you can restrict again.

Here is my working -but truncated- version, without installing any additional package such as Flask-OIDC:

class KeycloakSecurity(SupersetSecurityManager):
    """
    Create a new SecurityManager with own oauth_user_info to handle the information from Keycloak
    """

    def __init__(self, appbuilder):
        super(KeycloakSecurity, self).__init__(appbuilder)
        app = self.appbuilder.get_app
        app.config.setdefault("AUTH_ROLES_MAPPING", {})
        app.config.setdefault("AUTH_TYPE", AUTH_OAUTH)

    def oauth_user_info(self, provider, resp=None):
        if provider == "keycloak":
            log.debug("Keycloak response received : {0}".format(resp))
            log.debug("ID Token: %s", resp["id_token"])
            me = self.appbuilder.sm.oauth_remotes[provider].get(
                f'https://<sso.domain.name>/auth/realms/<realm-name>/protocol/openid-connect/userinfo'
            )
            me.raise_for_status()
            data = me.json()
            log.debug("User info from Keycloak: %s", data)
            return {
                "name": data["name"],
                "email": data["email"],
                "first_name": data["given_name"],
                "last_name": data["family_name"],
                "id": data["preferred_username"],
                "username": data["preferred_username"],
                "role_keys": data["groups"]
            }

CUSTOM_SECURITY_MANAGER = KeycloakSecurity

AUTH_TYPE = AUTH_OAUTH
OAUTH_PROVIDERS = [
    {
        "name": "keycloak",
        "icon": "fa-key",
        "token_key": "access_token",
        "remote_app": {
            "client_id": "superset",
            "client_secret": os.getenv("OAUTH_CLIENT_SECRET", None),
            "client_kwargs": {"scope": "openid email groups"},
            "server_metadata_url": "https://<sso.domain.name>/auth/realms/<realm-name>/.well-known/openid-configuration"
        }
    }]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
authentication:sso Single Sign On authentication Related to authentication
Projects
None yet
Development

No branches or pull requests

3 participants