From 239e40434bac381eab75c257c2396215813a0738 Mon Sep 17 00:00:00 2001 From: Cristi Date: Wed, 13 Nov 2024 20:57:20 +0100 Subject: [PATCH] fix: make sure to not call sync IO functions inside async functions (#615) * Don't use sync functions to introspect token * One more async * Fix some spacing * A few more async functions * Fix compatibility issue * Comment * Formatting --- src/keycloak/keycloak_admin.py | 14 +++++++------- src/keycloak/keycloak_openid.py | 31 +++++++++++++++++++++++++------ 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/src/keycloak/keycloak_admin.py b/src/keycloak/keycloak_admin.py index ec4388e..b37e8f5 100644 --- a/src/keycloak/keycloak_admin.py +++ b/src/keycloak/keycloak_admin.py @@ -6199,7 +6199,7 @@ async def a_create_client(self, payload, skip_exists=False): :rtype: str """ if skip_exists: - client_id = self.get_client_id(client_id=payload["clientId"]) + client_id = await self.a_get_client_id(client_id=payload["clientId"]) if client_id is not None: return client_id @@ -6369,7 +6369,7 @@ async def a_get_realm_default_roles(self): """ params_path = { "realm-name": self.connection.realm_name, - "role-id": self.get_default_realm_role_id(), + "role-id": await self.a_get_default_realm_role_id(), } data_raw = await self.connection.a_raw_get( urls_patterns.URL_ADMIN_REALM_ROLE_COMPOSITES_REALM.format(**params_path) @@ -6386,7 +6386,7 @@ async def a_remove_realm_default_roles(self, payload): """ params_path = { "realm-name": self.connection.realm_name, - "role-id": self.get_default_realm_role_id(), + "role-id": await self.a_get_default_realm_role_id(), } data_raw = await self.connection.a_raw_delete( urls_patterns.URL_ADMIN_REALM_ROLE_COMPOSITES.format(**params_path), @@ -6404,7 +6404,7 @@ async def a_add_realm_default_roles(self, payload): """ params_path = { "realm-name": self.connection.realm_name, - "role-id": self.get_default_realm_role_id(), + "role-id": await self.a_get_default_realm_role_id(), } data_raw = await self.connection.a_raw_post( urls_patterns.URL_ADMIN_REALM_ROLE_COMPOSITES.format(**params_path), @@ -7536,7 +7536,7 @@ async def a_get_authenticator_provider_config_description(self, provider_id): :rtype: dict """ params_path = {"realm-name": self.connection.realm_name, "provider-id": provider_id} - data_raw = self.connection.raw_get( + data_raw = await self.connection.a_raw_get( urls_patterns.URL_ADMIN_AUTHENTICATOR_CONFIG_DESCRIPTION.format(**params_path) ) return raise_error_from_response(data_raw, KeycloakGetError) @@ -7678,7 +7678,7 @@ async def a_create_client_scope(self, payload, skip_exists=False): :rtype: str """ if skip_exists: - exists = self.get_client_scope_by_name(client_scope_name=payload["name"]) + exists = await self.a_get_client_scope_by_name(client_scope_name=payload["name"]) if exists is not None: return exists["id"] @@ -8002,7 +8002,7 @@ async def a_get_all_roles_of_client_scope(self, client_scope_id): "realm-name": self.connection.realm_name, "scope-id": client_scope_id, } - data_raw = self.connection.raw_get( + data_raw = await self.connection.a_raw_get( urls_patterns.URL_ADMIN_CLIENT_SCOPE_ROLE_MAPPINGS.format(**params_path) ) return raise_error_from_response(data_raw, KeycloakGetError) diff --git a/src/keycloak/keycloak_openid.py b/src/keycloak/keycloak_openid.py index ae9cd82..1a2954f 100644 --- a/src/keycloak/keycloak_openid.py +++ b/src/keycloak/keycloak_openid.py @@ -674,7 +674,7 @@ def get_policies(self, token, method_token_info="introspect", **kwargs): return list(set(policies)) def get_permissions(self, token, method_token_info="introspect", **kwargs): - """Get permission by user token . + """Get permission by user token. :param token: user token :type token: str @@ -689,7 +689,7 @@ def get_permissions(self, token, method_token_info="introspect", **kwargs): """ if not self.authorization.policies: raise KeycloakAuthorizationConfigError( - "Keycloak settings not found. Load Authorization Keycloak settings ." + "Keycloak settings not found. Load Authorization Keycloak settings." ) token_info = self._token_info(token, method_token_info, **kwargs) @@ -892,6 +892,25 @@ def update_client(self, token: str, client_id: str, payload: dict): ) return raise_error_from_response(data_raw, KeycloakPutError) + async def _a_token_info(self, token, method_token_info, **kwargs): + """Asynchronous getter for the token data. + + :param token: Token + :type token: str + :param method_token_info: Token info method to use + :type method_token_info: str + :param kwargs: Additional keyword arguments passed to the decode_token method + :type kwargs: dict + :returns: Token info + :rtype: dict + """ + if method_token_info == "introspect": + token_info = await self.a_introspect(token) + else: + token_info = await self.a_decode_token(token, **kwargs) + + return token_info + async def a_well_known(self): """Get the well_known object asynchronously. @@ -1301,7 +1320,7 @@ async def a_get_policies(self, token, method_token_info="introspect", **kwargs): "Keycloak settings not found. Load Authorization Keycloak settings." ) - token_info = self._token_info(token, method_token_info, **kwargs) + token_info = await self._a_token_info(token, method_token_info, **kwargs) if method_token_info == "introspect" and not token_info["active"]: raise KeycloakInvalidTokenError("Token expired or invalid.") @@ -1339,7 +1358,7 @@ async def a_get_permissions(self, token, method_token_info="introspect", **kwarg "Keycloak settings not found. Load Authorization Keycloak settings." ) - token_info = self._token_info(token, method_token_info, **kwargs) + token_info = await self._a_token_info(token, method_token_info, **kwargs) if method_token_info == "introspect" and not token_info["active"]: raise KeycloakInvalidTokenError("Token expired or invalid.") @@ -1378,7 +1397,7 @@ async def a_uma_permissions(self, token, permissions=""): params_path = {"realm-name": self.realm_name} payload = { "grant_type": "urn:ietf:params:oauth:grant-type:uma-ticket", - "permission": permission, + "permission": list(permission), # httpx does not handle `set` correctly "response_mode": "permissions", "audience": self.client_id, } @@ -1387,7 +1406,7 @@ async def a_uma_permissions(self, token, permissions=""): self.connection.add_param_headers("Authorization", "Bearer " + token) content_type = self.connection.headers.get("Content-Type") self.connection.add_param_headers("Content-Type", "application/x-www-form-urlencoded") - data_raw = self.connection.raw_post(URL_TOKEN.format(**params_path), data=payload) + data_raw = await self.connection.a_raw_post(URL_TOKEN.format(**params_path), data=payload) ( self.connection.add_param_headers("Content-Type", content_type) if content_type