marcospereirampj / python-keycloak

MIT License
722 stars 300 forks source link

Cannot modify existing user realms #610

Open bclements opened 5 days ago

bclements commented 5 days ago

Fresh install of keycloak 26.0.0. python-keycloak 4.6.2

When I run the following against an existing realm

from keycloak import KeycloakAdmin
keycloak_admin = KeycloakAdmin(
            server_url="https://myauthserver",
            username='myadmin',
            password='mypassword',
            realm_name="master",            
            )
keycloak_admin.connection.realm_name = "mytestrealm"
keycloak_admin.get_users()

I get *** keycloak.exceptions.KeycloakAuthenticationError: 401: b'{"error":"invalid_grant","error_description":"Invalid user credentials"}'

But the odd thing is, if I create a realm and do anything, like get users, everything works as expected.

Why can't I access resources in my user realm?

RKN01011 commented 2 days ago

The same situation

RKN01011 commented 2 days ago

It starts from here: https://github.com/marcospereirampj/python-keycloak/blob/master/src/keycloak/keycloak_openid.py#L345

And occurs when you call keycloak.KeycloakAdmin.get_realm_role.

RKN01011 commented 2 days ago

In my case, the following helped:

keycloak_client: typing.Final = keycloak.KeycloakAdmin(
    server_url=settings.keycloak_server_url,
    realm_name=settings.keycloak_realm_name,
    client_id="test-rest-client",
    client_secret_key="test-client-secret",
    verify=settings.keycloak_verify_connection,
)

I simply omitted the username and password, then added client_id and client_secret_key

ryshoooo commented 2 days ago

This is a consequence of changes in https://github.com/marcospereirampj/python-keycloak/pull/566, which removed the automatic fetching of the token upon KeycloakAdmin initialization. So from then on, when you instantiate a KeycloakAdmin class, the token for communicating with Keycloak's Rest API is not fetched, until the first action call (like get_users).

If you change the realm before the token is fetched, the admin class will try to fetch the token from the mytestrealm instead of the master realm, which does not contain the user you are trying to use for authentication, thus the Invalid user credentials error.

A simple fix for your code is to explicitly fetch the token before changing the realm:

from keycloak import KeycloakAdmin
keycloak_admin = KeycloakAdmin(
            server_url="https://myauthserver",
            username='myadmin',
            password='mypassword',
            realm_name="master",            
            )
keycloak_admin.connection.get_token()
keycloak_admin.connection.realm_name = "mytestrealm"
keycloak_admin.get_users()
ryshoooo commented 2 days ago

I'm also going to add that I agree with you @bclements and @RKN01011, this is not the best UX we are experiencing right now. I think it can be easily fixed by storing the initial realm name and using that for fetching of the token in openid_connnection. Should prevent the most common pitfalls

ryshoooo commented 1 day ago

Actually, after going through the code again, I've just realized that this is already implemented. What you want to use is the parameter user_realm_name, which specifies which realm the user for authentication lives in. Therefore

keycloak_admin = KeycloakAdmin(
            server_url="https://myauthserver",
            username='myadmin',
            password='mypassword',
            realm_name="mytestrealm",
            user_realm_name="master",            
            )
keycloak_admin.get_users()

should just work out of the box.