Skip to content

Commit

Permalink
feat: Add functions to get/update realm users profile (#634)
Browse files Browse the repository at this point in the history
  • Loading branch information
asyd authored Jan 30, 2025
1 parent bcb1870 commit c5288f4
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 0 deletions.
76 changes: 76 additions & 0 deletions src/keycloak/keycloak_admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -2297,6 +2297,24 @@ def get_client_installation_provider(self, client_id: str, provider_id: str) ->
)
return raise_error_from_response(data_raw, KeycloakGetError, expected_codes=[HTTP_OK])

def get_realm_users_profile(self) -> dict:
"""
Get list of attributes and group for given realm.
Related documentation:
https://www.keycloak.org/docs-api/26.0.0/rest-api/index.html#_get_adminrealmsrealmusersprofile
Return https://www.keycloak.org/docs-api/26.0.0/rest-api/index.html#UPConfig
:returns: UPConfig
"""
params_path = {"realm-name": self.connection.realm_name}

data_raw = self.connection.raw_get(
urls_patterns.URL_ADMIN_REALM_USER_PROFILE.format(**params_path),
)
return raise_error_from_response(data_raw, KeycloakGetError, expected_codes=[HTTP_OK])

def get_realm_roles(self, brief_representation: bool = True, search_text: str = "") -> list:
"""
Get all roles for the realm or client.
Expand Down Expand Up @@ -2911,6 +2929,26 @@ def update_realm_role(self, role_name: str, payload: dict) -> bytes:
expected_codes=[HTTP_NO_CONTENT],
)

def update_realm_users_profile(self, payload: dict) -> dict:
"""
Update realm users profile for the current realm.
:param up_config: List of attributes, groups, unmamagedAttributePolicy
Related documentation:
https://www.keycloak.org/docs-api/26.0.0/rest-api/index.html#UPConfig
"""
params_path = {"realm-name": self.connection.realm_name}
data_raw = self.connection.raw_put(
urls_patterns.URL_ADMIN_REALM_USER_PROFILE.format(**params_path),
data=json.dumps(payload),
)
return raise_error_from_response(
data_raw,
KeycloakPutError,
expected_codes=[HTTP_OK],
)

def delete_realm_role(self, role_name: str) -> bytes:
"""
Delete a role for the realm by name.
Expand Down Expand Up @@ -5490,6 +5528,26 @@ async def a_update_realm(self, realm_name: str, payload: dict) -> dict:
expected_codes=[HTTP_NO_CONTENT],
)

async def a_update_realm_users_profile(self, payload: dict) -> dict:
"""
Update realm users profile for the current realm.
:param up_config: List of attributes, groups, unmamagedAttributePolicy
Related documentation:
https://www.keycloak.org/docs-api/26.0.0/rest-api/index.html#UPConfig
"""
params_path = {"realm-name": self.connection.realm_name}
data_raw = await self.connection.a_raw_put(
urls_patterns.URL_ADMIN_REALM_USER_PROFILE.format(**params_path),
data=json.dumps(payload),
)
return raise_error_from_response(
data_raw,
KeycloakPutError,
expected_codes=[HTTP_OK],
)

async def a_delete_realm(self, realm_name: str) -> bytes:
"""
Delete a realm asynchronously.
Expand Down Expand Up @@ -7391,6 +7449,24 @@ async def a_get_client_installation_provider(self, client_id: str, provider_id:
)
return raise_error_from_response(data_raw, KeycloakGetError, expected_codes=[HTTP_OK])

async def a_get_realm_users_profile(self) -> dict:
"""
Get list of attributes and group for given realm.
Related documentation:
https://www.keycloak.org/docs-api/26.0.0/rest-api/index.html#_get_adminrealmsrealmusersprofile
Return https://www.keycloak.org/docs-api/26.0.0/rest-api/index.html#UPConfig
:returns: UPConfig
"""
params_path = {"realm-name": self.connection.realm_name}

data_raw = await self.connection.a_raw_get(
urls_patterns.URL_ADMIN_REALM_USER_PROFILE.format(**params_path),
)
return raise_error_from_response(data_raw, KeycloakGetError, expected_codes=[HTTP_OK])

async def a_get_realm_roles(
self,
brief_representation: bool = True,
Expand Down
1 change: 1 addition & 0 deletions src/keycloak/urls_patterns.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@
URL_ADMIN_REALM_ROLES = "admin/realms/{realm-name}/roles"
URL_ADMIN_REALM_ROLES_MEMBERS = URL_ADMIN_REALM_ROLES + "/{role-name}/users"
URL_ADMIN_REALM_ROLES_GROUPS = URL_ADMIN_REALM_ROLES + "/{role-name}/groups"
URL_ADMIN_REALM_USER_PROFILE = "admin/realms/{realm-name}/users/profile"
URL_ADMIN_REALMS = "admin/realms"
URL_ADMIN_REALM = "admin/realms/{realm-name}"
URL_ADMIN_IDPS = "admin/realms/{realm-name}/identity-provider/instances"
Expand Down
45 changes: 45 additions & 0 deletions tests/test_keycloak_admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,28 @@ def test_realms(admin: KeycloakAdmin) -> None:
assert "master" in realm_names, realm_names
assert "test" in realm_names, realm_names


if os.environ["KEYCLOAK_DOCKER_IMAGE_TAG"] == "latest" or Version(
os.environ["KEYCLOAK_DOCKER_IMAGE_TAG"],
) >= Version("24"):
# Get users profile, add an attribute
user_profile = admin.get_realm_users_profile()
assert "attributes" in user_profile

new_attribute = {
"name": "surname",
"displayName": "",
"validations": {},
"annotations": {},
"permissions": {"view": [], "edit": ["admin"]},
"multivalued": False,
}
user_profile["attributes"].append(new_attribute)

res = admin.update_realm_users_profile(user_profile)
# Check for new attribute in result
assert "surname" in [x["name"] for x in res["attributes"]]

# Delete the realm
res = admin.delete_realm(realm_name="test")
assert res == {}, res
Expand Down Expand Up @@ -3427,6 +3449,29 @@ async def test_a_realms(admin: KeycloakAdmin) -> None:
assert "master" in realm_names, realm_names
assert "test" in realm_names, realm_names

# Get users profile, add an attribute and check
user_profile = await admin.a_get_realm_users_profile()
assert "attributes" in user_profile


if os.environ["KEYCLOAK_DOCKER_IMAGE_TAG"] == "latest" or Version(
os.environ["KEYCLOAK_DOCKER_IMAGE_TAG"],
) >= Version("24"):
new_attribute = {
"name": "nickname",
"displayName": "",
"validations": {},
"annotations": {},
"permissions": {"view": [], "edit": ["admin"]},
"multivalued": False,
}

user_profile["attributes"].append(new_attribute)

res = await admin.a_update_realm_users_profile(user_profile)
# Check for new attribute in result
assert "nickname" in [x["name"] for x in res["attributes"]]

# Delete the realm
res = await admin.a_delete_realm(realm_name="test")
assert res == {}, res
Expand Down

0 comments on commit c5288f4

Please sign in to comment.