From 41d20478e9faa59f67afa976f9087a6934821db7 Mon Sep 17 00:00:00 2001 From: alexrohozneanu <53479034+alexrohozneanu@users.noreply.github.com> Date: Wed, 2 Oct 2024 10:01:02 +0300 Subject: [PATCH] fix: Set client_credentials as grant_type also when x509 certificate is given (#597) * fix: Added grant type as openid_connection optional attribute * fix: Add getter and setter for grant_type --------- Co-authored-by: Alex Rohozneanu --- src/keycloak/keycloak_admin.py | 4 +++ src/keycloak/keycloak_openid.py | 12 ++++----- src/keycloak/openid_connection.py | 44 ++++++++++++++++++++----------- 3 files changed, 38 insertions(+), 22 deletions(-) diff --git a/src/keycloak/keycloak_admin.py b/src/keycloak/keycloak_admin.py index 3b1b00a..7af64ab 100644 --- a/src/keycloak/keycloak_admin.py +++ b/src/keycloak/keycloak_admin.py @@ -86,6 +86,7 @@ class KeycloakAdmin: def __init__( self, server_url=None, + grant_type=None, username=None, password=None, token=None, @@ -104,6 +105,8 @@ class KeycloakAdmin: :param server_url: Keycloak server url :type server_url: str + :param grant_type: grant type for authn + :type grant_type: str :param username: admin username :type username: str :param password: admin password @@ -136,6 +139,7 @@ class KeycloakAdmin: """ self.connection = connection or KeycloakOpenIDConnection( server_url=server_url, + grant_type=grant_type, username=username, password=password, token=token, diff --git a/src/keycloak/keycloak_openid.py b/src/keycloak/keycloak_openid.py index 7c0a558..a4453eb 100644 --- a/src/keycloak/keycloak_openid.py +++ b/src/keycloak/keycloak_openid.py @@ -276,7 +276,7 @@ class KeycloakOpenID: self, username="", password="", - grant_type=["password"], + grant_type="password", code="", redirect_uri="", totp=None, @@ -338,7 +338,7 @@ class KeycloakOpenID: ) return raise_error_from_response(data_raw, KeycloakPostError) - def refresh_token(self, refresh_token, grant_type=["refresh_token"]): + def refresh_token(self, refresh_token, grant_type="refresh_token"): """Refresh the user token. The token endpoint is used to obtain tokens. Tokens can either be obtained by @@ -409,7 +409,7 @@ class KeycloakOpenID: """ params_path = {"realm-name": self.realm_name} payload = { - "grant_type": ["urn:ietf:params:oauth:grant-type:token-exchange"], + "grant_type": "urn:ietf:params:oauth:grant-type:token-exchange", "client_id": self.client_id, "subject_token": token, "subject_token_type": subject_token_type, @@ -920,7 +920,7 @@ class KeycloakOpenID: self, username="", password="", - grant_type=["password"], + grant_type="password", code="", redirect_uri="", totp=None, @@ -982,7 +982,7 @@ class KeycloakOpenID: ) return raise_error_from_response(data_raw, KeycloakPostError) - async def a_refresh_token(self, refresh_token, grant_type=["refresh_token"]): + async def a_refresh_token(self, refresh_token, grant_type="refresh_token"): """Refresh the user token asynchronously. The token endpoint is used to obtain tokens. Tokens can either be obtained by @@ -1053,7 +1053,7 @@ class KeycloakOpenID: """ params_path = {"realm-name": self.realm_name} payload = { - "grant_type": ["urn:ietf:params:oauth:grant-type:token-exchange"], + "grant_type": "urn:ietf:params:oauth:grant-type:token-exchange", "client_id": self.client_id, "subject_token": token, "subject_token_type": subject_token_type, diff --git a/src/keycloak/openid_connection.py b/src/keycloak/openid_connection.py index 15d2cb9..73ab9d8 100644 --- a/src/keycloak/openid_connection.py +++ b/src/keycloak/openid_connection.py @@ -43,6 +43,7 @@ class KeycloakOpenIDConnection(ConnectionManager): """ _server_url = None + _grant_type = None _username = None _password = None _totp = None @@ -59,6 +60,7 @@ class KeycloakOpenIDConnection(ConnectionManager): def __init__( self, server_url, + grant_type=None, username=None, password=None, token=None, @@ -76,6 +78,8 @@ class KeycloakOpenIDConnection(ConnectionManager): :param server_url: Keycloak server url :type server_url: str + :param grant_type: grant type for authn + :type grant_type: str :param username: admin username :type username: str :param password: admin password @@ -110,6 +114,7 @@ class KeycloakOpenIDConnection(ConnectionManager): self.token_lifetime_fraction = 0.9 self.headers = {} self.server_url = server_url + self.grant_type = grant_type self.username = username self.password = password self.token = token @@ -124,6 +129,12 @@ class KeycloakOpenIDConnection(ConnectionManager): self.headers = {**self.headers, "Content-Type": "application/json"} self.cert = cert + if not self.grant_type: + if username and password: + self.grant_type = "password" + elif client_secret_key: + self.grant_type = "client_credentials" + super().__init__( base_url=self.server_url, headers=self.headers, @@ -145,6 +156,19 @@ class KeycloakOpenIDConnection(ConnectionManager): def server_url(self, value): self.base_url = value + @property + def grant_type(self): + """Get grant type. + + :returns: Grant type + :rtype: str + """ + return self._grant_type + + @grant_type.setter + def grant_type(self, value): + self._grant_type = value + @property def realm_name(self): """Get realm name. @@ -314,15 +338,9 @@ class KeycloakOpenIDConnection(ConnectionManager): The admin token is then set in the `token` attribute. """ - grant_type = [] - if self.username and self.password: - grant_type.append("password") - elif self.client_secret_key: - grant_type.append("client_credentials") - - if grant_type: + if self.grant_type: self.token = self.keycloak_openid.token( - self.username, self.password, grant_type=grant_type, totp=self.totp + self.username, self.password, grant_type=self.grant_type, totp=self.totp ) else: self.token = None @@ -426,15 +444,9 @@ class KeycloakOpenIDConnection(ConnectionManager): The admin token is then set in the `token` attribute. """ - grant_type = [] - if self.username and self.password: - grant_type.append("password") - elif self.client_secret_key: - grant_type.append("client_credentials") - - if grant_type: + if self.grant_type: self.token = await self.keycloak_openid.a_token( - self.username, self.password, grant_type=grant_type, totp=self.totp + self.username, self.password, grant_type=self.grant_type, totp=self.totp ) else: self.token = None