Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

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

How to Get Keycloak User Roles After Integrating Single Sign On with Keycloak #32023

Closed
3 tasks done
myselfuser1 opened this issue Jan 29, 2025 · 3 comments
Closed
3 tasks done
Labels
authentication:sso Single Sign On

Comments

@myselfuser1
Copy link

Bug description

Here is the code from superset_config.py

SECRET_KEY = 'my_secret_key'
AUTH_TYPE = AUTH_OAUTH
LOGOUT_REDIRECT_URL='https://localhost:3000/auth/realms/master/protocol/openid-connect/logout'
AUTH_USER_REGISTRATION = True
# AUTH_USER_REGISTRATION_ROLE = "Gamma"
OAUTH_PROVIDERS = [
    {
        'name': 'keycloak',
        'token_key': 'access_token',
        'icon': 'fa-key',
        'remote_app': {
            'client_id': 'MY_CLIENT_ID',  # Replace with your Keycloak client ID
            'client_secret': 'MY_CLIENT_SECRET',  # Replace with your Keycloak client secret
            'api_base_url': 'https://localhost:3000/auth/realms/master/protocol/openid-connect/',  # Replace with your Keycloak realm URL
            'client_kwargs': {
                'scope': 'openid profile email',
                'roles_key': 'realm_access.roles',
            },
            'server_metadata_url': 'https://localhost:3000/realms/master/.well-known/openid-configuration',
            'api_base_url': 'https://localhost:3000/realms/master/protocol/',
            'access_token_url': 'https://localhost:3000/auth/realms/master/protocol/openid-connect/token',  # Replace with your Keycloak token URL
            'authorize_url': 'https://localhost:3000/auth/realms/master/protocol/openid-connect/auth',  # Replace with your Keycloak authorization URL
            'jwks_uri': 'https://localhost:3000/auth/realms/master/protocol/openid-connect/certs',  # Replace with your Keycloak JWKS URI
        },
    }
]
AUTH_ROLES_SYNC_AT_LOGIN = True

JWT_ALGORITHM = "RS256"
# URL to the public key endpoint
public_key_url = "https://localhost:3000/auth/realms/master"


def fetch_keycloak_rs256_public_cert():
    with urllib.request.urlopen(public_key_url) as response:  # noqa: S310
        public_key_url_response = json.load(response)
    public_key = public_key_url_response["public_key"]
    if public_key:
        pem_lines = [
            "-----BEGIN PUBLIC KEY-----",
            public_key,
            "-----END PUBLIC KEY-----",
        ]
        cert_pem = "\n".join(pem_lines)
    else:
        cert_pem = "No cert found"
    return cert_pem

print("aaaaa")
JWT_PUBLIC_KEY = fetch_keycloak_rs256_public_cert()
print("bbbbbb")
AUTH_ROLES_MAPPING = {
    'Super Admin': ['Admin', 'sql_lab'],
    'Portal Admin': ['Admin',],
    'Company Admin': ['Admin',],
    'Admin': ['Admin',],
    'admin': ['Admin',],
    'Non C-Cash User': ['Public'],
    'Ex C-Cash User': ['Public'],
    'External Users': ['Public'],
    'Licensed C-Cash User': ['Alpha'],
    'C-Cash User': ['Gamma'],
}
AUTH_ROLES_SYNC_AT_LOGIN = True
AUTH_USER_REGISTRATION = True
AUTH_USER_REGISTRATION_ROLE = "Public"

class CustomSsoSecurityManager(SupersetSecurityManager):
    def oauth_user_info(self, provider, response=None):  # noqa: ARG002
        me = self.appbuilder.sm.oauth_remotes[provider].get("openid-connect/userinfo")
        me.raise_for_status()
        data = me.json()
        logging.debug("User info from Keycloak: %s", data)
        return {
            "username": data.get("preferred_username", ""),
            "first_name": data.get("given_name", ""),
            "last_name": data.get("family_name", ""),
            "email": data.get("email", ""),
            "role_keys": data.get("role_keys", []),
        }

    def load_user_jwt(self, _jwt_header, jwt_data):
        username = jwt_data["preferred_username"]
        user = self.find_user(username=username)
        if user.is_active:
            # Set flask g.user to JWT user, we can't do it on before request
            g.user = user
            return user
        return None

CUSTOM_SECURITY_MANAGER = CustomSsoSecurityManager

Screenshots/recordings

Every time i sign in , the public role is assigned to the user on superset irrespective of what role is present for that user in keycloak

Superset version

master / latest-dev

Python version

3.9

Node version

16

Browser

Chrome

Additional context

No response

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.
Copy link

dosubot bot commented Jan 29, 2025

To ensure that the correct Keycloak user roles are assigned in Superset after integrating Single Sign-On with Keycloak, you need to map the roles from Keycloak to Superset roles using the AUTH_ROLES_MAPPING configuration. It seems like you have already set up the AUTH_ROLES_MAPPING in your superset_config.py, but the issue might be with how the roles are being extracted and used.

Here are a few things to check and adjust:

  1. Role Extraction: In your CustomSsoSecurityManager, ensure that the roles are being correctly extracted from the Keycloak response. The oauth_user_info method should extract the roles from the correct field in the Keycloak response. It seems like you are using role_keys, but you should verify that this is the correct field in the Keycloak response.

  2. Role Mapping: Make sure that the roles you are mapping in AUTH_ROLES_MAPPING match exactly with the roles being sent by Keycloak. Any mismatch in role names will result in the default role being assigned.

  3. Debugging: Add logging to verify what roles are being received from Keycloak and how they are being processed. This can help identify if the roles are being correctly extracted and mapped.

  4. Sync at Login: Since you have AUTH_ROLES_SYNC_AT_LOGIN set to True, roles should be synced at every login. Ensure that this setting is being respected by checking the logs for any errors during the login process.

If these steps do not resolve the issue, you might want to review similar discussions for additional insights. For instance, there is an open discussion on Assigning Superset roles to Keycloak authenticated users using the AUTH_ROLES_MAPPING that might provide more context or solutions [1].

To continue talking to Dosu, mention @dosu.


Help Dosu learn! Give it feedback: Great Response | Irrelevant Answer | Incorrect Sources | Too Verbose | Hallucination | Other

@dosubot dosubot bot added the authentication:sso Single Sign On label Jan 29, 2025
@myselfuser1
Copy link
Author

myselfuser1 commented Jan 29, 2025

@dosu when i print data = me.json() i get this

{'sub': '182345b0-c8a1-1233-2da2-c22afe2b882c', 'email_verified': True, 
    'name': 'Abc def', 'preferred_username': '[email protected]',
 'given_name': 'Abc', 'family_name': 'def', 'email': '[email protected]'}

there is no role_keys

Copy link

dosubot bot commented Jan 29, 2025

To correctly extract roles from the Keycloak response, you need to ensure that the roles are included in the response from Keycloak. It seems that the current response does not include any roles. Here are some steps you can take:

  1. Configure Keycloak to Include Roles: In Keycloak, you need to configure the client to include roles in the token or userinfo response. This can typically be done by adding a mapper in the Keycloak client settings. You can add a "User Realm Role" or "User Client Role" mapper to include roles in the token.

  2. Update oauth_user_info Method: Once roles are included in the response, update the oauth_user_info method to extract the roles from the correct field. For example, if roles are included under realm_access in the token, you might access them like this:

    roles = data.get('realm_access', {}).get('roles', [])
  3. Verify Role Mapping: Ensure that the roles extracted from Keycloak match the roles defined in your AUTH_ROLES_MAPPING configuration.

By configuring Keycloak to include roles and updating your code to extract them correctly, you should be able to map Keycloak roles to Superset roles effectively.

To continue talking to Dosu, mention @dosu.


Help Dosu learn! Give it feedback: Great Response | Irrelevant Answer | Incorrect Sources | Too Verbose | Hallucination | Other

@apache apache locked and limited conversation to collaborators Feb 6, 2025
@rusackas rusackas converted this issue into discussion #32173 Feb 6, 2025

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
authentication:sso Single Sign On
Projects
None yet
Development

No branches or pull requests

1 participant