diff --git a/src/keycloak/keycloak_admin.py b/src/keycloak/keycloak_admin.py index 86649fc..07790b2 100644 --- a/src/keycloak/keycloak_admin.py +++ b/src/keycloak/keycloak_admin.py @@ -2569,6 +2569,60 @@ class KeycloakAdmin: urls_patterns.URL_ADMIN_CLIENT_ROLE_GROUPS.format(**params_path), query ) + def get_role_by_id(self, role_id): + """Get a specific role’s representation. + + RoleRepresentation + https://www.keycloak.org/docs-api/18.0/rest-api/index.html#_rolerepresentation + + :param role_id: id of role + :type role_id: str + :return: Keycloak server response (RoleRepresentation) + :rtype: bytes + """ + params_path = {"realm-name": self.connection.realm_name, "role-id": role_id} + data_raw = self.connection.raw_get( + urls_patterns.URL_ADMIN_REALM_ROLES_ROLE_BY_ID.format(**params_path) + ) + return raise_error_from_response(data_raw, KeycloakGetError, expected_codes=[200]) + + def update_role_by_id(self, role_id, payload): + """Update the role. + + RoleRepresentation + https://www.keycloak.org/docs-api/18.0/rest-api/index.html#_rolerepresentation + + :param payload: RoleRepresentation + :type payload: dict + :param role_id: id of role + :type role_id: str + :returns: Keycloak server response + :rtype: bytes + """ + params_path = {"realm-name": self.connection.realm_name, "role-id": role_id} + data_raw = self.connection.raw_put( + urls_patterns.URL_ADMIN_REALM_ROLES_ROLE_BY_ID.format(**params_path), + data=json.dumps(payload), + ) + return raise_error_from_response(data_raw, KeycloakPutError, expected_codes=[204]) + + def delete_role_by_id(self, role_id): + """Delete a role by its id. + + RoleRepresentation + https://www.keycloak.org/docs-api/18.0/rest-api/index.html#_rolerepresentation + + :param role_id: id of role + :type role_id: str + :returns: Keycloak server response + :rtype: bytes + """ + params_path = {"realm-name": self.connection.realm_name, "role-id": role_id} + data_raw = self.connection.raw_delete( + urls_patterns.URL_ADMIN_REALM_ROLES_ROLE_BY_ID.format(**params_path) + ) + return raise_error_from_response(data_raw, KeycloakDeleteError, expected_codes=[204]) + def create_realm_role(self, payload, skip_exists=False): """Create a new role for the realm or client. diff --git a/src/keycloak/keycloak_openid.py b/src/keycloak/keycloak_openid.py index bb52ea2..1bcc7f7 100644 --- a/src/keycloak/keycloak_openid.py +++ b/src/keycloak/keycloak_openid.py @@ -736,9 +736,7 @@ class KeycloakOpenID: :rtype: dict """ params_path = {"realm-name": self.realm_name} - payload = { - "client_id": self.client_id, - } + payload = {"client_id": self.client_id} payload = self._add_secret_key(payload) data_raw = self.connection.raw_post(URL_DEVICE.format(**params_path), data=payload) diff --git a/src/keycloak/urls_patterns.py b/src/keycloak/urls_patterns.py index 0531bd8..9db374f 100644 --- a/src/keycloak/urls_patterns.py +++ b/src/keycloak/urls_patterns.py @@ -43,6 +43,7 @@ URL_CLIENT_REGISTRATION = URL_REALM + "/clients-registrations/default" URL_CLIENT_UPDATE = URL_CLIENT_REGISTRATION + "/{client-id}" # ADMIN URLS +URL_ADMIN_ROOT = "admin/realms/{realm-name}" URL_ADMIN_USERS = "admin/realms/{realm-name}/users" URL_ADMIN_USERS_COUNT = "admin/realms/{realm-name}/users/count" URL_ADMIN_USER = "admin/realms/{realm-name}/users/{id}" diff --git a/tests/test_keycloak_admin.py b/tests/test_keycloak_admin.py index 7e6aa6a..a9a5904 100644 --- a/tests/test_keycloak_admin.py +++ b/tests/test_keycloak_admin.py @@ -1763,6 +1763,35 @@ def test_client_roles(admin: KeycloakAdmin, client: str): admin.delete_client_role(client_role_id=client, role_name="client-role-test-update") assert err.match('404: b\'{"error":"Could not find role"}\'') + # Test of roles by id - Get role + admin.create_client_role( + client_role_id=client, payload={"name": "client-role-by-id-test"}, skip_exists=True + ) + role = admin.get_client_role(client_id=client, role_name="client-role-by-id-test") + res = admin.get_role_by_id(role_id=role["id"]) + assert res["name"] == "client-role-by-id-test" + with pytest.raises(KeycloakGetError) as err: + admin.get_role_by_id(role_id="bad") + assert err.match('404: b\'{"error":"Could not find role with id"}\'') + + # Test of roles by id - Update role + res = admin.update_role_by_id( + role_id=role["id"], payload={"name": "client-role-by-id-test-update"} + ) + assert res == dict() + with pytest.raises(KeycloakPutError) as err: + res = admin.update_role_by_id( + role_id="bad", payload={"name": "client-role-by-id-test-update"} + ) + assert err.match('404: b\'{"error":"Could not find role with id"}\'') + + # Test of roles by id - Delete role + res = admin.delete_role_by_id(role_id=role["id"]) + assert res == dict() + with pytest.raises(KeycloakDeleteError) as err: + admin.delete_role_by_id(role_id="bad") + assert err.match('404: b\'{"error":"Could not find role with id"}\'') + def test_enable_token_exchange(admin: KeycloakAdmin, realm: str): """Test enable token exchange. diff --git a/tests/test_keycloak_openid.py b/tests/test_keycloak_openid.py index 171d70d..76e7264 100644 --- a/tests/test_keycloak_openid.py +++ b/tests/test_keycloak_openid.py @@ -208,9 +208,7 @@ def test_exchange_token( # Exchange token with the new user new_token = oid.exchange_token( - token=token["access_token"], - audience=oid.client_id, - subject=username, + token=token["access_token"], audience=oid.client_id, subject=username ) assert oid.userinfo(token=new_token["access_token"]) == { "email": f"{username}@test.test", diff --git a/tox.ini b/tox.ini index 419dc81..503ec2c 100644 --- a/tox.ini +++ b/tox.ini @@ -14,18 +14,21 @@ commands = isort -c --df src/keycloak tests docs flake8 src/keycloak tests docs codespell src tests docs +allowlist_externals = black, poetry [testenv:apply-check] commands = black -C src/keycloak tests docs black src/keycloak tests docs isort src/keycloak tests docs +allowlist_externals = black, poetry, isort [testenv:docs] commands_pre = poetry install --no-root --sync -E docs commands = sphinx-build -T -E -W -b html -d _build/doctrees -D language=en ./docs/source _build/html +allowlist_externals = sphinx-build, poetry [testenv:tests] setenv = file|tox.env