Skip to content

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

@myselfuser1

Description

@myselfuser1

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.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions