Skip to content

Commit c5288f4

Browse files
authored
feat: Add functions to get/update realm users profile (#634)
1 parent bcb1870 commit c5288f4

3 files changed

Lines changed: 122 additions & 0 deletions

File tree

src/keycloak/keycloak_admin.py

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2297,6 +2297,24 @@ def get_client_installation_provider(self, client_id: str, provider_id: str) ->
22972297
)
22982298
return raise_error_from_response(data_raw, KeycloakGetError, expected_codes=[HTTP_OK])
22992299

2300+
def get_realm_users_profile(self) -> dict:
2301+
"""
2302+
Get list of attributes and group for given realm.
2303+
2304+
Related documentation:
2305+
https://www.keycloak.org/docs-api/26.0.0/rest-api/index.html#_get_adminrealmsrealmusersprofile
2306+
2307+
Return https://www.keycloak.org/docs-api/26.0.0/rest-api/index.html#UPConfig
2308+
:returns: UPConfig
2309+
2310+
"""
2311+
params_path = {"realm-name": self.connection.realm_name}
2312+
2313+
data_raw = self.connection.raw_get(
2314+
urls_patterns.URL_ADMIN_REALM_USER_PROFILE.format(**params_path),
2315+
)
2316+
return raise_error_from_response(data_raw, KeycloakGetError, expected_codes=[HTTP_OK])
2317+
23002318
def get_realm_roles(self, brief_representation: bool = True, search_text: str = "") -> list:
23012319
"""
23022320
Get all roles for the realm or client.
@@ -2911,6 +2929,26 @@ def update_realm_role(self, role_name: str, payload: dict) -> bytes:
29112929
expected_codes=[HTTP_NO_CONTENT],
29122930
)
29132931

2932+
def update_realm_users_profile(self, payload: dict) -> dict:
2933+
"""
2934+
Update realm users profile for the current realm.
2935+
2936+
:param up_config: List of attributes, groups, unmamagedAttributePolicy
2937+
2938+
Related documentation:
2939+
https://www.keycloak.org/docs-api/26.0.0/rest-api/index.html#UPConfig
2940+
"""
2941+
params_path = {"realm-name": self.connection.realm_name}
2942+
data_raw = self.connection.raw_put(
2943+
urls_patterns.URL_ADMIN_REALM_USER_PROFILE.format(**params_path),
2944+
data=json.dumps(payload),
2945+
)
2946+
return raise_error_from_response(
2947+
data_raw,
2948+
KeycloakPutError,
2949+
expected_codes=[HTTP_OK],
2950+
)
2951+
29142952
def delete_realm_role(self, role_name: str) -> bytes:
29152953
"""
29162954
Delete a role for the realm by name.
@@ -5490,6 +5528,26 @@ async def a_update_realm(self, realm_name: str, payload: dict) -> dict:
54905528
expected_codes=[HTTP_NO_CONTENT],
54915529
)
54925530

5531+
async def a_update_realm_users_profile(self, payload: dict) -> dict:
5532+
"""
5533+
Update realm users profile for the current realm.
5534+
5535+
:param up_config: List of attributes, groups, unmamagedAttributePolicy
5536+
5537+
Related documentation:
5538+
https://www.keycloak.org/docs-api/26.0.0/rest-api/index.html#UPConfig
5539+
"""
5540+
params_path = {"realm-name": self.connection.realm_name}
5541+
data_raw = await self.connection.a_raw_put(
5542+
urls_patterns.URL_ADMIN_REALM_USER_PROFILE.format(**params_path),
5543+
data=json.dumps(payload),
5544+
)
5545+
return raise_error_from_response(
5546+
data_raw,
5547+
KeycloakPutError,
5548+
expected_codes=[HTTP_OK],
5549+
)
5550+
54935551
async def a_delete_realm(self, realm_name: str) -> bytes:
54945552
"""
54955553
Delete a realm asynchronously.
@@ -7391,6 +7449,24 @@ async def a_get_client_installation_provider(self, client_id: str, provider_id:
73917449
)
73927450
return raise_error_from_response(data_raw, KeycloakGetError, expected_codes=[HTTP_OK])
73937451

7452+
async def a_get_realm_users_profile(self) -> dict:
7453+
"""
7454+
Get list of attributes and group for given realm.
7455+
7456+
Related documentation:
7457+
https://www.keycloak.org/docs-api/26.0.0/rest-api/index.html#_get_adminrealmsrealmusersprofile
7458+
7459+
Return https://www.keycloak.org/docs-api/26.0.0/rest-api/index.html#UPConfig
7460+
:returns: UPConfig
7461+
7462+
"""
7463+
params_path = {"realm-name": self.connection.realm_name}
7464+
7465+
data_raw = await self.connection.a_raw_get(
7466+
urls_patterns.URL_ADMIN_REALM_USER_PROFILE.format(**params_path),
7467+
)
7468+
return raise_error_from_response(data_raw, KeycloakGetError, expected_codes=[HTTP_OK])
7469+
73947470
async def a_get_realm_roles(
73957471
self,
73967472
brief_representation: bool = True,

src/keycloak/urls_patterns.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@
153153
URL_ADMIN_REALM_ROLES = "admin/realms/{realm-name}/roles"
154154
URL_ADMIN_REALM_ROLES_MEMBERS = URL_ADMIN_REALM_ROLES + "/{role-name}/users"
155155
URL_ADMIN_REALM_ROLES_GROUPS = URL_ADMIN_REALM_ROLES + "/{role-name}/groups"
156+
URL_ADMIN_REALM_USER_PROFILE = "admin/realms/{realm-name}/users/profile"
156157
URL_ADMIN_REALMS = "admin/realms"
157158
URL_ADMIN_REALM = "admin/realms/{realm-name}"
158159
URL_ADMIN_IDPS = "admin/realms/{realm-name}/identity-provider/instances"

tests/test_keycloak_admin.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,28 @@ def test_realms(admin: KeycloakAdmin) -> None:
204204
assert "master" in realm_names, realm_names
205205
assert "test" in realm_names, realm_names
206206

207+
208+
if os.environ["KEYCLOAK_DOCKER_IMAGE_TAG"] == "latest" or Version(
209+
os.environ["KEYCLOAK_DOCKER_IMAGE_TAG"],
210+
) >= Version("24"):
211+
# Get users profile, add an attribute
212+
user_profile = admin.get_realm_users_profile()
213+
assert "attributes" in user_profile
214+
215+
new_attribute = {
216+
"name": "surname",
217+
"displayName": "",
218+
"validations": {},
219+
"annotations": {},
220+
"permissions": {"view": [], "edit": ["admin"]},
221+
"multivalued": False,
222+
}
223+
user_profile["attributes"].append(new_attribute)
224+
225+
res = admin.update_realm_users_profile(user_profile)
226+
# Check for new attribute in result
227+
assert "surname" in [x["name"] for x in res["attributes"]]
228+
207229
# Delete the realm
208230
res = admin.delete_realm(realm_name="test")
209231
assert res == {}, res
@@ -3427,6 +3449,29 @@ async def test_a_realms(admin: KeycloakAdmin) -> None:
34273449
assert "master" in realm_names, realm_names
34283450
assert "test" in realm_names, realm_names
34293451

3452+
# Get users profile, add an attribute and check
3453+
user_profile = await admin.a_get_realm_users_profile()
3454+
assert "attributes" in user_profile
3455+
3456+
3457+
if os.environ["KEYCLOAK_DOCKER_IMAGE_TAG"] == "latest" or Version(
3458+
os.environ["KEYCLOAK_DOCKER_IMAGE_TAG"],
3459+
) >= Version("24"):
3460+
new_attribute = {
3461+
"name": "nickname",
3462+
"displayName": "",
3463+
"validations": {},
3464+
"annotations": {},
3465+
"permissions": {"view": [], "edit": ["admin"]},
3466+
"multivalued": False,
3467+
}
3468+
3469+
user_profile["attributes"].append(new_attribute)
3470+
3471+
res = await admin.a_update_realm_users_profile(user_profile)
3472+
# Check for new attribute in result
3473+
assert "nickname" in [x["name"] for x in res["attributes"]]
3474+
34303475
# Delete the realm
34313476
res = await admin.a_delete_realm(realm_name="test")
34323477
assert res == {}, res

0 commit comments

Comments
 (0)