Browse Source

feat: Added initial access token support

pull/424/head
Martyn Klassen 1 year ago
parent
commit
ad4bb5c3a3
  1. 18
      src/keycloak/keycloak_admin.py
  2. 22
      src/keycloak/keycloak_openid.py
  3. 4
      src/keycloak/urls_patterns.py
  4. 36
      tests/test_keycloak_admin.py

18
src/keycloak/keycloak_admin.py

@ -1848,6 +1848,24 @@ class KeycloakAdmin:
)
return raise_error_from_response(data_raw, KeycloakDeleteError)
def create_initial_access_token(self, count: int = 1, expiration: int = 1):
"""Create an initial access token.
:param count: Number of clients that can be registered
:type count: int
:param expiration: Days until expireation
:type expiration: int
:return: initial access token
:rtype: str
"""
payload = {"count": count, "expiration": expiration}
params_path = {"realm-name": self.realm_name}
data_raw = self.connection.raw_post(
urls_patterns.URL_ADMIN_CLIENT_INITIAL_ACCESS.format(**params_path),
data=json.dumps(payload),
)
return raise_error_from_response(data_raw, KeycloakPostError, expected_codes=[200])
def create_client(self, payload, skip_exists=False):
"""Create a client.

22
src/keycloak/keycloak_openid.py

@ -47,6 +47,7 @@ from .uma_permissions import AuthStatus, build_permission_param
from .urls_patterns import (
URL_AUTH,
URL_CERTS,
URL_CLIENT_REGISTRATION,
URL_ENTITLEMENT,
URL_INTROSPECT,
URL_LOGOUT,
@ -679,3 +680,24 @@ class KeycloakOpenID:
return AuthStatus(
is_logged_in=True, is_authorized=len(needed) == 0, missing_permissions=needed
)
def register_client(self, token: str, payload: dict):
"""Create a client.
ClientRepresentation:
https://www.keycloak.org/docs-api/18.0/rest-api/index.html#_clientrepresentation
:param token: Initial access token
:type token: str
:param payload: ClientRepresentation
:type payload: dict
:return: Client Representation
:rtype: dict
"""
params_path = {"realm-name": self.realm_name}
self.connection.add_param_headers("Authorization", "Bearer " + token)
self.connection.add_param_headers("Content-Type", "application/json")
data_raw = self.connection.raw_post(
URL_CLIENT_REGISTRATION.format(**params_path), data=json.dumps(payload)
)
return raise_error_from_response(data_raw, KeycloakPostError)

4
src/keycloak/urls_patterns.py

@ -38,6 +38,9 @@ URL_AUTH = (
"&scope={scope}&state={state}"
)
URL_CLIENT_REGISTRATION = URL_REALM + "/clients-registrations/default"
URL_CLIENT_UPDATE = URL_CLIENT_REGISTRATION + "/{client-id}"
# ADMIN URLS
URL_ADMIN_USERS = "admin/realms/{realm-name}/users"
URL_ADMIN_USERS_COUNT = "admin/realms/{realm-name}/users/count"
@ -83,6 +86,7 @@ URL_ADMIN_GROUP_CHILD = "admin/realms/{realm-name}/groups/{id}/children"
URL_ADMIN_GROUP_PERMISSIONS = "admin/realms/{realm-name}/groups/{id}/management/permissions"
URL_ADMIN_GROUP_MEMBERS = "admin/realms/{realm-name}/groups/{id}/members"
URL_ADMIN_CLIENT_INITIAL_ACCESS = "admin/realms/{realm-name}/clients-initial-access"
URL_ADMIN_CLIENTS = "admin/realms/{realm-name}/clients"
URL_ADMIN_CLIENT = URL_ADMIN_CLIENTS + "/{id}"
URL_ADMIN_CLIENT_ALL_SESSIONS = URL_ADMIN_CLIENT + "/user-sessions"

36
tests/test_keycloak_admin.py

@ -1,6 +1,7 @@
"""Test the keycloak admin object."""
import copy
import uuid
from typing import Tuple
import freezegun
@ -2588,3 +2589,38 @@ def test_clear_user_cache(realm: str, admin: KeycloakAdmin) -> None:
admin.realm_name = realm
res = admin.clear_user_cache()
assert res == {}
def test_initial_access_token(
admin: KeycloakAdmin, oid_with_credentials: Tuple[KeycloakOpenID, str, str]
) -> None:
"""Test initial access token and client creation.
:param admin: Keycloak admin
:type admin: KeycloakAdmin
:param oid_with_credentials: Keycloak OpenID client with pre-configured user credentials
:type oid_with_credentials: Tuple[KeycloakOpenID, str, str]
"""
res = admin.create_initial_access_token(2, 3)
assert "token" in res
assert res["count"] == 2
assert res["expiration"] == 3
oid, username, password = oid_with_credentials
client = str(uuid.uuid4())
secret = str(uuid.uuid4())
res = oid.register_client(
token=res["token"],
payload={
"name": client,
"clientId": client,
"enabled": True,
"publicClient": False,
"protocol": "openid-connect",
"secret": secret,
"clientAuthenticatorType": "client-secret",
},
)
assert res["clientId"] == client
Loading…
Cancel
Save