Browse Source

Merge pull request #366 from antoniolucasnobar/master

feat: add client scope-mappings realm roles operations
pull/369/head v2.2.0
Richard Nemeth 2 years ago
committed by GitHub
parent
commit
8ee4018cfb
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 56
      README.md
  2. 42
      src/keycloak/keycloak_admin.py
  3. 1
      src/keycloak/urls_patterns.py
  4. 58
      tests/test_keycloak_admin.py

56
README.md

@ -65,9 +65,9 @@ from keycloak import KeycloakOpenID
# Configure client # Configure client
keycloak_openid = KeycloakOpenID(server_url="http://localhost:8080/auth/", keycloak_openid = KeycloakOpenID(server_url="http://localhost:8080/auth/",
client_id="example_client",
realm_name="example_realm",
client_secret_key="secret")
client_id="example_client",
realm_name="example_realm",
client_secret_key="secret")
# Get WellKnow # Get WellKnow
config_well_known = keycloak_openid.well_known() config_well_known = keycloak_openid.well_known()
@ -110,7 +110,7 @@ rpt = keycloak_openid.entitlement(token['access_token'], "resource_id")
# Instropect RPT # Instropect RPT
token_rpt_info = keycloak_openid.introspect(keycloak_openid.introspect(token['access_token'], rpt=rpt['rpt'], token_rpt_info = keycloak_openid.introspect(keycloak_openid.introspect(token['access_token'], rpt=rpt['rpt'],
token_type_hint="requesting_party_token"))
token_type_hint="requesting_party_token"))
# Introspect Token # Introspect Token
token_info = keycloak_openid.introspect(token['access_token']) token_info = keycloak_openid.introspect(token['access_token'])
@ -153,37 +153,37 @@ keycloak_admin = KeycloakAdmin(server_url="http://localhost:8080/auth/",
# Add user # Add user
new_user = keycloak_admin.create_user({"email": "example@example.com", new_user = keycloak_admin.create_user({"email": "example@example.com",
"username": "example@example.com",
"enabled": True,
"firstName": "Example",
"lastName": "Example"})
"username": "example@example.com",
"enabled": True,
"firstName": "Example",
"lastName": "Example"})
# Add user and raise exception if username already exists # Add user and raise exception if username already exists
# exist_ok currently defaults to True for backwards compatibility reasons # exist_ok currently defaults to True for backwards compatibility reasons
new_user = keycloak_admin.create_user({"email": "example@example.com", new_user = keycloak_admin.create_user({"email": "example@example.com",
"username": "example@example.com",
"enabled": True,
"firstName": "Example",
"lastName": "Example"},
exist_ok=False)
"username": "example@example.com",
"enabled": True,
"firstName": "Example",
"lastName": "Example"},
exist_ok=False)
# Add user and set password # Add user and set password
new_user = keycloak_admin.create_user({"email": "example@example.com", new_user = keycloak_admin.create_user({"email": "example@example.com",
"username": "example@example.com",
"enabled": True,
"firstName": "Example",
"lastName": "Example",
"username": "example@example.com",
"enabled": True,
"firstName": "Example",
"lastName": "Example",
"credentials": [{"value": "secret","type": "password",}]}) "credentials": [{"value": "secret","type": "password",}]})
# Add user and specify a locale # Add user and specify a locale
new_user = keycloak_admin.create_user({"email": "example@example.fr", new_user = keycloak_admin.create_user({"email": "example@example.fr",
"username": "example@example.fr",
"enabled": True,
"firstName": "Example",
"lastName": "Example",
"attributes": {
"locale": ["fr"]
}})
"username": "example@example.fr",
"enabled": True,
"firstName": "Example",
"lastName": "Example",
"attributes": {
"locale": ["fr"]
}})
# User counter # User counter
count_users = keycloak_admin.users_count() count_users = keycloak_admin.users_count()
@ -312,6 +312,14 @@ keycloak_admin.assign_client_role(client_id=client_id, user_id=user_id, role_id=
# Assign realm roles to user # Assign realm roles to user
keycloak_admin.assign_realm_roles(user_id=user_id, roles=realm_roles) keycloak_admin.assign_realm_roles(user_id=user_id, roles=realm_roles)
# Assign realm roles to client's scope
keycloak_admin.assign_realm_roles_to_client_scope(client_id=client_id, roles=realm_roles)
# Get realm roles assigned to client's scope
keycloak_admin.get_realm_roles_of_client_scope(client_id=client_id)
# Remove realm roles assigned to client's scope
keycloak_admin.delete_realm_roles_of_client_scope(client_id=client_id, roles=realm_roles)
# Get all ID Providers # Get all ID Providers
idps = keycloak_admin.get_idps() idps = keycloak_admin.get_idps()

42
src/keycloak/keycloak_admin.py

@ -1597,6 +1597,48 @@ class KeycloakAdmin:
) )
return raise_error_from_response(data_raw, KeycloakGetError) return raise_error_from_response(data_raw, KeycloakGetError)
def assign_realm_roles_to_client_scope(self, client_id, roles):
"""Assign realm roles to a client's scope.
:param client_id: id of client (not client-id)
:param roles: roles list or role (use RoleRepresentation)
:return: Keycloak server response
"""
payload = roles if isinstance(roles, list) else [roles]
params_path = {"realm-name": self.realm_name, "id": client_id}
data_raw = self.raw_post(
urls_patterns.URL_ADMIN_CLIENT_SCOPE_MAPPINGS_REALM_ROLES.format(**params_path),
data=json.dumps(payload),
)
return raise_error_from_response(data_raw, KeycloakPostError, expected_codes=[204])
def delete_realm_roles_of_client_scope(self, client_id, roles):
"""Delete realm roles of a client's scope.
:param client_id: id of client (not client-id)
:param roles: roles list or role (use RoleRepresentation)
:return: Keycloak server response
"""
payload = roles if isinstance(roles, list) else [roles]
params_path = {"realm-name": self.realm_name, "id": client_id}
data_raw = self.raw_delete(
urls_patterns.URL_ADMIN_CLIENT_SCOPE_MAPPINGS_REALM_ROLES.format(**params_path),
data=json.dumps(payload),
)
return raise_error_from_response(data_raw, KeycloakDeleteError, expected_codes=[204])
def get_realm_roles_of_client_scope(self, client_id):
"""Get all realm roles for a client's scope.
:param client_id: id of client (not client-id)
:return: Keycloak server response (array RoleRepresentation)
"""
params_path = {"realm-name": self.realm_name, "id": client_id}
data_raw = self.raw_get(
urls_patterns.URL_ADMIN_CLIENT_SCOPE_MAPPINGS_REALM_ROLES.format(**params_path)
)
return raise_error_from_response(data_raw, KeycloakGetError)
def assign_realm_roles(self, user_id, roles): def assign_realm_roles(self, user_id, roles):
"""Assign realm roles to a user. """Assign realm roles to a user.

1
src/keycloak/urls_patterns.py

@ -91,6 +91,7 @@ URL_ADMIN_CLIENT_ROLES_COMPOSITE_CLIENT_ROLE = URL_ADMIN_CLIENT_ROLE + "/composi
URL_ADMIN_CLIENT_ROLE_MEMBERS = URL_ADMIN_CLIENT + "/roles/{role-name}/users" URL_ADMIN_CLIENT_ROLE_MEMBERS = URL_ADMIN_CLIENT + "/roles/{role-name}/users"
URL_ADMIN_CLIENT_ROLE_GROUPS = URL_ADMIN_CLIENT + "/roles/{role-name}/groups" URL_ADMIN_CLIENT_ROLE_GROUPS = URL_ADMIN_CLIENT + "/roles/{role-name}/groups"
URL_ADMIN_CLIENT_MANAGEMENT_PERMISSIONS = URL_ADMIN_CLIENT + "/management/permissions" URL_ADMIN_CLIENT_MANAGEMENT_PERMISSIONS = URL_ADMIN_CLIENT + "/management/permissions"
URL_ADMIN_CLIENT_SCOPE_MAPPINGS_REALM_ROLES = URL_ADMIN_CLIENT + "/scope-mappings/realm"
URL_ADMIN_CLIENT_AUTHZ_SETTINGS = URL_ADMIN_CLIENT + "/authz/resource-server/settings" URL_ADMIN_CLIENT_AUTHZ_SETTINGS = URL_ADMIN_CLIENT + "/authz/resource-server/settings"
URL_ADMIN_CLIENT_AUTHZ_RESOURCES = URL_ADMIN_CLIENT + "/authz/resource-server/resource?max=-1" URL_ADMIN_CLIENT_AUTHZ_RESOURCES = URL_ADMIN_CLIENT + "/authz/resource-server/resource?max=-1"

58
tests/test_keycloak_admin.py

@ -1030,6 +1030,64 @@ def test_realm_roles(admin: KeycloakAdmin, realm: str):
assert err.match('404: b\'{"error":"Could not find role"}\'') assert err.match('404: b\'{"error":"Could not find role"}\'')
def test_client_scope_realm_roles(admin: KeycloakAdmin, realm: str):
"""Test client realm roles."""
admin.realm_name = realm
# Test get realm roles
roles = admin.get_realm_roles()
assert len(roles) == 3, roles
role_names = [x["name"] for x in roles]
assert "uma_authorization" in role_names, role_names
assert "offline_access" in role_names, role_names
# create realm role for test
role_id = admin.create_realm_role(payload={"name": "test-realm-role"}, skip_exists=True)
assert role_id, role_id
# Test realm role client assignment
client_id = admin.create_client(
payload={"name": "role-testing-client", "clientId": "role-testing-client"}
)
with pytest.raises(KeycloakPostError) as err:
admin.assign_realm_roles_to_client_scope(client_id=client_id, roles=["bad"])
assert err.match('500: b\'{"error":"unknown_error"}\'')
res = admin.assign_realm_roles_to_client_scope(
client_id=client_id,
roles=[
admin.get_realm_role(role_name="offline_access"),
admin.get_realm_role(role_name="test-realm-role"),
],
)
assert res == dict(), res
roles = admin.get_realm_roles_of_client_scope(client_id=client_id)
assert len(roles) == 2
client_role_names = [x["name"] for x in roles]
assert "offline_access" in client_role_names, client_role_names
assert "test-realm-role" in client_role_names, client_role_names
assert "uma_authorization" not in client_role_names, client_role_names
# Test remove realm role of client
with pytest.raises(KeycloakDeleteError) as err:
admin.delete_realm_roles_of_client_scope(client_id=client_id, roles=["bad"])
assert err.match('500: b\'{"error":"unknown_error"}\'')
res = admin.delete_realm_roles_of_client_scope(
client_id=client_id, roles=[admin.get_realm_role(role_name="offline_access")]
)
assert res == dict(), res
roles = admin.get_realm_roles_of_client_scope(client_id=client_id)
assert len(roles) == 1
assert "test-realm-role" in [x["name"] for x in roles]
res = admin.delete_realm_roles_of_client_scope(
client_id=client_id, roles=[admin.get_realm_role(role_name="test-realm-role")]
)
assert res == dict(), res
roles = admin.get_realm_roles_of_client_scope(client_id=client_id)
assert len(roles) == 0
def test_client_roles(admin: KeycloakAdmin, client: str): def test_client_roles(admin: KeycloakAdmin, client: str):
"""Test client roles.""" """Test client roles."""
# Test get client roles # Test get client roles

Loading…
Cancel
Save