Browse Source

chore: Merge branch 'master' into grudloffev/master

pull/670/head
Richard Nemeth 4 weeks ago
parent
commit
ca23903b76
No known key found for this signature in database GPG Key ID: 21C39470DF3DEC39
  1. 2
      .github/workflows/daily.yaml
  2. 8
      .github/workflows/lint.yaml
  3. 2
      .github/workflows/publish.yaml
  4. 2
      .readthedocs.yaml
  5. 18
      CHANGELOG.md
  6. 4
      docs/source/modules/admin.rst
  7. 3
      docs/source/modules/openid_client.rst
  8. 2021
      poetry.lock
  9. 5
      pyproject.toml
  10. 35
      src/keycloak/connection.py
  11. 104
      src/keycloak/keycloak_admin.py
  12. 7
      src/keycloak/keycloak_openid.py
  13. 4
      src/keycloak/openid_connection.py
  14. 1
      src/keycloak/urls_patterns.py
  15. 181
      tests/test_keycloak_admin.py
  16. 13
      tests/test_keycloak_openid.py

2
.github/workflows/daily.yaml

@ -10,7 +10,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
keycloak-version: ["22.0", "23.0", "24.0", "25.0", "26.0", "latest"]
env:
KEYCLOAK_DOCKER_IMAGE_TAG: ${{ matrix.keycloak-version }}

8
.github/workflows/lint.yaml

@ -20,7 +20,7 @@ jobs:
- name: Set up Python 3.13
uses: actions/setup-python@v5
with:
python-version: "3.13"
python-version: "3.14"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
@ -40,7 +40,7 @@ jobs:
- name: Set up Python 3.13
uses: actions/setup-python@v5
with:
python-version: "3.13"
python-version: "3.14"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
@ -55,7 +55,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
keycloak-version: ["22.0", "23.0", "24.0", "25.0", "26.0", "latest"]
needs:
- check-commits
@ -91,7 +91,7 @@ jobs:
- name: Set up Python 3.13
uses: actions/setup-python@v5
with:
python-version: "3.13"
python-version: "3.14"
- name: Install dependencies
run: |
python -m pip install --upgrade pip

2
.github/workflows/publish.yaml

@ -15,7 +15,7 @@ jobs:
- name: Set up Python 3.13
uses: actions/setup-python@v5
with:
python-version: "3.13"
python-version: "3.14"
- name: Install dependencies
run: |
python -m pip install --upgrade pip

2
.readthedocs.yaml

@ -6,7 +6,7 @@ sphinx:
build:
os: "ubuntu-24.04"
tools:
python: "3.13"
python: "3.14"
jobs:
post_create_environment:
- python -m pip install poetry

18
CHANGELOG.md

@ -1,3 +1,21 @@
## v5.11.0 (2025-12-27)
### Feat
- implement authz import request (#685)
## v5.10.0 (2025-12-27)
### Feat
- add get_role_composites_by_id method (#680)
## v5.9.0 (2025-12-27)
### Feat
- add pool_maxsize parameter to connection managers (#651)
## v5.8.1 (2025-08-19)
### Fix

4
docs/source/modules/admin.rst

@ -15,7 +15,8 @@ Configure admin client
username='example-admin',
password='secret',
realm_name="master",
user_realm_name="only_if_other_realm_than_master")
user_realm_name="only_if_other_realm_than_master",
pool_maxsize=20)
Configure admin client with connection
@ -34,6 +35,7 @@ Configure admin client with connection
user_realm_name="only_if_other_realm_than_master",
client_id="my_client",
client_secret_key="client-secret",
pool_maxsize=25,
verify=True)
keycloak_admin = KeycloakAdmin(connection=keycloak_connection)

3
docs/source/modules/openid_client.rst

@ -16,7 +16,8 @@ Configure client OpenID
keycloak_openid = KeycloakOpenID(server_url="http://localhost:8080/",
client_id="example_client",
realm_name="example_realm",
client_secret_key="secret")
client_secret_key="secret",
pool_maxsize=15) # Example: Set connection pool size
Get .well_know

2021
poetry.lock
File diff suppressed because it is too large
View File

5
pyproject.toml

@ -65,10 +65,7 @@ twine = ">=4.0.2"
freezegun = ">=1.2.2"
docutils = "<0.21"
ruff = ">=0.9.3"
[[tool.poetry.source]]
name = "PyPI"
priority = "primary"
backports-asyncio-runner = { "version" = ">=1.2.0", "python" = ">=3.9,<3.11" }
[build-system]
requires = ["poetry-core>=1.0.0"]

35
src/keycloak/connection.py

@ -59,6 +59,8 @@ class ConnectionManager:
:type cert: Union[str,Tuple[str,str]]
:param max_retries: The total number of times to retry HTTP requests.
:type max_retries: int
:param pool_maxsize: The maximum number of connections to save in the pool.
:type pool_maxsize: int
"""
def __init__(
@ -70,6 +72,7 @@ class ConnectionManager:
proxies: dict | None = None,
cert: str | tuple | None = None,
max_retries: int = 1,
pool_maxsize: int | None = None,
) -> None:
"""
Init method.
@ -91,19 +94,25 @@ class ConnectionManager:
:type cert: Union[str,Tuple[str,str]]
:param max_retries: The total number of times to retry HTTP requests.
:type max_retries: int
:param pool_maxsize: The maximum number of connections to save in the pool.
:type pool_maxsize: int
"""
self.base_url = base_url
self.headers = headers
self.timeout = timeout
self.verify = verify
self.cert = cert
self.pool_maxsize = pool_maxsize
self._s = requests.Session()
self._s.auth = lambda x: x # don't let requests add auth headers
# retry once to reset connection with Keycloak after tomcat's ConnectionTimeout
# see https://github.com/marcospereirampj/python-keycloak/issues/36
for protocol in ("https://", "http://"):
adapter = HTTPAdapter(max_retries=max_retries)
adapter_kwargs = {"max_retries": max_retries}
if pool_maxsize is not None:
adapter_kwargs["pool_maxsize"] = pool_maxsize
adapter = HTTPAdapter(**adapter_kwargs)
# adds POST to retry whitelist
allowed_methods = set(adapter.max_retries.allowed_methods)
allowed_methods.add("POST")
@ -114,7 +123,15 @@ class ConnectionManager:
if proxies:
self._s.proxies.update(proxies)
self.async_s = httpx.AsyncClient(verify=verify, mounts=proxies, cert=cert)
self.async_s = httpx.AsyncClient(
verify=verify,
mounts=proxies,
cert=cert,
limits=httpx.Limits(
max_connections=100 if pool_maxsize is None else pool_maxsize,
max_keepalive_connections=20,
),
)
self.async_s.auth = None # don't let requests add auth headers
self.async_s.transport = httpx.AsyncHTTPTransport(retries=1)
@ -184,6 +201,20 @@ class ConnectionManager:
def cert(self, value: str | tuple) -> None:
self._cert = value
@property
def pool_maxsize(self) -> int | None:
"""
Return the maximum number of connections to save in the pool.
:returns: Pool maxsize
:rtype: int or None
"""
return self._pool_maxsize
@pool_maxsize.setter
def pool_maxsize(self, value: int | None) -> None:
self._pool_maxsize = value
@property
def headers(self) -> dict:
"""

104
src/keycloak/keycloak_admin.py

@ -88,6 +88,8 @@ class KeycloakAdmin:
:type max_retries: int
:param connection: A KeycloakOpenIDConnection as an alternative to individual params.
:type connection: KeycloakOpenIDConnection
:param pool_maxsize: The maximum number of connections to save in the pool.
:type pool_maxsize: int
"""
PAGE_SIZE = 100
@ -110,6 +112,7 @@ class KeycloakAdmin:
cert: str | tuple | None = None,
max_retries: int = 1,
connection: KeycloakOpenIDConnection | None = None,
pool_maxsize: int | None = None,
) -> None:
"""
Init method.
@ -149,6 +152,8 @@ class KeycloakAdmin:
:type max_retries: int
:param connection: An OpenID Connection as an alternative to individual params.
:type connection: KeycloakOpenIDConnection
:param pool_maxsize: The maximum number of connections to save in the pool.
:type pool_maxsize: int
"""
self.connection = connection or KeycloakOpenIDConnection(
server_url=server_url,
@ -166,6 +171,7 @@ class KeycloakAdmin:
timeout=timeout,
cert=cert,
max_retries=max_retries,
pool_maxsize=pool_maxsize,
)
@property
@ -1671,7 +1677,7 @@ class KeycloakAdmin:
def send_update_account(
self,
user_id: str,
payload: dict,
payload: list,
client_id: str | None = None,
lifespan: int | None = None,
redirect_uri: str | None = None,
@ -2210,6 +2216,33 @@ class KeycloakAdmin:
)
return raise_error_from_response(data_raw, KeycloakGetError)
def import_client_authz_config(self, client_id: str, payload: dict) -> dict:
"""
Import client authorization configuration.
ResourceServerRepresentation
https://www.keycloak.org/docs-api/latest/rest-api/index.html#ResourceServerRepresentation
:param client_id: id in ClientRepresentation
https://www.keycloak.org/docs-api/24.0.2/rest-api/index.html#_clientrepresentation
:type client_id: str
:param payload: ResourceServerRepresentation
:type payload: dict
:return: None
"""
params_path = {"realm-name": self.connection.realm_name, "id": client_id}
data_raw = self.connection.raw_post(
urls_patterns.URL_ADMIN_CLIENT_AUTHZ_IMPORT.format(**params_path),
data=json.dumps(payload),
)
return raise_error_from_response(
data_raw,
KeycloakPostError,
expected_codes=[HTTP_NO_CONTENT],
)
def create_client_authz_resource(
self,
client_id: str,
@ -3475,6 +3508,26 @@ class KeycloakAdmin:
expected_codes=[HTTP_NO_CONTENT],
)
def get_role_composites_by_id(self, role_id: str, query: dict | None = None) -> list:
"""
Get all composite roles by role id.
:param role_id: id of role
:type role_id: str
:param query: Query parameters (optional). Supported keys: 'first', 'max', 'search'
:type query: dict
:return: Keycloak server response (RoleRepresentation)
:rtype: list
"""
query = query or {}
params_path = {"realm-name": self.connection.realm_name, "role-id": role_id}
url = urls_patterns.URL_ADMIN_REALM_ROLE_COMPOSITES.format(**params_path)
if "first" in query or "max" in query:
return self.__fetch_paginated(url, query)
return self.__fetch_all(url, query)
def create_realm_role(self, payload: dict, skip_exists: bool = False) -> str:
"""
Create a new role for the realm or client.
@ -6955,7 +7008,7 @@ class KeycloakAdmin:
async def a_send_update_account(
self,
user_id: str,
payload: dict,
payload: list,
client_id: str | None = None,
lifespan: int | None = None,
redirect_uri: str | None = None,
@ -7501,6 +7554,33 @@ class KeycloakAdmin:
)
return raise_error_from_response(data_raw, KeycloakGetError)
async def a_import_client_authz_config(self, client_id: str, payload: dict) -> dict:
"""
Import client authorization configuration asynchronously.
ResourceServerRepresentation
https://www.keycloak.org/docs-api/latest/rest-api/index.html#ResourceServerRepresentation
:param client_id: id in ClientRepresentation
https://www.keycloak.org/docs-api/24.0.2/rest-api/index.html#_clientrepresentation
:type client_id: str
:param payload: ResourceServerRepresentation
:type payload: dict
:return: None
"""
params_path = {"realm-name": self.connection.realm_name, "id": client_id}
data_raw = await self.connection.a_raw_post(
urls_patterns.URL_ADMIN_CLIENT_AUTHZ_IMPORT.format(**params_path),
data=json.dumps(payload),
)
return raise_error_from_response(
data_raw,
KeycloakPostError,
expected_codes=[HTTP_NO_CONTENT],
)
async def a_create_client_authz_resource(
self,
client_id: str,
@ -8773,6 +8853,26 @@ class KeycloakAdmin:
expected_codes=[HTTP_NO_CONTENT],
)
async def a_get_role_composites_by_id(self, role_id: str, query: dict | None = None) -> list:
"""
Get all composite roles by role id asynchronously.
:param role_id: id of role
:type role_id: str
:param query: Query parameters (optional). Supported keys: 'first', 'max', 'search'
:type query: dict
:return: Keycloak server response (RoleRepresentation)
:rtype: list
"""
query = query or {}
params_path = {"realm-name": self.connection.realm_name, "role-id": role_id}
url = urls_patterns.URL_ADMIN_REALM_ROLE_COMPOSITES.format(**params_path)
if "first" in query or "max" in query:
return await self.a___fetch_paginated(url, query)
return await self.a___fetch_all(url, query)
async def a_create_realm_role(self, payload: dict, skip_exists: bool = False) -> str:
"""
Create a new role for the realm or client asynchronously.

7
src/keycloak/keycloak_openid.py

@ -87,7 +87,8 @@ class KeycloakOpenID:
Either a path to an SSL certificate file, or two-tuple of
(certificate file, key file).
:param max_retries: The total number of times to retry HTTP requests.
:type max_retries: int
:param pool_maxsize: The maximum number of connections to save in the pool.
:type pool_maxsize: int
"""
def __init__(
@ -102,6 +103,7 @@ class KeycloakOpenID:
timeout: int = 60,
cert: str | tuple | None = None,
max_retries: int = 1,
pool_maxsize: int | None = None,
) -> None:
"""
Init method.
@ -129,6 +131,8 @@ class KeycloakOpenID:
:type cert: Union[str,Tuple[str,str]]
:param max_retries: The total number of times to retry HTTP requests.
:type max_retries: int
:param pool_maxsize: The maximum number of connections to save in the pool.
:type pool_maxsize: int
"""
self.client_id = client_id
self.client_secret_key = client_secret_key
@ -142,6 +146,7 @@ class KeycloakOpenID:
proxies=proxies,
cert=cert,
max_retries=max_retries,
pool_maxsize=pool_maxsize,
)
self.authorization = Authorization()

4
src/keycloak/openid_connection.py

@ -82,6 +82,7 @@ class KeycloakOpenIDConnection(ConnectionManager):
timeout: int | None = 60,
cert: str | tuple | None = None,
max_retries: int = 1,
pool_maxsize: int | None = None,
) -> None:
"""
Init method.
@ -120,6 +121,8 @@ class KeycloakOpenIDConnection(ConnectionManager):
:type cert: Union[str,Tuple[str,str]]
:param max_retries: The total number of times to retry HTTP requests.
:type max_retries: int
:param pool_maxsize: The maximum number of connections to save in the pool.
:type pool_maxsize: int
"""
# token is renewed when it hits 90% of its lifetime. This is to account for any possible
# clock skew.
@ -154,6 +157,7 @@ class KeycloakOpenIDConnection(ConnectionManager):
verify=self.verify,
cert=cert,
max_retries=max_retries,
pool_maxsize=pool_maxsize,
)
@property

1
src/keycloak/urls_patterns.py

@ -115,6 +115,7 @@ URL_ADMIN_CLIENT_DEFAULT_CLIENT_SCOPE = (
URL_ADMIN_CLIENT_AUTHZ = URL_ADMIN_CLIENT + "/authz/resource-server"
URL_ADMIN_CLIENT_AUTHZ_SETTINGS = URL_ADMIN_CLIENT_AUTHZ + "/settings"
URL_ADMIN_CLIENT_AUTHZ_IMPORT = URL_ADMIN_CLIENT_AUTHZ + "/import"
URL_ADMIN_CLIENT_AUTHZ_RESOURCE = URL_ADMIN_CLIENT_AUTHZ + "/resource/{resource-id}"
URL_ADMIN_CLIENT_AUTHZ_RESOURCES = URL_ADMIN_CLIENT_AUTHZ + "/resource"
URL_ADMIN_CLIENT_AUTHZ_SCOPES = URL_ADMIN_CLIENT_AUTHZ + "/scope"

181
tests/test_keycloak_admin.py

@ -57,6 +57,7 @@ def test_keycloak_admin_init(env: KeycloakTestEnv) -> None:
server_url=f"http://{env.keycloak_host}:{env.keycloak_port}",
username=env.keycloak_admin,
password=env.keycloak_admin_password,
pool_maxsize=5,
)
assert admin.connection.server_url == f"http://{env.keycloak_host}:{env.keycloak_port}", (
admin.connection.server_url
@ -72,6 +73,7 @@ def test_keycloak_admin_init(env: KeycloakTestEnv) -> None:
assert admin.connection.token is None, admin.connection.token
assert admin.connection.user_realm_name is None, admin.connection.user_realm_name
assert admin.connection.custom_headers is None, admin.connection.custom_headers
assert admin.connection.pool_maxsize == 5, admin.connection.pool_maxsize
admin = KeycloakAdmin(
server_url=f"http://{env.keycloak_host}:{env.keycloak_port}",
@ -1432,6 +1434,41 @@ def test_clients(admin: KeycloakAdmin, realm: str) -> None:
UNKOWN_ERROR_REGEX,
)
# Test import authz
authz_config = admin.get_client_authz_settings(client_id=auth_client_id)
authz_config["resources"] = [{"name": "test-import-resource"}]
authz_config["policies"] = [
{
"name": "test-import-policy",
"type": "time",
"config": {"hourEnd": "18", "hour": "9"},
}
]
admin.import_client_authz_config(client_id=auth_client_id, payload=authz_config)
exported = admin.get_client_authz_settings(client_id=auth_client_id)
assert (
len(
[
resource
for resource in exported["resources"]
if resource["name"] == "test-import-resource"
]
)
== 1
)
assert (
len(
[
resource
for resource in exported["policies"]
if resource["name"] == "test-import-policy"
]
)
== 1
)
# Test delete client
res = admin.delete_client(client_id=auth_client_id)
assert res == {}, res
@ -2620,7 +2657,7 @@ def test_auth_flows(admin: KeycloakAdmin, realm: str) -> None:
# Test flow executions
res = admin.get_authentication_flow_executions(flow_alias="browser")
assert len(res) in [8, 12, 14], res
assert len(res) in [8, 12, 14, 15], res
with pytest.raises(KeycloakGetError) as err:
admin.get_authentication_flow_executions(flow_alias="bad")
@ -2763,7 +2800,7 @@ def test_authentication_configs(admin: KeycloakAdmin, realm: str) -> None:
# Test list of auth providers
res = admin.get_authenticator_providers()
assert len(res) <= 41
assert len(res) <= 42
res = admin.get_authenticator_provider_config_description(provider_id="auth-cookie")
assert res == {
@ -3285,6 +3322,48 @@ def test_get_role_client_level_children(
assert child["id"] in [x["id"] for x in res]
def test_get_role_composites_by_id(
admin: KeycloakAdmin,
realm: str,
client: str,
composite_client_role: str,
client_role: str,
) -> None:
"""
Test get role's children by role ID.
:param admin: Keycloak Admin client
:type admin: KeycloakAdmin
:param realm: Keycloak realm
:type realm: str
:param client: Keycloak client
:type client: str
:param composite_client_role: Composite client role
:type composite_client_role: str
:param client_role: Client role
:type client_role: str
"""
admin.change_current_realm(realm)
parent_role = admin.get_client_role(client, composite_client_role)
child_role = admin.get_client_role(client, client_role)
composites = admin.get_role_composites_by_id(parent_role["id"])
assert len(composites) > 0
assert child_role["id"] in [x["id"] for x in composites]
composites_paginated = admin.get_role_composites_by_id(
parent_role["id"], query={"first": 0, "max": 10}
)
assert len(composites_paginated) > 0
assert child_role["id"] in [x["id"] for x in composites_paginated]
composites_searched = admin.get_role_composites_by_id(
parent_role["id"], query={"search": client_role[:3]}
)
assert len(composites_searched) > 0
def test_upload_certificate(
admin: KeycloakAdmin,
realm: str,
@ -3326,7 +3405,7 @@ def test_get_bruteforce_status_for_user(
:param realm: Keycloak realm
:type realm: str
"""
oid, username, password = oid_with_credentials
oid, username, _ = oid_with_credentials
admin.change_current_realm(realm)
# Turn on bruteforce protection
@ -3364,7 +3443,7 @@ def test_clear_bruteforce_attempts_for_user(
:param realm: Keycloak realm
:type realm: str
"""
oid, username, password = oid_with_credentials
oid, username, _ = oid_with_credentials
admin.change_current_realm(realm)
# Turn on bruteforce protection
@ -3405,7 +3484,7 @@ def test_clear_bruteforce_attempts_for_all_users(
:param realm: Keycloak realm
:type realm: str
"""
oid, username, password = oid_with_credentials
oid, username, _ = oid_with_credentials
admin.change_current_realm(realm)
# Turn on bruteforce protection
@ -3566,7 +3645,7 @@ def test_initial_access_token(
assert res["count"] == 2
assert res["expiration"] == 3
oid, username, password = oid_with_credentials
oid, _, _ = oid_with_credentials
client = str(uuid.uuid4())
secret = str(uuid.uuid4())
@ -4998,6 +5077,41 @@ async def test_a_clients(admin: KeycloakAdmin, realm: str) -> None:
UNKOWN_ERROR_REGEX,
)
# Test async import authz
authz_config = await admin.a_get_client_authz_settings(client_id=auth_client_id)
authz_config["resources"] = [{"name": "test-import-resource"}]
authz_config["policies"] = [
{
"name": "test-import-policy",
"type": "time",
"config": {"hourEnd": "18", "hour": "9"},
}
]
await admin.a_import_client_authz_config(client_id=auth_client_id, payload=authz_config)
exported = await admin.a_get_client_authz_settings(client_id=auth_client_id)
assert (
len(
[
resource
for resource in exported["resources"]
if resource["name"] == "test-import-resource"
]
)
== 1
)
assert (
len(
[
resource
for resource in exported["policies"]
if resource["name"] == "test-import-policy"
]
)
== 1
)
# Test delete client
res = await admin.a_delete_client(client_id=auth_client_id)
assert res == {}, res
@ -6326,7 +6440,7 @@ async def test_a_auth_flows(admin: KeycloakAdmin, realm: str) -> None:
# Test flow executions
res = await admin.a_get_authentication_flow_executions(flow_alias="browser")
assert len(res) in [8, 12, 14], res
assert len(res) in [8, 12, 14, 15], res
with pytest.raises(KeycloakGetError) as err:
await admin.a_get_authentication_flow_executions(flow_alias="bad")
@ -6474,7 +6588,7 @@ async def test_a_authentication_configs(admin: KeycloakAdmin, realm: str) -> Non
# Test list of auth providers
res = await admin.a_get_authenticator_providers()
assert len(res) <= 41
assert len(res) <= 42
res = await admin.a_get_authenticator_provider_config_description(provider_id="auth-cookie")
assert res == {
@ -7017,6 +7131,49 @@ async def test_a_get_role_client_level_children(
assert child["id"] in [x["id"] for x in res]
@pytest.mark.asyncio
async def test_a_get_role_composites_by_id(
admin: KeycloakAdmin,
realm: str,
client: str,
composite_client_role: str,
client_role: str,
) -> None:
"""
Test get all composite roles by role id asynchronously.
:param admin: Keycloak Admin client
:type admin: KeycloakAdmin
:param realm: Keycloak realm
:type realm: str
:param client: Keycloak client
:type client: str
:param composite_client_role: Composite client role
:type composite_client_role: str
:param client_role: Client role
:type client_role: str
"""
await admin.a_change_current_realm(realm)
parent_role = await admin.a_get_client_role(client, composite_client_role)
child_role = await admin.a_get_client_role(client, client_role)
composites = await admin.a_get_role_composites_by_id(parent_role["id"])
assert len(composites) > 0
assert child_role["id"] in [x["id"] for x in composites]
composites_paginated = await admin.a_get_role_composites_by_id(
parent_role["id"], query={"first": 0, "max": 10}
)
assert len(composites_paginated) > 0
assert child_role["id"] in [x["id"] for x in composites_paginated]
composites_searched = await admin.a_get_role_composites_by_id(
parent_role["id"], query={"search": client_role[:3]}
)
assert len(composites_searched) > 0
@pytest.mark.asyncio
async def test_a_upload_certificate(
admin: KeycloakAdmin,
@ -7060,7 +7217,7 @@ async def test_a_get_bruteforce_status_for_user(
:param realm: Keycloak realm
:type realm: str
"""
oid, username, password = oid_with_credentials
oid, username, _ = oid_with_credentials
await admin.a_change_current_realm(realm)
# Turn on bruteforce protection
@ -7099,7 +7256,7 @@ async def test_a_clear_bruteforce_attempts_for_user(
:param realm: Keycloak realm
:type realm: str
"""
oid, username, password = oid_with_credentials
oid, username, _ = oid_with_credentials
await admin.a_change_current_realm(realm)
# Turn on bruteforce protection
@ -7141,7 +7298,7 @@ async def test_a_clear_bruteforce_attempts_for_all_users(
:param realm: Keycloak realm
:type realm: str
"""
oid, username, password = oid_with_credentials
oid, username, _ = oid_with_credentials
await admin.a_change_current_realm(realm)
# Turn on bruteforce protection
@ -7315,7 +7472,7 @@ async def test_a_initial_access_token(
assert res["count"] == 2
assert res["expiration"] == 3
oid, username, password = oid_with_credentials
oid, _, _ = oid_with_credentials
client = str(uuid.uuid4())
secret = str(uuid.uuid4())

13
tests/test_keycloak_openid.py

@ -35,6 +35,7 @@ def test_keycloak_openid_init(env: KeycloakTestEnv) -> None:
server_url=f"http://{env.keycloak_host}:{env.keycloak_port}",
realm_name="master",
client_id="admin-cli",
pool_maxsize=5,
)
assert oid.client_id == "admin-cli"
@ -42,6 +43,14 @@ def test_keycloak_openid_init(env: KeycloakTestEnv) -> None:
assert oid.realm_name == "master"
assert isinstance(oid.connection, ConnectionManager)
assert isinstance(oid.authorization, Authorization)
assert oid.connection.pool_maxsize == 5
oid_default = KeycloakOpenID(
server_url=f"http://{env.keycloak_host}:{env.keycloak_port}",
realm_name="master",
client_id="admin-cli",
)
assert oid_default.connection.pool_maxsize is None
def test_well_known(oid: KeycloakOpenID) -> None:
@ -383,7 +392,7 @@ def test_load_authorization_config(
server with client credentials
:type oid_with_credentials_authz: Tuple[KeycloakOpenID, str, str]
"""
oid, username, password = oid_with_credentials_authz
oid, _, _ = oid_with_credentials_authz
oid.load_authorization_config(path="tests/data/authz_settings.json")
assert "test-authz-rb-policy" in oid.authorization.policies
@ -927,7 +936,7 @@ async def test_a_load_authorization_config(
server with client credentials
:type oid_with_credentials_authz: Tuple[KeycloakOpenID, str, str]
"""
oid, username, password = oid_with_credentials_authz
oid, _, _ = oid_with_credentials_authz
await oid.a_load_authorization_config(path="tests/data/authz_settings.json")
assert "test-authz-rb-policy" in oid.authorization.policies

Loading…
Cancel
Save