Skip to content

Commit 97fdb1a

Browse files
cainotisCainã S. G
andauthored
feat: Implement missing admin method create_client_authz_scope_based_permission() and create_client_authz_policy() (#460)
* feat: add create_client_authz_scope_permission and create_client_authz_policy to keycloak_admin Signed-off-by: Cainã S. G <p-caina.galante@pd.tec.br> * fix: fixed create_client_authz_policy url Signed-off-by: Cainã S. G <p-caina.galante@pd.tec.br> * fix: fixed test expect number of policies Signed-off-by: Cainã S. G <p-caina.galante@pd.tec.br> * fix: fixed typo in test for create_client_authz_scope_based_permission Signed-off-by: Cainã S. G <p-caina.galante@pd.tec.br> * fix: removed duplicated test Signed-off-by: Cainã S. G <p-caina.galante@pd.tec.br> * fix: chenge url to use existing variables Signed-off-by: Cainã S. G <p-caina.galante@pd.tec.br> * fix: linting Signed-off-by: Cainã S. G <p-caina.galante@pd.tec.br> * fix: linting Signed-off-by: Cainã S. G <p-caina.galante@pd.tec.br> --------- Signed-off-by: Cainã S. G <p-caina.galante@pd.tec.br> Co-authored-by: Cainã S. G <p-caina.galante@pd.tec.br>
1 parent 4a751f9 commit 97fdb1a

3 files changed

Lines changed: 146 additions & 1 deletion

File tree

src/keycloak/keycloak_admin.py

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1632,6 +1632,43 @@ def create_client_authz_role_based_policy(self, client_id, payload, skip_exists=
16321632
data_raw, KeycloakPostError, expected_codes=[201], skip_exists=skip_exists
16331633
)
16341634

1635+
def create_client_authz_policy(self, client_id, payload, skip_exists=False):
1636+
"""Create an authz policy of client.
1637+
1638+
Payload example::
1639+
1640+
payload={
1641+
"name": "Policy-time-based",
1642+
"type": "time",
1643+
"logic": "POSITIVE",
1644+
"decisionStrategy": "UNANIMOUS",
1645+
"config": {
1646+
"hourEnd": "18",
1647+
"hour": "9"
1648+
}
1649+
}
1650+
1651+
:param client_id: id in ClientRepresentation
1652+
https://www.keycloak.org/docs-api/18.0/rest-api/index.html#_clientrepresentation
1653+
:type client_id: str
1654+
:param payload: No Document
1655+
:type payload: dict
1656+
:param skip_exists: Skip creation in case the object exists
1657+
:type skip_exists: bool
1658+
:return: Keycloak server response
1659+
:rtype: bytes
1660+
1661+
"""
1662+
params_path = {"realm-name": self.connection.realm_name, "id": client_id}
1663+
1664+
data_raw = self.connection.raw_post(
1665+
urls_patterns.URL_ADMIN_CLIENT_AUTHZ_POLICIES.format(**params_path),
1666+
data=json.dumps(payload),
1667+
)
1668+
return raise_error_from_response(
1669+
data_raw, KeycloakPostError, expected_codes=[201], skip_exists=skip_exists
1670+
)
1671+
16351672
def create_client_authz_resource_based_permission(self, client_id, payload, skip_exists=False):
16361673
"""Create resource-based permission of client.
16371674
@@ -1671,6 +1708,48 @@ def create_client_authz_resource_based_permission(self, client_id, payload, skip
16711708
data_raw, KeycloakPostError, expected_codes=[201], skip_exists=skip_exists
16721709
)
16731710

1711+
def create_client_authz_scope_based_permission(self, client_id, payload, skip_exists=False):
1712+
"""Create scope-based permission of client.
1713+
1714+
Payload example::
1715+
1716+
payload={
1717+
"type": "resource",
1718+
"logic": "POSITIVE",
1719+
"decisionStrategy": "UNANIMOUS",
1720+
"name": "Permission-Name",
1721+
"resources": [
1722+
resource_id
1723+
],
1724+
"policies": [
1725+
policy_id
1726+
],
1727+
"scopes": [
1728+
scope_id
1729+
]
1730+
1731+
:param client_id: id in ClientRepresentation
1732+
https://www.keycloak.org/docs-api/18.0/rest-api/index.html#_clientrepresentation
1733+
:type client_id: str
1734+
:param payload: PolicyRepresentation
1735+
https://www.keycloak.org/docs-api/18.0/rest-api/index.html#_policyrepresentation
1736+
:type payload: dict
1737+
:param skip_exists: Skip creation in case the object already exists
1738+
:type skip_exists: bool
1739+
:return: Keycloak server response
1740+
:rtype: bytes
1741+
1742+
"""
1743+
params_path = {"realm-name": self.realm_name, "id": client_id}
1744+
1745+
data_raw = self.raw_post(
1746+
urls_patterns.URL_ADMIN_CLIENT_AUTHZ_SCOPE_BASED_PERMISSION.format(**params_path),
1747+
data=json.dumps(payload),
1748+
)
1749+
return raise_error_from_response(
1750+
data_raw, KeycloakPostError, expected_codes=[201], skip_exists=skip_exists
1751+
)
1752+
16741753
def get_client_authz_scopes(self, client_id):
16751754
"""Get scopes from client.
16761755

src/keycloak/urls_patterns.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@
121121
URL_ADMIN_CLIENT_AUTHZ_RESOURCE_BASED_PERMISSION = (
122122
URL_ADMIN_CLIENT_AUTHZ + "/permission/resource?max=-1"
123123
)
124+
URL_ADMIN_CLIENT_AUTHZ_SCOPE_BASED_PERMISSION = URL_ADMIN_CLIENT_AUTHZ + "/permission/scope?max=-1"
124125
URL_ADMIN_CLIENT_AUTHZ_POLICY = URL_ADMIN_CLIENT_AUTHZ + "/policy/{policy-id}"
125126
URL_ADMIN_CLIENT_AUTHZ_POLICY_SCOPES = URL_ADMIN_CLIENT_AUTHZ_POLICY + "/scopes"
126127
URL_ADMIN_CLIENT_AUTHZ_POLICY_RESOURCES = URL_ADMIN_CLIENT_AUTHZ_POLICY + "/resources"
@@ -212,6 +213,5 @@
212213
URL_ADMIN_CLEAR_REALM_CACHE = URL_ADMIN_REALM + "/clear-realm-cache"
213214
URL_ADMIN_CLEAR_USER_CACHE = URL_ADMIN_REALM + "/clear-user-cache"
214215

215-
216216
# UMA URLS
217217
URL_UMA_WELL_KNOWN = URL_WELL_KNOWN_BASE + "/uma2-configuration"

tests/test_keycloak_admin.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -897,6 +897,37 @@ def test_clients(admin: KeycloakAdmin, realm: str):
897897
admin.get_client_authz_policy(client_id=auth_client_id, policy_id=res["id"])
898898
assert err.match("404: b''")
899899

900+
res = admin.create_client_authz_policy(
901+
client_id=auth_client_id,
902+
payload={
903+
"name": "test-authz-policy",
904+
"type": "time",
905+
"config": {"hourEnd": "18", "hour": "9"},
906+
},
907+
)
908+
assert res["name"] == "test-authz-policy", res
909+
910+
with pytest.raises(KeycloakPostError) as err:
911+
admin.create_client_authz_policy(
912+
client_id=auth_client_id,
913+
payload={
914+
"name": "test-authz-policy",
915+
"type": "time",
916+
"config": {"hourEnd": "18", "hour": "9"},
917+
},
918+
)
919+
assert err.match('409: b\'{"error":"Policy with name')
920+
assert admin.create_client_authz_policy(
921+
client_id=auth_client_id,
922+
payload={
923+
"name": "test-authz-policy",
924+
"type": "time",
925+
"config": {"hourEnd": "18", "hour": "9"},
926+
},
927+
skip_exists=True,
928+
) == {"msg": "Already exists"}
929+
assert len(admin.get_client_authz_policies(client_id=auth_client_id)) == 3
930+
900931
# Test authz permissions
901932
res = admin.get_client_authz_permissions(client_id=auth_client_id)
902933
assert len(res) == 1, res
@@ -939,6 +970,7 @@ def test_clients(admin: KeycloakAdmin, realm: str):
939970
client_id=auth_client_id, payload={"name": "test-authz-scope"}
940971
)
941972
assert res["name"] == "test-authz-scope", res
973+
test_scope_id = res["id"]
942974

943975
with pytest.raises(KeycloakPostError) as err:
944976
admin.create_client_authz_scopes(
@@ -953,6 +985,40 @@ def test_clients(admin: KeycloakAdmin, realm: str):
953985
assert len(res) == 1
954986
assert {x["name"] for x in res} == {"test-authz-scope"}
955987

988+
res = admin.create_client_authz_scope_based_permission(
989+
client_id=auth_client_id,
990+
payload={
991+
"name": "test-permission-sb",
992+
"resources": [test_resource_id],
993+
"scopes": [test_scope_id],
994+
},
995+
)
996+
assert res, res
997+
assert res["name"] == "test-permission-sb"
998+
assert res["resources"] == [test_resource_id]
999+
assert res["scopes"] == [test_scope_id]
1000+
1001+
with pytest.raises(KeycloakPostError) as err:
1002+
admin.create_client_authz_scope_based_permission(
1003+
client_id=auth_client_id,
1004+
payload={
1005+
"name": "test-permission-sb",
1006+
"resources": [test_resource_id],
1007+
"scopes": [test_scope_id],
1008+
},
1009+
)
1010+
assert err.match('409: b\'{"error":"Policy with name')
1011+
assert admin.create_client_authz_scope_based_permission(
1012+
client_id=auth_client_id,
1013+
payload={
1014+
"name": "test-permission-sb",
1015+
"resources": [test_resource_id],
1016+
"scopes": [test_scope_id],
1017+
},
1018+
skip_exists=True,
1019+
) == {"msg": "Already exists"}
1020+
assert len(admin.get_client_authz_permissions(client_id=auth_client_id)) == 3
1021+
9561022
# Test service account user
9571023
res = admin.get_client_service_account_user(client_id=auth_client_id)
9581024
assert res["username"] == "service-account-authz-client", res

0 commit comments

Comments
 (0)