From a7407cd9c89a308a6644136f8542661f1a1658e8 Mon Sep 17 00:00:00 2001 From: Raspreet Singh Date: Fri, 28 Apr 2023 19:48:38 +0530 Subject: [PATCH] feat: Add get and delete methods for client authz resources (#435) * feat: add tests and logic for deleting client authz resource * feat: add tests and logic for getting client authz resource * fix: update return type of get_client_authz_resource from bytes to dict * fix: update return type of get_client_authz_resources admin method --- src/keycloak/keycloak_admin.py | 50 ++++++++++++++++++++++++++++++++-- src/keycloak/urls_patterns.py | 1 + tests/test_keycloak_admin.py | 14 ++++++++++ 3 files changed, 63 insertions(+), 2 deletions(-) diff --git a/src/keycloak/keycloak_admin.py b/src/keycloak/keycloak_admin.py index 9091ec0..e740ce1 100644 --- a/src/keycloak/keycloak_admin.py +++ b/src/keycloak/keycloak_admin.py @@ -1523,14 +1523,37 @@ class KeycloakAdmin: data_raw, KeycloakPostError, expected_codes=[201], skip_exists=skip_exists ) + def delete_client_authz_resource(self, client_id: str, resource_id: str): + """Delete a client resource. + + :param client_id: id in ClientRepresentation + https://www.keycloak.org/docs-api/18.0/rest-api/index.html#_clientrepresentation + :type client_id: str + :param resource_id: id in ResourceRepresentation + https://www.keycloak.org/docs-api/18.0/rest-api/index.html#_resourcerepresentation + :type resource_id: str + + :return: Keycloak server response + :rtype: bytes + """ + params_path = { + "realm-name": self.connection.realm_name, + "id": client_id, + "resource-id": resource_id, + } + data_raw = self.connection.raw_delete( + urls_patterns.URL_ADMIN_CLIENT_AUTHZ_RESOURCE.format(**params_path) + ) + return raise_error_from_response(data_raw, KeycloakDeleteError, expected_codes=[204]) + def get_client_authz_resources(self, client_id): """Get resources from client. :param client_id: id in ClientRepresentation https://www.keycloak.org/docs-api/18.0/rest-api/index.html#_clientrepresentation :type client_id: str - :return: Keycloak server response - :rtype: dict + :return: Keycloak server response (ResourceRepresentation) + :rtype: list """ params_path = {"realm-name": self.connection.realm_name, "id": client_id} data_raw = self.connection.raw_get( @@ -1538,6 +1561,29 @@ class KeycloakAdmin: ) return raise_error_from_response(data_raw, KeycloakGetError) + def get_client_authz_resource(self, client_id: str, resource_id: str): + """Get a client resource. + + :param client_id: id in ClientRepresentation + https://www.keycloak.org/docs-api/18.0/rest-api/index.html#_clientrepresentation + :type client_id: str + :param resource_id: id in ResourceRepresentation + https://www.keycloak.org/docs-api/18.0/rest-api/index.html#_resourcerepresentation + :type resource_id: str + + :return: Keycloak server response (ResourceRepresentation) + :rtype: dict + """ + params_path = { + "realm-name": self.connection.realm_name, + "id": client_id, + "resource-id": resource_id, + } + data_raw = self.connection.raw_get( + urls_patterns.URL_ADMIN_CLIENT_AUTHZ_RESOURCE.format(**params_path) + ) + return raise_error_from_response(data_raw, KeycloakGetError, expected_codes=[200]) + def create_client_authz_role_based_policy(self, client_id, payload, skip_exists=False): """Create role-based policy of client. diff --git a/src/keycloak/urls_patterns.py b/src/keycloak/urls_patterns.py index ef9facf..31069e5 100644 --- a/src/keycloak/urls_patterns.py +++ b/src/keycloak/urls_patterns.py @@ -112,6 +112,7 @@ URL_ADMIN_CLIENT_DEFAULT_CLIENT_SCOPE = ( URL_ADMIN_CLIENT_AUTHZ = URL_ADMIN_CLIENT + "/authz/resource-server" URL_ADMIN_CLIENT_AUTHZ_SETTINGS = URL_ADMIN_CLIENT_AUTHZ + "/settings" +URL_ADMIN_CLIENT_AUTHZ_RESOURCE = URL_ADMIN_CLIENT_AUTHZ + "/resource/{resource-id}" URL_ADMIN_CLIENT_AUTHZ_RESOURCES = URL_ADMIN_CLIENT_AUTHZ + "/resource?max=-1" URL_ADMIN_CLIENT_AUTHZ_SCOPES = URL_ADMIN_CLIENT_AUTHZ + "/scope?max=-1" URL_ADMIN_CLIENT_AUTHZ_PERMISSIONS = URL_ADMIN_CLIENT_AUTHZ + "/permission?max=-1" diff --git a/tests/test_keycloak_admin.py b/tests/test_keycloak_admin.py index 7aeaaa4..e984023 100644 --- a/tests/test_keycloak_admin.py +++ b/tests/test_keycloak_admin.py @@ -790,6 +790,10 @@ def test_clients(admin: KeycloakAdmin, realm: str): assert res["name"] == "test-resource", res test_resource_id = res["_id"] + res = admin.get_client_authz_resource(client_id=auth_client_id, resource_id=test_resource_id) + assert res["_id"] == test_resource_id, res + assert res["name"] == "test-resource", res + with pytest.raises(KeycloakPostError) as err: admin.create_client_authz_resource( client_id=auth_client_id, payload={"name": "test-resource"} @@ -803,6 +807,16 @@ def test_clients(admin: KeycloakAdmin, realm: str): assert len(res) == 2 assert {x["name"] for x in res} == {"Default Resource", "test-resource"} + res = admin.create_client_authz_resource( + client_id=auth_client_id, payload={"name": "temp-resource"} + ) + assert res["name"] == "temp-resource", res + temp_resource_id = res["_id"] + admin.delete_client_authz_resource(client_id=auth_client_id, resource_id=temp_resource_id) + with pytest.raises(KeycloakGetError) as err: + admin.get_client_authz_resource(client_id=auth_client_id, resource_id=temp_resource_id) + assert err.match("404: b''") + # Authz policies res = admin.get_client_authz_policies(client_id=auth_client_id) assert len(res) == 1, res