Browse Source

fix: correctly pass query params in a_send_update_account and a_send_verify_email (#581)

pull/582/head v4.2.2
Philipp Böhm 5 months ago
committed by GitHub
parent
commit
5f8c0307e8
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 22
      src/keycloak/connection.py
  2. 4
      src/keycloak/keycloak_admin.py
  3. 57
      tests/test_keycloak_admin.py

22
src/keycloak/connection.py

@ -307,7 +307,7 @@ class ConnectionManager(object):
try: try:
return await self.async_s.get( return await self.async_s.get(
urljoin(self.base_url, path), urljoin(self.base_url, path),
params=kwargs,
params=self._filter_query_params(kwargs),
headers=self.headers, headers=self.headers,
timeout=self.timeout, timeout=self.timeout,
) )
@ -331,7 +331,7 @@ class ConnectionManager(object):
return await self.async_s.request( return await self.async_s.request(
method="POST", method="POST",
url=urljoin(self.base_url, path), url=urljoin(self.base_url, path),
params=kwargs,
params=self._filter_query_params(kwargs),
data=data, data=data,
headers=self.headers, headers=self.headers,
timeout=self.timeout, timeout=self.timeout,
@ -355,7 +355,7 @@ class ConnectionManager(object):
try: try:
return await self.async_s.put( return await self.async_s.put(
urljoin(self.base_url, path), urljoin(self.base_url, path),
params=kwargs,
params=self._filter_query_params(kwargs),
data=data, data=data,
headers=self.headers, headers=self.headers,
timeout=self.timeout, timeout=self.timeout,
@ -381,9 +381,23 @@ class ConnectionManager(object):
method="DELETE", method="DELETE",
url=urljoin(self.base_url, path), url=urljoin(self.base_url, path),
data=data or dict(), data=data or dict(),
params=kwargs,
params=self._filter_query_params(kwargs),
headers=self.headers, headers=self.headers,
timeout=self.timeout, timeout=self.timeout,
) )
except Exception as e: except Exception as e:
raise KeycloakConnectionError("Can't connect to server (%s)" % e) raise KeycloakConnectionError("Can't connect to server (%s)" % e)
@staticmethod
def _filter_query_params(query_params):
"""Explicitly filter query params with None values for compatibility.
Httpx and requests differ in the way they handle query params with the value None,
requests does not include params with the value None while httpx includes them as-is.
:param query_params: the query params
:type query_params: dict
:returns: the filtered query params
:rtype: dict
"""
return {k: v for k, v in query_params.items() if v is not None}

4
src/keycloak/keycloak_admin.py

@ -5073,7 +5073,7 @@ class KeycloakAdmin:
data_raw = await self.connection.a_raw_put( data_raw = await self.connection.a_raw_put(
urls_patterns.URL_ADMIN_SEND_UPDATE_ACCOUNT.format(**params_path), urls_patterns.URL_ADMIN_SEND_UPDATE_ACCOUNT.format(**params_path),
data=json.dumps(payload), data=json.dumps(payload),
kwargs=params_query,
**params_query,
) )
return raise_error_from_response(data_raw, KeycloakPutError) return raise_error_from_response(data_raw, KeycloakPutError)
@ -5097,7 +5097,7 @@ class KeycloakAdmin:
data_raw = await self.connection.a_raw_put( data_raw = await self.connection.a_raw_put(
urls_patterns.URL_ADMIN_SEND_VERIFY_EMAIL.format(**params_path), urls_patterns.URL_ADMIN_SEND_VERIFY_EMAIL.format(**params_path),
data={}, data={},
kwargs=params_query,
**params_query,
) )
return raise_error_from_response(data_raw, KeycloakPutError) return raise_error_from_response(data_raw, KeycloakPutError)

57
tests/test_keycloak_admin.py

@ -5,6 +5,7 @@ import os
import uuid import uuid
from inspect import iscoroutinefunction, signature from inspect import iscoroutinefunction, signature
from typing import Tuple from typing import Tuple
from unittest.mock import ANY, patch
import freezegun import freezegun
import pytest import pytest
@ -12,7 +13,12 @@ from dateutil import parser as datetime_parser
from packaging.version import Version from packaging.version import Version
import keycloak import keycloak
from keycloak import KeycloakAdmin, KeycloakOpenID, KeycloakOpenIDConnection
from keycloak import (
KeycloakAdmin,
KeycloakConnectionError,
KeycloakOpenID,
KeycloakOpenIDConnection,
)
from keycloak.connection import ConnectionManager from keycloak.connection import ConnectionManager
from keycloak.exceptions import ( from keycloak.exceptions import (
KeycloakAuthenticationError, KeycloakAuthenticationError,
@ -5170,6 +5176,55 @@ async def test_a_email(admin: KeycloakAdmin, user: str):
assert err.match('500: b\'{"errorMessage":"Failed to send .*"}\'') assert err.match('500: b\'{"errorMessage":"Failed to send .*"}\'')
@pytest.mark.asyncio
async def test_a_email_query_param_handling(admin: KeycloakAdmin, user: str):
"""Test that the optional parameters are correctly transformed into query params.
:param admin: Keycloak Admin client
:type admin: KeycloakAdmin
:param user: Keycloak user
:type user: str
"""
with patch.object(
admin.connection.async_s, "put", side_effect=Exception("An expected error")
) as mock_put, pytest.raises(KeycloakConnectionError):
await admin.a_send_update_account(
user_id=user,
payload=["UPDATE_PASSWORD"],
client_id="update-account-client-id",
redirect_uri="https://example.com",
)
mock_put.assert_awaited_once_with(
ANY,
data='["UPDATE_PASSWORD"]',
params={
"client_id": "update-account-client-id",
"redirect_uri": "https://example.com",
},
headers=ANY,
timeout=60,
)
with patch.object(
admin.connection.async_s, "put", side_effect=Exception("An expected error")
) as mock_put, pytest.raises(KeycloakConnectionError):
await admin.a_send_verify_email(
user_id=user, client_id="verify-client-id", redirect_uri="https://example.com"
)
mock_put.assert_awaited_once_with(
ANY,
data=ANY,
params={
"client_id": "verify-client-id",
"redirect_uri": "https://example.com",
},
headers=ANY,
timeout=60,
)
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_a_get_sessions(admin: KeycloakAdmin): async def test_a_get_sessions(admin: KeycloakAdmin):
"""Test get sessions. """Test get sessions.

Loading…
Cancel
Save