From b293f0170a2ea58ef9e14593387ddf92eedfd9ff Mon Sep 17 00:00:00 2001 From: BartoszCki Date: Wed, 21 Oct 2020 22:40:27 +0200 Subject: [PATCH 01/34] Fetch users/groups/group members with pagination --- keycloak/keycloak_admin.py | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/keycloak/keycloak_admin.py b/keycloak/keycloak_admin.py index ae443b6..b168d86 100644 --- a/keycloak/keycloak_admin.py +++ b/keycloak/keycloak_admin.py @@ -222,6 +222,13 @@ class KeycloakAdmin: page += 1 return results + def __fetch_paginated(self, url, query=None): + query = query or {} + + return raise_error_from_response( + self.raw_get(url, **query), + KeycloakGetError) + def import_realm(self, payload): """ Import a new realm from a RealmRepresentation. Realm name must be unique. @@ -303,8 +310,14 @@ class KeycloakAdmin: :param query: Query parameters (optional) :return: users list """ + query = query or {} params_path = {"realm-name": self.realm_name} - return self.__fetch_all(URL_ADMIN_USERS.format(**params_path), query) + url = URL_ADMIN_USERS.format(**params_path) + + if "first" in query or "max" in query: + return self.__fetch_paginated(url, query) + + return self.__fetch_all(url, query) def get_idps(self): """ @@ -541,7 +554,7 @@ class KeycloakAdmin: data_raw = self.raw_get(URL_ADMIN_SERVER_INFO) return raise_error_from_response(data_raw, KeycloakGetError) - def get_groups(self): + def get_groups(self, query=None): """ Returns a list of groups belonging to the realm @@ -550,8 +563,14 @@ class KeycloakAdmin: :return: array GroupRepresentation """ + query = query or {} params_path = {"realm-name": self.realm_name} - return self.__fetch_all(URL_ADMIN_GROUPS.format(**params_path)) + url = URL_ADMIN_USERS.format(**params_path) + + if "first" in query or "max" in query: + return self.__fetch_paginated(url, query) + + return self.__fetch_all(url, query) def get_group(self, group_id): """ @@ -603,7 +622,12 @@ class KeycloakAdmin: :return: Keycloak server response (UserRepresentation) """ params_path = {"realm-name": self.realm_name, "id": group_id} - return self.__fetch_all(URL_ADMIN_GROUP_MEMBERS.format(**params_path), query) + url = URL_ADMIN_USERS.format(**params_path) + + if "first" in query or "max" in query: + return self.__fetch_paginated(url, query) + + return self.__fetch_all(url, query) def get_group_by_path(self, path, search_in_subgroups=False): """ From 0646f2819b9862fb15d84d62d782e1b849708ef1 Mon Sep 17 00:00:00 2001 From: "J. Brunswicker" Date: Thu, 3 Dec 2020 15:47:16 +0100 Subject: [PATCH 02/34] - add function to update a client-scope --- keycloak/keycloak_admin.py | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/keycloak/keycloak_admin.py b/keycloak/keycloak_admin.py index f88d00d..3722950 100644 --- a/keycloak/keycloak_admin.py +++ b/keycloak/keycloak_admin.py @@ -52,7 +52,7 @@ from .urls_patterns import URL_ADMIN_SERVER_INFO, URL_ADMIN_CLIENT_AUTHZ_RESOURC class KeycloakAdmin: PAGE_SIZE = 100 - + _server_url = None _username = None _password = None @@ -519,7 +519,7 @@ class KeycloakAdmin: payload = {"identityProvider": provider_id, "userId": provider_userid, "userName": provider_username} params_path = {"realm-name": self.realm_name, "id": user_id, "provider": provider_id} data_raw = self.raw_post(URL_ADMIN_USER_FEDERATED_IDENTITY.format(**params_path), data=json.dumps(payload)) - + def send_update_account(self, user_id, payload, client_id=None, lifespan=None, redirect_uri=None): """ Send an update account email to the user. An email contains a @@ -1330,14 +1330,14 @@ class KeycloakAdmin: params_path = {"realm-name": self.realm_name} data_raw = self.raw_get(URL_ADMIN_FLOWS.format(**params_path)) return raise_error_from_response(data_raw, KeycloakGetError) - + def get_authentication_flow_for_id(self, flow_id): """ Get one authentication flow by it's id/alias. Returns all flow details AuthenticationFlowRepresentation https://www.keycloak.org/docs-api/8.0/rest-api/index.html#_authenticationflowrepresentation - + :param flow_id: the id of a flow NOT it's alias :return: Keycloak server response (AuthenticationFlowRepresentation) """ @@ -1403,7 +1403,7 @@ class KeycloakAdmin: data_raw = self.raw_put(URL_ADMIN_FLOWS_EXECUTIONS.format(**params_path), data=payload) return raise_error_from_response(data_raw, KeycloakGetError, expected_codes=[204]) - + def create_authentication_flow_execution(self, payload, flow_alias): """ Create an authentication flow execution @@ -1496,6 +1496,22 @@ class KeycloakAdmin: data=json.dumps(payload)) return raise_error_from_response(data_raw, KeycloakGetError, expected_codes=[201], skip_exists=skip_exists) + def update_client_scope(self, client_scope_id, payload): + """ + Update a client scope + + ClientScopeRepresentation: https://www.keycloak.org/docs-api/8.0/rest-api/index.html#_client_scopes_resource + + :param client_scope_id: The id of the client scope + :param payload: ClientScopeRepresentation + :return: Keycloak server response (ClientScopeRepresentation) + """ + + params_path = {"realm-name": self.realm_name, "scope-id": client_scope_id} + data_raw = self.raw_put(URL_ADMIN_CLIENT_SCOPE.format(**params_path), + data=json.dumps(payload)) + return raise_error_from_response(data_raw, KeycloakGetError, expected_codes=[204]) + def add_mapper_to_client_scope(self, client_scope_id, payload): """ Add a mapper to a client scope @@ -1725,18 +1741,18 @@ class KeycloakAdmin: grant_type = ["password"] if self.client_secret_key: grant_type = ["client_credentials"] - + self._token = self.keycloak_openid.token(self.username, self.password, grant_type=grant_type) headers = { 'Authorization': 'Bearer ' + self.token.get('access_token'), 'Content-Type': 'application/json' } - + if self.custom_headers is not None: # merge custom headers to main headers headers.update(self.custom_headers) - + self._connection = ConnectionManager(base_url=self.server_url, headers=headers, timeout=60, From 21333dc6491c4b741151d4ee44c6124b6a277ec9 Mon Sep 17 00:00:00 2001 From: pjrm <4622652+pjrm@users.noreply.github.com> Date: Fri, 18 Dec 2020 15:07:19 +0000 Subject: [PATCH 03/34] Add Keycloak authenticator config management (add, update and delete methods) --- keycloak/keycloak_admin.py | 43 +++++++++++++++++++++++++++++++++++++- keycloak/urls_patterns.py | 1 + 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/keycloak/keycloak_admin.py b/keycloak/keycloak_admin.py index f88d00d..3126833 100644 --- a/keycloak/keycloak_admin.py +++ b/keycloak/keycloak_admin.py @@ -46,7 +46,7 @@ from .urls_patterns import URL_ADMIN_SERVER_INFO, URL_ADMIN_CLIENT_AUTHZ_RESOURC URL_ADMIN_USER_FEDERATED_IDENTITY, URL_ADMIN_USER_FEDERATED_IDENTITIES, URL_ADMIN_CLIENT_ROLE_MEMBERS, \ URL_ADMIN_REALM_ROLES_MEMBERS, URL_ADMIN_CLIENT_PROTOCOL_MAPPER, URL_ADMIN_CLIENT_SCOPES_MAPPERS, \ URL_ADMIN_FLOWS_EXECUTIONS_EXEUCUTION, URL_ADMIN_FLOWS_EXECUTIONS_FLOW, URL_ADMIN_FLOWS_COPY, \ - URL_ADMIN_FLOWS_ALIAS, URL_ADMIN_CLIENT_SERVICE_ACCOUNT_USER + URL_ADMIN_FLOWS_ALIAS, URL_ADMIN_CLIENT_SERVICE_ACCOUNT_USER, URL_ADMIN_AUTHENTICATOR_CONFIG class KeycloakAdmin: @@ -1439,6 +1439,47 @@ class KeycloakAdmin: data=payload) return raise_error_from_response(data_raw, KeycloakGetError, expected_codes=[201], skip_exists=skip_exists) + def get_authenticator_config(self, config_id): + """ + Get authenticator configuration. Returns all configuration details. + + :param config_id: Authenticator config id + :return: Response(json) + """ + params_path = {"realm-name": self.realm_name, "id": config_id} + data_raw = self.raw_get(URL_ADMIN_AUTHENTICATOR_CONFIG.format(**params_path)) + return raise_error_from_response(data_raw, KeycloakGetError) + + def update_authenticator_config(self, payload, config_id): + """ + Update an authenticator configuration. + + AuthenticatorConfigRepresentation + https://www.keycloak.org/docs-api/8.0/rest-api/index.html#_authenticatorconfigrepresentation + + :param payload: AuthenticatorConfigRepresentation + :param config_id: Authenticator config id + :return: Response(json) + """ + params_path = {"realm-name": self.realm_name, "id": config_id} + data_raw = self.raw_put(URL_ADMIN_AUTHENTICATOR_CONFIG.format(**params_path), + data=json.dumps(payload)) + return raise_error_from_response(data_raw, KeycloakGetError, expected_codes=[204]) + + def delete_authenticator_config(self, config_id): + """ + Delete a authenticator configuration. + https://www.keycloak.org/docs-api/8.0/rest-api/index.html#_authentication_management_resource + + :param config_id: Authenticator config id + :return: Keycloak server Response + """ + + params_path = {"realm-name": self.realm_name, "id": config_id} + data_raw = self.raw_delete(URL_ADMIN_AUTHENTICATOR_CONFIG.format(**params_path)) + + return raise_error_from_response(data_raw, KeycloakGetError, expected_codes=[204]) + def sync_users(self, storage_id, action): """ Function to trigger user sync from provider diff --git a/keycloak/urls_patterns.py b/keycloak/urls_patterns.py index 14410d8..d45ef8d 100644 --- a/keycloak/urls_patterns.py +++ b/keycloak/urls_patterns.py @@ -95,6 +95,7 @@ URL_ADMIN_FLOWS_COPY = "admin/realms/{realm-name}/authentication/flows/{flow-ali URL_ADMIN_FLOWS_EXECUTIONS = "admin/realms/{realm-name}/authentication/flows/{flow-alias}/executions" URL_ADMIN_FLOWS_EXECUTIONS_EXEUCUTION = "admin/realms/{realm-name}/authentication/flows/{flow-alias}/executions/execution" URL_ADMIN_FLOWS_EXECUTIONS_FLOW = "admin/realms/{realm-name}/authentication/flows/{flow-alias}/executions/flow" +URL_ADMIN_AUTHENTICATOR_CONFIG = "admin/realms/{realm-name}/authentication/config/{id}" URL_ADMIN_COMPONENTS = "admin/realms/{realm-name}/components" URL_ADMIN_COMPONENT = "admin/realms/{realm-name}/components/{component-id}" From 354cd76cee958ffcc613dc6d2e35352f082f8091 Mon Sep 17 00:00:00 2001 From: Marcos Pereira Date: Fri, 18 Dec 2020 12:28:03 -0300 Subject: [PATCH 04/34] Release: 0.24.0 --- docs/source/conf.py | 4 ++-- setup.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 637a63b..1ab699d 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -60,9 +60,9 @@ author = 'Marcos Pereira' # built documents. # # The short X.Y version. -version = '0.23.0' +version = '0.24.0' # The full version, including alpha/beta/rc tags. -release = '0.23.0' +release = '0.24.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/setup.py b/setup.py index 78b8d96..362f177 100644 --- a/setup.py +++ b/setup.py @@ -7,7 +7,7 @@ with open("README.md", "r") as fh: setup( name='python-keycloak', - version='0.23.0', + version='0.24.0', url='https://github.com/marcospereirampj/python-keycloak', license='The MIT License', author='Marcos Pereira', From b07ecce9a970498da050d11d6b419c316056ab21 Mon Sep 17 00:00:00 2001 From: pjrm <4622652+pjrm@users.noreply.github.com> Date: Fri, 18 Dec 2020 15:27:13 +0000 Subject: [PATCH 05/34] Maintain consistency across all methods and force all payload content to be in JSON format --- keycloak/keycloak_admin.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/keycloak/keycloak_admin.py b/keycloak/keycloak_admin.py index 8fd19f6..9c1155c 100644 --- a/keycloak/keycloak_admin.py +++ b/keycloak/keycloak_admin.py @@ -536,7 +536,7 @@ class KeycloakAdmin: params_path = {"realm-name": self.realm_name, "id": user_id} params_query = {"client_id": client_id, "lifespan": lifespan, "redirect_uri": redirect_uri} data_raw = self.raw_put(URL_ADMIN_SEND_UPDATE_ACCOUNT.format(**params_path), - data=payload, **params_query) + data=json.dumps(payload), **params_query) return raise_error_from_response(data_raw, KeycloakGetError) def send_verify_email(self, user_id, client_id=None, redirect_uri=None): @@ -1359,7 +1359,7 @@ class KeycloakAdmin: params_path = {"realm-name": self.realm_name} data_raw = self.raw_post(URL_ADMIN_FLOWS.format(**params_path), - data=payload) + data=json.dumps(payload)) return raise_error_from_response(data_raw, KeycloakGetError, expected_codes=[201], skip_exists=skip_exists) def copy_authentication_flow(self, payload, flow_alias): @@ -1373,7 +1373,7 @@ class KeycloakAdmin: params_path = {"realm-name": self.realm_name, "flow-alias": flow_alias} data_raw = self.raw_post(URL_ADMIN_FLOWS_COPY.format(**params_path), - data=payload) + data=json.dumps(payload)) return raise_error_from_response(data_raw, KeycloakGetError, expected_codes=[201]) def get_authentication_flow_executions(self, flow_alias): @@ -1401,7 +1401,7 @@ class KeycloakAdmin: params_path = {"realm-name": self.realm_name, "flow-alias": flow_alias} data_raw = self.raw_put(URL_ADMIN_FLOWS_EXECUTIONS.format(**params_path), - data=payload) + data=json.dumps(payload)) return raise_error_from_response(data_raw, KeycloakGetError, expected_codes=[204]) def create_authentication_flow_execution(self, payload, flow_alias): @@ -1418,7 +1418,7 @@ class KeycloakAdmin: params_path = {"realm-name": self.realm_name, "flow-alias": flow_alias} data_raw = self.raw_post(URL_ADMIN_FLOWS_EXECUTIONS_EXEUCUTION.format(**params_path), - data=payload) + data=json.dumps(payload)) return raise_error_from_response(data_raw, KeycloakGetError, expected_codes=[201]) def create_authentication_flow_subflow(self, payload, flow_alias, skip_exists=False): @@ -1436,7 +1436,7 @@ class KeycloakAdmin: params_path = {"realm-name": self.realm_name, "flow-alias": flow_alias} data_raw = self.raw_post(URL_ADMIN_FLOWS_EXECUTIONS_FLOW.format(**params_path), - data=payload) + data=json.dumps(payload)) return raise_error_from_response(data_raw, KeycloakGetError, expected_codes=[201], skip_exists=skip_exists) def get_authenticator_config(self, config_id): From 021c549e30a522f322cb140dec28d64e4c8952d2 Mon Sep 17 00:00:00 2001 From: hamedSh Date: Sun, 10 Jan 2021 13:48:04 +0330 Subject: [PATCH 06/34] Get sessions associated with the client. --- keycloak/keycloak_admin.py | 20 ++++++++++++++++++-- keycloak/urls_patterns.py | 1 + 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/keycloak/keycloak_admin.py b/keycloak/keycloak_admin.py index 8fd19f6..76219c3 100644 --- a/keycloak/keycloak_admin.py +++ b/keycloak/keycloak_admin.py @@ -32,7 +32,7 @@ from .connection import ConnectionManager from .exceptions import raise_error_from_response, KeycloakGetError from .keycloak_openid import KeycloakOpenID from .urls_patterns import URL_ADMIN_SERVER_INFO, URL_ADMIN_CLIENT_AUTHZ_RESOURCES, URL_ADMIN_CLIENT_ROLES, \ - URL_ADMIN_GET_SESSIONS, URL_ADMIN_RESET_PASSWORD, URL_ADMIN_SEND_UPDATE_ACCOUNT, URL_ADMIN_GROUPS_REALM_ROLES,\ + URL_ADMIN_GET_SESSIONS, URL_ADMIN_RESET_PASSWORD, URL_ADMIN_SEND_UPDATE_ACCOUNT, URL_ADMIN_GROUPS_REALM_ROLES, \ URL_ADMIN_REALM_ROLES_COMPOSITE_REALM_ROLE, URL_ADMIN_CLIENT_INSTALLATION_PROVIDER, \ URL_ADMIN_REALM_ROLES_ROLE_BY_NAME, URL_ADMIN_GET_GROUPS_REALM_ROLES, URL_ADMIN_GROUPS_CLIENT_ROLES, \ URL_ADMIN_USER_CLIENT_ROLES_COMPOSITE, URL_ADMIN_USER_GROUP, URL_ADMIN_REALM_ROLES, URL_ADMIN_GROUP_CHILD, \ @@ -46,7 +46,8 @@ from .urls_patterns import URL_ADMIN_SERVER_INFO, URL_ADMIN_CLIENT_AUTHZ_RESOURC URL_ADMIN_USER_FEDERATED_IDENTITY, URL_ADMIN_USER_FEDERATED_IDENTITIES, URL_ADMIN_CLIENT_ROLE_MEMBERS, \ URL_ADMIN_REALM_ROLES_MEMBERS, URL_ADMIN_CLIENT_PROTOCOL_MAPPER, URL_ADMIN_CLIENT_SCOPES_MAPPERS, \ URL_ADMIN_FLOWS_EXECUTIONS_EXEUCUTION, URL_ADMIN_FLOWS_EXECUTIONS_FLOW, URL_ADMIN_FLOWS_COPY, \ - URL_ADMIN_FLOWS_ALIAS, URL_ADMIN_CLIENT_SERVICE_ACCOUNT_USER, URL_ADMIN_AUTHENTICATOR_CONFIG + URL_ADMIN_FLOWS_ALIAS, URL_ADMIN_CLIENT_SERVICE_ACCOUNT_USER, URL_ADMIN_AUTHENTICATOR_CONFIG, \ + URL_ADMIN_CLIENT_ALL_SESSIONS class KeycloakAdmin: @@ -1810,3 +1811,18 @@ class KeycloakAdmin: else: raise self.connection.add_param_headers('Authorization', 'Bearer ' + self.token.get('access_token')) + + def get_client_all_sessions(self, client_id): + """ + Get sessions associated with the client + + :param client_id: id of client + + UserSessionRepresentation + http://www.keycloak.org/docs-api/3.3/rest-api/index.html#_usersessionrepresentation + + :return: UserSessionRepresentation + """ + params_path = {"realm-name": self.realm_name, "client-id": client_id} + data_raw = self.connection.raw_get(URL_ADMIN_CLIENT_ALL_SESSIONS.format(**params_path)) + return raise_error_from_response(data_raw, KeycloakGetError) diff --git a/keycloak/urls_patterns.py b/keycloak/urls_patterns.py index d45ef8d..95acaf9 100644 --- a/keycloak/urls_patterns.py +++ b/keycloak/urls_patterns.py @@ -63,6 +63,7 @@ URL_ADMIN_GROUP_MEMBERS = "admin/realms/{realm-name}/groups/{id}/members" URL_ADMIN_CLIENTS = "admin/realms/{realm-name}/clients" URL_ADMIN_CLIENT = URL_ADMIN_CLIENTS + "/{id}" +URL_ADMIN_CLIENT_ALL_SESSIONS = URL_ADMIN_CLIENT + "/user-sessions" URL_ADMIN_CLIENT_SECRETS= URL_ADMIN_CLIENT + "/client-secret" URL_ADMIN_CLIENT_ROLES = URL_ADMIN_CLIENT + "/roles" URL_ADMIN_CLIENT_ROLE = URL_ADMIN_CLIENT + "/roles/{role-name}" From 6ed65ea4e51098e9eb805dbfd31f4a0ac62212a5 Mon Sep 17 00:00:00 2001 From: Lukas Martini Date: Thu, 14 Jan 2021 11:57:45 +0100 Subject: [PATCH 07/34] Add exist_ok attribute to KeycloakAdmin.create_user This attribute allows configuration of the behaviour of create_user when a user with the passed username already exists. If set to False, an exception will be raised (passed through) from the API. If set to True (default), the existing user ID will silently be returned. --- README.md | 10 ++++++++++ keycloak/keycloak_admin.py | 10 ++++++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index c2af7fc..095782b 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,7 @@ The documentation for python-keycloak is available on [readthedocs](http://pytho * [Josha Inglis](https://bitbucket.org/joshainglis/) * [Alex](https://bitbucket.org/alex_zel/) * [Ewan Jone](https://bitbucket.org/kisamoto/) +* [Lukas Martini](https://github.com/lutoma) ## Usage @@ -125,6 +126,15 @@ new_user = keycloak_admin.create_user({"email": "example@example.com", "enabled": True, "firstName": "Example", "lastName": "Example"}) + +# Add user and raise exception if username already exists +# exist_ok currently defaults to True for backwards compatibility reasons +new_user = keycloak_admin.create_user({"email": "example@example.com", + "username": "example@example.com", + "enabled": True, + "firstName": "Example", + "lastName": "Example"}, + exist_ok=False) # Add user and set password new_user = keycloak_admin.create_user({"email": "example@example.com", diff --git a/keycloak/keycloak_admin.py b/keycloak/keycloak_admin.py index 8fd19f6..b42f6a3 100644 --- a/keycloak/keycloak_admin.py +++ b/keycloak/keycloak_admin.py @@ -361,7 +361,7 @@ class KeycloakAdmin: data_raw = self.raw_delete(URL_ADMIN_IDP.format(**params_path)) return raise_error_from_response(data_raw, KeycloakGetError, expected_codes=[204]) - def create_user(self, payload): + def create_user(self, payload, exist_ok=True): """ Create a new user. Username must be unique @@ -369,15 +369,17 @@ class KeycloakAdmin: https://www.keycloak.org/docs-api/8.0/rest-api/index.html#_userrepresentation :param payload: UserRepresentation + :param exist_ok: If False, raise KeycloakGetError if username already exists. Otherwise, return existing user ID. :return: UserRepresentation """ params_path = {"realm-name": self.realm_name} - exists = self.get_user_id(username=payload['username']) + if exist_ok: + exists = self.get_user_id(username=payload['username']) - if exists is not None: - return str(exists) + if exists is not None: + return str(exists) data_raw = self.raw_post(URL_ADMIN_USERS.format(**params_path), data=json.dumps(payload)) From 0d4815ddb2bbcf5f9c642d1e5ac1b7dd3d3beecb Mon Sep 17 00:00:00 2001 From: Hans Erik Heggem Date: Wed, 3 Feb 2021 21:54:36 +0100 Subject: [PATCH 08/34] added composite clients role feature --- keycloak/keycloak_admin.py | 21 +++++++++++++++++++-- keycloak/urls_patterns.py | 3 ++- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/keycloak/keycloak_admin.py b/keycloak/keycloak_admin.py index 8fd19f6..8965332 100644 --- a/keycloak/keycloak_admin.py +++ b/keycloak/keycloak_admin.py @@ -32,7 +32,7 @@ from .connection import ConnectionManager from .exceptions import raise_error_from_response, KeycloakGetError from .keycloak_openid import KeycloakOpenID from .urls_patterns import URL_ADMIN_SERVER_INFO, URL_ADMIN_CLIENT_AUTHZ_RESOURCES, URL_ADMIN_CLIENT_ROLES, \ - URL_ADMIN_GET_SESSIONS, URL_ADMIN_RESET_PASSWORD, URL_ADMIN_SEND_UPDATE_ACCOUNT, URL_ADMIN_GROUPS_REALM_ROLES,\ + URL_ADMIN_GET_SESSIONS, URL_ADMIN_RESET_PASSWORD, URL_ADMIN_SEND_UPDATE_ACCOUNT, URL_ADMIN_GROUPS_REALM_ROLES, \ URL_ADMIN_REALM_ROLES_COMPOSITE_REALM_ROLE, URL_ADMIN_CLIENT_INSTALLATION_PROVIDER, \ URL_ADMIN_REALM_ROLES_ROLE_BY_NAME, URL_ADMIN_GET_GROUPS_REALM_ROLES, URL_ADMIN_GROUPS_CLIENT_ROLES, \ URL_ADMIN_USER_CLIENT_ROLES_COMPOSITE, URL_ADMIN_USER_GROUP, URL_ADMIN_REALM_ROLES, URL_ADMIN_GROUP_CHILD, \ @@ -46,7 +46,8 @@ from .urls_patterns import URL_ADMIN_SERVER_INFO, URL_ADMIN_CLIENT_AUTHZ_RESOURC URL_ADMIN_USER_FEDERATED_IDENTITY, URL_ADMIN_USER_FEDERATED_IDENTITIES, URL_ADMIN_CLIENT_ROLE_MEMBERS, \ URL_ADMIN_REALM_ROLES_MEMBERS, URL_ADMIN_CLIENT_PROTOCOL_MAPPER, URL_ADMIN_CLIENT_SCOPES_MAPPERS, \ URL_ADMIN_FLOWS_EXECUTIONS_EXEUCUTION, URL_ADMIN_FLOWS_EXECUTIONS_FLOW, URL_ADMIN_FLOWS_COPY, \ - URL_ADMIN_FLOWS_ALIAS, URL_ADMIN_CLIENT_SERVICE_ACCOUNT_USER, URL_ADMIN_AUTHENTICATOR_CONFIG + URL_ADMIN_FLOWS_ALIAS, URL_ADMIN_CLIENT_SERVICE_ACCOUNT_USER, URL_ADMIN_AUTHENTICATOR_CONFIG, \ + URL_ADMIN_CLIENT_ROLES_COMPOSITE_CLIENT_ROLE class KeycloakAdmin: @@ -1013,6 +1014,22 @@ class KeycloakAdmin: data=json.dumps(payload)) return raise_error_from_response(data_raw, KeycloakGetError, expected_codes=[201], skip_exists=skip_exists) + def add_composite_client_roles_to_role(self, client_role_id, role_name, roles): + """ + Add composite roles to client role + + :param client_role_id: id of client (not client-id) + :param role_name: The name of the role + :param roles: roles list or role (use RoleRepresentation) to be updated + :return Keycloak server response + """ + + payload = roles if isinstance(roles, list) else [roles] + params_path = {"realm-name": self.realm_name, "id": client_role_id, "role-name": role_name} + data_raw = self.raw_post(URL_ADMIN_CLIENT_ROLES_COMPOSITE_CLIENT_ROLE.format(**params_path), + data=json.dumps(payload)) + return raise_error_from_response(data_raw, KeycloakGetError, expected_codes=[204]) + def delete_client_role(self, client_role_id, role_name): """ Delete a client role diff --git a/keycloak/urls_patterns.py b/keycloak/urls_patterns.py index d45ef8d..64c658c 100644 --- a/keycloak/urls_patterns.py +++ b/keycloak/urls_patterns.py @@ -63,9 +63,10 @@ URL_ADMIN_GROUP_MEMBERS = "admin/realms/{realm-name}/groups/{id}/members" URL_ADMIN_CLIENTS = "admin/realms/{realm-name}/clients" URL_ADMIN_CLIENT = URL_ADMIN_CLIENTS + "/{id}" -URL_ADMIN_CLIENT_SECRETS= URL_ADMIN_CLIENT + "/client-secret" +URL_ADMIN_CLIENT_SECRETS = URL_ADMIN_CLIENT + "/client-secret" URL_ADMIN_CLIENT_ROLES = URL_ADMIN_CLIENT + "/roles" URL_ADMIN_CLIENT_ROLE = URL_ADMIN_CLIENT + "/roles/{role-name}" +URL_ADMIN_CLIENT_ROLES_COMPOSITE_CLIENT_ROLE = URL_ADMIN_CLIENT_ROLE + "/composites" URL_ADMIN_CLIENT_ROLE_MEMBERS = URL_ADMIN_CLIENT + "/roles/{role-name}/users" URL_ADMIN_CLIENT_AUTHZ_SETTINGS = URL_ADMIN_CLIENT + "/authz/resource-server/settings" URL_ADMIN_CLIENT_AUTHZ_RESOURCES = URL_ADMIN_CLIENT + "/authz/resource-server/resource" From c71549813c2b14b6d2f787798203c9d2997bc7a5 Mon Sep 17 00:00:00 2001 From: Bekzhan Date: Mon, 8 Feb 2021 17:42:23 +0600 Subject: [PATCH 09/34] fix pytest warning --- keycloak/connection.py | 3 ++ keycloak/tests/test_connection.py | 64 ++++++++++++++++--------------- 2 files changed, 36 insertions(+), 31 deletions(-) diff --git a/keycloak/connection.py b/keycloak/connection.py index 12903a0..3871482 100644 --- a/keycloak/connection.py +++ b/keycloak/connection.py @@ -60,6 +60,9 @@ class ConnectionManager(object): self._s.mount(protocol, adapter) + def __del__(self): + self._s.close() + @property def base_url(self): """ Return base url in use for requests to the server. """ diff --git a/keycloak/tests/test_connection.py b/keycloak/tests/test_connection.py index 4c54183..cb98feb 100644 --- a/keycloak/tests/test_connection.py +++ b/keycloak/tests/test_connection.py @@ -156,34 +156,36 @@ class TestConnection(unittest.TestCase): with mock.patch.object(KeycloakOpenID, "__init__", return_value=None) as mock_keycloak_open_id: with mock.patch("keycloak.keycloak_openid.KeycloakOpenID.token", return_value=fake_token): with mock.patch("keycloak.connection.ConnectionManager.__init__", return_value=None) as mock_connection_manager: - server_url = "https://localhost/auth/" - username = "admin" - password = "secret" - realm_name = "master" - - headers = { - 'Custom': 'test-custom-header' - } - KeycloakAdmin(server_url=server_url, - username=username, - password=password, - realm_name=realm_name, - verify=False, - custom_headers=headers) - - mock_keycloak_open_id.assert_called_with(server_url=server_url, - realm_name=realm_name, - client_id='admin-cli', - client_secret_key=None, - verify=False, - custom_headers=headers) - - expected_header = {'Authorization': 'Bearer faketoken', - 'Content-Type': 'application/json', - 'Custom': 'test-custom-header' - } - - mock_connection_manager.assert_called_with(base_url=server_url, - headers=expected_header, - timeout=60, - verify=False) + with mock.patch("keycloak.connection.ConnectionManager.__del__", return_value=None) as mock_connection_manager_delete: + server_url = "https://localhost/auth/" + username = "admin" + password = "secret" + realm_name = "master" + + headers = { + 'Custom': 'test-custom-header' + } + KeycloakAdmin(server_url=server_url, + username=username, + password=password, + realm_name=realm_name, + verify=False, + custom_headers=headers) + + mock_keycloak_open_id.assert_called_with(server_url=server_url, + realm_name=realm_name, + client_id='admin-cli', + client_secret_key=None, + verify=False, + custom_headers=headers) + + expected_header = {'Authorization': 'Bearer faketoken', + 'Content-Type': 'application/json', + 'Custom': 'test-custom-header' + } + + mock_connection_manager.assert_called_with(base_url=server_url, + headers=expected_header, + timeout=60, + verify=False) + mock_connection_manager_delete.assert_called_once_with() From 02d82f70bce4cb3ca0a4ea53b4cf142a03b459fb Mon Sep 17 00:00:00 2001 From: Clive Jevons Date: Fri, 12 Feb 2021 20:47:38 +0100 Subject: [PATCH 10/34] update mapper in client scope --- keycloak/keycloak_admin.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/keycloak/keycloak_admin.py b/keycloak/keycloak_admin.py index 8fd19f6..39fbdf4 100644 --- a/keycloak/keycloak_admin.py +++ b/keycloak/keycloak_admin.py @@ -1588,6 +1588,26 @@ class KeycloakAdmin: return raise_error_from_response(data_raw, KeycloakGetError, expected_codes=[204]) + def update_mapper_in_client_scope(self, client_scope_id, protocol_mapper_id, payload): + """ + Update an existing protocol mapper in a client scope + https://www.keycloak.org/docs-api/8.0/rest-api/index.html#_protocol_mappers_resource + + :param client_scope_id: The id of the client scope + :param protocol_mapper_id: The id of the protocol mapper which exists in the client scope + and should to be updated + :param payload: ProtocolMapperRepresentation + :return: Keycloak server Response + """ + + params_path = {"realm-name": self.realm_name, "scope-id": client_scope_id, + "protocol-mapper-id": protocol_mapper_id} + + data_raw = self.raw_put( + URL_ADMIN_CLIENT_SCOPES_MAPPERS.format(**params_path), data=json.dumps(payload)) + + return raise_error_from_response(data_raw, KeycloakGetError, expected_codes=[204]) + def add_mapper_to_client(self, client_id, payload): """ Add a mapper to a client From 04ef9a0e64c69c3a2170f05fc5d0945212d13a2c Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 3 Mar 2021 20:44:46 +0100 Subject: [PATCH 11/34] Update keycloak_admin.py Fixed typo in params_path (leads to error) --- keycloak/keycloak_admin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/keycloak/keycloak_admin.py b/keycloak/keycloak_admin.py index c0ac364..af1e799 100644 --- a/keycloak/keycloak_admin.py +++ b/keycloak/keycloak_admin.py @@ -1861,6 +1861,6 @@ class KeycloakAdmin: :return: UserSessionRepresentation """ - params_path = {"realm-name": self.realm_name, "client-id": client_id} + params_path = {"realm-name": self.realm_name, "id": client_id} data_raw = self.connection.raw_get(URL_ADMIN_CLIENT_ALL_SESSIONS.format(**params_path)) return raise_error_from_response(data_raw, KeycloakGetError) From 9c8835c2550a55c689355e3118f8a00da924a3a4 Mon Sep 17 00:00:00 2001 From: Lilis Iskandar Date: Tue, 9 Mar 2021 18:26:10 +0800 Subject: [PATCH 12/34] Added get_events method for KeycloakAdmin Signed-off-by: Lilis Iskandar --- keycloak/keycloak_admin.py | 16 +++++++++++++++- keycloak/urls_patterns.py | 2 ++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/keycloak/keycloak_admin.py b/keycloak/keycloak_admin.py index c0ac364..e2e5648 100644 --- a/keycloak/keycloak_admin.py +++ b/keycloak/keycloak_admin.py @@ -47,7 +47,7 @@ from .urls_patterns import URL_ADMIN_SERVER_INFO, URL_ADMIN_CLIENT_AUTHZ_RESOURC URL_ADMIN_REALM_ROLES_MEMBERS, URL_ADMIN_CLIENT_PROTOCOL_MAPPER, URL_ADMIN_CLIENT_SCOPES_MAPPERS, \ URL_ADMIN_FLOWS_EXECUTIONS_EXEUCUTION, URL_ADMIN_FLOWS_EXECUTIONS_FLOW, URL_ADMIN_FLOWS_COPY, \ URL_ADMIN_FLOWS_ALIAS, URL_ADMIN_CLIENT_SERVICE_ACCOUNT_USER, URL_ADMIN_AUTHENTICATOR_CONFIG, \ - URL_ADMIN_CLIENT_ROLES_COMPOSITE_CLIENT_ROLE, URL_ADMIN_CLIENT_ALL_SESSIONS + URL_ADMIN_CLIENT_ROLES_COMPOSITE_CLIENT_ROLE, URL_ADMIN_CLIENT_ALL_SESSIONS, URL_ADMIN_EVENTS class KeycloakAdmin: @@ -1760,6 +1760,20 @@ class KeycloakAdmin: data=None) return raise_error_from_response(data_raw, KeycloakGetError) + def get_events(self, query=None): + """ + Return a list of events, filtered according to query parameters + + EventRepresentation array + https://www.keycloak.org/docs-api/8.0/rest-api/index.html#_eventrepresentation + + :return: events list + """ + params_path = {"realm-name": self.realm_name} + data_raw = self.raw_get(URL_ADMIN_EVENTS.format(**params_path), + data=None, **query) + return raise_error_from_response(data_raw, KeycloakGetError) + def raw_get(self, *args, **kwargs): """ Calls connection.raw_get. diff --git a/keycloak/urls_patterns.py b/keycloak/urls_patterns.py index 7aa40f8..b594efe 100644 --- a/keycloak/urls_patterns.py +++ b/keycloak/urls_patterns.py @@ -105,3 +105,5 @@ URL_ADMIN_KEYS = "admin/realms/{realm-name}/keys" URL_ADMIN_USER_FEDERATED_IDENTITIES = "admin/realms/{realm-name}/users/{id}/federated-identity" URL_ADMIN_USER_FEDERATED_IDENTITY = "admin/realms/{realm-name}/users/{id}/federated-identity/{provider}" + +URL_ADMIN_EVENTS = 'admin/realms/{realm-name}/events' \ No newline at end of file From 6d90d48048d6bfdbb683a56e8e265959465b5ccf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 24 Mar 2021 19:05:36 +0000 Subject: [PATCH 13/34] Bump rsa from 4.0 to 4.1 Bumps [rsa](https://github.com/sybrenstuvel/python-rsa) from 4.0 to 4.1. - [Release notes](https://github.com/sybrenstuvel/python-rsa/releases) - [Changelog](https://github.com/sybrenstuvel/python-rsa/blob/main/CHANGELOG.md) - [Commits](https://github.com/sybrenstuvel/python-rsa/compare/version-4.0...version-4.1) Signed-off-by: dependabot[bot] --- Pipfile.lock | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/Pipfile.lock b/Pipfile.lock index 172a600..da51fb7 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -18,10 +18,10 @@ "default": { "certifi": { "hashes": [ - "sha256:e4f3620cfea4f83eedc95b24abd9cd56f3c4b146dd0177e83a21b4eb49e21e50", - "sha256:fd7c7c74727ddcf00e9acd26bba8da604ffec95bf1c2144e67aff7a8b50e6cef" + "sha256:1a4995114262bffbc2413b159f2a1a480c969de6e6eb13ee966d470af86af59c", + "sha256:719a74fb9e33b9bd44cc7f3a8d94bc35e4049deebe19ba7d8e108280cfd59830" ], - "version": "==2019.9.11" + "version": "==2020.12.5" }, "chardet": { "hashes": [ @@ -32,17 +32,16 @@ }, "ecdsa": { "hashes": [ - "sha256:163c80b064a763ea733870feb96f9dd9b92216cfcacd374837af18e4e8ec3d4d", - "sha256:9814e700890991abeceeb2242586024d4758c8fc18445b194a49bd62d85861db" + "sha256:881fa5e12bb992972d3d1b3d4dfbe149ab76a89f13da02daa5ea1ec7dea6e747", + "sha256:cfc046a2ddd425adbd1a78b3c46f0d1325c657811c0f45ecc3a0a6236c1e50ff" ], - "index": "pypi", - "version": "==0.13.3" + "version": "==0.16.1" }, "future": { "hashes": [ - "sha256:6142ef79e2416e432931d527452a1cab3aa4a754a0a53d25b2589f79e1106f34" + "sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d" ], - "version": "==0.18.0" + "version": "==0.18.2" }, "httmock": { "hashes": [ @@ -60,10 +59,10 @@ }, "pyasn1": { "hashes": [ - "sha256:62cdade8b5530f0b185e09855dd422bc05c0bbff6b72ff61381c09dac7befd8c", - "sha256:a9495356ca1d66ed197a0f72b41eb1823cf7ea8b5bd07191673e8147aecf8604" + "sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d", + "sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba" ], - "version": "==0.4.7" + "version": "==0.4.8" }, "python-jose": { "hashes": [ @@ -83,17 +82,18 @@ }, "rsa": { "hashes": [ - "sha256:14ba45700ff1ec9eeb206a2ce76b32814958a98e372006c8fb76ba820211be66", - "sha256:1a836406405730121ae9823e19c6e806c62bbad73f890574fff50efa4122c487" + "sha256:2c7c8624ef9b55bacc3be8bdcec5cefc381ddc156e968d6437fe0fd08af00eb0", + "sha256:6fa6a54eb72bfc0abca7f27880b978b14a643ba2a6ad9f4a56a95be82129ca1b" ], - "version": "==4.0" + "index": "pypi", + "version": "==4.1" }, "six": { "hashes": [ - "sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", - "sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73" + "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259", + "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced" ], - "version": "==1.12.0" + "version": "==1.15.0" }, "urllib3": { "hashes": [ From 988700bc8191b9f565379e6be6e536b8b6829be9 Mon Sep 17 00:00:00 2001 From: andreas Date: Mon, 29 Mar 2021 16:22:47 +0200 Subject: [PATCH 14/34] Replaced deprecated method, improved description and added packages to requirements. --- keycloak/connection.py | 6 +++--- keycloak/keycloak_admin.py | 2 +- requirements.txt | 4 +++- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/keycloak/connection.py b/keycloak/connection.py index 3871482..7d5ed2f 100644 --- a/keycloak/connection.py +++ b/keycloak/connection.py @@ -54,9 +54,9 @@ class ConnectionManager(object): for protocol in ('https://', 'http://'): adapter = HTTPAdapter(max_retries=1) # adds POST to retry whitelist - method_whitelist = set(adapter.max_retries.method_whitelist) - method_whitelist.add('POST') - adapter.max_retries.method_whitelist = frozenset(method_whitelist) + allowed_methods = set(adapter.max_retries.allowed_methods) + allowed_methods.add('POST') + adapter.max_retries.allowed_methods = frozenset(allowed_methods) self._s.mount(protocol, adapter) diff --git a/keycloak/keycloak_admin.py b/keycloak/keycloak_admin.py index c0ac364..e52d20e 100644 --- a/keycloak/keycloak_admin.py +++ b/keycloak/keycloak_admin.py @@ -77,7 +77,7 @@ class KeycloakAdmin: :param realm_name: realm name :param client_id: client id :param verify: True if want check connection SSL - :param client_secret_key: client secret key + :param client_secret_key: client secret key (optional, required only for access type confidential) :param custom_headers: dict of custom header to pass to each HTML request :param user_realm_name: The realm name of the user, if different from realm_name :param auto_refresh_token: list of methods that allows automatic token refresh. ex: ['get', 'put', 'post', 'delete'] diff --git a/requirements.txt b/requirements.txt index d4776e3..f4faf6d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,6 @@ requests>=2.20.0 httmock>=1.2.5 python-jose>=1.4.0 -twine==1.13.0 \ No newline at end of file +twine==1.13.0 +jose~=1.0.0 +setuptools~=54.2.0 \ No newline at end of file From 92cef305787dec2485596f769692bcaa2af2b29e Mon Sep 17 00:00:00 2001 From: obdeijn Date: Tue, 6 Apr 2021 10:24:22 +0200 Subject: [PATCH 15/34] Fix get_group_realm_roles, set correct url to get realm roles. Remove the no longer used, wrong url. --- keycloak/keycloak_admin.py | 4 ++-- keycloak/urls_patterns.py | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/keycloak/keycloak_admin.py b/keycloak/keycloak_admin.py index c0ac364..238d157 100644 --- a/keycloak/keycloak_admin.py +++ b/keycloak/keycloak_admin.py @@ -34,7 +34,7 @@ from .keycloak_openid import KeycloakOpenID from .urls_patterns import URL_ADMIN_SERVER_INFO, URL_ADMIN_CLIENT_AUTHZ_RESOURCES, URL_ADMIN_CLIENT_ROLES, \ URL_ADMIN_GET_SESSIONS, URL_ADMIN_RESET_PASSWORD, URL_ADMIN_SEND_UPDATE_ACCOUNT, URL_ADMIN_GROUPS_REALM_ROLES, \ URL_ADMIN_REALM_ROLES_COMPOSITE_REALM_ROLE, URL_ADMIN_CLIENT_INSTALLATION_PROVIDER, \ - URL_ADMIN_REALM_ROLES_ROLE_BY_NAME, URL_ADMIN_GET_GROUPS_REALM_ROLES, URL_ADMIN_GROUPS_CLIENT_ROLES, \ + URL_ADMIN_REALM_ROLES_ROLE_BY_NAME, URL_ADMIN_GROUPS_CLIENT_ROLES, \ URL_ADMIN_USER_CLIENT_ROLES_COMPOSITE, URL_ADMIN_USER_GROUP, URL_ADMIN_REALM_ROLES, URL_ADMIN_GROUP_CHILD, \ URL_ADMIN_USER_CONSENTS, URL_ADMIN_SEND_VERIFY_EMAIL, URL_ADMIN_CLIENT, URL_ADMIN_USER, URL_ADMIN_CLIENT_ROLE, \ URL_ADMIN_USER_GROUPS, URL_ADMIN_CLIENTS, URL_ADMIN_FLOWS_EXECUTIONS, URL_ADMIN_GROUPS, URL_ADMIN_USER_CLIENT_ROLES, \ @@ -1239,7 +1239,7 @@ class KeycloakAdmin: :return: Keycloak server response (array RoleRepresentation) """ params_path = {"realm-name": self.realm_name, "id": group_id} - data_raw = self.raw_get(URL_ADMIN_GET_GROUPS_REALM_ROLES.format(**params_path)) + data_raw = self.raw_get(URL_ADMIN_GROUPS_REALM_ROLES.format(**params_path)) return raise_error_from_response(data_raw, KeycloakGetError) def assign_group_client_roles(self, group_id, client_id, roles): diff --git a/keycloak/urls_patterns.py b/keycloak/urls_patterns.py index 7aa40f8..3fae695 100644 --- a/keycloak/urls_patterns.py +++ b/keycloak/urls_patterns.py @@ -44,7 +44,6 @@ URL_ADMIN_GET_SESSIONS = "admin/realms/{realm-name}/users/{id}/sessions" URL_ADMIN_USER_CLIENT_ROLES = "admin/realms/{realm-name}/users/{id}/role-mappings/clients/{client-id}" URL_ADMIN_USER_REALM_ROLES = "admin/realms/{realm-name}/users/{id}/role-mappings/realm" URL_ADMIN_GROUPS_REALM_ROLES = "admin/realms/{realm-name}/groups/{id}/role-mappings/realm" -URL_ADMIN_GET_GROUPS_REALM_ROLES = "admin/realms/{realm-name}/groups/{id}/role-mappings" URL_ADMIN_GROUPS_CLIENT_ROLES = "admin/realms/{realm-name}/groups/{id}/role-mappings/clients/{client-id}" URL_ADMIN_USER_CLIENT_ROLES_AVAILABLE = "admin/realms/{realm-name}/users/{id}/role-mappings/clients/{client-id}/available" URL_ADMIN_USER_CLIENT_ROLES_COMPOSITE = "admin/realms/{realm-name}/users/{id}/role-mappings/clients/{client-id}/composite" From c91df2b5c8a046f541e684ee2b70e67930d3bef2 Mon Sep 17 00:00:00 2001 From: arata-honda Date: Mon, 19 Apr 2021 22:39:49 +0900 Subject: [PATCH 16/34] Fix get_user_id to non case-sensitive --- keycloak/keycloak_admin.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/keycloak/keycloak_admin.py b/keycloak/keycloak_admin.py index c0ac364..cd9660a 100644 --- a/keycloak/keycloak_admin.py +++ b/keycloak/keycloak_admin.py @@ -410,9 +410,9 @@ class KeycloakAdmin: :return: user_id """ - - users = self.get_users(query={"search": username}) - return next((user["id"] for user in users if user["username"] == username), None) + lower_user_name = username.lower() + users = self.get_users(query={"search": lower_user_name}) + return next((user["id"] for user in users if user["username"] == lower_user_name), None) def get_user(self, user_id): """ From a39ff81e6250fcc6b5bb92c23a94eebac151358b Mon Sep 17 00:00:00 2001 From: Sandro Covo Date: Fri, 30 Apr 2021 16:40:38 +0200 Subject: [PATCH 17/34] add example to create user and specify locale Usage of the `attributes`for this kind of task with not quite obvious and documentation hard to find. --- README.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 095782b..63abe49 100644 --- a/README.md +++ b/README.md @@ -142,7 +142,17 @@ new_user = keycloak_admin.create_user({"email": "example@example.com", "enabled": True, "firstName": "Example", "lastName": "Example", - "credentials": [{"value": "secret","type": "password",}]}) + "credentials": [{"value": "secret","type": "password",}]}) + +# Add user and specify a locale +new_user = keycloak_admin.create_user({"email": "example@example.fr", + "username": "example@example.fr", + "enabled": True, + "firstName": "Example", + "lastName": "Example", + "attributes": { + "locale": ["fr"] + }) # User counter count_users = keycloak_admin.users_count() From 992de97378f35af6aa88aeb5d261ff693afbe3c7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 30 Apr 2021 21:02:32 +0000 Subject: [PATCH 18/34] Bump rsa from 4.1 to 4.7 Bumps [rsa](https://github.com/sybrenstuvel/python-rsa) from 4.1 to 4.7. - [Release notes](https://github.com/sybrenstuvel/python-rsa/releases) - [Changelog](https://github.com/sybrenstuvel/python-rsa/blob/main/CHANGELOG.md) - [Commits](https://github.com/sybrenstuvel/python-rsa/compare/version-4.1...version-4.7) Signed-off-by: dependabot[bot] --- Pipfile.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Pipfile.lock b/Pipfile.lock index da51fb7..0430b1e 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -82,11 +82,11 @@ }, "rsa": { "hashes": [ - "sha256:2c7c8624ef9b55bacc3be8bdcec5cefc381ddc156e968d6437fe0fd08af00eb0", - "sha256:6fa6a54eb72bfc0abca7f27880b978b14a643ba2a6ad9f4a56a95be82129ca1b" + "sha256:69805d6b69f56eb05b62daea3a7dbd7aa44324ad1306445e05da8060232d00f4", + "sha256:a8774e55b59fd9fc893b0d05e9bfc6f47081f46ff5b46f39ccf24631b7be356b" ], "index": "pypi", - "version": "==4.1" + "version": "==4.7" }, "six": { "hashes": [ From 62dc333d8236fed9705006a07bd0d7f7c0420914 Mon Sep 17 00:00:00 2001 From: Marcos Pereira Date: Tue, 1 Jun 2021 14:47:35 -0300 Subject: [PATCH 19/34] Release 0.25.0 --- bin/deploy.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 bin/deploy.sh diff --git a/bin/deploy.sh b/bin/deploy.sh old mode 100644 new mode 100755 From 0ebcf990941f600e6ff562091a81cbeafbd21f3e Mon Sep 17 00:00:00 2001 From: Marcos Pereira Date: Tue, 1 Jun 2021 14:47:54 -0300 Subject: [PATCH 20/34] Release 0.25.0 --- docs/source/conf.py | 4 ++-- setup.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 1ab699d..61db46e 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -60,9 +60,9 @@ author = 'Marcos Pereira' # built documents. # # The short X.Y version. -version = '0.24.0' +version = '0.25.0' # The full version, including alpha/beta/rc tags. -release = '0.24.0' +release = '0.25.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/setup.py b/setup.py index 362f177..dcde1e8 100644 --- a/setup.py +++ b/setup.py @@ -7,7 +7,7 @@ with open("README.md", "r") as fh: setup( name='python-keycloak', - version='0.24.0', + version='0.25.0', url='https://github.com/marcospereirampj/python-keycloak', license='The MIT License', author='Marcos Pereira', From 420779e3d25e9a49f0257ca3458d8f27943690dc Mon Sep 17 00:00:00 2001 From: phala Date: Wed, 9 Jun 2021 14:16:23 +0200 Subject: [PATCH 21/34] Remove unused client_id from assign_realm_roles --- keycloak/keycloak_admin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/keycloak/keycloak_admin.py b/keycloak/keycloak_admin.py index ffb5968..3db6d47 100644 --- a/keycloak/keycloak_admin.py +++ b/keycloak/keycloak_admin.py @@ -1173,7 +1173,7 @@ class KeycloakAdmin: URL_ADMIN_REALM_ROLES_COMPOSITE_REALM_ROLE.format(**params_path)) return raise_error_from_response(data_raw, KeycloakGetError) - def assign_realm_roles(self, user_id, client_id, roles): + def assign_realm_roles(self, user_id, roles): """ Assign realm roles to a user From 56fdb467be46de2e64c56c63b6c582ca0afaa234 Mon Sep 17 00:00:00 2001 From: phala Date: Wed, 9 Jun 2021 14:30:03 +0200 Subject: [PATCH 22/34] Add user logout --- keycloak/keycloak_admin.py | 15 ++++++++++++++- keycloak/urls_patterns.py | 1 + 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/keycloak/keycloak_admin.py b/keycloak/keycloak_admin.py index ffb5968..9758cf0 100644 --- a/keycloak/keycloak_admin.py +++ b/keycloak/keycloak_admin.py @@ -47,7 +47,7 @@ from .urls_patterns import URL_ADMIN_SERVER_INFO, URL_ADMIN_CLIENT_AUTHZ_RESOURC URL_ADMIN_REALM_ROLES_MEMBERS, URL_ADMIN_CLIENT_PROTOCOL_MAPPER, URL_ADMIN_CLIENT_SCOPES_MAPPERS, \ URL_ADMIN_FLOWS_EXECUTIONS_EXEUCUTION, URL_ADMIN_FLOWS_EXECUTIONS_FLOW, URL_ADMIN_FLOWS_COPY, \ URL_ADMIN_FLOWS_ALIAS, URL_ADMIN_CLIENT_SERVICE_ACCOUNT_USER, URL_ADMIN_AUTHENTICATOR_CONFIG, \ - URL_ADMIN_CLIENT_ROLES_COMPOSITE_CLIENT_ROLE, URL_ADMIN_CLIENT_ALL_SESSIONS, URL_ADMIN_EVENTS + URL_ADMIN_CLIENT_ROLES_COMPOSITE_CLIENT_ROLE, URL_ADMIN_CLIENT_ALL_SESSIONS, URL_ADMIN_EVENTS, URL_ADMIN_USER_LOGOUT class KeycloakAdmin: @@ -487,6 +487,19 @@ class KeycloakAdmin: data=json.dumps(payload)) return raise_error_from_response(data_raw, KeycloakGetError, expected_codes=[204]) + def logout(self, user_id): + """ + Logs out user. + + https://www.keycloak.org/docs-api/8.0/rest-api/index.html#_logout + + :param user_id: User id + :return: + """ + params_path = {"realm-name": self.realm_name, "id": user_id} + data_raw = self.raw_post(URL_ADMIN_USER_LOGOUT.format(**params_path), data="") + return raise_error_from_response(data_raw, KeycloakGetError, expected_codes=[204]) + def consents_user(self, user_id): """ Get consents granted by the user diff --git a/keycloak/urls_patterns.py b/keycloak/urls_patterns.py index 8dfbadb..3bb0ccf 100644 --- a/keycloak/urls_patterns.py +++ b/keycloak/urls_patterns.py @@ -50,6 +50,7 @@ URL_ADMIN_USER_CLIENT_ROLES_COMPOSITE = "admin/realms/{realm-name}/users/{id}/ro URL_ADMIN_USER_GROUP = "admin/realms/{realm-name}/users/{id}/groups/{group-id}" URL_ADMIN_USER_GROUPS = "admin/realms/{realm-name}/users/{id}/groups" URL_ADMIN_USER_PASSWORD = "admin/realms/{realm-name}/users/{id}/reset-password" +URL_ADMIN_USER_LOGOUT = "admin/realms/{realm-name}/users/{id}/logout" URL_ADMIN_USER_STORAGE = "admin/realms/{realm-name}/user-storage/{id}/sync" URL_ADMIN_SERVER_INFO = "admin/serverinfo" From 11e4a12c83754bf6a7ffe95f6bcc80266113b0a9 Mon Sep 17 00:00:00 2001 From: Adrian_Cin Date: Mon, 14 Jun 2021 16:17:47 +0700 Subject: [PATCH 23/34] Correct public key format Keycloak returns public key in PEM format --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 63abe49..28b218d 100644 --- a/README.md +++ b/README.md @@ -98,7 +98,7 @@ token_rpt_info = keycloak_openid.introspect(keycloak_openid.introspect(token['ac token_info = keycloak_openid.introspect(token['access_token']) # Decode Token -KEYCLOAK_PUBLIC_KEY = keycloak_openid.public_key() +KEYCLOAK_PUBLIC_KEY = "-----BEGIN PUBLIC KEY-----\n" + keycloak_openid.public_key() + "\n-----END PUBLIC KEY-----" options = {"verify_signature": True, "verify_aud": True, "verify_exp": True} token_info = keycloak_openid.decode_token(token['access_token'], key=KEYCLOAK_PUBLIC_KEY, options=options) From 31b4efd7ab903354bb844d9eec1671dbdaa9dbf0 Mon Sep 17 00:00:00 2001 From: bostonkenne Date: Thu, 17 Jun 2021 15:51:11 +0100 Subject: [PATCH 24/34] add remove user realm role --- keycloak/keycloak_admin.py | 15 ++++++++++++++- keycloak/urls_patterns.py | 4 +++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/keycloak/keycloak_admin.py b/keycloak/keycloak_admin.py index ffb5968..4272482 100644 --- a/keycloak/keycloak_admin.py +++ b/keycloak/keycloak_admin.py @@ -47,7 +47,8 @@ from .urls_patterns import URL_ADMIN_SERVER_INFO, URL_ADMIN_CLIENT_AUTHZ_RESOURC URL_ADMIN_REALM_ROLES_MEMBERS, URL_ADMIN_CLIENT_PROTOCOL_MAPPER, URL_ADMIN_CLIENT_SCOPES_MAPPERS, \ URL_ADMIN_FLOWS_EXECUTIONS_EXEUCUTION, URL_ADMIN_FLOWS_EXECUTIONS_FLOW, URL_ADMIN_FLOWS_COPY, \ URL_ADMIN_FLOWS_ALIAS, URL_ADMIN_CLIENT_SERVICE_ACCOUNT_USER, URL_ADMIN_AUTHENTICATOR_CONFIG, \ - URL_ADMIN_CLIENT_ROLES_COMPOSITE_CLIENT_ROLE, URL_ADMIN_CLIENT_ALL_SESSIONS, URL_ADMIN_EVENTS + URL_ADMIN_CLIENT_ROLES_COMPOSITE_CLIENT_ROLE, URL_ADMIN_CLIENT_ALL_SESSIONS, URL_ADMIN_EVENTS,\ + URL_ADMIN_DELETE_USER_ROLE class KeycloakAdmin: @@ -1878,3 +1879,15 @@ class KeycloakAdmin: params_path = {"realm-name": self.realm_name, "id": client_id} data_raw = self.connection.raw_get(URL_ADMIN_CLIENT_ALL_SESSIONS.format(**params_path)) return raise_error_from_response(data_raw, KeycloakGetError) + + + def delete_user_realm_role(self, user_id, payload): + """ + Delete realm-level role mappings + DELETE admin/realms/{realm-name}/users/{id}/role-mappings/realm + + """ + params_path = {"realm-name": self.realm_name, "id": str(user_id) } + data_raw = self.connection.raw_delete(URL_ADMIN_DELETE_USER_ROLE.format(**params_path), + data=json.dumps(payload)) + return raise_error_from_response(data_raw, KeycloakGetError, expected_code=204) \ No newline at end of file diff --git a/keycloak/urls_patterns.py b/keycloak/urls_patterns.py index 8dfbadb..460ae8b 100644 --- a/keycloak/urls_patterns.py +++ b/keycloak/urls_patterns.py @@ -105,4 +105,6 @@ URL_ADMIN_KEYS = "admin/realms/{realm-name}/keys" URL_ADMIN_USER_FEDERATED_IDENTITIES = "admin/realms/{realm-name}/users/{id}/federated-identity" URL_ADMIN_USER_FEDERATED_IDENTITY = "admin/realms/{realm-name}/users/{id}/federated-identity/{provider}" -URL_ADMIN_EVENTS = 'admin/realms/{realm-name}/events' \ No newline at end of file +URL_ADMIN_EVENTS = 'admin/realms/{realm-name}/events' + +URL_ADMIN_DELETE_USER_ROLE = "admin/realms/{realm-name}/users/{id}/role-mappings/realm" \ No newline at end of file From d7d661a38c7a6bf5daaea513616f4f9936460bef Mon Sep 17 00:00:00 2001 From: bostonkenne Date: Thu, 17 Jun 2021 15:53:16 +0100 Subject: [PATCH 25/34] fix json response --- keycloak/keycloak_admin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/keycloak/keycloak_admin.py b/keycloak/keycloak_admin.py index 4272482..15ee759 100644 --- a/keycloak/keycloak_admin.py +++ b/keycloak/keycloak_admin.py @@ -1890,4 +1890,4 @@ class KeycloakAdmin: params_path = {"realm-name": self.realm_name, "id": str(user_id) } data_raw = self.connection.raw_delete(URL_ADMIN_DELETE_USER_ROLE.format(**params_path), data=json.dumps(payload)) - return raise_error_from_response(data_raw, KeycloakGetError, expected_code=204) \ No newline at end of file + return raise_error_from_response(data_raw, KeycloakGetError, expected_codes=[204]) \ No newline at end of file From 8f6de6c3c84faaf354484811160c8d95c33ee3c8 Mon Sep 17 00:00:00 2001 From: Yannick Chabbert Date: Mon, 28 Jun 2021 15:42:54 +0200 Subject: [PATCH 26/34] openid - minor typo fix, change nothing yet --- keycloak/keycloak_openid.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/keycloak/keycloak_openid.py b/keycloak/keycloak_openid.py index 0f801ea..197dd26 100644 --- a/keycloak/keycloak_openid.py +++ b/keycloak/keycloak_openid.py @@ -189,7 +189,7 @@ class KeycloakOpenID: payload = {"username": username, "password": password, "client_id": self.client_id, "grant_type": grant_type, "code": code, "redirect_uri": redirect_uri} - if payload: + if extra: payload.update(extra) if totp: From 44fe7b714aa08743fc95a8de5d9ea469dabb2799 Mon Sep 17 00:00:00 2001 From: Manjeetsinh Alonja Date: Fri, 9 Jul 2021 11:33:35 +0530 Subject: [PATCH 27/34] Added realm partial export feature --- keycloak/keycloak_admin.py | 13 ++++++++++++- keycloak/urls_patterns.py | 1 + 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/keycloak/keycloak_admin.py b/keycloak/keycloak_admin.py index ffb5968..41f71eb 100644 --- a/keycloak/keycloak_admin.py +++ b/keycloak/keycloak_admin.py @@ -47,7 +47,8 @@ from .urls_patterns import URL_ADMIN_SERVER_INFO, URL_ADMIN_CLIENT_AUTHZ_RESOURC URL_ADMIN_REALM_ROLES_MEMBERS, URL_ADMIN_CLIENT_PROTOCOL_MAPPER, URL_ADMIN_CLIENT_SCOPES_MAPPERS, \ URL_ADMIN_FLOWS_EXECUTIONS_EXEUCUTION, URL_ADMIN_FLOWS_EXECUTIONS_FLOW, URL_ADMIN_FLOWS_COPY, \ URL_ADMIN_FLOWS_ALIAS, URL_ADMIN_CLIENT_SERVICE_ACCOUNT_USER, URL_ADMIN_AUTHENTICATOR_CONFIG, \ - URL_ADMIN_CLIENT_ROLES_COMPOSITE_CLIENT_ROLE, URL_ADMIN_CLIENT_ALL_SESSIONS, URL_ADMIN_EVENTS + URL_ADMIN_CLIENT_ROLES_COMPOSITE_CLIENT_ROLE, URL_ADMIN_CLIENT_ALL_SESSIONS, URL_ADMIN_EVENTS, \ + URL_ADMIN_REALM_EXPORT class KeycloakAdmin: @@ -242,6 +243,16 @@ class KeycloakAdmin: data=json.dumps(payload)) return raise_error_from_response(data_raw, KeycloakGetError, expected_codes=[201]) + def export_realm(self, export_clients=False, export_groups_and_role=False): + """ + Export the realm configurations in the json format + + :return: realm configurations JSON + """ + params_path = {"realm-name": self.realm_name, "export-clients": export_clients, "export-groups-and-roles": export_groups_and_role } + data_raw = self.raw_post(URL_ADMIN_REALM_EXPORT.format(**params_path), data="") + return raise_error_from_response(data_raw, KeycloakGetError) + def get_realms(self): """ Lists all realms in Keycloak deployment diff --git a/keycloak/urls_patterns.py b/keycloak/urls_patterns.py index 8dfbadb..65ffbeb 100644 --- a/keycloak/urls_patterns.py +++ b/keycloak/urls_patterns.py @@ -89,6 +89,7 @@ URL_ADMIN_IDP_MAPPERS = "admin/realms/{realm-name}/identity-provider/instances/{ URL_ADMIN_IDP = "admin/realms//{realm-name}/identity-provider/instances/{alias}" URL_ADMIN_REALM_ROLES_ROLE_BY_NAME = "admin/realms/{realm-name}/roles/{role-name}" URL_ADMIN_REALM_ROLES_COMPOSITE_REALM_ROLE = "admin/realms/{realm-name}/roles/{role-name}/composites" +URL_ADMIN_REALM_EXPORT = "admin/realms/{realm-name}/partial-export?exportClients={export-clients}&exportGroupsAndRoles={export-groups-and-roles}" URL_ADMIN_FLOWS = "admin/realms/{realm-name}/authentication/flows" URL_ADMIN_FLOWS_ALIAS = "admin/realms/{realm-name}/authentication/flows/{flow-id}" From 71a92f8b4911edfc0f7c26b6829ce519a44e9979 Mon Sep 17 00:00:00 2001 From: Manjeetsinh Alonja Date: Fri, 9 Jul 2021 12:05:58 +0530 Subject: [PATCH 28/34] Fix feature function documents --- keycloak/keycloak_admin.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/keycloak/keycloak_admin.py b/keycloak/keycloak_admin.py index 41f71eb..3abf55b 100644 --- a/keycloak/keycloak_admin.py +++ b/keycloak/keycloak_admin.py @@ -247,6 +247,12 @@ class KeycloakAdmin: """ Export the realm configurations in the json format + RealmRepresentation + https://www.keycloak.org/docs-api/5.0/rest-api/index.html#_partialexport + + :param export-clients: Skip if not want to export realm clients + :param export-groups-and-roles: Skip if not want to export realm groups and roles + :return: realm configurations JSON """ params_path = {"realm-name": self.realm_name, "export-clients": export_clients, "export-groups-and-roles": export_groups_and_role } From 227b698b3fd1552fbac9d0e619d2ff3640ddcf8a Mon Sep 17 00:00:00 2001 From: Michael Kao Date: Tue, 20 Jul 2021 17:23:44 +0200 Subject: [PATCH 29/34] Stopping pagination requests if response count is lower than page size. --- keycloak/keycloak_admin.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/keycloak/keycloak_admin.py b/keycloak/keycloak_admin.py index ffb5968..e018dbc 100644 --- a/keycloak/keycloak_admin.py +++ b/keycloak/keycloak_admin.py @@ -223,6 +223,8 @@ class KeycloakAdmin: if not partial_results: break results.extend(partial_results) + if len(partial_results) < query['max']: + break page += 1 return results From a9b39248543b521fe2a5936fe09b3d8509d681c0 Mon Sep 17 00:00:00 2001 From: Jacky Boen Date: Mon, 2 Aug 2021 10:27:17 +0800 Subject: [PATCH 30/34] Fix KeycloakAdmin using wrong realm when authenticating with a service account Signed-off-by: Jacky Boen --- keycloak/keycloak_admin.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/keycloak/keycloak_admin.py b/keycloak/keycloak_admin.py index ffb5968..5feceaf 100644 --- a/keycloak/keycloak_admin.py +++ b/keycloak/keycloak_admin.py @@ -1827,14 +1827,17 @@ class KeycloakAdmin: return r def get_token(self): + token_realm_name = 'master' if self.client_secret_key else self.user_realm_name or self.realm_name self.keycloak_openid = KeycloakOpenID(server_url=self.server_url, client_id=self.client_id, - realm_name=self.user_realm_name or self.realm_name, verify=self.verify, + realm_name=token_realm_name, verify=self.verify, client_secret_key=self.client_secret_key, custom_headers=self.custom_headers) grant_type = ["password"] if self.client_secret_key: grant_type = ["client_credentials"] + if self.user_realm_name: + self.realm_name = self.user_realm_name self._token = self.keycloak_openid.token(self.username, self.password, grant_type=grant_type) From bd8af2924e8b479428a4f2ee3000cbf9bba0e7bf Mon Sep 17 00:00:00 2001 From: Julien Bouquillon Date: Wed, 18 Aug 2021 00:45:53 +0200 Subject: [PATCH 31/34] feat: add KeycloakAdmin.set_events --- keycloak/keycloak_admin.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/keycloak/keycloak_admin.py b/keycloak/keycloak_admin.py index ffb5968..0344721 100644 --- a/keycloak/keycloak_admin.py +++ b/keycloak/keycloak_admin.py @@ -1774,6 +1774,20 @@ class KeycloakAdmin: data=None, **query) return raise_error_from_response(data_raw, KeycloakGetError) + def set_events(self, payload): + """ + Set realm events configuration + + RealmEventsConfigRepresentation + https://www.keycloak.org/docs-api/8.0/rest-api/index.html#_realmeventsconfigrepresentation + + :return: Http response + """ + params_path = {"realm-name": self.realm_name} + data_raw = self.raw_put(URL_ADMIN_EVENTS.format(**params_path), + data=json.dumps(payload)) + return raise_error_from_response(data_raw, KeycloakGetError, expected_codes=[204]) + def raw_get(self, *args, **kwargs): """ Calls connection.raw_get. From 81b12d2d556883f5770e81818b9e3f5eb666a10b Mon Sep 17 00:00:00 2001 From: Bas van der Linden <33874522+BvdLind@users.noreply.github.com> Date: Thu, 19 Aug 2021 19:50:37 +0200 Subject: [PATCH 32/34] Update README example create_client_role syntax In the README the `create_client_role` function has a `client_id` argument, but in [keycloak_admin.py](https://github.com/marcospereirampj/python-keycloak/blob/0ebcf990941f600e6ff562091a81cbeafbd21f3e/keycloak/keycloak_admin.py#L1001) `client_role_id` seems to be used instead. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 63abe49..d076555 100644 --- a/README.md +++ b/README.md @@ -215,7 +215,7 @@ role = keycloak_admin.get_client_role(client_id="client_id", role_name="role_nam role_id = keycloak_admin.get_client_role_id(client_id="client_id", role_name="test") # Create client role -keycloak_admin.create_client_role(client_id='client_id', {'name': 'roleName', 'clientRole': True}) +keycloak_admin.create_client_role(client_role_id='client_id', {'name': 'roleName', 'clientRole': True}) # Assign client role to user. Note that BOTH role_name and role_id appear to be required. keycloak_admin.assign_client_role(client_id="client_id", user_id="user_id", role_id="role_id", role_name="test") From 6acadaca5b5804b01a91d12c43c11f213b05acb5 Mon Sep 17 00:00:00 2001 From: Marcos Pereira Jr Date: Mon, 30 Aug 2021 10:12:40 -0300 Subject: [PATCH 33/34] Release 0.26.0 --- docs/source/conf.py | 4 ++-- setup.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 61db46e..78454a2 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -60,9 +60,9 @@ author = 'Marcos Pereira' # built documents. # # The short X.Y version. -version = '0.25.0' +version = '0.26.0' # The full version, including alpha/beta/rc tags. -release = '0.25.0' +release = '0.26.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/setup.py b/setup.py index dcde1e8..81dc85f 100644 --- a/setup.py +++ b/setup.py @@ -7,7 +7,7 @@ with open("README.md", "r") as fh: setup( name='python-keycloak', - version='0.25.0', + version='0.26.0', url='https://github.com/marcospereirampj/python-keycloak', license='The MIT License', author='Marcos Pereira', From dd130a0365da390ae28d8a9cb6f76103ecb5c83f Mon Sep 17 00:00:00 2001 From: Marcos Pereira Jr Date: Mon, 30 Aug 2021 10:15:58 -0300 Subject: [PATCH 34/34] Release 0.26.1 --- Pipfile | 1 + docs/source/conf.py | 4 ++-- requirements.txt | 3 ++- setup.py | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Pipfile b/Pipfile index a85e8e5..828d298 100644 --- a/Pipfile +++ b/Pipfile @@ -7,6 +7,7 @@ name = "pypi" requests = ">=2.20.0" httmock = ">=1.2.5" python-jose = ">=1.4.0" +urllib3 = ">=1.26.5" [dev-packages] diff --git a/docs/source/conf.py b/docs/source/conf.py index 78454a2..7b52edc 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -60,9 +60,9 @@ author = 'Marcos Pereira' # built documents. # # The short X.Y version. -version = '0.26.0' +version = '0.26.1' # The full version, including alpha/beta/rc tags. -release = '0.26.0' +release = '0.26.1' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/requirements.txt b/requirements.txt index f4faf6d..a353c7f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,4 +3,5 @@ httmock>=1.2.5 python-jose>=1.4.0 twine==1.13.0 jose~=1.0.0 -setuptools~=54.2.0 \ No newline at end of file +setuptools~=54.2.0 +urllib3>=1.26.5 \ No newline at end of file diff --git a/setup.py b/setup.py index 81dc85f..e6cb84b 100644 --- a/setup.py +++ b/setup.py @@ -7,7 +7,7 @@ with open("README.md", "r") as fh: setup( name='python-keycloak', - version='0.26.0', + version='0.26.1', url='https://github.com/marcospereirampj/python-keycloak', license='The MIT License', author='Marcos Pereira',