You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

6517 lines
233 KiB

1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
11 months ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
  1. """Test the keycloak admin object."""
  2. import copy
  3. import os
  4. import uuid
  5. from inspect import iscoroutinefunction, signature
  6. from typing import Tuple
  7. from unittest.mock import ANY, patch
  8. import freezegun
  9. import pytest
  10. from dateutil import parser as datetime_parser
  11. from packaging.version import Version
  12. import keycloak
  13. from keycloak import (
  14. KeycloakAdmin,
  15. KeycloakConnectionError,
  16. KeycloakOpenID,
  17. KeycloakOpenIDConnection,
  18. )
  19. from keycloak.connection import ConnectionManager
  20. from keycloak.exceptions import (
  21. KeycloakAuthenticationError,
  22. KeycloakDeleteError,
  23. KeycloakGetError,
  24. KeycloakPostError,
  25. KeycloakPutError,
  26. )
  27. CLIENT_NOT_FOUND_REGEX = '404: b\'{"error":"Client not found".*}\''
  28. CLIENT_SCOPE_NOT_FOUND_REGEX = '404: b\'{"error":"Client scope not found".*}\''
  29. COULD_NOT_FIND_ROLE_REGEX = '404: b\'{"error":"Could not find role".*}\''
  30. COULD_NOT_FIND_ROLE_WITH_ID_REGEX = '404: b\'{"error":"Could not find role with id".*}\''
  31. HTTP_404_REGEX = '404: b\'{"error":"HTTP 404 Not Found".*}\''
  32. ILLEGAL_EXECUTION_REGEX = '404: b\'{"error":"Illegal execution".*}\''
  33. NO_CLIENT_SCOPE_REGEX = '404: b\'{"error":"Could not find client scope".*}\''
  34. UNKOWN_ERROR_REGEX = 'b\'{"error":"unknown_error".*}\''
  35. USER_NOT_FOUND_REGEX = '404: b\'{"error":"User not found".*}\''
  36. def test_keycloak_version():
  37. """Test version."""
  38. assert keycloak.__version__, keycloak.__version__
  39. def test_keycloak_admin_init(env):
  40. """Test keycloak admin init.
  41. :param env: Environment fixture
  42. :type env: KeycloakTestEnv
  43. """
  44. admin = KeycloakAdmin(
  45. server_url=f"http://{env.KEYCLOAK_HOST}:{env.KEYCLOAK_PORT}",
  46. username=env.KEYCLOAK_ADMIN,
  47. password=env.KEYCLOAK_ADMIN_PASSWORD,
  48. )
  49. assert admin.connection.server_url == f"http://{env.KEYCLOAK_HOST}:{env.KEYCLOAK_PORT}", (
  50. admin.connection.server_url
  51. )
  52. assert admin.connection.realm_name == "master", admin.connection.realm_name
  53. assert isinstance(admin.connection, ConnectionManager), type(admin.connection)
  54. assert admin.connection.client_id == "admin-cli", admin.connection.client_id
  55. assert admin.connection.client_secret_key is None, admin.connection.client_secret_key
  56. assert admin.connection.verify, admin.connection.verify
  57. assert admin.connection.username == env.KEYCLOAK_ADMIN, admin.connection.username
  58. assert admin.connection.password == env.KEYCLOAK_ADMIN_PASSWORD, admin.connection.password
  59. assert admin.connection.totp is None, admin.connection.totp
  60. assert admin.connection.token is None, admin.connection.token
  61. assert admin.connection.user_realm_name is None, admin.connection.user_realm_name
  62. assert admin.connection.custom_headers is None, admin.connection.custom_headers
  63. admin = KeycloakAdmin(
  64. server_url=f"http://{env.KEYCLOAK_HOST}:{env.KEYCLOAK_PORT}",
  65. username=env.KEYCLOAK_ADMIN,
  66. password=env.KEYCLOAK_ADMIN_PASSWORD,
  67. realm_name=None,
  68. user_realm_name="master",
  69. )
  70. assert admin.connection.token is None
  71. admin = KeycloakAdmin(
  72. server_url=f"http://{env.KEYCLOAK_HOST}:{env.KEYCLOAK_PORT}",
  73. username=env.KEYCLOAK_ADMIN,
  74. password=env.KEYCLOAK_ADMIN_PASSWORD,
  75. realm_name=None,
  76. user_realm_name=None,
  77. )
  78. assert admin.connection.token is None
  79. admin.get_realms()
  80. token = admin.connection.token
  81. admin = KeycloakAdmin(
  82. server_url=f"http://{env.KEYCLOAK_HOST}:{env.KEYCLOAK_PORT}",
  83. token=token,
  84. realm_name=None,
  85. user_realm_name=None,
  86. )
  87. assert admin.connection.token == token
  88. admin.create_realm(payload={"realm": "authz", "enabled": True})
  89. admin.connection.realm_name = "authz"
  90. admin.create_client(
  91. payload={
  92. "name": "authz-client",
  93. "clientId": "authz-client",
  94. "authorizationServicesEnabled": True,
  95. "serviceAccountsEnabled": True,
  96. "clientAuthenticatorType": "client-secret",
  97. "directAccessGrantsEnabled": False,
  98. "enabled": True,
  99. "implicitFlowEnabled": False,
  100. "publicClient": False,
  101. },
  102. )
  103. secret = admin.generate_client_secrets(client_id=admin.get_client_id("authz-client"))
  104. adminAuth = KeycloakAdmin(
  105. server_url=f"http://{env.KEYCLOAK_HOST}:{env.KEYCLOAK_PORT}",
  106. user_realm_name="authz",
  107. client_id="authz-client",
  108. client_secret_key=secret["value"],
  109. )
  110. adminAuth.connection.refresh_token()
  111. assert adminAuth.connection.token is not None
  112. admin.delete_realm(realm_name="authz")
  113. assert (
  114. KeycloakAdmin(
  115. server_url=f"http://{env.KEYCLOAK_HOST}:{env.KEYCLOAK_PORT}",
  116. username=None,
  117. password=None,
  118. client_secret_key=None,
  119. custom_headers={"custom": "header"},
  120. ).connection.token
  121. is None
  122. )
  123. keycloak_connection = KeycloakOpenIDConnection(
  124. server_url=f"http://{env.KEYCLOAK_HOST}:{env.KEYCLOAK_PORT}",
  125. username=env.KEYCLOAK_ADMIN,
  126. password=env.KEYCLOAK_ADMIN_PASSWORD,
  127. realm_name="master",
  128. client_id="admin-cli",
  129. verify=True,
  130. )
  131. keycloak_admin = KeycloakAdmin(connection=keycloak_connection)
  132. keycloak_admin.connection.get_token()
  133. assert keycloak_admin.connection.token
  134. def test_realms(admin: KeycloakAdmin):
  135. """Test realms.
  136. :param admin: Keycloak Admin client
  137. :type admin: KeycloakAdmin
  138. """
  139. # Get realms
  140. realms = admin.get_realms()
  141. assert len(realms) == 1, realms
  142. assert realms[0]["realm"] == "master"
  143. # Create a test realm
  144. res = admin.create_realm(payload={"realm": "test"})
  145. assert res == b"", res
  146. # Create the same realm, should fail
  147. with pytest.raises(KeycloakPostError) as err:
  148. res = admin.create_realm(payload={"realm": "test"})
  149. assert err.match('409: b\'{"errorMessage":"Conflict detected. See logs for details"}\'')
  150. # Create the same realm, skip_exists true
  151. res = admin.create_realm(payload={"realm": "test"}, skip_exists=True)
  152. assert res == {"msg": "Already exists"}, res
  153. # Get a single realm
  154. res = admin.get_realm(realm_name="test")
  155. assert res["realm"] == "test"
  156. # Get non-existing realm
  157. with pytest.raises(KeycloakGetError) as err:
  158. admin.get_realm(realm_name="non-existent")
  159. assert err.match('404: b\'{"error":"Realm not found.".*\'')
  160. # Update realm
  161. res = admin.update_realm(realm_name="test", payload={"accountTheme": "test"})
  162. assert res == dict(), res
  163. # Check that the update worked
  164. res = admin.get_realm(realm_name="test")
  165. assert res["realm"] == "test"
  166. assert res["accountTheme"] == "test"
  167. # Update wrong payload
  168. with pytest.raises(KeycloakPutError) as err:
  169. admin.update_realm(realm_name="test", payload={"wrong": "payload"})
  170. assert err.match("Unrecognized field")
  171. # Check that get realms returns both realms
  172. realms = admin.get_realms()
  173. realm_names = [x["realm"] for x in realms]
  174. assert len(realms) == 2, realms
  175. assert "master" in realm_names, realm_names
  176. assert "test" in realm_names, realm_names
  177. # Delete the realm
  178. res = admin.delete_realm(realm_name="test")
  179. assert res == dict(), res
  180. # Check that the realm does not exist anymore
  181. with pytest.raises(KeycloakGetError) as err:
  182. admin.get_realm(realm_name="test")
  183. assert err.match('404: b\'{"error":"Realm not found.".*}\'')
  184. # Delete non-existing realm
  185. with pytest.raises(KeycloakDeleteError) as err:
  186. admin.delete_realm(realm_name="non-existent")
  187. assert err.match('404: b\'{"error":"Realm not found.".*}\'')
  188. def test_changing_of_realms(admin: KeycloakAdmin, realm: str):
  189. """Test changing of realms.
  190. :param admin: Keycloak Admin client
  191. :type admin: KeycloakAdmin
  192. :param realm: Keycloak realm
  193. :type realm: str
  194. """
  195. assert admin.get_current_realm() == "master"
  196. admin.change_current_realm(realm)
  197. assert admin.get_current_realm() == realm
  198. def test_import_export_realms(admin: KeycloakAdmin, realm: str):
  199. """Test import and export of realms.
  200. :param admin: Keycloak Admin client
  201. :type admin: KeycloakAdmin
  202. :param realm: Keycloak realm
  203. :type realm: str
  204. """
  205. admin.change_current_realm(realm)
  206. realm_export = admin.export_realm(export_clients=True, export_groups_and_role=True)
  207. assert realm_export != dict(), realm_export
  208. admin.delete_realm(realm_name=realm)
  209. admin.realm_name = "master"
  210. res = admin.import_realm(payload=realm_export)
  211. assert res == b"", res
  212. # Test bad import
  213. with pytest.raises(KeycloakPostError) as err:
  214. admin.import_realm(payload=dict())
  215. assert err.match(
  216. '500: b\'{"error":"unknown_error"}\'|400: b\'{"errorMessage":"Realm name cannot be empty"}\'', # noqa: E501
  217. )
  218. def test_partial_import_realm(admin: KeycloakAdmin, realm: str):
  219. """Test partial import of realm configuration.
  220. :param admin: Keycloak Admin client
  221. :type admin: KeycloakAdmin
  222. :param realm: Keycloak realm
  223. :type realm: str
  224. """
  225. test_realm_role = str(uuid.uuid4())
  226. test_user = str(uuid.uuid4())
  227. test_client = str(uuid.uuid4())
  228. admin.change_current_realm(realm)
  229. client_id = admin.create_client(payload={"name": test_client, "clientId": test_client})
  230. realm_export = admin.export_realm(export_clients=True, export_groups_and_role=False)
  231. client_config = [
  232. client_entry for client_entry in realm_export["clients"] if client_entry["id"] == client_id
  233. ][0]
  234. # delete before partial import
  235. admin.delete_client(client_id)
  236. payload = {
  237. "ifResourceExists": "SKIP",
  238. "id": realm_export["id"],
  239. "realm": realm,
  240. "clients": [client_config],
  241. "roles": {"realm": [{"name": test_realm_role}]},
  242. "users": [{"username": test_user, "email": f"{test_user}@test.test"}],
  243. }
  244. # check add
  245. res = admin.partial_import_realm(realm_name=realm, payload=payload)
  246. assert res["added"] == 3
  247. # check skip
  248. res = admin.partial_import_realm(realm_name=realm, payload=payload)
  249. assert res["skipped"] == 3
  250. # check overwrite
  251. payload["ifResourceExists"] = "OVERWRITE"
  252. res = admin.partial_import_realm(realm_name=realm, payload=payload)
  253. assert res["overwritten"] == 3
  254. def test_users(admin: KeycloakAdmin, realm: str):
  255. """Test users.
  256. :param admin: Keycloak Admin client
  257. :type admin: KeycloakAdmin
  258. :param realm: Keycloak realm
  259. :type realm: str
  260. """
  261. admin.change_current_realm(realm)
  262. # Check no users present
  263. users = admin.get_users()
  264. assert users == list(), users
  265. # Test create user
  266. user_id = admin.create_user(payload={"username": "test", "email": "test@test.test"})
  267. assert user_id is not None, user_id
  268. # Test create the same user
  269. with pytest.raises(KeycloakPostError) as err:
  270. admin.create_user(payload={"username": "test", "email": "test@test.test"})
  271. assert err.match(".*User exists with same.*")
  272. # Test create the same user, exists_ok true
  273. user_id_2 = admin.create_user(
  274. payload={"username": "test", "email": "test@test.test"}, exist_ok=True,
  275. )
  276. assert user_id == user_id_2
  277. # Test get user
  278. user = admin.get_user(user_id=user_id)
  279. assert user["username"] == "test", user["username"]
  280. assert user["email"] == "test@test.test", user["email"]
  281. # Test update user
  282. res = admin.update_user(user_id=user_id, payload={"firstName": "Test"})
  283. assert res == dict(), res
  284. user = admin.get_user(user_id=user_id)
  285. assert user["firstName"] == "Test"
  286. # Test update user fail
  287. with pytest.raises(KeycloakPutError) as err:
  288. admin.update_user(user_id=user_id, payload={"wrong": "payload"})
  289. assert err.match("Unrecognized field")
  290. # Test disable user
  291. res = admin.disable_user(user_id=user_id)
  292. assert res == {}, res
  293. assert not admin.get_user(user_id=user_id)["enabled"]
  294. # Test enable user
  295. res = admin.enable_user(user_id=user_id)
  296. assert res == {}, res
  297. assert admin.get_user(user_id=user_id)["enabled"]
  298. # Test get users again
  299. users = admin.get_users()
  300. usernames = [x["username"] for x in users]
  301. assert "test" in usernames
  302. # Test users counts
  303. count = admin.users_count()
  304. assert count == 1, count
  305. # Test users count with query
  306. count = admin.users_count(query={"username": "notpresent"})
  307. assert count == 0
  308. # Test user groups
  309. groups = admin.get_user_groups(user_id=user["id"])
  310. assert len(groups) == 0
  311. # Test user groups bad id
  312. with pytest.raises(KeycloakGetError) as err:
  313. admin.get_user_groups(user_id="does-not-exist")
  314. assert err.match(USER_NOT_FOUND_REGEX)
  315. # Test logout
  316. res = admin.user_logout(user_id=user["id"])
  317. assert res == dict(), res
  318. # Test logout fail
  319. with pytest.raises(KeycloakPostError) as err:
  320. admin.user_logout(user_id="non-existent-id")
  321. assert err.match(USER_NOT_FOUND_REGEX)
  322. # Test consents
  323. res = admin.user_consents(user_id=user["id"])
  324. assert len(res) == 0, res
  325. # Test consents fail
  326. with pytest.raises(KeycloakGetError) as err:
  327. admin.user_consents(user_id="non-existent-id")
  328. assert err.match(USER_NOT_FOUND_REGEX)
  329. # Test delete user
  330. res = admin.delete_user(user_id=user_id)
  331. assert res == dict(), res
  332. with pytest.raises(KeycloakGetError) as err:
  333. admin.get_user(user_id=user_id)
  334. err.match(USER_NOT_FOUND_REGEX)
  335. # Test delete fail
  336. with pytest.raises(KeycloakDeleteError) as err:
  337. admin.delete_user(user_id="non-existent-id")
  338. assert err.match(USER_NOT_FOUND_REGEX)
  339. def test_enable_disable_all_users(admin: KeycloakAdmin, realm: str):
  340. """Test enable and disable all users.
  341. :param admin: Keycloak Admin client
  342. :type admin: KeycloakAdmin
  343. :param realm: Keycloak realm
  344. :type realm: str
  345. """
  346. admin.change_current_realm(realm)
  347. user_id_1 = admin.create_user(
  348. payload={"username": "test", "email": "test@test.test", "enabled": True},
  349. )
  350. user_id_2 = admin.create_user(
  351. payload={"username": "test2", "email": "test2@test.test", "enabled": True},
  352. )
  353. user_id_3 = admin.create_user(
  354. payload={"username": "test3", "email": "test3@test.test", "enabled": True},
  355. )
  356. assert admin.get_user(user_id_1)["enabled"]
  357. assert admin.get_user(user_id_2)["enabled"]
  358. assert admin.get_user(user_id_3)["enabled"]
  359. admin.disable_all_users()
  360. assert not admin.get_user(user_id_1)["enabled"]
  361. assert not admin.get_user(user_id_2)["enabled"]
  362. assert not admin.get_user(user_id_3)["enabled"]
  363. admin.enable_all_users()
  364. assert admin.get_user(user_id_1)["enabled"]
  365. assert admin.get_user(user_id_2)["enabled"]
  366. assert admin.get_user(user_id_3)["enabled"]
  367. def test_users_roles(admin: KeycloakAdmin, realm: str):
  368. """Test users roles.
  369. :param admin: Keycloak Admin client
  370. :type admin: KeycloakAdmin
  371. :param realm: Keycloak realm
  372. :type realm: str
  373. """
  374. user_id = admin.create_user(payload={"username": "test", "email": "test@test.test"})
  375. # Test all level user roles
  376. client_id = admin.create_client(payload={"name": "test-client", "clientId": "test-client"})
  377. admin.create_client_role(client_role_id=client_id, payload={"name": "test-role"})
  378. admin.assign_client_role(
  379. client_id=client_id,
  380. user_id=user_id,
  381. roles=[admin.get_client_role(client_id=client_id, role_name="test-role")],
  382. )
  383. all_roles = admin.get_all_roles_of_user(user_id=user_id)
  384. realm_roles = all_roles["realmMappings"]
  385. assert len(realm_roles) == 1, realm_roles
  386. client_roles = all_roles["clientMappings"]
  387. assert len(client_roles) == 1, client_roles
  388. # Test all level user roles fail
  389. with pytest.raises(KeycloakGetError) as err:
  390. admin.get_all_roles_of_user(user_id="non-existent-id")
  391. err.match('404: b\'{"error":"User not found"')
  392. admin.delete_user(user_id)
  393. admin.delete_client(client_id)
  394. def test_users_pagination(admin: KeycloakAdmin, realm: str):
  395. """Test user pagination.
  396. :param admin: Keycloak Admin client
  397. :type admin: KeycloakAdmin
  398. :param realm: Keycloak realm
  399. :type realm: str
  400. """
  401. admin.change_current_realm(realm)
  402. for ind in range(admin.PAGE_SIZE + 50):
  403. username = f"user_{ind}"
  404. admin.create_user(payload={"username": username, "email": f"{username}@test.test"})
  405. users = admin.get_users()
  406. assert len(users) == admin.PAGE_SIZE + 50, len(users)
  407. users = admin.get_users(query={"first": 100})
  408. assert len(users) == 50, len(users)
  409. users = admin.get_users(query={"max": 20})
  410. assert len(users) == 20, len(users)
  411. def test_user_groups_pagination(admin: KeycloakAdmin, realm: str):
  412. """Test user groups pagination.
  413. :param admin: Keycloak Admin client
  414. :type admin: KeycloakAdmin
  415. :param realm: Keycloak realm
  416. :type realm: str
  417. """
  418. admin.change_current_realm(realm)
  419. user_id = admin.create_user(
  420. payload={"username": "username_1", "email": "username_1@test.test"},
  421. )
  422. for ind in range(admin.PAGE_SIZE + 50):
  423. group_name = f"group_{ind}"
  424. group_id = admin.create_group(payload={"name": group_name})
  425. admin.group_user_add(user_id=user_id, group_id=group_id)
  426. groups = admin.get_user_groups(user_id=user_id)
  427. assert len(groups) == admin.PAGE_SIZE + 50, len(groups)
  428. groups = admin.get_user_groups(user_id=user_id, query={"first": 100, "max": -1, "search": ""})
  429. assert len(groups) == 50, len(groups)
  430. groups = admin.get_user_groups(user_id=user_id, query={"max": 20, "first": -1, "search": ""})
  431. assert len(groups) == 20, len(groups)
  432. def test_idps(admin: KeycloakAdmin, realm: str):
  433. """Test IDPs.
  434. :param admin: Keycloak Admin client
  435. :type admin: KeycloakAdmin
  436. :param realm: Keycloak realm
  437. :type realm: str
  438. """
  439. admin.change_current_realm(realm)
  440. # Create IDP
  441. res = admin.create_idp(
  442. payload=dict(
  443. providerId="github", alias="github", config=dict(clientId="test", clientSecret="test"),
  444. ),
  445. )
  446. assert res == b"", res
  447. # Test create idp fail
  448. with pytest.raises(KeycloakPostError) as err:
  449. admin.create_idp(payload={"providerId": "does-not-exist", "alias": "something"})
  450. assert err.match("Invalid identity provider id"), err
  451. # Test listing
  452. idps = admin.get_idps()
  453. assert len(idps) == 1
  454. assert idps[0]["alias"] == "github"
  455. # Test get idp
  456. idp = admin.get_idp("github")
  457. assert idp["alias"] == "github"
  458. assert idp.get("config")
  459. assert idp["config"]["clientId"] == "test"
  460. assert idp["config"]["clientSecret"] == "**********"
  461. # Test get idp fail
  462. with pytest.raises(KeycloakGetError) as err:
  463. admin.get_idp("does-not-exist")
  464. assert err.match(HTTP_404_REGEX)
  465. # Test IdP update
  466. res = admin.update_idp(idp_alias="github", payload=idps[0])
  467. assert res == {}, res
  468. # Test adding a mapper
  469. res = admin.add_mapper_to_idp(
  470. idp_alias="github",
  471. payload={
  472. "identityProviderAlias": "github",
  473. "identityProviderMapper": "github-user-attribute-mapper",
  474. "name": "test",
  475. },
  476. )
  477. assert res == b"", res
  478. # Test mapper fail
  479. with pytest.raises(KeycloakPostError) as err:
  480. admin.add_mapper_to_idp(idp_alias="does-no-texist", payload=dict())
  481. assert err.match(HTTP_404_REGEX)
  482. # Test IdP mappers listing
  483. idp_mappers = admin.get_idp_mappers(idp_alias="github")
  484. assert len(idp_mappers) == 1
  485. # Test IdP mapper update
  486. res = admin.update_mapper_in_idp(
  487. idp_alias="github",
  488. mapper_id=idp_mappers[0]["id"],
  489. # For an obscure reason, keycloak expect all fields
  490. payload={
  491. "id": idp_mappers[0]["id"],
  492. "identityProviderAlias": "github-alias",
  493. "identityProviderMapper": "github-user-attribute-mapper",
  494. "name": "test",
  495. "config": idp_mappers[0]["config"],
  496. },
  497. )
  498. assert res == dict(), res
  499. # Test delete
  500. res = admin.delete_idp(idp_alias="github")
  501. assert res == dict(), res
  502. # Test delete fail
  503. with pytest.raises(KeycloakDeleteError) as err:
  504. admin.delete_idp(idp_alias="does-not-exist")
  505. assert err.match(HTTP_404_REGEX)
  506. def test_user_credentials(admin: KeycloakAdmin, user: str):
  507. """Test user credentials.
  508. :param admin: Keycloak Admin client
  509. :type admin: KeycloakAdmin
  510. :param user: Keycloak user
  511. :type user: str
  512. """
  513. res = admin.set_user_password(user_id=user, password="booya", temporary=True)
  514. assert res == dict(), res
  515. # Test user password set fail
  516. with pytest.raises(KeycloakPutError) as err:
  517. admin.set_user_password(user_id="does-not-exist", password="")
  518. assert err.match(USER_NOT_FOUND_REGEX)
  519. credentials = admin.get_credentials(user_id=user)
  520. assert len(credentials) == 1
  521. assert credentials[0]["type"] == "password", credentials
  522. # Test get credentials fail
  523. with pytest.raises(KeycloakGetError) as err:
  524. admin.get_credentials(user_id="does-not-exist")
  525. assert err.match(USER_NOT_FOUND_REGEX)
  526. res = admin.delete_credential(user_id=user, credential_id=credentials[0]["id"])
  527. assert res == dict(), res
  528. # Test delete fail
  529. with pytest.raises(KeycloakDeleteError) as err:
  530. admin.delete_credential(user_id=user, credential_id="does-not-exist")
  531. assert err.match('404: b\'{"error":"Credential not found".*}\'')
  532. def test_social_logins(admin: KeycloakAdmin, user: str):
  533. """Test social logins.
  534. :param admin: Keycloak Admin client
  535. :type admin: KeycloakAdmin
  536. :param user: Keycloak user
  537. :type user: str
  538. """
  539. res = admin.add_user_social_login(
  540. user_id=user, provider_id="gitlab", provider_userid="test", provider_username="test",
  541. )
  542. assert res == dict(), res
  543. admin.add_user_social_login(
  544. user_id=user, provider_id="github", provider_userid="test", provider_username="test",
  545. )
  546. assert res == dict(), res
  547. # Test add social login fail
  548. with pytest.raises(KeycloakPostError) as err:
  549. admin.add_user_social_login(
  550. user_id="does-not-exist",
  551. provider_id="does-not-exist",
  552. provider_userid="test",
  553. provider_username="test",
  554. )
  555. assert err.match(USER_NOT_FOUND_REGEX)
  556. res = admin.get_user_social_logins(user_id=user)
  557. assert res == list(), res
  558. # Test get social logins fail
  559. with pytest.raises(KeycloakGetError) as err:
  560. admin.get_user_social_logins(user_id="does-not-exist")
  561. assert err.match(USER_NOT_FOUND_REGEX)
  562. res = admin.delete_user_social_login(user_id=user, provider_id="gitlab")
  563. assert res == {}, res
  564. res = admin.delete_user_social_login(user_id=user, provider_id="github")
  565. assert res == {}, res
  566. with pytest.raises(KeycloakDeleteError) as err:
  567. admin.delete_user_social_login(user_id=user, provider_id="instagram")
  568. assert err.match('404: b\'{"error":"Link not found".*}\''), err
  569. def test_server_info(admin: KeycloakAdmin):
  570. """Test server info.
  571. :param admin: Keycloak Admin client
  572. :type admin: KeycloakAdmin
  573. """
  574. info = admin.get_server_info()
  575. assert set(info.keys()).issubset(
  576. {
  577. "systemInfo",
  578. "memoryInfo",
  579. "profileInfo",
  580. "features",
  581. "themes",
  582. "socialProviders",
  583. "identityProviders",
  584. "providers",
  585. "protocolMapperTypes",
  586. "builtinProtocolMappers",
  587. "clientInstallations",
  588. "componentTypes",
  589. "passwordPolicies",
  590. "enums",
  591. "cryptoInfo",
  592. },
  593. ), info.keys()
  594. def test_groups(admin: KeycloakAdmin, user: str):
  595. """Test groups.
  596. :param admin: Keycloak Admin client
  597. :type admin: KeycloakAdmin
  598. :param user: Keycloak user
  599. :type user: str
  600. """
  601. # Test get groups
  602. groups = admin.get_groups()
  603. assert len(groups) == 0
  604. # Test create group
  605. group_id = admin.create_group(payload={"name": "main-group"})
  606. assert group_id is not None, group_id
  607. # Test group count
  608. count = admin.groups_count()
  609. assert count.get("count") == 1, count
  610. # Test group count with query
  611. count = admin.groups_count(query={"search": "notpresent"})
  612. assert count.get("count") == 0
  613. # Test create subgroups
  614. subgroup_id_1 = admin.create_group(payload={"name": "subgroup-1"}, parent=group_id)
  615. subgroup_id_2 = admin.create_group(payload={"name": "subgroup-2"}, parent=group_id)
  616. # Test create group fail
  617. with pytest.raises(KeycloakPostError) as err:
  618. admin.create_group(payload={"name": "subgroup-1"}, parent=group_id)
  619. assert err.match("409"), err
  620. # Test skip exists OK
  621. subgroup_id_1_eq = admin.create_group(
  622. payload={"name": "subgroup-1"}, parent=group_id, skip_exists=True,
  623. )
  624. assert subgroup_id_1_eq is None
  625. # Test get groups again
  626. groups = admin.get_groups()
  627. assert len(groups) == 1, groups
  628. assert len(groups[0]["subGroups"]) == 2, groups[0]["subGroups"]
  629. assert groups[0]["id"] == group_id
  630. assert {x["id"] for x in groups[0]["subGroups"]} == {subgroup_id_1, subgroup_id_2}
  631. # Test get groups query
  632. groups = admin.get_groups(query={"max": 10})
  633. assert len(groups) == 1, groups
  634. assert len(groups[0]["subGroups"]) == 2, groups[0]["subGroups"]
  635. assert groups[0]["id"] == group_id
  636. assert {x["id"] for x in groups[0]["subGroups"]} == {subgroup_id_1, subgroup_id_2}
  637. # Test get group
  638. res = admin.get_group(group_id=subgroup_id_1)
  639. assert res["id"] == subgroup_id_1, res
  640. assert res["name"] == "subgroup-1"
  641. assert res["path"] == "/main-group/subgroup-1"
  642. # Test get group fail
  643. with pytest.raises(KeycloakGetError) as err:
  644. admin.get_group(group_id="does-not-exist")
  645. assert err.match('404: b\'{"error":"Could not find group by id".*}\''), err
  646. # Create 1 more subgroup
  647. subsubgroup_id_1 = admin.create_group(payload={"name": "subsubgroup-1"}, parent=subgroup_id_2)
  648. main_group = admin.get_group(group_id=group_id)
  649. # Test nested searches
  650. subgroup_2 = admin.get_group(group_id=subgroup_id_2)
  651. res = admin.get_subgroups(group=subgroup_2, path="/main-group/subgroup-2/subsubgroup-1")
  652. assert res is not None, res
  653. assert res["id"] == subsubgroup_id_1
  654. # Test nested search from main group
  655. res = admin.get_subgroups(
  656. group=admin.get_group(group_id=group_id, full_hierarchy=True),
  657. path="/main-group/subgroup-2/subsubgroup-1",
  658. )
  659. assert res["id"] == subsubgroup_id_1
  660. # Test nested search from all groups
  661. res = admin.get_groups(full_hierarchy=True)
  662. assert len(res) == 1
  663. assert len(res[0]["subGroups"]) == 2
  664. assert len([x for x in res[0]["subGroups"] if x["id"] == subgroup_id_1][0]["subGroups"]) == 0
  665. assert len([x for x in res[0]["subGroups"] if x["id"] == subgroup_id_2][0]["subGroups"]) == 1
  666. # Test that query params are not allowed for full hierarchy
  667. with pytest.raises(ValueError) as err:
  668. admin.get_group_children(group_id=group_id, full_hierarchy=True, query={"max": 10})
  669. # Test that query params are passed
  670. if os.environ["KEYCLOAK_DOCKER_IMAGE_TAG"] == "latest" or Version(
  671. os.environ["KEYCLOAK_DOCKER_IMAGE_TAG"],
  672. ) >= Version("23"):
  673. res = admin.get_group_children(group_id=group_id, query={"max": 1})
  674. assert len(res) == 1
  675. assert err.match("Cannot use both query and full_hierarchy parameters")
  676. main_group_id_2 = admin.create_group(payload={"name": "main-group-2"})
  677. assert len(admin.get_groups(full_hierarchy=True)) == 2
  678. # Test empty search
  679. res = admin.get_subgroups(group=main_group, path="/none")
  680. assert res is None, res
  681. # Test get group by path
  682. res = admin.get_group_by_path(path="/main-group/subgroup-1")
  683. assert res is not None, res
  684. assert res["id"] == subgroup_id_1, res
  685. res = admin.get_group_by_path(path="/main-group/subgroup-2/subsubgroup-1/test")
  686. assert res["error"] == "Group path does not exist"
  687. res = admin.get_group_by_path(path="/main-group/subgroup-2/subsubgroup-1")
  688. assert res is not None, res
  689. assert res["id"] == subsubgroup_id_1
  690. res = admin.get_group_by_path(path="/main-group")
  691. assert res is not None, res
  692. assert res["id"] == group_id, res
  693. # Test group members
  694. res = admin.get_group_members(group_id=subgroup_id_2)
  695. assert len(res) == 0, res
  696. # Test fail group members
  697. with pytest.raises(KeycloakGetError) as err:
  698. admin.get_group_members(group_id="does-not-exist")
  699. assert err.match('404: b\'{"error":"Could not find group by id".*}\'')
  700. res = admin.group_user_add(user_id=user, group_id=subgroup_id_2)
  701. assert res == dict(), res
  702. res = admin.get_group_members(group_id=subgroup_id_2)
  703. assert len(res) == 1, res
  704. assert res[0]["id"] == user
  705. # Test get group members query
  706. res = admin.get_group_members(group_id=subgroup_id_2, query={"max": 10})
  707. assert len(res) == 1, res
  708. assert res[0]["id"] == user
  709. with pytest.raises(KeycloakDeleteError) as err:
  710. admin.group_user_remove(user_id="does-not-exist", group_id=subgroup_id_2)
  711. assert err.match(USER_NOT_FOUND_REGEX), err
  712. res = admin.group_user_remove(user_id=user, group_id=subgroup_id_2)
  713. assert res == dict(), res
  714. # Test set permissions
  715. res = admin.group_set_permissions(group_id=subgroup_id_2, enabled=True)
  716. assert res["enabled"], res
  717. res = admin.group_set_permissions(group_id=subgroup_id_2, enabled=False)
  718. assert not res["enabled"], res
  719. with pytest.raises(KeycloakPutError) as err:
  720. admin.group_set_permissions(group_id=subgroup_id_2, enabled="blah")
  721. assert err.match(UNKOWN_ERROR_REGEX), err
  722. # Test update group
  723. res = admin.update_group(group_id=subgroup_id_2, payload={"name": "new-subgroup-2"})
  724. assert res == dict(), res
  725. assert admin.get_group(group_id=subgroup_id_2)["name"] == "new-subgroup-2"
  726. # test update fail
  727. with pytest.raises(KeycloakPutError) as err:
  728. admin.update_group(group_id="does-not-exist", payload=dict())
  729. assert err.match('404: b\'{"error":"Could not find group by id".*}\''), err
  730. # Test delete
  731. res = admin.delete_group(group_id=group_id)
  732. assert res == dict(), res
  733. res = admin.delete_group(group_id=main_group_id_2)
  734. assert res == dict(), res
  735. assert len(admin.get_groups()) == 0
  736. # Test delete fail
  737. with pytest.raises(KeycloakDeleteError) as err:
  738. admin.delete_group(group_id="does-not-exist")
  739. assert err.match('404: b\'{"error":"Could not find group by id".*}\''), err
  740. def test_clients(admin: KeycloakAdmin, realm: str):
  741. """Test clients.
  742. :param admin: Keycloak Admin client
  743. :type admin: KeycloakAdmin
  744. :param realm: Keycloak realm
  745. :type realm: str
  746. """
  747. admin.change_current_realm(realm)
  748. # Test get clients
  749. clients = admin.get_clients()
  750. assert len(clients) == 6, clients
  751. assert {x["name"] for x in clients} == set(
  752. [
  753. "${client_admin-cli}",
  754. "${client_security-admin-console}",
  755. "${client_account-console}",
  756. "${client_broker}",
  757. "${client_account}",
  758. "${client_realm-management}",
  759. ],
  760. ), clients
  761. # Test create client
  762. client_id = admin.create_client(payload={"name": "test-client", "clientId": "test-client"})
  763. assert client_id, client_id
  764. with pytest.raises(KeycloakPostError) as err:
  765. admin.create_client(payload={"name": "test-client", "clientId": "test-client"})
  766. assert err.match('409: b\'{"errorMessage":"Client test-client already exists"}\''), err
  767. client_id_2 = admin.create_client(
  768. payload={"name": "test-client", "clientId": "test-client"}, skip_exists=True,
  769. )
  770. assert client_id == client_id_2, client_id_2
  771. # Test get client
  772. res = admin.get_client(client_id=client_id)
  773. assert res["clientId"] == "test-client", res
  774. assert res["name"] == "test-client", res
  775. assert res["id"] == client_id, res
  776. with pytest.raises(KeycloakGetError) as err:
  777. admin.get_client(client_id="does-not-exist")
  778. assert err.match('404: b\'{"error":"Could not find client".*}\'')
  779. assert len(admin.get_clients()) == 7
  780. # Test get client id
  781. assert admin.get_client_id(client_id="test-client") == client_id
  782. assert admin.get_client_id(client_id="does-not-exist") is None
  783. # Test update client
  784. res = admin.update_client(client_id=client_id, payload={"name": "test-client-change"})
  785. assert res == dict(), res
  786. with pytest.raises(KeycloakPutError) as err:
  787. admin.update_client(client_id="does-not-exist", payload={"name": "test-client-change"})
  788. assert err.match('404: b\'{"error":"Could not find client".*}\'')
  789. # Test client mappers
  790. res = admin.get_mappers_from_client(client_id=client_id)
  791. assert len(res) == 0
  792. with pytest.raises(KeycloakPostError) as err:
  793. admin.add_mapper_to_client(client_id="does-not-exist", payload=dict())
  794. assert err.match('404: b\'{"error":"Could not find client".*}\'')
  795. res = admin.add_mapper_to_client(
  796. client_id=client_id,
  797. payload={
  798. "name": "test-mapper",
  799. "protocol": "openid-connect",
  800. "protocolMapper": "oidc-usermodel-attribute-mapper",
  801. },
  802. )
  803. assert res == b""
  804. assert len(admin.get_mappers_from_client(client_id=client_id)) == 1
  805. mapper = admin.get_mappers_from_client(client_id=client_id)[0]
  806. with pytest.raises(KeycloakPutError) as err:
  807. admin.update_client_mapper(client_id=client_id, mapper_id="does-not-exist", payload=dict())
  808. assert err.match('404: b\'{"error":"Model not found".*}\'')
  809. mapper["config"]["user.attribute"] = "test"
  810. res = admin.update_client_mapper(client_id=client_id, mapper_id=mapper["id"], payload=mapper)
  811. assert res == dict()
  812. res = admin.remove_client_mapper(client_id=client_id, client_mapper_id=mapper["id"])
  813. assert res == dict()
  814. with pytest.raises(KeycloakDeleteError) as err:
  815. admin.remove_client_mapper(client_id=client_id, client_mapper_id=mapper["id"])
  816. assert err.match('404: b\'{"error":"Model not found".*}\'')
  817. # Test client sessions
  818. with pytest.raises(KeycloakGetError) as err:
  819. admin.get_client_all_sessions(client_id="does-not-exist")
  820. assert err.match('404: b\'{"error":"Could not find client".*}\'')
  821. assert admin.get_client_all_sessions(client_id=client_id) == list()
  822. assert admin.get_client_sessions_stats() == list()
  823. # Test authz
  824. auth_client_id = admin.create_client(
  825. payload={
  826. "name": "authz-client",
  827. "clientId": "authz-client",
  828. "authorizationServicesEnabled": True,
  829. "serviceAccountsEnabled": True,
  830. },
  831. )
  832. res = admin.get_client_authz_settings(client_id=auth_client_id)
  833. assert res["allowRemoteResourceManagement"]
  834. assert res["decisionStrategy"] == "UNANIMOUS"
  835. assert len(res["policies"]) >= 0
  836. with pytest.raises(KeycloakGetError) as err:
  837. admin.get_client_authz_settings(client_id=client_id)
  838. assert err.match(HTTP_404_REGEX)
  839. # Authz resources
  840. res = admin.get_client_authz_resources(client_id=auth_client_id)
  841. assert len(res) == 1
  842. assert res[0]["name"] == "Default Resource"
  843. with pytest.raises(KeycloakGetError) as err:
  844. admin.get_client_authz_resources(client_id=client_id)
  845. assert err.match(HTTP_404_REGEX)
  846. res = admin.create_client_authz_resource(
  847. client_id=auth_client_id, payload={"name": "test-resource"},
  848. )
  849. assert res["name"] == "test-resource", res
  850. test_resource_id = res["_id"]
  851. res = admin.get_client_authz_resource(client_id=auth_client_id, resource_id=test_resource_id)
  852. assert res["_id"] == test_resource_id, res
  853. assert res["name"] == "test-resource", res
  854. with pytest.raises(KeycloakPostError) as err:
  855. admin.create_client_authz_resource(
  856. client_id=auth_client_id, payload={"name": "test-resource"},
  857. )
  858. assert err.match('409: b\'{"error":"invalid_request"')
  859. assert admin.create_client_authz_resource(
  860. client_id=auth_client_id, payload={"name": "test-resource"}, skip_exists=True,
  861. ) == {"msg": "Already exists"}
  862. res = admin.get_client_authz_resources(client_id=auth_client_id)
  863. assert len(res) == 2
  864. assert {x["name"] for x in res} == {"Default Resource", "test-resource"}
  865. res = admin.create_client_authz_resource(
  866. client_id=auth_client_id, payload={"name": "temp-resource"},
  867. )
  868. assert res["name"] == "temp-resource", res
  869. temp_resource_id: str = res["_id"]
  870. # Test update authz resources
  871. admin.update_client_authz_resource(
  872. client_id=auth_client_id,
  873. resource_id=temp_resource_id,
  874. payload={"name": "temp-updated-resource"},
  875. )
  876. res = admin.get_client_authz_resource(client_id=auth_client_id, resource_id=temp_resource_id)
  877. assert res["name"] == "temp-updated-resource", res
  878. with pytest.raises(KeycloakPutError) as err:
  879. admin.update_client_authz_resource(
  880. client_id=auth_client_id,
  881. resource_id="invalid_resource_id",
  882. payload={"name": "temp-updated-resource"},
  883. )
  884. assert err.match("404: b''"), err
  885. admin.delete_client_authz_resource(client_id=auth_client_id, resource_id=temp_resource_id)
  886. with pytest.raises(KeycloakGetError) as err:
  887. admin.get_client_authz_resource(client_id=auth_client_id, resource_id=temp_resource_id)
  888. assert err.match("404: b''")
  889. # Authz policies
  890. res = admin.get_client_authz_policies(client_id=auth_client_id)
  891. assert len(res) == 1, res
  892. assert res[0]["name"] == "Default Policy"
  893. with pytest.raises(KeycloakGetError) as err:
  894. admin.get_client_authz_policies(client_id="does-not-exist")
  895. assert err.match('404: b\'{"error":"Could not find client".*}\'')
  896. role_id = admin.get_realm_role(role_name="offline_access")["id"]
  897. res = admin.create_client_authz_role_based_policy(
  898. client_id=auth_client_id,
  899. payload={"name": "test-authz-rb-policy", "roles": [{"id": role_id}]},
  900. )
  901. assert res["name"] == "test-authz-rb-policy", res
  902. role_based_policy_id = res["id"]
  903. role_based_policy_name = res["name"]
  904. with pytest.raises(KeycloakPostError) as err:
  905. admin.create_client_authz_role_based_policy(
  906. client_id=auth_client_id,
  907. payload={"name": "test-authz-rb-policy", "roles": [{"id": role_id}]},
  908. )
  909. assert err.match('409: b\'{"error":"Policy with name')
  910. assert admin.create_client_authz_role_based_policy(
  911. client_id=auth_client_id,
  912. payload={"name": "test-authz-rb-policy", "roles": [{"id": role_id}]},
  913. skip_exists=True,
  914. ) == {"msg": "Already exists"}
  915. assert len(admin.get_client_authz_policies(client_id=auth_client_id)) == 2
  916. res = admin.create_client_authz_role_based_policy(
  917. client_id=auth_client_id,
  918. payload={"name": "test-authz-rb-policy-delete", "roles": [{"id": role_id}]},
  919. )
  920. res2 = admin.get_client_authz_policy(client_id=auth_client_id, policy_id=res["id"])
  921. assert res["id"] == res2["id"]
  922. admin.delete_client_authz_policy(client_id=auth_client_id, policy_id=res["id"])
  923. with pytest.raises(KeycloakGetError) as err:
  924. admin.get_client_authz_policy(client_id=auth_client_id, policy_id=res["id"])
  925. assert err.match("404: b''")
  926. res = admin.create_client_authz_policy(
  927. client_id=auth_client_id,
  928. payload={
  929. "name": "test-authz-policy",
  930. "type": "time",
  931. "config": {"hourEnd": "18", "hour": "9"},
  932. },
  933. )
  934. assert res["name"] == "test-authz-policy", res
  935. with pytest.raises(KeycloakPostError) as err:
  936. admin.create_client_authz_policy(
  937. client_id=auth_client_id,
  938. payload={
  939. "name": "test-authz-policy",
  940. "type": "time",
  941. "config": {"hourEnd": "18", "hour": "9"},
  942. },
  943. )
  944. assert err.match('409: b\'{"error":"Policy with name')
  945. assert admin.create_client_authz_policy(
  946. client_id=auth_client_id,
  947. payload={
  948. "name": "test-authz-policy",
  949. "type": "time",
  950. "config": {"hourEnd": "18", "hour": "9"},
  951. },
  952. skip_exists=True,
  953. ) == {"msg": "Already exists"}
  954. assert len(admin.get_client_authz_policies(client_id=auth_client_id)) == 3
  955. # Test authz permissions
  956. res = admin.get_client_authz_permissions(client_id=auth_client_id)
  957. assert len(res) == 1, res
  958. assert res[0]["name"] == "Default Permission"
  959. with pytest.raises(KeycloakGetError) as err:
  960. admin.get_client_authz_permissions(client_id="does-not-exist")
  961. assert err.match('404: b\'{"error":"Could not find client".*}\'')
  962. res = admin.create_client_authz_resource_based_permission(
  963. client_id=auth_client_id,
  964. payload={"name": "test-permission-rb", "resources": [test_resource_id]},
  965. )
  966. assert res, res
  967. assert res["name"] == "test-permission-rb"
  968. assert res["resources"] == [test_resource_id]
  969. resource_based_permission_id = res["id"]
  970. resource_based_permission_name = res["name"]
  971. with pytest.raises(KeycloakPostError) as err:
  972. admin.create_client_authz_resource_based_permission(
  973. client_id=auth_client_id,
  974. payload={"name": "test-permission-rb", "resources": [test_resource_id]},
  975. )
  976. assert err.match('409: b\'{"error":"Policy with name')
  977. assert admin.create_client_authz_resource_based_permission(
  978. client_id=auth_client_id,
  979. payload={"name": "test-permission-rb", "resources": [test_resource_id]},
  980. skip_exists=True,
  981. ) == {"msg": "Already exists"}
  982. assert len(admin.get_client_authz_permissions(client_id=auth_client_id)) == 2
  983. # Test associating client policy with resource based permission
  984. res = admin.update_client_authz_resource_permission(
  985. client_id=auth_client_id,
  986. resource_id=resource_based_permission_id,
  987. payload={
  988. "id": resource_based_permission_id,
  989. "name": resource_based_permission_name,
  990. "type": "resource",
  991. "logic": "POSITIVE",
  992. "decisionStrategy": "UNANIMOUS",
  993. "resources": [test_resource_id],
  994. "scopes": [],
  995. "policies": [role_based_policy_id],
  996. },
  997. )
  998. # Test getting associated policies for a permission
  999. associated_policies = admin.get_client_authz_permission_associated_policies(
  1000. client_id=auth_client_id, policy_id=resource_based_permission_id,
  1001. )
  1002. assert len(associated_policies) == 1
  1003. assert associated_policies[0]["name"].startswith(role_based_policy_name)
  1004. # Test authz scopes
  1005. res = admin.get_client_authz_scopes(client_id=auth_client_id)
  1006. assert len(res) == 0, res
  1007. with pytest.raises(KeycloakGetError) as err:
  1008. admin.get_client_authz_scopes(client_id=client_id)
  1009. assert err.match(HTTP_404_REGEX)
  1010. res = admin.create_client_authz_scopes(
  1011. client_id=auth_client_id, payload={"name": "test-authz-scope"},
  1012. )
  1013. assert res["name"] == "test-authz-scope", res
  1014. with pytest.raises(KeycloakPostError) as err:
  1015. admin.create_client_authz_scopes(
  1016. client_id="invalid_client_id", payload={"name": "test-authz-scope"},
  1017. )
  1018. assert err.match('404: b\'{"error":"Could not find client".*}\'')
  1019. assert admin.create_client_authz_scopes(
  1020. client_id=auth_client_id, payload={"name": "test-authz-scope"},
  1021. )
  1022. res = admin.get_client_authz_scopes(client_id=auth_client_id)
  1023. assert len(res) == 1
  1024. assert {x["name"] for x in res} == {"test-authz-scope"}
  1025. # Test service account user
  1026. res = admin.get_client_service_account_user(client_id=auth_client_id)
  1027. assert res["username"] == "service-account-authz-client", res
  1028. with pytest.raises(KeycloakGetError) as err:
  1029. admin.get_client_service_account_user(client_id=client_id)
  1030. assert ('b\'{"error":"Service account not enabled for the client' in str(err)) or err.match(
  1031. UNKOWN_ERROR_REGEX,
  1032. )
  1033. # Test delete client
  1034. res = admin.delete_client(client_id=auth_client_id)
  1035. assert res == dict(), res
  1036. with pytest.raises(KeycloakDeleteError) as err:
  1037. admin.delete_client(client_id=auth_client_id)
  1038. assert err.match('404: b\'{"error":"Could not find client".*}\'')
  1039. # Test client credentials
  1040. admin.create_client(
  1041. payload={
  1042. "name": "test-confidential",
  1043. "enabled": True,
  1044. "protocol": "openid-connect",
  1045. "publicClient": False,
  1046. "redirectUris": ["http://localhost/*"],
  1047. "webOrigins": ["+"],
  1048. "clientId": "test-confidential",
  1049. "secret": "test-secret",
  1050. "clientAuthenticatorType": "client-secret",
  1051. },
  1052. )
  1053. with pytest.raises(KeycloakGetError) as err:
  1054. admin.get_client_secrets(client_id="does-not-exist")
  1055. assert err.match('404: b\'{"error":"Could not find client".*}\'')
  1056. secrets = admin.get_client_secrets(
  1057. client_id=admin.get_client_id(client_id="test-confidential"),
  1058. )
  1059. assert secrets == {"type": "secret", "value": "test-secret"}
  1060. with pytest.raises(KeycloakPostError) as err:
  1061. admin.generate_client_secrets(client_id="does-not-exist")
  1062. assert err.match('404: b\'{"error":"Could not find client".*}\'')
  1063. res = admin.generate_client_secrets(
  1064. client_id=admin.get_client_id(client_id="test-confidential"),
  1065. )
  1066. assert res
  1067. assert (
  1068. admin.get_client_secrets(client_id=admin.get_client_id(client_id="test-confidential"))
  1069. == res
  1070. )
  1071. def test_realm_roles(admin: KeycloakAdmin, realm: str):
  1072. """Test realm roles.
  1073. :param admin: Keycloak Admin client
  1074. :type admin: KeycloakAdmin
  1075. :param realm: Keycloak realm
  1076. :type realm: str
  1077. """
  1078. admin.change_current_realm(realm)
  1079. # Test get realm roles
  1080. roles = admin.get_realm_roles()
  1081. assert len(roles) == 3, roles
  1082. role_names = [x["name"] for x in roles]
  1083. assert "uma_authorization" in role_names, role_names
  1084. assert "offline_access" in role_names, role_names
  1085. # Test get realm roles with search text
  1086. searched_roles = admin.get_realm_roles(search_text="uma_a")
  1087. searched_role_names = [x["name"] for x in searched_roles]
  1088. assert "uma_authorization" in searched_role_names, searched_role_names
  1089. assert "offline_access" not in searched_role_names, searched_role_names
  1090. # Test empty members
  1091. with pytest.raises(KeycloakGetError) as err:
  1092. admin.get_realm_role_members(role_name="does-not-exist")
  1093. assert err.match(COULD_NOT_FIND_ROLE_REGEX)
  1094. members = admin.get_realm_role_members(role_name="offline_access")
  1095. assert members == list(), members
  1096. # Test create realm role
  1097. role_id = admin.create_realm_role(payload={"name": "test-realm-role"}, skip_exists=True)
  1098. assert role_id, role_id
  1099. with pytest.raises(KeycloakPostError) as err:
  1100. admin.create_realm_role(payload={"name": "test-realm-role"})
  1101. assert err.match('409: b\'{"errorMessage":"Role with name test-realm-role already exists"}\'')
  1102. role_id_2 = admin.create_realm_role(payload={"name": "test-realm-role"}, skip_exists=True)
  1103. assert role_id == role_id_2
  1104. # Test get realm role by its id
  1105. role_id = admin.get_realm_role(role_name="test-realm-role")["id"]
  1106. res = admin.get_realm_role_by_id(role_id)
  1107. assert res["name"] == "test-realm-role"
  1108. # Test update realm role
  1109. res = admin.update_realm_role(
  1110. role_name="test-realm-role", payload={"name": "test-realm-role-update"},
  1111. )
  1112. assert res == dict(), res
  1113. with pytest.raises(KeycloakPutError) as err:
  1114. admin.update_realm_role(
  1115. role_name="test-realm-role", payload={"name": "test-realm-role-update"},
  1116. )
  1117. assert err.match(COULD_NOT_FIND_ROLE_REGEX)
  1118. # Test realm role user assignment
  1119. user_id = admin.create_user(payload={"username": "role-testing", "email": "test@test.test"})
  1120. with pytest.raises(KeycloakPostError) as err:
  1121. admin.assign_realm_roles(user_id=user_id, roles=["bad"])
  1122. assert err.match(UNKOWN_ERROR_REGEX), err
  1123. res = admin.assign_realm_roles(
  1124. user_id=user_id,
  1125. roles=[
  1126. admin.get_realm_role(role_name="offline_access"),
  1127. admin.get_realm_role(role_name="test-realm-role-update"),
  1128. ],
  1129. )
  1130. assert res == dict(), res
  1131. assert admin.get_user(user_id=user_id)["username"] in [
  1132. x["username"] for x in admin.get_realm_role_members(role_name="offline_access")
  1133. ]
  1134. assert admin.get_user(user_id=user_id)["username"] in [
  1135. x["username"] for x in admin.get_realm_role_members(role_name="test-realm-role-update")
  1136. ]
  1137. roles = admin.get_realm_roles_of_user(user_id=user_id)
  1138. assert len(roles) == 3
  1139. assert "offline_access" in [x["name"] for x in roles]
  1140. assert "test-realm-role-update" in [x["name"] for x in roles]
  1141. with pytest.raises(KeycloakDeleteError) as err:
  1142. admin.delete_realm_roles_of_user(user_id=user_id, roles=["bad"])
  1143. assert err.match(UNKOWN_ERROR_REGEX), err
  1144. res = admin.delete_realm_roles_of_user(
  1145. user_id=user_id, roles=[admin.get_realm_role(role_name="offline_access")],
  1146. )
  1147. assert res == dict(), res
  1148. assert admin.get_realm_role_members(role_name="offline_access") == list()
  1149. roles = admin.get_realm_roles_of_user(user_id=user_id)
  1150. assert len(roles) == 2
  1151. assert "offline_access" not in [x["name"] for x in roles]
  1152. assert "test-realm-role-update" in [x["name"] for x in roles]
  1153. roles = admin.get_available_realm_roles_of_user(user_id=user_id)
  1154. assert len(roles) == 2
  1155. assert "offline_access" in [x["name"] for x in roles]
  1156. assert "uma_authorization" in [x["name"] for x in roles]
  1157. # Test realm role group assignment
  1158. group_id = admin.create_group(payload={"name": "test-group"})
  1159. with pytest.raises(KeycloakPostError) as err:
  1160. admin.assign_group_realm_roles(group_id=group_id, roles=["bad"])
  1161. assert err.match(UNKOWN_ERROR_REGEX), err
  1162. res = admin.assign_group_realm_roles(
  1163. group_id=group_id,
  1164. roles=[
  1165. admin.get_realm_role(role_name="offline_access"),
  1166. admin.get_realm_role(role_name="test-realm-role-update"),
  1167. ],
  1168. )
  1169. assert res == dict(), res
  1170. roles = admin.get_group_realm_roles(group_id=group_id)
  1171. assert len(roles) == 2
  1172. assert "offline_access" in [x["name"] for x in roles]
  1173. assert "test-realm-role-update" in [x["name"] for x in roles]
  1174. with pytest.raises(KeycloakDeleteError) as err:
  1175. admin.delete_group_realm_roles(group_id=group_id, roles=["bad"])
  1176. assert err.match(UNKOWN_ERROR_REGEX)
  1177. res = admin.delete_group_realm_roles(
  1178. group_id=group_id, roles=[admin.get_realm_role(role_name="offline_access")],
  1179. )
  1180. assert res == dict(), res
  1181. roles = admin.get_group_realm_roles(group_id=group_id)
  1182. assert len(roles) == 1
  1183. assert "test-realm-role-update" in [x["name"] for x in roles]
  1184. # Test composite realm roles
  1185. composite_role = admin.create_realm_role(payload={"name": "test-composite-role"})
  1186. with pytest.raises(KeycloakPostError) as err:
  1187. admin.add_composite_realm_roles_to_role(role_name=composite_role, roles=["bad"])
  1188. assert err.match(UNKOWN_ERROR_REGEX), err
  1189. res = admin.add_composite_realm_roles_to_role(
  1190. role_name=composite_role, roles=[admin.get_realm_role(role_name="test-realm-role-update")],
  1191. )
  1192. assert res == dict(), res
  1193. res = admin.get_composite_realm_roles_of_role(role_name=composite_role)
  1194. assert len(res) == 1
  1195. assert "test-realm-role-update" in res[0]["name"]
  1196. with pytest.raises(KeycloakGetError) as err:
  1197. admin.get_composite_realm_roles_of_role(role_name="bad")
  1198. assert err.match(COULD_NOT_FIND_ROLE_REGEX)
  1199. res = admin.get_composite_realm_roles_of_user(user_id=user_id)
  1200. assert len(res) == 4
  1201. assert "offline_access" in {x["name"] for x in res}
  1202. assert "test-realm-role-update" in {x["name"] for x in res}
  1203. assert "uma_authorization" in {x["name"] for x in res}
  1204. with pytest.raises(KeycloakGetError) as err:
  1205. admin.get_composite_realm_roles_of_user(user_id="bad")
  1206. assert err.match(USER_NOT_FOUND_REGEX), err
  1207. with pytest.raises(KeycloakDeleteError) as err:
  1208. admin.remove_composite_realm_roles_to_role(role_name=composite_role, roles=["bad"])
  1209. assert err.match(UNKOWN_ERROR_REGEX), err
  1210. res = admin.remove_composite_realm_roles_to_role(
  1211. role_name=composite_role, roles=[admin.get_realm_role(role_name="test-realm-role-update")],
  1212. )
  1213. assert res == dict(), res
  1214. res = admin.get_composite_realm_roles_of_role(role_name=composite_role)
  1215. assert len(res) == 0
  1216. # Test realm role group list
  1217. res = admin.get_realm_role_groups(role_name="test-realm-role-update")
  1218. assert len(res) == 1
  1219. assert res[0]["id"] == group_id
  1220. with pytest.raises(KeycloakGetError) as err:
  1221. admin.get_realm_role_groups(role_name="non-existent-role")
  1222. assert err.match(COULD_NOT_FIND_ROLE_REGEX)
  1223. # Test with query params
  1224. res = admin.get_realm_role_groups(role_name="test-realm-role-update", query={"max": 1})
  1225. assert len(res) == 1
  1226. # Test delete realm role
  1227. res = admin.delete_realm_role(role_name=composite_role)
  1228. assert res == dict(), res
  1229. with pytest.raises(KeycloakDeleteError) as err:
  1230. admin.delete_realm_role(role_name=composite_role)
  1231. assert err.match(COULD_NOT_FIND_ROLE_REGEX)
  1232. @pytest.mark.parametrize(
  1233. "testcase, arg_brief_repr, includes_attributes",
  1234. [
  1235. ("brief True", {"brief_representation": True}, False),
  1236. ("brief False", {"brief_representation": False}, True),
  1237. ("default", {}, False),
  1238. ],
  1239. )
  1240. def test_role_attributes(
  1241. admin: KeycloakAdmin,
  1242. realm: str,
  1243. client: str,
  1244. arg_brief_repr: dict,
  1245. includes_attributes: bool,
  1246. testcase: str,
  1247. ):
  1248. """Test getting role attributes for bulk calls.
  1249. :param admin: Keycloak admin
  1250. :type admin: KeycloakAdmin
  1251. :param realm: Keycloak realm
  1252. :type realm: str
  1253. :param client: Keycloak client
  1254. :type client: str
  1255. :param arg_brief_repr: Brief representation
  1256. :type arg_brief_repr: dict
  1257. :param includes_attributes: Indicator whether to include attributes
  1258. :type includes_attributes: bool
  1259. :param testcase: Test case
  1260. :type testcase: str
  1261. """
  1262. # setup
  1263. attribute_role = "test-realm-role-w-attr"
  1264. test_attrs = {"attr1": ["val1"], "attr2": ["val2-1", "val2-2"]}
  1265. role_id = admin.create_realm_role(
  1266. payload={"name": attribute_role, "attributes": test_attrs}, skip_exists=True,
  1267. )
  1268. assert role_id, role_id
  1269. cli_role_id = admin.create_client_role(
  1270. client, payload={"name": attribute_role, "attributes": test_attrs}, skip_exists=True,
  1271. )
  1272. assert cli_role_id, cli_role_id
  1273. if not includes_attributes:
  1274. test_attrs = None
  1275. # tests
  1276. roles = admin.get_realm_roles(**arg_brief_repr)
  1277. roles_filtered = [role for role in roles if role["name"] == role_id]
  1278. assert roles_filtered, roles_filtered
  1279. role = roles_filtered[0]
  1280. assert role.get("attributes") == test_attrs, testcase
  1281. roles = admin.get_client_roles(client, **arg_brief_repr)
  1282. roles_filtered = [role for role in roles if role["name"] == cli_role_id]
  1283. assert roles_filtered, roles_filtered
  1284. role = roles_filtered[0]
  1285. assert role.get("attributes") == test_attrs, testcase
  1286. # cleanup
  1287. res = admin.delete_realm_role(role_name=attribute_role)
  1288. assert res == dict(), res
  1289. res = admin.delete_client_role(client, role_name=attribute_role)
  1290. assert res == dict(), res
  1291. def test_client_scope_realm_roles(admin: KeycloakAdmin, realm: str):
  1292. """Test client realm roles.
  1293. :param admin: Keycloak admin
  1294. :type admin: KeycloakAdmin
  1295. :param realm: Keycloak realm
  1296. :type realm: str
  1297. """
  1298. admin.change_current_realm(realm)
  1299. # Test get realm roles
  1300. roles = admin.get_realm_roles()
  1301. assert len(roles) == 3, roles
  1302. role_names = [x["name"] for x in roles]
  1303. assert "uma_authorization" in role_names, role_names
  1304. assert "offline_access" in role_names, role_names
  1305. # create realm role for test
  1306. role_id = admin.create_realm_role(payload={"name": "test-realm-role"}, skip_exists=True)
  1307. assert role_id, role_id
  1308. # Test realm role client assignment
  1309. client_id = admin.create_client(
  1310. payload={"name": "role-testing-client", "clientId": "role-testing-client"},
  1311. )
  1312. with pytest.raises(KeycloakPostError) as err:
  1313. admin.assign_realm_roles_to_client_scope(client_id=client_id, roles=["bad"])
  1314. assert err.match(UNKOWN_ERROR_REGEX), err
  1315. res = admin.assign_realm_roles_to_client_scope(
  1316. client_id=client_id,
  1317. roles=[
  1318. admin.get_realm_role(role_name="offline_access"),
  1319. admin.get_realm_role(role_name="test-realm-role"),
  1320. ],
  1321. )
  1322. assert res == dict(), res
  1323. roles = admin.get_realm_roles_of_client_scope(client_id=client_id)
  1324. assert len(roles) == 2
  1325. client_role_names = [x["name"] for x in roles]
  1326. assert "offline_access" in client_role_names, client_role_names
  1327. assert "test-realm-role" in client_role_names, client_role_names
  1328. assert "uma_authorization" not in client_role_names, client_role_names
  1329. # Test remove realm role of client
  1330. with pytest.raises(KeycloakDeleteError) as err:
  1331. admin.delete_realm_roles_of_client_scope(client_id=client_id, roles=["bad"])
  1332. assert err.match(UNKOWN_ERROR_REGEX), err
  1333. res = admin.delete_realm_roles_of_client_scope(
  1334. client_id=client_id, roles=[admin.get_realm_role(role_name="offline_access")],
  1335. )
  1336. assert res == dict(), res
  1337. roles = admin.get_realm_roles_of_client_scope(client_id=client_id)
  1338. assert len(roles) == 1
  1339. assert "test-realm-role" in [x["name"] for x in roles]
  1340. res = admin.delete_realm_roles_of_client_scope(
  1341. client_id=client_id, roles=[admin.get_realm_role(role_name="test-realm-role")],
  1342. )
  1343. assert res == dict(), res
  1344. roles = admin.get_realm_roles_of_client_scope(client_id=client_id)
  1345. assert len(roles) == 0
  1346. def test_client_scope_client_roles(admin: KeycloakAdmin, realm: str, client: str):
  1347. """Test client assignment of other client roles.
  1348. :param admin: Keycloak admin
  1349. :type admin: KeycloakAdmin
  1350. :param realm: Keycloak realm
  1351. :type realm: str
  1352. :param client: Keycloak client
  1353. :type client: str
  1354. """
  1355. admin.change_current_realm(realm)
  1356. client_id = admin.create_client(
  1357. payload={"name": "role-testing-client", "clientId": "role-testing-client"},
  1358. )
  1359. # Test get client roles
  1360. roles = admin.get_client_roles_of_client_scope(client_id, client)
  1361. assert len(roles) == 0, roles
  1362. # create client role for test
  1363. client_role_id = admin.create_client_role(
  1364. client_role_id=client, payload={"name": "client-role-test"}, skip_exists=True,
  1365. )
  1366. assert client_role_id, client_role_id
  1367. # Test client role assignment to other client
  1368. with pytest.raises(KeycloakPostError) as err:
  1369. admin.assign_client_roles_to_client_scope(
  1370. client_id=client_id, client_roles_owner_id=client, roles=["bad"],
  1371. )
  1372. assert err.match(UNKOWN_ERROR_REGEX), err
  1373. res = admin.assign_client_roles_to_client_scope(
  1374. client_id=client_id,
  1375. client_roles_owner_id=client,
  1376. roles=[admin.get_client_role(client_id=client, role_name="client-role-test")],
  1377. )
  1378. assert res == dict(), res
  1379. roles = admin.get_client_roles_of_client_scope(
  1380. client_id=client_id, client_roles_owner_id=client,
  1381. )
  1382. assert len(roles) == 1
  1383. client_role_names = [x["name"] for x in roles]
  1384. assert "client-role-test" in client_role_names, client_role_names
  1385. # Test remove realm role of client
  1386. with pytest.raises(KeycloakDeleteError) as err:
  1387. admin.delete_client_roles_of_client_scope(
  1388. client_id=client_id, client_roles_owner_id=client, roles=["bad"],
  1389. )
  1390. assert err.match(UNKOWN_ERROR_REGEX), err
  1391. res = admin.delete_client_roles_of_client_scope(
  1392. client_id=client_id,
  1393. client_roles_owner_id=client,
  1394. roles=[admin.get_client_role(client_id=client, role_name="client-role-test")],
  1395. )
  1396. assert res == dict(), res
  1397. roles = admin.get_client_roles_of_client_scope(
  1398. client_id=client_id, client_roles_owner_id=client,
  1399. )
  1400. assert len(roles) == 0
  1401. def test_client_scope_mapping_client_roles(admin: KeycloakAdmin, realm: str, client: str):
  1402. """Test client scope assignment of client roles.
  1403. :param admin: Keycloak admin
  1404. :type admin: KeycloakAdmin
  1405. :param realm: Keycloak realm
  1406. :type realm: str
  1407. :param client: Keycloak client owning roles
  1408. :type client: str
  1409. """
  1410. CLIENT_ROLE_NAME = "some-client-role"
  1411. admin.change_current_realm(realm)
  1412. client_name = admin.get_client(client)["name"]
  1413. client_scope = {
  1414. "name": "test_client_scope",
  1415. "description": "Test Client Scope",
  1416. "protocol": "openid-connect",
  1417. "attributes": {},
  1418. }
  1419. client_scope_id = admin.create_client_scope(client_scope, skip_exists=False)
  1420. # Test get client roles
  1421. client_specific_roles = admin.get_client_specific_roles_of_client_scope(
  1422. client_scope_id, client,
  1423. )
  1424. assert len(client_specific_roles) == 0, client_specific_roles
  1425. all_roles = admin.get_all_roles_of_client_scope(client_scope_id)
  1426. assert len(all_roles) == 0, all_roles
  1427. # create client role for test
  1428. client_role_name = admin.create_client_role(
  1429. client_role_id=client, payload={"name": CLIENT_ROLE_NAME}, skip_exists=True,
  1430. )
  1431. assert client_role_name, client_role_name
  1432. # Test client role assignment to other client
  1433. with pytest.raises(KeycloakPostError) as err:
  1434. admin.add_client_specific_roles_to_client_scope(
  1435. client_scope_id=client_scope_id, client_roles_owner_id=client, roles=["bad"],
  1436. )
  1437. assert err.match(UNKOWN_ERROR_REGEX), err
  1438. res = admin.add_client_specific_roles_to_client_scope(
  1439. client_scope_id=client_scope_id,
  1440. client_roles_owner_id=client,
  1441. roles=[admin.get_client_role(client_id=client, role_name=CLIENT_ROLE_NAME)],
  1442. )
  1443. assert res == dict(), res
  1444. # Test when getting roles for the specific owner client
  1445. client_specific_roles = admin.get_client_specific_roles_of_client_scope(
  1446. client_scope_id=client_scope_id, client_roles_owner_id=client,
  1447. )
  1448. assert len(client_specific_roles) == 1
  1449. client_role_names = [x["name"] for x in client_specific_roles]
  1450. assert CLIENT_ROLE_NAME in client_role_names, client_role_names
  1451. # Test when getting all roles for the client scope
  1452. all_roles = admin.get_all_roles_of_client_scope(client_scope_id=client_scope_id)
  1453. assert "clientMappings" in all_roles, all_roles
  1454. all_roles_clients = all_roles["clientMappings"]
  1455. assert client_name in all_roles_clients, all_roles_clients
  1456. mappings = all_roles_clients[client_name]["mappings"]
  1457. client_role_names = [x["name"] for x in mappings]
  1458. assert CLIENT_ROLE_NAME in client_role_names, client_role_names
  1459. # Test remove realm role of client
  1460. with pytest.raises(KeycloakDeleteError) as err:
  1461. admin.remove_client_specific_roles_of_client_scope(
  1462. client_scope_id=client_scope_id, client_roles_owner_id=client, roles=["bad"],
  1463. )
  1464. assert err.match(UNKOWN_ERROR_REGEX), err
  1465. res = admin.remove_client_specific_roles_of_client_scope(
  1466. client_scope_id=client_scope_id,
  1467. client_roles_owner_id=client,
  1468. roles=[admin.get_client_role(client_id=client, role_name=CLIENT_ROLE_NAME)],
  1469. )
  1470. assert res == dict(), res
  1471. all_roles = admin.get_all_roles_of_client_scope(client_scope_id=client_scope_id)
  1472. assert len(all_roles) == 0
  1473. def test_client_default_client_scopes(admin: KeycloakAdmin, realm: str, client: str):
  1474. """Test client assignment of default client scopes.
  1475. :param admin: Keycloak admin
  1476. :type admin: KeycloakAdmin
  1477. :param realm: Keycloak realm
  1478. :type realm: str
  1479. :param client: Keycloak client
  1480. :type client: str
  1481. """
  1482. admin.change_current_realm(realm)
  1483. client_id = admin.create_client(
  1484. payload={"name": "role-testing-client", "clientId": "role-testing-client"},
  1485. )
  1486. # Test get client default scopes
  1487. # keycloak default roles: web-origins, acr, profile, roles, email
  1488. default_client_scopes = admin.get_client_default_client_scopes(client_id)
  1489. assert len(default_client_scopes) in [6, 5], default_client_scopes
  1490. # Test add a client scope to client default scopes
  1491. default_client_scope = "test-client-default-scope"
  1492. new_client_scope = {
  1493. "name": default_client_scope,
  1494. "description": f"Test Client Scope: {default_client_scope}",
  1495. "protocol": "openid-connect",
  1496. "attributes": {},
  1497. }
  1498. new_client_scope_id = admin.create_client_scope(new_client_scope, skip_exists=False)
  1499. new_default_client_scope_data = {
  1500. "realm": realm,
  1501. "client": client_id,
  1502. "clientScopeId": new_client_scope_id,
  1503. }
  1504. admin.add_client_default_client_scope(
  1505. client_id, new_client_scope_id, new_default_client_scope_data,
  1506. )
  1507. default_client_scopes = admin.get_client_default_client_scopes(client_id)
  1508. assert len(default_client_scopes) in [6, 7], default_client_scopes
  1509. # Test remove a client default scope
  1510. admin.delete_client_default_client_scope(client_id, new_client_scope_id)
  1511. default_client_scopes = admin.get_client_default_client_scopes(client_id)
  1512. assert len(default_client_scopes) in [5, 6], default_client_scopes
  1513. def test_client_optional_client_scopes(admin: KeycloakAdmin, realm: str, client: str):
  1514. """Test client assignment of optional client scopes.
  1515. :param admin: Keycloak admin
  1516. :type admin: KeycloakAdmin
  1517. :param realm: Keycloak realm
  1518. :type realm: str
  1519. :param client: Keycloak client
  1520. :type client: str
  1521. """
  1522. admin.change_current_realm(realm)
  1523. client_id = admin.create_client(
  1524. payload={"name": "role-testing-client", "clientId": "role-testing-client"},
  1525. )
  1526. # Test get client optional scopes
  1527. # keycloak optional roles: microprofile-jwt, offline_access, address, --> for versions < 26.0.0
  1528. # starting with Keycloak version 26.0.0 a new optional role is added: organization
  1529. optional_client_scopes = admin.get_client_optional_client_scopes(client_id)
  1530. assert len(optional_client_scopes) in [4, 5], optional_client_scopes
  1531. # Test add a client scope to client optional scopes
  1532. optional_client_scope = "test-client-optional-scope"
  1533. new_client_scope = {
  1534. "name": optional_client_scope,
  1535. "description": f"Test Client Scope: {optional_client_scope}",
  1536. "protocol": "openid-connect",
  1537. "attributes": {},
  1538. }
  1539. new_client_scope_id = admin.create_client_scope(new_client_scope, skip_exists=False)
  1540. new_optional_client_scope_data = {
  1541. "realm": realm,
  1542. "client": client_id,
  1543. "clientScopeId": new_client_scope_id,
  1544. }
  1545. admin.add_client_optional_client_scope(
  1546. client_id, new_client_scope_id, new_optional_client_scope_data,
  1547. )
  1548. optional_client_scopes = admin.get_client_optional_client_scopes(client_id)
  1549. assert len(optional_client_scopes) in [5, 6], optional_client_scopes
  1550. # Test remove a client optional scope
  1551. admin.delete_client_optional_client_scope(client_id, new_client_scope_id)
  1552. optional_client_scopes = admin.get_client_optional_client_scopes(client_id)
  1553. assert len(optional_client_scopes) in [4, 5], optional_client_scopes
  1554. def test_client_roles(admin: KeycloakAdmin, client: str):
  1555. """Test client roles.
  1556. :param admin: Keycloak Admin client
  1557. :type admin: KeycloakAdmin
  1558. :param client: Keycloak client
  1559. :type client: str
  1560. """
  1561. # Test get client roles
  1562. res = admin.get_client_roles(client_id=client)
  1563. assert len(res) == 0
  1564. with pytest.raises(KeycloakGetError) as err:
  1565. admin.get_client_roles(client_id="bad")
  1566. assert err.match('404: b\'{"error":"Could not find client".*}\'')
  1567. # Test create client role
  1568. client_role_id = admin.create_client_role(
  1569. client_role_id=client, payload={"name": "client-role-test"}, skip_exists=True,
  1570. )
  1571. with pytest.raises(KeycloakPostError) as err:
  1572. admin.create_client_role(client_role_id=client, payload={"name": "client-role-test"})
  1573. assert err.match('409: b\'{"errorMessage":"Role with name client-role-test already exists"}\'')
  1574. client_role_id_2 = admin.create_client_role(
  1575. client_role_id=client, payload={"name": "client-role-test"}, skip_exists=True,
  1576. )
  1577. assert client_role_id == client_role_id_2
  1578. # Test get client role
  1579. res = admin.get_client_role(client_id=client, role_name="client-role-test")
  1580. assert res["name"] == client_role_id
  1581. with pytest.raises(KeycloakGetError) as err:
  1582. admin.get_client_role(client_id=client, role_name="bad")
  1583. assert err.match(COULD_NOT_FIND_ROLE_REGEX)
  1584. res_ = admin.get_client_role_id(client_id=client, role_name="client-role-test")
  1585. assert res_ == res["id"]
  1586. with pytest.raises(KeycloakGetError) as err:
  1587. admin.get_client_role_id(client_id=client, role_name="bad")
  1588. assert err.match(COULD_NOT_FIND_ROLE_REGEX)
  1589. assert len(admin.get_client_roles(client_id=client)) == 1
  1590. # Test update client role
  1591. res = admin.update_client_role(
  1592. client_id=client, role_name="client-role-test", payload={"name": "client-role-test-update"},
  1593. )
  1594. assert res == dict()
  1595. with pytest.raises(KeycloakPutError) as err:
  1596. res = admin.update_client_role(
  1597. client_id=client,
  1598. role_name="client-role-test",
  1599. payload={"name": "client-role-test-update"},
  1600. )
  1601. assert err.match(COULD_NOT_FIND_ROLE_REGEX)
  1602. # Test user with client role
  1603. res = admin.get_client_role_members(client_id=client, role_name="client-role-test-update")
  1604. assert len(res) == 0
  1605. with pytest.raises(KeycloakGetError) as err:
  1606. admin.get_client_role_members(client_id=client, role_name="bad")
  1607. assert err.match(COULD_NOT_FIND_ROLE_REGEX)
  1608. user_id = admin.create_user(payload={"username": "test", "email": "test@test.test"})
  1609. with pytest.raises(KeycloakPostError) as err:
  1610. admin.assign_client_role(user_id=user_id, client_id=client, roles=["bad"])
  1611. assert err.match(UNKOWN_ERROR_REGEX), err
  1612. res = admin.assign_client_role(
  1613. user_id=user_id,
  1614. client_id=client,
  1615. roles=[admin.get_client_role(client_id=client, role_name="client-role-test-update")],
  1616. )
  1617. assert res == dict()
  1618. assert (
  1619. len(admin.get_client_role_members(client_id=client, role_name="client-role-test-update"))
  1620. == 1
  1621. )
  1622. roles = admin.get_client_roles_of_user(user_id=user_id, client_id=client)
  1623. assert len(roles) == 1, roles
  1624. with pytest.raises(KeycloakGetError) as err:
  1625. admin.get_client_roles_of_user(user_id=user_id, client_id="bad")
  1626. assert err.match(CLIENT_NOT_FOUND_REGEX)
  1627. roles = admin.get_composite_client_roles_of_user(user_id=user_id, client_id=client)
  1628. assert len(roles) == 1, roles
  1629. with pytest.raises(KeycloakGetError) as err:
  1630. admin.get_composite_client_roles_of_user(user_id=user_id, client_id="bad")
  1631. assert err.match(CLIENT_NOT_FOUND_REGEX)
  1632. roles = admin.get_available_client_roles_of_user(user_id=user_id, client_id=client)
  1633. assert len(roles) == 0, roles
  1634. with pytest.raises(KeycloakGetError) as err:
  1635. admin.get_composite_client_roles_of_user(user_id=user_id, client_id="bad")
  1636. assert err.match(CLIENT_NOT_FOUND_REGEX)
  1637. with pytest.raises(KeycloakDeleteError) as err:
  1638. admin.delete_client_roles_of_user(user_id=user_id, client_id=client, roles=["bad"])
  1639. assert err.match(UNKOWN_ERROR_REGEX), err
  1640. admin.delete_client_roles_of_user(
  1641. user_id=user_id,
  1642. client_id=client,
  1643. roles=[admin.get_client_role(client_id=client, role_name="client-role-test-update")],
  1644. )
  1645. assert len(admin.get_client_roles_of_user(user_id=user_id, client_id=client)) == 0
  1646. # Test groups and client roles
  1647. res = admin.get_client_role_groups(client_id=client, role_name="client-role-test-update")
  1648. assert len(res) == 0
  1649. with pytest.raises(KeycloakGetError) as err:
  1650. admin.get_client_role_groups(client_id=client, role_name="bad")
  1651. assert err.match(COULD_NOT_FIND_ROLE_REGEX)
  1652. group_id = admin.create_group(payload={"name": "test-group"})
  1653. res = admin.get_group_client_roles(group_id=group_id, client_id=client)
  1654. assert len(res) == 0
  1655. with pytest.raises(KeycloakGetError) as err:
  1656. admin.get_group_client_roles(group_id=group_id, client_id="bad")
  1657. assert err.match(CLIENT_NOT_FOUND_REGEX)
  1658. with pytest.raises(KeycloakPostError) as err:
  1659. admin.assign_group_client_roles(group_id=group_id, client_id=client, roles=["bad"])
  1660. assert err.match(UNKOWN_ERROR_REGEX), err
  1661. res = admin.assign_group_client_roles(
  1662. group_id=group_id,
  1663. client_id=client,
  1664. roles=[admin.get_client_role(client_id=client, role_name="client-role-test-update")],
  1665. )
  1666. assert res == dict()
  1667. assert (
  1668. len(admin.get_client_role_groups(client_id=client, role_name="client-role-test-update"))
  1669. == 1
  1670. )
  1671. assert len(admin.get_group_client_roles(group_id=group_id, client_id=client)) == 1
  1672. with pytest.raises(KeycloakDeleteError) as err:
  1673. admin.delete_group_client_roles(group_id=group_id, client_id=client, roles=["bad"])
  1674. assert err.match(UNKOWN_ERROR_REGEX), err
  1675. res = admin.delete_group_client_roles(
  1676. group_id=group_id,
  1677. client_id=client,
  1678. roles=[admin.get_client_role(client_id=client, role_name="client-role-test-update")],
  1679. )
  1680. assert res == dict()
  1681. # Test composite client roles
  1682. with pytest.raises(KeycloakPostError) as err:
  1683. admin.add_composite_client_roles_to_role(
  1684. client_role_id=client, role_name="client-role-test-update", roles=["bad"],
  1685. )
  1686. assert err.match(UNKOWN_ERROR_REGEX), err
  1687. res = admin.add_composite_client_roles_to_role(
  1688. client_role_id=client,
  1689. role_name="client-role-test-update",
  1690. roles=[admin.get_realm_role(role_name="offline_access")],
  1691. )
  1692. assert res == dict()
  1693. assert admin.get_client_role(client_id=client, role_name="client-role-test-update")[
  1694. "composite"
  1695. ]
  1696. # Test removal of composite client roles
  1697. with pytest.raises(KeycloakDeleteError) as err:
  1698. admin.remove_composite_client_roles_from_role(
  1699. client_role_id=client, role_name="client-role-test-update", roles=["bad"],
  1700. )
  1701. assert err.match(UNKOWN_ERROR_REGEX), err
  1702. res = admin.remove_composite_client_roles_from_role(
  1703. client_role_id=client,
  1704. role_name="client-role-test-update",
  1705. roles=[admin.get_realm_role(role_name="offline_access")],
  1706. )
  1707. assert res == dict()
  1708. assert not admin.get_client_role(client_id=client, role_name="client-role-test-update")[
  1709. "composite"
  1710. ]
  1711. # Test delete of client role
  1712. res = admin.delete_client_role(client_role_id=client, role_name="client-role-test-update")
  1713. assert res == dict()
  1714. with pytest.raises(KeycloakDeleteError) as err:
  1715. admin.delete_client_role(client_role_id=client, role_name="client-role-test-update")
  1716. assert err.match(COULD_NOT_FIND_ROLE_REGEX)
  1717. # Test of roles by id - Get role
  1718. admin.create_client_role(
  1719. client_role_id=client, payload={"name": "client-role-by-id-test"}, skip_exists=True,
  1720. )
  1721. role = admin.get_client_role(client_id=client, role_name="client-role-by-id-test")
  1722. res = admin.get_role_by_id(role_id=role["id"])
  1723. assert res["name"] == "client-role-by-id-test"
  1724. with pytest.raises(KeycloakGetError) as err:
  1725. admin.get_role_by_id(role_id="bad")
  1726. assert err.match(COULD_NOT_FIND_ROLE_WITH_ID_REGEX)
  1727. # Test of roles by id - Update role
  1728. res = admin.update_role_by_id(
  1729. role_id=role["id"], payload={"name": "client-role-by-id-test-update"},
  1730. )
  1731. assert res == dict()
  1732. with pytest.raises(KeycloakPutError) as err:
  1733. res = admin.update_role_by_id(
  1734. role_id="bad", payload={"name": "client-role-by-id-test-update"},
  1735. )
  1736. assert err.match(COULD_NOT_FIND_ROLE_WITH_ID_REGEX)
  1737. # Test of roles by id - Delete role
  1738. res = admin.delete_role_by_id(role_id=role["id"])
  1739. assert res == dict()
  1740. with pytest.raises(KeycloakDeleteError) as err:
  1741. admin.delete_role_by_id(role_id="bad")
  1742. assert err.match(COULD_NOT_FIND_ROLE_WITH_ID_REGEX)
  1743. def test_enable_token_exchange(admin: KeycloakAdmin, realm: str):
  1744. """Test enable token exchange.
  1745. :param admin: Keycloak Admin client
  1746. :type admin: KeycloakAdmin
  1747. :param realm: Keycloak realm
  1748. :type realm: str
  1749. :raises AssertionError: In case of bad configuration
  1750. """
  1751. # Test enabling token exchange between two confidential clients
  1752. admin.change_current_realm(realm)
  1753. # Create test clients
  1754. source_client_id = admin.create_client(
  1755. payload={"name": "Source Client", "clientId": "source-client"},
  1756. )
  1757. target_client_id = admin.create_client(
  1758. payload={"name": "Target Client", "clientId": "target-client"},
  1759. )
  1760. for c in admin.get_clients():
  1761. if c["clientId"] == "realm-management":
  1762. realm_management_id = c["id"]
  1763. break
  1764. else:
  1765. raise AssertionError("Missing realm management client")
  1766. # Enable permissions on the Superset client
  1767. admin.update_client_management_permissions(
  1768. payload={"enabled": True}, client_id=target_client_id,
  1769. )
  1770. # Fetch various IDs and strings needed when creating the permission
  1771. token_exchange_permission_id = admin.get_client_management_permissions(
  1772. client_id=target_client_id,
  1773. )["scopePermissions"]["token-exchange"]
  1774. scopes = admin.get_client_authz_policy_scopes(
  1775. client_id=realm_management_id, policy_id=token_exchange_permission_id,
  1776. )
  1777. for s in scopes:
  1778. if s["name"] == "token-exchange":
  1779. token_exchange_scope_id = s["id"]
  1780. break
  1781. else:
  1782. raise AssertionError("Missing token-exchange scope")
  1783. resources = admin.get_client_authz_policy_resources(
  1784. client_id=realm_management_id, policy_id=token_exchange_permission_id,
  1785. )
  1786. for r in resources:
  1787. if r["name"] == f"client.resource.{target_client_id}":
  1788. token_exchange_resource_id = r["_id"]
  1789. break
  1790. else:
  1791. raise AssertionError("Missing client resource")
  1792. # Create a client policy for source client
  1793. policy_name = "Exchange source client token with target client token"
  1794. client_policy_id = admin.create_client_authz_client_policy(
  1795. payload={
  1796. "type": "client",
  1797. "logic": "POSITIVE",
  1798. "decisionStrategy": "UNANIMOUS",
  1799. "name": policy_name,
  1800. "clients": [source_client_id],
  1801. },
  1802. client_id=realm_management_id,
  1803. )["id"]
  1804. policies = admin.get_client_authz_client_policies(client_id=realm_management_id)
  1805. for policy in policies:
  1806. if policy["name"] == policy_name:
  1807. assert policy["clients"] == [source_client_id]
  1808. break
  1809. else:
  1810. raise AssertionError("Missing client policy")
  1811. # Update permissions on the target client to reference this policy
  1812. permission_name = admin.get_client_authz_scope_permission(
  1813. client_id=realm_management_id, scope_id=token_exchange_permission_id,
  1814. )["name"]
  1815. admin.update_client_authz_scope_permission(
  1816. payload={
  1817. "id": token_exchange_permission_id,
  1818. "name": permission_name,
  1819. "type": "scope",
  1820. "logic": "POSITIVE",
  1821. "decisionStrategy": "UNANIMOUS",
  1822. "resources": [token_exchange_resource_id],
  1823. "scopes": [token_exchange_scope_id],
  1824. "policies": [client_policy_id],
  1825. },
  1826. client_id=realm_management_id,
  1827. scope_id=token_exchange_permission_id,
  1828. )
  1829. # Create permissions on the target client to reference this policy
  1830. admin.create_client_authz_scope_permission(
  1831. payload={
  1832. "id": "some-id",
  1833. "name": "test-permission",
  1834. "type": "scope",
  1835. "logic": "POSITIVE",
  1836. "decisionStrategy": "UNANIMOUS",
  1837. "resources": [token_exchange_resource_id],
  1838. "scopes": [token_exchange_scope_id],
  1839. "policies": [client_policy_id],
  1840. },
  1841. client_id=realm_management_id,
  1842. )
  1843. permission_name = admin.get_client_authz_scope_permission(
  1844. client_id=realm_management_id, scope_id=token_exchange_permission_id,
  1845. )["name"]
  1846. assert permission_name.startswith("token-exchange.permission.client.")
  1847. with pytest.raises(KeycloakPostError) as err:
  1848. admin.create_client_authz_scope_permission(
  1849. payload={"name": "test-permission", "scopes": [token_exchange_scope_id]},
  1850. client_id="realm_management_id",
  1851. )
  1852. assert err.match('404: b\'{"error":"Could not find client".*}\'')
  1853. def test_email(admin: KeycloakAdmin, user: str):
  1854. """Test email.
  1855. :param admin: Keycloak Admin client
  1856. :type admin: KeycloakAdmin
  1857. :param user: Keycloak user
  1858. :type user: str
  1859. """
  1860. # Emails will fail as we don't have SMTP test setup
  1861. with pytest.raises(KeycloakPutError) as err:
  1862. admin.send_update_account(user_id=user, payload=dict())
  1863. assert err.match(UNKOWN_ERROR_REGEX), err
  1864. admin.update_user(user_id=user, payload={"enabled": True})
  1865. with pytest.raises(KeycloakPutError) as err:
  1866. admin.send_verify_email(user_id=user)
  1867. assert err.match('500: b\'{"errorMessage":"Failed to send .*"}\'')
  1868. def test_get_sessions(admin: KeycloakAdmin):
  1869. """Test get sessions.
  1870. :param admin: Keycloak Admin client
  1871. :type admin: KeycloakAdmin
  1872. """
  1873. sessions = admin.get_sessions(user_id=admin.get_user_id(username=admin.connection.username))
  1874. assert len(sessions) >= 1
  1875. with pytest.raises(KeycloakGetError) as err:
  1876. admin.get_sessions(user_id="bad")
  1877. assert err.match(USER_NOT_FOUND_REGEX)
  1878. def test_get_client_installation_provider(admin: KeycloakAdmin, client: str):
  1879. """Test get client installation provider.
  1880. :param admin: Keycloak Admin client
  1881. :type admin: KeycloakAdmin
  1882. :param client: Keycloak client
  1883. :type client: str
  1884. """
  1885. with pytest.raises(KeycloakGetError) as err:
  1886. admin.get_client_installation_provider(client_id=client, provider_id="bad")
  1887. assert err.match('404: b\'{"error":"Unknown Provider".*}\'')
  1888. installation = admin.get_client_installation_provider(
  1889. client_id=client, provider_id="keycloak-oidc-keycloak-json",
  1890. )
  1891. assert set(installation.keys()) == {
  1892. "auth-server-url",
  1893. "confidential-port",
  1894. "credentials",
  1895. "realm",
  1896. "resource",
  1897. "ssl-required",
  1898. }
  1899. def test_auth_flows(admin: KeycloakAdmin, realm: str):
  1900. """Test auth flows.
  1901. :param admin: Keycloak Admin client
  1902. :type admin: KeycloakAdmin
  1903. :param realm: Keycloak realm
  1904. :type realm: str
  1905. """
  1906. admin.change_current_realm(realm)
  1907. res = admin.get_authentication_flows()
  1908. assert len(res) <= 8, res
  1909. default_flows = len(res)
  1910. assert {x["alias"] for x in res}.issubset(
  1911. {
  1912. "reset credentials",
  1913. "browser",
  1914. "registration",
  1915. "http challenge",
  1916. "docker auth",
  1917. "direct grant",
  1918. "first broker login",
  1919. "clients",
  1920. },
  1921. )
  1922. assert set(res[0].keys()) == {
  1923. "alias",
  1924. "authenticationExecutions",
  1925. "builtIn",
  1926. "description",
  1927. "id",
  1928. "providerId",
  1929. "topLevel",
  1930. }
  1931. assert {x["alias"] for x in res}.issubset(
  1932. {
  1933. "reset credentials",
  1934. "browser",
  1935. "registration",
  1936. "docker auth",
  1937. "direct grant",
  1938. "first broker login",
  1939. "clients",
  1940. "http challenge",
  1941. },
  1942. )
  1943. with pytest.raises(KeycloakGetError) as err:
  1944. admin.get_authentication_flow_for_id(flow_id="bad")
  1945. assert err.match('404: b\'{"error":"Could not find flow with id".*}\'')
  1946. browser_flow_id = [x for x in res if x["alias"] == "browser"][0]["id"]
  1947. res = admin.get_authentication_flow_for_id(flow_id=browser_flow_id)
  1948. assert res["alias"] == "browser"
  1949. # Test copying
  1950. with pytest.raises(KeycloakPostError) as err:
  1951. admin.copy_authentication_flow(payload=dict(), flow_alias="bad")
  1952. assert ('b\'{"error":"Flow not found"' in str(err)) or err.match("404: b''")
  1953. res = admin.copy_authentication_flow(payload={"newName": "test-browser"}, flow_alias="browser")
  1954. assert res == b"", res
  1955. assert len(admin.get_authentication_flows()) == (default_flows + 1)
  1956. # Test create
  1957. res = admin.create_authentication_flow(
  1958. payload={"alias": "test-create", "providerId": "basic-flow"},
  1959. )
  1960. assert res == b""
  1961. with pytest.raises(KeycloakPostError) as err:
  1962. admin.create_authentication_flow(payload={"alias": "test-create", "builtIn": False})
  1963. assert err.match('409: b\'{"errorMessage":"Flow test-create already exists"}\'')
  1964. assert admin.create_authentication_flow(
  1965. payload={"alias": "test-create"}, skip_exists=True,
  1966. ) == {"msg": "Already exists"}
  1967. # Test flow executions
  1968. res = admin.get_authentication_flow_executions(flow_alias="browser")
  1969. assert len(res) in [8, 12], res
  1970. with pytest.raises(KeycloakGetError) as err:
  1971. admin.get_authentication_flow_executions(flow_alias="bad")
  1972. assert ('b\'{"error":"Flow not found"' in str(err)) or err.match("404: b''")
  1973. exec_id = res[0]["id"]
  1974. res = admin.get_authentication_flow_execution(execution_id=exec_id)
  1975. assert set(res.keys()).issubset(
  1976. {
  1977. "alternative",
  1978. "authenticator",
  1979. "authenticatorFlow",
  1980. "autheticatorFlow",
  1981. "conditional",
  1982. "disabled",
  1983. "enabled",
  1984. "id",
  1985. "parentFlow",
  1986. "priority",
  1987. "required",
  1988. "requirement",
  1989. },
  1990. ), res.keys()
  1991. with pytest.raises(KeycloakGetError) as err:
  1992. admin.get_authentication_flow_execution(execution_id="bad")
  1993. assert err.match(ILLEGAL_EXECUTION_REGEX)
  1994. with pytest.raises(KeycloakPostError) as err:
  1995. admin.create_authentication_flow_execution(payload=dict(), flow_alias="browser")
  1996. assert err.match('400: b\'{"error":"It is illegal to add execution to a built in flow".*}\'')
  1997. res = admin.create_authentication_flow_execution(
  1998. payload={"provider": "auth-cookie"}, flow_alias="test-create",
  1999. )
  2000. assert res == b""
  2001. assert len(admin.get_authentication_flow_executions(flow_alias="test-create")) == 1
  2002. with pytest.raises(KeycloakPutError) as err:
  2003. admin.update_authentication_flow_executions(
  2004. payload={"required": "yes"}, flow_alias="test-create",
  2005. )
  2006. assert err.match("Unrecognized field")
  2007. payload = admin.get_authentication_flow_executions(flow_alias="test-create")[0]
  2008. payload["displayName"] = "test"
  2009. res = admin.update_authentication_flow_executions(payload=payload, flow_alias="test-create")
  2010. assert res or (res == {})
  2011. exec_id = admin.get_authentication_flow_executions(flow_alias="test-create")[0]["id"]
  2012. res = admin.delete_authentication_flow_execution(execution_id=exec_id)
  2013. assert res == dict()
  2014. with pytest.raises(KeycloakDeleteError) as err:
  2015. admin.delete_authentication_flow_execution(execution_id=exec_id)
  2016. assert err.match(ILLEGAL_EXECUTION_REGEX)
  2017. # Test subflows
  2018. res = admin.create_authentication_flow_subflow(
  2019. payload={
  2020. "alias": "test-subflow",
  2021. "provider": "basic-flow",
  2022. "type": "something",
  2023. "description": "something",
  2024. },
  2025. flow_alias="test-browser",
  2026. )
  2027. assert res == b""
  2028. with pytest.raises(KeycloakPostError) as err:
  2029. admin.create_authentication_flow_subflow(
  2030. payload={"alias": "test-subflow", "providerId": "basic-flow"},
  2031. flow_alias="test-browser",
  2032. )
  2033. assert err.match('409: b\'{"errorMessage":"New flow alias name already exists"}\'')
  2034. res = admin.create_authentication_flow_subflow(
  2035. payload={
  2036. "alias": "test-subflow",
  2037. "provider": "basic-flow",
  2038. "type": "something",
  2039. "description": "something",
  2040. },
  2041. flow_alias="test-create",
  2042. skip_exists=True,
  2043. )
  2044. assert res == {"msg": "Already exists"}
  2045. # Test delete auth flow
  2046. flow_id = [x for x in admin.get_authentication_flows() if x["alias"] == "test-browser"][0][
  2047. "id"
  2048. ]
  2049. res = admin.delete_authentication_flow(flow_id=flow_id)
  2050. assert res == dict()
  2051. with pytest.raises(KeycloakDeleteError) as err:
  2052. admin.delete_authentication_flow(flow_id=flow_id)
  2053. assert ('b\'{"error":"Could not find flow with id"' in str(err)) or (
  2054. 'b\'{"error":"Flow not found"' in str(err)
  2055. )
  2056. def test_authentication_configs(admin: KeycloakAdmin, realm: str):
  2057. """Test authentication configs.
  2058. :param admin: Keycloak Admin client
  2059. :type admin: KeycloakAdmin
  2060. :param realm: Keycloak realm
  2061. :type realm: str
  2062. """
  2063. admin.change_current_realm(realm)
  2064. # Test list of auth providers
  2065. res = admin.get_authenticator_providers()
  2066. assert len(res) <= 38
  2067. res = admin.get_authenticator_provider_config_description(provider_id="auth-cookie")
  2068. assert res == {
  2069. "helpText": "Validates the SSO cookie set by the auth server.",
  2070. "name": "Cookie",
  2071. "properties": [],
  2072. "providerId": "auth-cookie",
  2073. }
  2074. # Test authenticator config
  2075. # Currently unable to find a sustainable way to fetch the config id,
  2076. # therefore testing only failures
  2077. with pytest.raises(KeycloakGetError) as err:
  2078. admin.get_authenticator_config(config_id="bad")
  2079. assert err.match('404: b\'{"error":"Could not find authenticator config".*}\'')
  2080. with pytest.raises(KeycloakPutError) as err:
  2081. admin.update_authenticator_config(payload=dict(), config_id="bad")
  2082. assert err.match('404: b\'{"error":"Could not find authenticator config".*}\'')
  2083. with pytest.raises(KeycloakDeleteError) as err:
  2084. admin.delete_authenticator_config(config_id="bad")
  2085. assert err.match('404: b\'{"error":"Could not find authenticator config".*}\'')
  2086. def test_sync_users(admin: KeycloakAdmin, realm: str):
  2087. """Test sync users.
  2088. :param admin: Keycloak Admin client
  2089. :type admin: KeycloakAdmin
  2090. :param realm: Keycloak realm
  2091. :type realm: str
  2092. """
  2093. admin.change_current_realm(realm)
  2094. # Only testing the error message
  2095. with pytest.raises(KeycloakPostError) as err:
  2096. admin.sync_users(storage_id="does-not-exist", action="triggerFullSync")
  2097. assert err.match('404: b\'{"error":"Could not find component".*}\'')
  2098. def test_client_scopes(admin: KeycloakAdmin, realm: str):
  2099. """Test client scopes.
  2100. :param admin: Keycloak Admin client
  2101. :type admin: KeycloakAdmin
  2102. :param realm: Keycloak realm
  2103. :type realm: str
  2104. """
  2105. admin.change_current_realm(realm)
  2106. # Test get client scopes
  2107. res = admin.get_client_scopes()
  2108. scope_names = {x["name"] for x in res}
  2109. assert len(res) in [10, 11, 13]
  2110. assert "email" in scope_names
  2111. assert "profile" in scope_names
  2112. assert "offline_access" in scope_names
  2113. with pytest.raises(KeycloakGetError) as err:
  2114. admin.get_client_scope(client_scope_id="does-not-exist")
  2115. assert err.match(NO_CLIENT_SCOPE_REGEX)
  2116. scope = admin.get_client_scope(client_scope_id=res[0]["id"])
  2117. assert res[0] == scope
  2118. scope = admin.get_client_scope_by_name(client_scope_name=res[0]["name"])
  2119. assert res[0] == scope
  2120. # Test create client scope
  2121. res = admin.create_client_scope(
  2122. payload={"name": "test-scope", "protocol": "openid-connect"}, skip_exists=True,
  2123. )
  2124. assert res
  2125. res2 = admin.create_client_scope(
  2126. payload={"name": "test-scope", "protocol": "openid-connect"}, skip_exists=True,
  2127. )
  2128. assert res == res2
  2129. with pytest.raises(KeycloakPostError) as err:
  2130. admin.create_client_scope(
  2131. payload={"name": "test-scope", "protocol": "openid-connect"}, skip_exists=False,
  2132. )
  2133. assert err.match('409: b\'{"errorMessage":"Client Scope test-scope already exists"}\'')
  2134. # Test update client scope
  2135. with pytest.raises(KeycloakPutError) as err:
  2136. admin.update_client_scope(client_scope_id="does-not-exist", payload=dict())
  2137. assert err.match(NO_CLIENT_SCOPE_REGEX)
  2138. res_update = admin.update_client_scope(
  2139. client_scope_id=res, payload={"name": "test-scope-update"},
  2140. )
  2141. assert res_update == dict()
  2142. assert admin.get_client_scope(client_scope_id=res)["name"] == "test-scope-update"
  2143. # Test get mappers
  2144. mappers = admin.get_mappers_from_client_scope(client_scope_id=res)
  2145. assert mappers == list()
  2146. # Test add mapper
  2147. with pytest.raises(KeycloakPostError) as err:
  2148. admin.add_mapper_to_client_scope(client_scope_id=res, payload=dict())
  2149. assert err.match('404: b\'{"error":"ProtocolMapper provider not found".*}\'')
  2150. res_add = admin.add_mapper_to_client_scope(
  2151. client_scope_id=res,
  2152. payload={
  2153. "name": "test-mapper",
  2154. "protocol": "openid-connect",
  2155. "protocolMapper": "oidc-usermodel-attribute-mapper",
  2156. },
  2157. )
  2158. assert res_add == b""
  2159. assert len(admin.get_mappers_from_client_scope(client_scope_id=res)) == 1
  2160. # Test update mapper
  2161. test_mapper = admin.get_mappers_from_client_scope(client_scope_id=res)[0]
  2162. with pytest.raises(KeycloakPutError) as err:
  2163. admin.update_mapper_in_client_scope(
  2164. client_scope_id="does-not-exist", protocol_mapper_id=test_mapper["id"], payload=dict(),
  2165. )
  2166. assert err.match(NO_CLIENT_SCOPE_REGEX)
  2167. test_mapper["config"]["user.attribute"] = "test"
  2168. res_update = admin.update_mapper_in_client_scope(
  2169. client_scope_id=res, protocol_mapper_id=test_mapper["id"], payload=test_mapper,
  2170. )
  2171. assert res_update == dict()
  2172. assert (
  2173. admin.get_mappers_from_client_scope(client_scope_id=res)[0]["config"]["user.attribute"]
  2174. == "test"
  2175. )
  2176. # Test delete mapper
  2177. res_del = admin.delete_mapper_from_client_scope(
  2178. client_scope_id=res, protocol_mapper_id=test_mapper["id"],
  2179. )
  2180. assert res_del == dict()
  2181. with pytest.raises(KeycloakDeleteError) as err:
  2182. admin.delete_mapper_from_client_scope(
  2183. client_scope_id=res, protocol_mapper_id=test_mapper["id"],
  2184. )
  2185. assert err.match('404: b\'{"error":"Model not found".*}\'')
  2186. # Test default default scopes
  2187. res_defaults = admin.get_default_default_client_scopes()
  2188. assert len(res_defaults) in [6, 7, 8]
  2189. with pytest.raises(KeycloakPutError) as err:
  2190. admin.add_default_default_client_scope(scope_id="does-not-exist")
  2191. assert err.match(CLIENT_SCOPE_NOT_FOUND_REGEX)
  2192. res_add = admin.add_default_default_client_scope(scope_id=res)
  2193. assert res_add == dict()
  2194. assert len(admin.get_default_default_client_scopes()) in [7, 8, 9]
  2195. with pytest.raises(KeycloakDeleteError) as err:
  2196. admin.delete_default_default_client_scope(scope_id="does-not-exist")
  2197. assert err.match(CLIENT_SCOPE_NOT_FOUND_REGEX)
  2198. res_del = admin.delete_default_default_client_scope(scope_id=res)
  2199. assert res_del == dict()
  2200. assert len(admin.get_default_default_client_scopes()) in [6, 7, 8]
  2201. # Test default optional scopes
  2202. res_defaults = admin.get_default_optional_client_scopes()
  2203. assert len(res_defaults) in [4, 5]
  2204. with pytest.raises(KeycloakPutError) as err:
  2205. admin.add_default_optional_client_scope(scope_id="does-not-exist")
  2206. assert err.match(CLIENT_SCOPE_NOT_FOUND_REGEX)
  2207. res_add = admin.add_default_optional_client_scope(scope_id=res)
  2208. assert res_add == dict()
  2209. assert len(admin.get_default_optional_client_scopes()) in [5, 6]
  2210. with pytest.raises(KeycloakDeleteError) as err:
  2211. admin.delete_default_optional_client_scope(scope_id="does-not-exist")
  2212. assert err.match(CLIENT_SCOPE_NOT_FOUND_REGEX)
  2213. res_del = admin.delete_default_optional_client_scope(scope_id=res)
  2214. assert res_del == dict()
  2215. assert len(admin.get_default_optional_client_scopes()) in [4, 5]
  2216. # Test client scope delete
  2217. res_del = admin.delete_client_scope(client_scope_id=res)
  2218. assert res_del == dict()
  2219. with pytest.raises(KeycloakDeleteError) as err:
  2220. admin.delete_client_scope(client_scope_id=res)
  2221. assert err.match(NO_CLIENT_SCOPE_REGEX)
  2222. def test_components(admin: KeycloakAdmin, realm: str):
  2223. """Test components.
  2224. :param admin: Keycloak Admin client
  2225. :type admin: KeycloakAdmin
  2226. :param realm: Keycloak realm
  2227. :type realm: str
  2228. """
  2229. admin.change_current_realm(realm)
  2230. # Test get components
  2231. res = admin.get_components()
  2232. assert len(res) == 12
  2233. with pytest.raises(KeycloakGetError) as err:
  2234. admin.get_component(component_id="does-not-exist")
  2235. assert err.match('404: b\'{"error":"Could not find component".*}\'')
  2236. res_get = admin.get_component(component_id=res[0]["id"])
  2237. assert res_get == res[0]
  2238. # Test create component
  2239. with pytest.raises(KeycloakPostError) as err:
  2240. admin.create_component(payload={"bad": "dict"})
  2241. assert err.match("Unrecognized field")
  2242. res = admin.create_component(
  2243. payload={
  2244. "name": "Test Component",
  2245. "providerId": "max-clients",
  2246. "providerType": "org.keycloak.services.clientregistration."
  2247. + "policy.ClientRegistrationPolicy",
  2248. "config": {"max-clients": ["1000"]},
  2249. },
  2250. )
  2251. assert res
  2252. assert admin.get_component(component_id=res)["name"] == "Test Component"
  2253. # Test update component
  2254. component = admin.get_component(component_id=res)
  2255. component["name"] = "Test Component Update"
  2256. with pytest.raises(KeycloakPutError) as err:
  2257. admin.update_component(component_id="does-not-exist", payload=dict())
  2258. assert err.match('404: b\'{"error":"Could not find component".*}\'')
  2259. res_upd = admin.update_component(component_id=res, payload=component)
  2260. assert res_upd == dict()
  2261. assert admin.get_component(component_id=res)["name"] == "Test Component Update"
  2262. # Test delete component
  2263. res_del = admin.delete_component(component_id=res)
  2264. assert res_del == dict()
  2265. with pytest.raises(KeycloakDeleteError) as err:
  2266. admin.delete_component(component_id=res)
  2267. assert err.match('404: b\'{"error":"Could not find component".*}\'')
  2268. def test_keys(admin: KeycloakAdmin, realm: str):
  2269. """Test keys.
  2270. :param admin: Keycloak Admin client
  2271. :type admin: KeycloakAdmin
  2272. :param realm: Keycloak realm
  2273. :type realm: str
  2274. """
  2275. admin.change_current_realm(realm)
  2276. assert set(admin.get_keys()["active"].keys()) == {"AES", "HS256", "RS256", "RSA-OAEP"} or set(
  2277. admin.get_keys()["active"].keys(),
  2278. ) == {"RSA-OAEP", "RS256", "HS512", "AES"}
  2279. assert {k["algorithm"] for k in admin.get_keys()["keys"]} == {
  2280. "HS256",
  2281. "RSA-OAEP",
  2282. "AES",
  2283. "RS256",
  2284. } or {k["algorithm"] for k in admin.get_keys()["keys"]} == {
  2285. "HS512",
  2286. "RSA-OAEP",
  2287. "AES",
  2288. "RS256",
  2289. }
  2290. def test_admin_events(admin: KeycloakAdmin, realm: str):
  2291. """Test events.
  2292. :param admin: Keycloak Admin client
  2293. :type admin: KeycloakAdmin
  2294. :param realm: Keycloak realm
  2295. :type realm: str
  2296. """
  2297. admin.change_current_realm(realm)
  2298. admin.create_client(payload={"name": "test", "clientId": "test"})
  2299. events = admin.get_admin_events()
  2300. assert events == list()
  2301. def test_user_events(admin: KeycloakAdmin, realm: str):
  2302. """Test events.
  2303. :param admin: Keycloak Admin client
  2304. :type admin: KeycloakAdmin
  2305. :param realm: Keycloak realm
  2306. :type realm: str
  2307. """
  2308. admin.change_current_realm(realm)
  2309. events = admin.get_events()
  2310. assert events == list()
  2311. with pytest.raises(KeycloakPutError) as err:
  2312. admin.set_events(payload={"bad": "conf"})
  2313. assert err.match("Unrecognized field")
  2314. res = admin.set_events(payload={"adminEventsDetailsEnabled": True, "adminEventsEnabled": True})
  2315. assert res == dict()
  2316. admin.create_client(payload={"name": "test", "clientId": "test"})
  2317. events = admin.get_events()
  2318. assert events == list()
  2319. @freezegun.freeze_time("2023-02-25 10:00:00")
  2320. def test_auto_refresh(admin_frozen: KeycloakAdmin, realm: str):
  2321. """Test auto refresh token.
  2322. :param admin_frozen: Keycloak Admin client with time frozen in place
  2323. :type admin_frozen: KeycloakAdmin
  2324. :param realm: Keycloak realm
  2325. :type realm: str
  2326. """
  2327. admin = admin_frozen
  2328. admin.get_realm(realm_name=realm)
  2329. # Test get refresh
  2330. admin.connection.custom_headers = {
  2331. "Authorization": "Bearer bad",
  2332. "Content-Type": "application/json",
  2333. }
  2334. res = admin.get_realm(realm_name=realm)
  2335. assert res["realm"] == realm
  2336. # Freeze time to simulate the access token expiring
  2337. with freezegun.freeze_time("2023-02-25 10:05:00"):
  2338. assert admin.connection.expires_at < datetime_parser.parse("2023-02-25 10:05:00")
  2339. assert admin.get_realm(realm_name=realm)
  2340. assert admin.connection.expires_at > datetime_parser.parse("2023-02-25 10:05:00")
  2341. # Test bad refresh token, but first make sure access token has expired again
  2342. with freezegun.freeze_time("2023-02-25 10:10:00"):
  2343. admin.connection.custom_headers = {"Content-Type": "application/json"}
  2344. admin.connection.token["refresh_token"] = "bad"
  2345. with pytest.raises(KeycloakPostError) as err:
  2346. admin.get_realm(realm_name="test-refresh")
  2347. assert err.match(
  2348. '400: b\'{"error":"invalid_grant","error_description":"Invalid refresh token"}\'',
  2349. )
  2350. admin.connection.get_token()
  2351. # Test post refresh
  2352. with freezegun.freeze_time("2023-02-25 10:15:00"):
  2353. assert admin.connection.expires_at < datetime_parser.parse("2023-02-25 10:15:00")
  2354. admin.connection.token = None
  2355. assert admin.create_realm(payload={"realm": "test-refresh"}) == b""
  2356. assert admin.connection.expires_at > datetime_parser.parse("2023-02-25 10:15:00")
  2357. # Test update refresh
  2358. with freezegun.freeze_time("2023-02-25 10:25:00"):
  2359. assert admin.connection.expires_at < datetime_parser.parse("2023-02-25 10:25:00")
  2360. admin.connection.token = None
  2361. assert (
  2362. admin.update_realm(realm_name="test-refresh", payload={"accountTheme": "test"})
  2363. == dict()
  2364. )
  2365. assert admin.connection.expires_at > datetime_parser.parse("2023-02-25 10:25:00")
  2366. # Test delete refresh
  2367. with freezegun.freeze_time("2023-02-25 10:35:00"):
  2368. assert admin.connection.expires_at < datetime_parser.parse("2023-02-25 10:35:00")
  2369. admin.connection.token = None
  2370. assert admin.delete_realm(realm_name="test-refresh") == dict()
  2371. assert admin.connection.expires_at > datetime_parser.parse("2023-02-25 10:35:00")
  2372. def test_get_required_actions(admin: KeycloakAdmin, realm: str):
  2373. """Test required actions.
  2374. :param admin: Keycloak Admin client
  2375. :type admin: KeycloakAdmin
  2376. :param realm: Keycloak realm
  2377. :type realm: str
  2378. """
  2379. admin.change_current_realm(realm)
  2380. ractions = admin.get_required_actions()
  2381. assert isinstance(ractions, list)
  2382. for ra in ractions:
  2383. for key in [
  2384. "alias",
  2385. "name",
  2386. "providerId",
  2387. "enabled",
  2388. "defaultAction",
  2389. "priority",
  2390. "config",
  2391. ]:
  2392. assert key in ra
  2393. def test_get_required_action_by_alias(admin: KeycloakAdmin, realm: str):
  2394. """Test get required action by alias.
  2395. :param admin: Keycloak Admin client
  2396. :type admin: KeycloakAdmin
  2397. :param realm: Keycloak realm
  2398. :type realm: str
  2399. """
  2400. admin.change_current_realm(realm)
  2401. ractions = admin.get_required_actions()
  2402. ra = admin.get_required_action_by_alias("UPDATE_PASSWORD")
  2403. assert ra in ractions
  2404. assert ra["alias"] == "UPDATE_PASSWORD"
  2405. assert admin.get_required_action_by_alias("does-not-exist") is None
  2406. def test_update_required_action(admin: KeycloakAdmin, realm: str):
  2407. """Test update required action.
  2408. :param admin: Keycloak Admin client
  2409. :type admin: KeycloakAdmin
  2410. :param realm: Keycloak realm
  2411. :type realm: str
  2412. """
  2413. admin.change_current_realm(realm)
  2414. ra = admin.get_required_action_by_alias("UPDATE_PASSWORD")
  2415. old = copy.deepcopy(ra)
  2416. ra["enabled"] = False
  2417. admin.update_required_action("UPDATE_PASSWORD", ra)
  2418. newra = admin.get_required_action_by_alias("UPDATE_PASSWORD")
  2419. assert old != newra
  2420. assert newra["enabled"] is False
  2421. def test_get_composite_client_roles_of_group(
  2422. admin: KeycloakAdmin, realm: str, client: str, group: str, composite_client_role: str,
  2423. ):
  2424. """Test get composite client roles of group.
  2425. :param admin: Keycloak Admin client
  2426. :type admin: KeycloakAdmin
  2427. :param realm: Keycloak realm
  2428. :type realm: str
  2429. :param client: Keycloak client
  2430. :type client: str
  2431. :param group: Keycloak group
  2432. :type group: str
  2433. :param composite_client_role: Composite client role
  2434. :type composite_client_role: str
  2435. """
  2436. admin.change_current_realm(realm)
  2437. role = admin.get_client_role(client, composite_client_role)
  2438. admin.assign_group_client_roles(group_id=group, client_id=client, roles=[role])
  2439. result = admin.get_composite_client_roles_of_group(client, group)
  2440. assert role["id"] in [x["id"] for x in result]
  2441. def test_get_role_client_level_children(
  2442. admin: KeycloakAdmin, realm: str, client: str, composite_client_role: str, client_role: str,
  2443. ):
  2444. """Test get children of composite client role.
  2445. :param admin: Keycloak Admin client
  2446. :type admin: KeycloakAdmin
  2447. :param realm: Keycloak realm
  2448. :type realm: str
  2449. :param client: Keycloak client
  2450. :type client: str
  2451. :param composite_client_role: Composite client role
  2452. :type composite_client_role: str
  2453. :param client_role: Client role
  2454. :type client_role: str
  2455. """
  2456. admin.change_current_realm(realm)
  2457. child = admin.get_client_role(client, client_role)
  2458. parent = admin.get_client_role(client, composite_client_role)
  2459. res = admin.get_role_client_level_children(client, parent["id"])
  2460. assert child["id"] in [x["id"] for x in res]
  2461. def test_upload_certificate(admin: KeycloakAdmin, realm: str, client: str, selfsigned_cert: tuple):
  2462. """Test upload certificate.
  2463. :param admin: Keycloak Admin client
  2464. :type admin: KeycloakAdmin
  2465. :param realm: Keycloak realm
  2466. :type realm: str
  2467. :param client: Keycloak client
  2468. :type client: str
  2469. :param selfsigned_cert: Selfsigned certificates
  2470. :type selfsigned_cert: tuple
  2471. """
  2472. admin.change_current_realm(realm)
  2473. cert, _ = selfsigned_cert
  2474. cert = cert.decode("utf-8").strip()
  2475. admin.upload_certificate(client, cert)
  2476. cl = admin.get_client(client)
  2477. assert cl["attributes"]["jwt.credential.certificate"] == "".join(cert.splitlines()[1:-1])
  2478. def test_get_bruteforce_status_for_user(
  2479. admin: KeycloakAdmin, oid_with_credentials: Tuple[KeycloakOpenID, str, str], realm: str,
  2480. ):
  2481. """Test users.
  2482. :param admin: Keycloak Admin client
  2483. :type admin: KeycloakAdmin
  2484. :param oid_with_credentials: Keycloak OpenID client with pre-configured user credentials
  2485. :type oid_with_credentials: Tuple[KeycloakOpenID, str, str]
  2486. :param realm: Keycloak realm
  2487. :type realm: str
  2488. """
  2489. oid, username, password = oid_with_credentials
  2490. admin.change_current_realm(realm)
  2491. # Turn on bruteforce protection
  2492. res = admin.update_realm(realm_name=realm, payload={"bruteForceProtected": True})
  2493. res = admin.get_realm(realm_name=realm)
  2494. assert res["bruteForceProtected"] is True
  2495. # Test login user with wrong credentials
  2496. try:
  2497. oid.token(username=username, password="wrongpassword")
  2498. except KeycloakAuthenticationError:
  2499. pass
  2500. user_id = admin.get_user_id(username)
  2501. bruteforce_status = admin.get_bruteforce_detection_status(user_id)
  2502. assert bruteforce_status["numFailures"] == 1
  2503. # Cleanup
  2504. res = admin.update_realm(realm_name=realm, payload={"bruteForceProtected": False})
  2505. res = admin.get_realm(realm_name=realm)
  2506. assert res["bruteForceProtected"] is False
  2507. def test_clear_bruteforce_attempts_for_user(
  2508. admin: KeycloakAdmin, oid_with_credentials: Tuple[KeycloakOpenID, str, str], realm: str,
  2509. ):
  2510. """Test users.
  2511. :param admin: Keycloak Admin client
  2512. :type admin: KeycloakAdmin
  2513. :param oid_with_credentials: Keycloak OpenID client with pre-configured user credentials
  2514. :type oid_with_credentials: Tuple[KeycloakOpenID, str, str]
  2515. :param realm: Keycloak realm
  2516. :type realm: str
  2517. """
  2518. oid, username, password = oid_with_credentials
  2519. admin.change_current_realm(realm)
  2520. # Turn on bruteforce protection
  2521. res = admin.update_realm(realm_name=realm, payload={"bruteForceProtected": True})
  2522. res = admin.get_realm(realm_name=realm)
  2523. assert res["bruteForceProtected"] is True
  2524. # Test login user with wrong credentials
  2525. try:
  2526. oid.token(username=username, password="wrongpassword")
  2527. except KeycloakAuthenticationError:
  2528. pass
  2529. user_id = admin.get_user_id(username)
  2530. bruteforce_status = admin.get_bruteforce_detection_status(user_id)
  2531. assert bruteforce_status["numFailures"] == 1
  2532. res = admin.clear_bruteforce_attempts_for_user(user_id)
  2533. bruteforce_status = admin.get_bruteforce_detection_status(user_id)
  2534. assert bruteforce_status["numFailures"] == 0
  2535. # Cleanup
  2536. res = admin.update_realm(realm_name=realm, payload={"bruteForceProtected": False})
  2537. res = admin.get_realm(realm_name=realm)
  2538. assert res["bruteForceProtected"] is False
  2539. def test_clear_bruteforce_attempts_for_all_users(
  2540. admin: KeycloakAdmin, oid_with_credentials: Tuple[KeycloakOpenID, str, str], realm: str,
  2541. ):
  2542. """Test users.
  2543. :param admin: Keycloak Admin client
  2544. :type admin: KeycloakAdmin
  2545. :param oid_with_credentials: Keycloak OpenID client with pre-configured user credentials
  2546. :type oid_with_credentials: Tuple[KeycloakOpenID, str, str]
  2547. :param realm: Keycloak realm
  2548. :type realm: str
  2549. """
  2550. oid, username, password = oid_with_credentials
  2551. admin.change_current_realm(realm)
  2552. # Turn on bruteforce protection
  2553. res = admin.update_realm(realm_name=realm, payload={"bruteForceProtected": True})
  2554. res = admin.get_realm(realm_name=realm)
  2555. assert res["bruteForceProtected"] is True
  2556. # Test login user with wrong credentials
  2557. try:
  2558. oid.token(username=username, password="wrongpassword")
  2559. except KeycloakAuthenticationError:
  2560. pass
  2561. user_id = admin.get_user_id(username)
  2562. bruteforce_status = admin.get_bruteforce_detection_status(user_id)
  2563. assert bruteforce_status["numFailures"] == 1
  2564. res = admin.clear_all_bruteforce_attempts()
  2565. bruteforce_status = admin.get_bruteforce_detection_status(user_id)
  2566. assert bruteforce_status["numFailures"] == 0
  2567. # Cleanup
  2568. res = admin.update_realm(realm_name=realm, payload={"bruteForceProtected": False})
  2569. res = admin.get_realm(realm_name=realm)
  2570. assert res["bruteForceProtected"] is False
  2571. def test_default_realm_role_present(realm: str, admin: KeycloakAdmin) -> None:
  2572. """Test that the default realm role is present in a brand new realm.
  2573. :param realm: Realm name
  2574. :type realm: str
  2575. :param admin: Keycloak admin
  2576. :type admin: KeycloakAdmin
  2577. """
  2578. admin.change_current_realm(realm)
  2579. assert f"default-roles-{realm}" in [x["name"] for x in admin.get_realm_roles()]
  2580. assert (
  2581. len([x["name"] for x in admin.get_realm_roles() if x["name"] == f"default-roles-{realm}"])
  2582. == 1
  2583. )
  2584. def test_get_default_realm_role_id(realm: str, admin: KeycloakAdmin) -> None:
  2585. """Test getter for the ID of the default realm role.
  2586. :param realm: Realm name
  2587. :type realm: str
  2588. :param admin: Keycloak admin
  2589. :type admin: KeycloakAdmin
  2590. """
  2591. admin.change_current_realm(realm)
  2592. assert (
  2593. admin.get_default_realm_role_id()
  2594. == [x["id"] for x in admin.get_realm_roles() if x["name"] == f"default-roles-{realm}"][0]
  2595. )
  2596. def test_realm_default_roles(admin: KeycloakAdmin, realm: str) -> None:
  2597. """Test getting, adding and deleting default realm roles.
  2598. :param realm: Realm name
  2599. :type realm: str
  2600. :param admin: Keycloak admin
  2601. :type admin: KeycloakAdmin
  2602. """
  2603. admin.change_current_realm(realm)
  2604. # Test listing all default realm roles
  2605. roles = admin.get_realm_default_roles()
  2606. assert len(roles) == 2
  2607. assert {x["name"] for x in roles} == {"offline_access", "uma_authorization"}
  2608. with pytest.raises(KeycloakGetError) as err:
  2609. admin.change_current_realm("doesnotexist")
  2610. admin.get_realm_default_roles()
  2611. assert err.match('404: b\'{"error":"Realm not found.".*}\'')
  2612. admin.change_current_realm(realm)
  2613. # Test removing a default realm role
  2614. res = admin.remove_realm_default_roles(payload=[roles[0]])
  2615. assert res == {}
  2616. assert roles[0] not in admin.get_realm_default_roles()
  2617. assert len(admin.get_realm_default_roles()) == 1
  2618. with pytest.raises(KeycloakDeleteError) as err:
  2619. admin.remove_realm_default_roles(payload=[{"id": "bad id"}])
  2620. assert err.match('404: b\'{"error":"Could not find composite role".*}\'')
  2621. # Test adding a default realm role
  2622. res = admin.add_realm_default_roles(payload=[roles[0]])
  2623. assert res == {}
  2624. assert roles[0] in admin.get_realm_default_roles()
  2625. assert len(admin.get_realm_default_roles()) == 2
  2626. with pytest.raises(KeycloakPostError) as err:
  2627. admin.add_realm_default_roles(payload=[{"id": "bad id"}])
  2628. assert err.match('404: b\'{"error":"Could not find composite role".*}\'')
  2629. def test_clear_keys_cache(realm: str, admin: KeycloakAdmin) -> None:
  2630. """Test clearing the keys cache.
  2631. :param realm: Realm name
  2632. :type realm: str
  2633. :param admin: Keycloak admin
  2634. :type admin: KeycloakAdmin
  2635. """
  2636. admin.change_current_realm(realm)
  2637. res = admin.clear_keys_cache()
  2638. assert res == {}
  2639. def test_clear_realm_cache(realm: str, admin: KeycloakAdmin) -> None:
  2640. """Test clearing the realm cache.
  2641. :param realm: Realm name
  2642. :type realm: str
  2643. :param admin: Keycloak admin
  2644. :type admin: KeycloakAdmin
  2645. """
  2646. admin.change_current_realm(realm)
  2647. res = admin.clear_realm_cache()
  2648. assert res == {}
  2649. def test_clear_user_cache(realm: str, admin: KeycloakAdmin) -> None:
  2650. """Test clearing the user cache.
  2651. :param realm: Realm name
  2652. :type realm: str
  2653. :param admin: Keycloak admin
  2654. :type admin: KeycloakAdmin
  2655. """
  2656. admin.change_current_realm(realm)
  2657. res = admin.clear_user_cache()
  2658. assert res == {}
  2659. def test_initial_access_token(
  2660. admin: KeycloakAdmin, oid_with_credentials: Tuple[KeycloakOpenID, str, str],
  2661. ) -> None:
  2662. """Test initial access token and client creation.
  2663. :param admin: Keycloak admin
  2664. :type admin: KeycloakAdmin
  2665. :param oid_with_credentials: Keycloak OpenID client with pre-configured user credentials
  2666. :type oid_with_credentials: Tuple[KeycloakOpenID, str, str]
  2667. """
  2668. res = admin.create_initial_access_token(2, 3)
  2669. assert "token" in res
  2670. assert res["count"] == 2
  2671. assert res["expiration"] == 3
  2672. oid, username, password = oid_with_credentials
  2673. client = str(uuid.uuid4())
  2674. secret = str(uuid.uuid4())
  2675. res = oid.register_client(
  2676. token=res["token"],
  2677. payload={
  2678. "name": "DynamicRegisteredClient",
  2679. "clientId": client,
  2680. "enabled": True,
  2681. "publicClient": False,
  2682. "protocol": "openid-connect",
  2683. "secret": secret,
  2684. "clientAuthenticatorType": "client-secret",
  2685. },
  2686. )
  2687. assert res["clientId"] == client
  2688. new_secret = str(uuid.uuid4())
  2689. res = oid.update_client(res["registrationAccessToken"], client, payload={"secret": new_secret})
  2690. assert res["secret"] == new_secret
  2691. def test_refresh_token(admin: KeycloakAdmin):
  2692. """Test refresh token on connection even if it is expired.
  2693. :param admin: Keycloak admin
  2694. :type admin: KeycloakAdmin
  2695. """
  2696. admin.get_realms()
  2697. assert admin.connection.token is not None
  2698. admin.user_logout(admin.get_user_id(admin.connection.username))
  2699. admin.connection.refresh_token()
  2700. # async function start
  2701. @pytest.mark.asyncio
  2702. async def test_a_realms(admin: KeycloakAdmin):
  2703. """Test realms.
  2704. :param admin: Keycloak Admin client
  2705. :type admin: KeycloakAdmin
  2706. """
  2707. # Get realms
  2708. realms = await admin.a_get_realms()
  2709. assert len(realms) == 1, realms
  2710. assert realms[0]["realm"] == "master"
  2711. # Create a test realm
  2712. res = await admin.a_create_realm(payload={"realm": "test"})
  2713. assert res == b"", res
  2714. # Create the same realm, should fail
  2715. with pytest.raises(KeycloakPostError) as err:
  2716. res = await admin.a_create_realm(payload={"realm": "test"})
  2717. assert err.match('409: b\'{"errorMessage":"Conflict detected. See logs for details"}\'')
  2718. # Create the same realm, skip_exists true
  2719. res = await admin.a_create_realm(payload={"realm": "test"}, skip_exists=True)
  2720. assert res == {"msg": "Already exists"}, res
  2721. # Get a single realm
  2722. res = await admin.a_get_realm(realm_name="test")
  2723. assert res["realm"] == "test"
  2724. # Get non-existing realm
  2725. with pytest.raises(KeycloakGetError) as err:
  2726. await admin.a_get_realm(realm_name="non-existent")
  2727. assert err.match('404: b\'{"error":"Realm not found.".*\'')
  2728. # Update realm
  2729. res = await admin.a_update_realm(realm_name="test", payload={"accountTheme": "test"})
  2730. assert res == dict(), res
  2731. # Check that the update worked
  2732. res = await admin.a_get_realm(realm_name="test")
  2733. assert res["realm"] == "test"
  2734. assert res["accountTheme"] == "test"
  2735. # Update wrong payload
  2736. with pytest.raises(KeycloakPutError) as err:
  2737. await admin.a_update_realm(realm_name="test", payload={"wrong": "payload"})
  2738. assert err.match("Unrecognized field")
  2739. # Check that get realms returns both realms
  2740. realms = await admin.a_get_realms()
  2741. realm_names = [x["realm"] for x in realms]
  2742. assert len(realms) == 2, realms
  2743. assert "master" in realm_names, realm_names
  2744. assert "test" in realm_names, realm_names
  2745. # Delete the realm
  2746. res = await admin.a_delete_realm(realm_name="test")
  2747. assert res == dict(), res
  2748. # Check that the realm does not exist anymore
  2749. with pytest.raises(KeycloakGetError) as err:
  2750. await admin.a_get_realm(realm_name="test")
  2751. assert err.match('404: b\'{"error":"Realm not found.".*}\'')
  2752. # Delete non-existing realm
  2753. with pytest.raises(KeycloakDeleteError) as err:
  2754. await admin.a_delete_realm(realm_name="non-existent")
  2755. assert err.match('404: b\'{"error":"Realm not found.".*}\'')
  2756. @pytest.mark.asyncio
  2757. async def test_a_changing_of_realms(admin: KeycloakAdmin, realm: str):
  2758. """Test changing of realms.
  2759. :param admin: Keycloak Admin client
  2760. :type admin: KeycloakAdmin
  2761. :param realm: Keycloak realm
  2762. :type realm: str
  2763. """
  2764. assert await admin.a_get_current_realm() == "master"
  2765. await admin.a_change_current_realm(realm)
  2766. assert await admin.a_get_current_realm() == realm
  2767. @pytest.mark.asyncio
  2768. async def test_a_import_export_realms(admin: KeycloakAdmin, realm: str):
  2769. """Test import and export of realms.
  2770. :param admin: Keycloak Admin client
  2771. :type admin: KeycloakAdmin
  2772. :param realm: Keycloak realm
  2773. :type realm: str
  2774. """
  2775. await admin.a_change_current_realm(realm)
  2776. realm_export = await admin.a_export_realm(export_clients=True, export_groups_and_role=True)
  2777. assert realm_export != dict(), realm_export
  2778. await admin.a_delete_realm(realm_name=realm)
  2779. admin.realm_name = "master"
  2780. res = await admin.a_import_realm(payload=realm_export)
  2781. assert res == b"", res
  2782. # Test bad import
  2783. with pytest.raises(KeycloakPostError) as err:
  2784. await admin.a_import_realm(payload=dict())
  2785. assert err.match(
  2786. '500: b\'{"error":"unknown_error"}\'|400: b\'{"errorMessage":"Realm name cannot be empty"}\'', # noqa: E501
  2787. )
  2788. @pytest.mark.asyncio
  2789. async def test_a_partial_import_realm(admin: KeycloakAdmin, realm: str):
  2790. """Test partial import of realm configuration.
  2791. :param admin: Keycloak Admin client
  2792. :type admin: KeycloakAdmin
  2793. :param realm: Keycloak realm
  2794. :type realm: str
  2795. """
  2796. test_realm_role = str(uuid.uuid4())
  2797. test_user = str(uuid.uuid4())
  2798. test_client = str(uuid.uuid4())
  2799. await admin.a_change_current_realm(realm)
  2800. client_id = await admin.a_create_client(payload={"name": test_client, "clientId": test_client})
  2801. realm_export = await admin.a_export_realm(export_clients=True, export_groups_and_role=False)
  2802. client_config = [
  2803. client_entry for client_entry in realm_export["clients"] if client_entry["id"] == client_id
  2804. ][0]
  2805. # delete before partial import
  2806. await admin.a_delete_client(client_id)
  2807. payload = {
  2808. "ifResourceExists": "SKIP",
  2809. "id": realm_export["id"],
  2810. "realm": realm,
  2811. "clients": [client_config],
  2812. "roles": {"realm": [{"name": test_realm_role}]},
  2813. "users": [{"username": test_user, "email": f"{test_user}@test.test"}],
  2814. }
  2815. # check add
  2816. res = await admin.a_partial_import_realm(realm_name=realm, payload=payload)
  2817. assert res["added"] == 3
  2818. # check skip
  2819. res = await admin.a_partial_import_realm(realm_name=realm, payload=payload)
  2820. assert res["skipped"] == 3
  2821. # check overwrite
  2822. payload["ifResourceExists"] = "OVERWRITE"
  2823. res = await admin.a_partial_import_realm(realm_name=realm, payload=payload)
  2824. assert res["overwritten"] == 3
  2825. @pytest.mark.asyncio
  2826. async def test_a_users(admin: KeycloakAdmin, realm: str):
  2827. """Test users.
  2828. :param admin: Keycloak Admin client
  2829. :type admin: KeycloakAdmin
  2830. :param realm: Keycloak realm
  2831. :type realm: str
  2832. """
  2833. await admin.a_change_current_realm(realm)
  2834. # Check no users present
  2835. users = await admin.a_get_users()
  2836. assert users == list(), users
  2837. # Test create user
  2838. user_id = await admin.a_create_user(payload={"username": "test", "email": "test@test.test"})
  2839. assert user_id is not None, user_id
  2840. # Test create the same user
  2841. with pytest.raises(KeycloakPostError) as err:
  2842. await admin.a_create_user(payload={"username": "test", "email": "test@test.test"})
  2843. assert err.match(".*User exists with same.*")
  2844. # Test create the same user, exists_ok true
  2845. user_id_2 = await admin.a_create_user(
  2846. payload={"username": "test", "email": "test@test.test"}, exist_ok=True,
  2847. )
  2848. assert user_id == user_id_2
  2849. # Test get user
  2850. user = await admin.a_get_user(user_id=user_id)
  2851. assert user["username"] == "test", user["username"]
  2852. assert user["email"] == "test@test.test", user["email"]
  2853. # Test update user
  2854. res = await admin.a_update_user(user_id=user_id, payload={"firstName": "Test"})
  2855. assert res == dict(), res
  2856. user = await admin.a_get_user(user_id=user_id)
  2857. assert user["firstName"] == "Test"
  2858. # Test update user fail
  2859. with pytest.raises(KeycloakPutError) as err:
  2860. await admin.a_update_user(user_id=user_id, payload={"wrong": "payload"})
  2861. assert err.match("Unrecognized field")
  2862. # Test disable user
  2863. res = await admin.a_disable_user(user_id=user_id)
  2864. assert res == {}, res
  2865. assert not (await admin.a_get_user(user_id=user_id))["enabled"]
  2866. # Test enable user
  2867. res = await admin.a_enable_user(user_id=user_id)
  2868. assert res == {}, res
  2869. assert (await admin.a_get_user(user_id=user_id))["enabled"]
  2870. # Test get users again
  2871. users = await admin.a_get_users()
  2872. usernames = [x["username"] for x in users]
  2873. assert "test" in usernames
  2874. # Test users counts
  2875. count = await admin.a_users_count()
  2876. assert count == 1, count
  2877. # Test users count with query
  2878. count = await admin.a_users_count(query={"username": "notpresent"})
  2879. assert count == 0
  2880. # Test user groups
  2881. groups = await admin.a_get_user_groups(user_id=user["id"])
  2882. assert len(groups) == 0
  2883. # Test user groups bad id
  2884. with pytest.raises(KeycloakGetError) as err:
  2885. await admin.a_get_user_groups(user_id="does-not-exist")
  2886. assert err.match(USER_NOT_FOUND_REGEX)
  2887. # Test logout
  2888. res = await admin.a_user_logout(user_id=user["id"])
  2889. assert res == dict(), res
  2890. # Test logout fail
  2891. with pytest.raises(KeycloakPostError) as err:
  2892. await admin.a_user_logout(user_id="non-existent-id")
  2893. assert err.match(USER_NOT_FOUND_REGEX)
  2894. # Test consents
  2895. res = await admin.a_user_consents(user_id=user["id"])
  2896. assert len(res) == 0, res
  2897. # Test consents fail
  2898. with pytest.raises(KeycloakGetError) as err:
  2899. await admin.a_user_consents(user_id="non-existent-id")
  2900. assert err.match(USER_NOT_FOUND_REGEX)
  2901. # Test delete user
  2902. res = await admin.a_delete_user(user_id=user_id)
  2903. assert res == dict(), res
  2904. with pytest.raises(KeycloakGetError) as err:
  2905. await admin.a_get_user(user_id=user_id)
  2906. err.match(USER_NOT_FOUND_REGEX)
  2907. # Test delete fail
  2908. with pytest.raises(KeycloakDeleteError) as err:
  2909. await admin.a_delete_user(user_id="non-existent-id")
  2910. assert err.match(USER_NOT_FOUND_REGEX)
  2911. @pytest.mark.asyncio
  2912. async def test_a_enable_disable_all_users(admin: KeycloakAdmin, realm: str):
  2913. """Test enable and disable all users.
  2914. :param admin: Keycloak Admin client
  2915. :type admin: KeycloakAdmin
  2916. :param realm: Keycloak realm
  2917. :type realm: str
  2918. """
  2919. admin.change_current_realm(realm)
  2920. user_id_1 = await admin.a_create_user(
  2921. payload={"username": "test", "email": "test@test.test", "enabled": True},
  2922. )
  2923. user_id_2 = await admin.a_create_user(
  2924. payload={"username": "test2", "email": "test2@test.test", "enabled": True},
  2925. )
  2926. user_id_3 = await admin.a_create_user(
  2927. payload={"username": "test3", "email": "test3@test.test", "enabled": True},
  2928. )
  2929. assert (await admin.a_get_user(user_id_1))["enabled"]
  2930. assert (await admin.a_get_user(user_id_2))["enabled"]
  2931. assert (await admin.a_get_user(user_id_3))["enabled"]
  2932. await admin.a_disable_all_users()
  2933. assert not (await admin.a_get_user(user_id_1))["enabled"]
  2934. assert not (await admin.a_get_user(user_id_2))["enabled"]
  2935. assert not (await admin.a_get_user(user_id_3))["enabled"]
  2936. await admin.a_enable_all_users()
  2937. assert (await admin.a_get_user(user_id_1))["enabled"]
  2938. assert (await admin.a_get_user(user_id_2))["enabled"]
  2939. assert (await admin.a_get_user(user_id_3))["enabled"]
  2940. @pytest.mark.asyncio
  2941. async def test_a_users_roles(admin: KeycloakAdmin, realm: str):
  2942. """Test users roles.
  2943. :param admin: Keycloak Admin client
  2944. :type admin: KeycloakAdmin
  2945. :param realm: Keycloak realm
  2946. :type realm: str
  2947. """
  2948. user_id = await admin.a_create_user(payload={"username": "test", "email": "test@test.test"})
  2949. # Test all level user roles
  2950. client_id = await admin.a_create_client(
  2951. payload={"name": "test-client", "clientId": "test-client"},
  2952. )
  2953. await admin.a_create_client_role(client_role_id=client_id, payload={"name": "test-role"})
  2954. await admin.a_assign_client_role(
  2955. client_id=client_id,
  2956. user_id=user_id,
  2957. roles=[admin.get_client_role(client_id=client_id, role_name="test-role")],
  2958. )
  2959. all_roles = await admin.a_get_all_roles_of_user(user_id=user_id)
  2960. realm_roles = all_roles["realmMappings"]
  2961. assert len(realm_roles) == 1, realm_roles
  2962. client_roles = all_roles["clientMappings"]
  2963. assert len(client_roles) == 1, client_roles
  2964. # Test all level user roles fail
  2965. with pytest.raises(KeycloakGetError) as err:
  2966. await admin.a_get_all_roles_of_user(user_id="non-existent-id")
  2967. err.match('404: b\'{"error":"User not found"')
  2968. await admin.a_delete_user(user_id)
  2969. await admin.a_delete_client(client_id)
  2970. @pytest.mark.asyncio
  2971. async def test_a_users_pagination(admin: KeycloakAdmin, realm: str):
  2972. """Test user pagination.
  2973. :param admin: Keycloak Admin client
  2974. :type admin: KeycloakAdmin
  2975. :param realm: Keycloak realm
  2976. :type realm: str
  2977. """
  2978. await admin.a_change_current_realm(realm)
  2979. for ind in range(admin.PAGE_SIZE + 50):
  2980. username = f"user_{ind}"
  2981. admin.create_user(payload={"username": username, "email": f"{username}@test.test"})
  2982. users = await admin.a_get_users()
  2983. assert len(users) == admin.PAGE_SIZE + 50, len(users)
  2984. users = await admin.a_get_users(query={"first": 100})
  2985. assert len(users) == 50, len(users)
  2986. users = await admin.a_get_users(query={"max": 20})
  2987. assert len(users) == 20, len(users)
  2988. @pytest.mark.asyncio
  2989. async def test_a_user_groups_pagination(admin: KeycloakAdmin, realm: str):
  2990. """Test user groups pagination.
  2991. :param admin: Keycloak Admin client
  2992. :type admin: KeycloakAdmin
  2993. :param realm: Keycloak realm
  2994. :type realm: str
  2995. """
  2996. await admin.a_change_current_realm(realm)
  2997. user_id = await admin.a_create_user(
  2998. payload={"username": "username_1", "email": "username_1@test.test"},
  2999. )
  3000. for ind in range(admin.PAGE_SIZE + 50):
  3001. group_name = f"group_{ind}"
  3002. group_id = await admin.a_create_group(payload={"name": group_name})
  3003. await admin.a_group_user_add(user_id=user_id, group_id=group_id)
  3004. groups = await admin.a_get_user_groups(user_id=user_id)
  3005. assert len(groups) == admin.PAGE_SIZE + 50, len(groups)
  3006. groups = await admin.a_get_user_groups(
  3007. user_id=user_id, query={"first": 100, "max": -1, "search": ""},
  3008. )
  3009. assert len(groups) == 50, len(groups)
  3010. groups = await admin.a_get_user_groups(
  3011. user_id=user_id, query={"max": 20, "first": -1, "search": ""},
  3012. )
  3013. assert len(groups) == 20, len(groups)
  3014. @pytest.mark.asyncio
  3015. async def test_a_idps(admin: KeycloakAdmin, realm: str):
  3016. """Test IDPs.
  3017. :param admin: Keycloak Admin client
  3018. :type admin: KeycloakAdmin
  3019. :param realm: Keycloak realm
  3020. :type realm: str
  3021. """
  3022. await admin.a_change_current_realm(realm)
  3023. # Create IDP
  3024. res = await admin.a_create_idp(
  3025. payload=dict(
  3026. providerId="github", alias="github", config=dict(clientId="test", clientSecret="test"),
  3027. ),
  3028. )
  3029. assert res == b"", res
  3030. # Test create idp fail
  3031. with pytest.raises(KeycloakPostError) as err:
  3032. await admin.a_create_idp(payload={"providerId": "does-not-exist", "alias": "something"})
  3033. assert err.match("Invalid identity provider id"), err
  3034. # Test listing
  3035. idps = await admin.a_get_idps()
  3036. assert len(idps) == 1
  3037. assert idps[0]["alias"] == "github"
  3038. # Test get idp
  3039. idp = await admin.a_get_idp("github")
  3040. assert idp["alias"] == "github"
  3041. assert idp.get("config")
  3042. assert idp["config"]["clientId"] == "test"
  3043. assert idp["config"]["clientSecret"] == "**********"
  3044. # Test get idp fail
  3045. with pytest.raises(KeycloakGetError) as err:
  3046. await admin.a_get_idp("does-not-exist")
  3047. assert err.match(HTTP_404_REGEX)
  3048. # Test IdP update
  3049. res = await admin.a_update_idp(idp_alias="github", payload=idps[0])
  3050. assert res == {}, res
  3051. # Test adding a mapper
  3052. res = await admin.a_add_mapper_to_idp(
  3053. idp_alias="github",
  3054. payload={
  3055. "identityProviderAlias": "github",
  3056. "identityProviderMapper": "github-user-attribute-mapper",
  3057. "name": "test",
  3058. },
  3059. )
  3060. assert res == b"", res
  3061. # Test mapper fail
  3062. with pytest.raises(KeycloakPostError) as err:
  3063. await admin.a_add_mapper_to_idp(idp_alias="does-no-texist", payload=dict())
  3064. assert err.match(HTTP_404_REGEX)
  3065. # Test IdP mappers listing
  3066. idp_mappers = await admin.a_get_idp_mappers(idp_alias="github")
  3067. assert len(idp_mappers) == 1
  3068. # Test IdP mapper update
  3069. res = await admin.a_update_mapper_in_idp(
  3070. idp_alias="github",
  3071. mapper_id=idp_mappers[0]["id"],
  3072. # For an obscure reason, keycloak expect all fields
  3073. payload={
  3074. "id": idp_mappers[0]["id"],
  3075. "identityProviderAlias": "github-alias",
  3076. "identityProviderMapper": "github-user-attribute-mapper",
  3077. "name": "test",
  3078. "config": idp_mappers[0]["config"],
  3079. },
  3080. )
  3081. assert res == dict(), res
  3082. # Test delete
  3083. res = await admin.a_delete_idp(idp_alias="github")
  3084. assert res == dict(), res
  3085. # Test delete fail
  3086. with pytest.raises(KeycloakDeleteError) as err:
  3087. await admin.a_delete_idp(idp_alias="does-not-exist")
  3088. assert err.match(HTTP_404_REGEX)
  3089. @pytest.mark.asyncio
  3090. async def test_a_user_credentials(admin: KeycloakAdmin, user: str):
  3091. """Test user credentials.
  3092. :param admin: Keycloak Admin client
  3093. :type admin: KeycloakAdmin
  3094. :param user: Keycloak user
  3095. :type user: str
  3096. """
  3097. res = await admin.a_set_user_password(user_id=user, password="booya", temporary=True)
  3098. assert res == dict(), res
  3099. # Test user password set fail
  3100. with pytest.raises(KeycloakPutError) as err:
  3101. await admin.a_set_user_password(user_id="does-not-exist", password="")
  3102. assert err.match(USER_NOT_FOUND_REGEX)
  3103. credentials = await admin.a_get_credentials(user_id=user)
  3104. assert len(credentials) == 1
  3105. assert credentials[0]["type"] == "password", credentials
  3106. # Test get credentials fail
  3107. with pytest.raises(KeycloakGetError) as err:
  3108. await admin.a_get_credentials(user_id="does-not-exist")
  3109. assert err.match(USER_NOT_FOUND_REGEX)
  3110. res = await admin.a_delete_credential(user_id=user, credential_id=credentials[0]["id"])
  3111. assert res == dict(), res
  3112. # Test delete fail
  3113. with pytest.raises(KeycloakDeleteError) as err:
  3114. await admin.a_delete_credential(user_id=user, credential_id="does-not-exist")
  3115. assert err.match('404: b\'{"error":"Credential not found".*}\'')
  3116. @pytest.mark.asyncio
  3117. async def test_a_social_logins(admin: KeycloakAdmin, user: str):
  3118. """Test social logins.
  3119. :param admin: Keycloak Admin client
  3120. :type admin: KeycloakAdmin
  3121. :param user: Keycloak user
  3122. :type user: str
  3123. """
  3124. res = await admin.a_add_user_social_login(
  3125. user_id=user, provider_id="gitlab", provider_userid="test", provider_username="test",
  3126. )
  3127. assert res == dict(), res
  3128. await admin.a_add_user_social_login(
  3129. user_id=user, provider_id="github", provider_userid="test", provider_username="test",
  3130. )
  3131. assert res == dict(), res
  3132. # Test add social login fail
  3133. with pytest.raises(KeycloakPostError) as err:
  3134. await admin.a_add_user_social_login(
  3135. user_id="does-not-exist",
  3136. provider_id="does-not-exist",
  3137. provider_userid="test",
  3138. provider_username="test",
  3139. )
  3140. assert err.match(USER_NOT_FOUND_REGEX)
  3141. res = await admin.a_get_user_social_logins(user_id=user)
  3142. assert res == list(), res
  3143. # Test get social logins fail
  3144. with pytest.raises(KeycloakGetError) as err:
  3145. await admin.a_get_user_social_logins(user_id="does-not-exist")
  3146. assert err.match(USER_NOT_FOUND_REGEX)
  3147. res = await admin.a_delete_user_social_login(user_id=user, provider_id="gitlab")
  3148. assert res == {}, res
  3149. res = await admin.a_delete_user_social_login(user_id=user, provider_id="github")
  3150. assert res == {}, res
  3151. with pytest.raises(KeycloakDeleteError) as err:
  3152. await admin.a_delete_user_social_login(user_id=user, provider_id="instagram")
  3153. assert err.match('404: b\'{"error":"Link not found".*}\''), err
  3154. @pytest.mark.asyncio
  3155. async def test_a_server_info(admin: KeycloakAdmin):
  3156. """Test server info.
  3157. :param admin: Keycloak Admin client
  3158. :type admin: KeycloakAdmin
  3159. """
  3160. info = await admin.a_get_server_info()
  3161. assert set(info.keys()).issubset(
  3162. {
  3163. "systemInfo",
  3164. "memoryInfo",
  3165. "profileInfo",
  3166. "features",
  3167. "themes",
  3168. "socialProviders",
  3169. "identityProviders",
  3170. "providers",
  3171. "protocolMapperTypes",
  3172. "builtinProtocolMappers",
  3173. "clientInstallations",
  3174. "componentTypes",
  3175. "passwordPolicies",
  3176. "enums",
  3177. "cryptoInfo",
  3178. },
  3179. ), info.keys()
  3180. @pytest.mark.asyncio
  3181. async def test_a_groups(admin: KeycloakAdmin, user: str):
  3182. """Test groups.
  3183. :param admin: Keycloak Admin client
  3184. :type admin: KeycloakAdmin
  3185. :param user: Keycloak user
  3186. :type user: str
  3187. """
  3188. # Test get groups
  3189. groups = await admin.a_get_groups()
  3190. assert len(groups) == 0
  3191. # Test create group
  3192. group_id = await admin.a_create_group(payload={"name": "main-group"})
  3193. assert group_id is not None, group_id
  3194. # Test group count
  3195. count = await admin.a_groups_count()
  3196. assert count.get("count") == 1, count
  3197. # Test group count with query
  3198. count = await admin.a_groups_count(query={"search": "notpresent"})
  3199. assert count.get("count") == 0
  3200. # Test create subgroups
  3201. subgroup_id_1 = await admin.a_create_group(payload={"name": "subgroup-1"}, parent=group_id)
  3202. subgroup_id_2 = await admin.a_create_group(payload={"name": "subgroup-2"}, parent=group_id)
  3203. # Test create group fail
  3204. with pytest.raises(KeycloakPostError) as err:
  3205. await admin.a_create_group(payload={"name": "subgroup-1"}, parent=group_id)
  3206. assert err.match("409"), err
  3207. # Test skip exists OK
  3208. subgroup_id_1_eq = await admin.a_create_group(
  3209. payload={"name": "subgroup-1"}, parent=group_id, skip_exists=True,
  3210. )
  3211. assert subgroup_id_1_eq is None
  3212. # Test get groups again
  3213. groups = await admin.a_get_groups()
  3214. assert len(groups) == 1, groups
  3215. assert len(groups[0]["subGroups"]) == 2, groups[0]["subGroups"]
  3216. assert groups[0]["id"] == group_id
  3217. assert {x["id"] for x in groups[0]["subGroups"]} == {subgroup_id_1, subgroup_id_2}
  3218. # Test get groups query
  3219. groups = await admin.a_get_groups(query={"max": 10})
  3220. assert len(groups) == 1, groups
  3221. assert len(groups[0]["subGroups"]) == 2, groups[0]["subGroups"]
  3222. assert groups[0]["id"] == group_id
  3223. assert {x["id"] for x in groups[0]["subGroups"]} == {subgroup_id_1, subgroup_id_2}
  3224. # Test get group
  3225. res = await admin.a_get_group(group_id=subgroup_id_1)
  3226. assert res["id"] == subgroup_id_1, res
  3227. assert res["name"] == "subgroup-1"
  3228. assert res["path"] == "/main-group/subgroup-1"
  3229. # Test get group fail
  3230. with pytest.raises(KeycloakGetError) as err:
  3231. await admin.a_get_group(group_id="does-not-exist")
  3232. assert err.match('404: b\'{"error":"Could not find group by id".*}\''), err
  3233. # Create 1 more subgroup
  3234. subsubgroup_id_1 = await admin.a_create_group(
  3235. payload={"name": "subsubgroup-1"}, parent=subgroup_id_2,
  3236. )
  3237. main_group = await admin.a_get_group(group_id=group_id)
  3238. # Test nested searches
  3239. subgroup_2 = await admin.a_get_group(group_id=subgroup_id_2)
  3240. res = await admin.a_get_subgroups(
  3241. group=subgroup_2, path="/main-group/subgroup-2/subsubgroup-1",
  3242. )
  3243. assert res is not None, res
  3244. assert res["id"] == subsubgroup_id_1
  3245. # Test nested search from main group
  3246. res = await admin.a_get_subgroups(
  3247. group=await admin.a_get_group(group_id=group_id, full_hierarchy=True),
  3248. path="/main-group/subgroup-2/subsubgroup-1",
  3249. )
  3250. assert res["id"] == subsubgroup_id_1
  3251. # Test nested search from all groups
  3252. res = await admin.a_get_groups(full_hierarchy=True)
  3253. assert len(res) == 1
  3254. assert len(res[0]["subGroups"]) == 2
  3255. assert len([x for x in res[0]["subGroups"] if x["id"] == subgroup_id_1][0]["subGroups"]) == 0
  3256. assert len([x for x in res[0]["subGroups"] if x["id"] == subgroup_id_2][0]["subGroups"]) == 1
  3257. # Test that query params are not allowed for full hierarchy
  3258. with pytest.raises(ValueError) as err:
  3259. await admin.a_get_group_children(group_id=group_id, full_hierarchy=True, query={"max": 10})
  3260. # Test that query params are passed
  3261. if os.environ["KEYCLOAK_DOCKER_IMAGE_TAG"] == "latest" or Version(
  3262. os.environ["KEYCLOAK_DOCKER_IMAGE_TAG"],
  3263. ) >= Version("23"):
  3264. res = await admin.a_get_group_children(group_id=group_id, query={"max": 1})
  3265. assert len(res) == 1
  3266. assert err.match("Cannot use both query and full_hierarchy parameters")
  3267. main_group_id_2 = await admin.a_create_group(payload={"name": "main-group-2"})
  3268. assert len(await admin.a_get_groups(full_hierarchy=True)) == 2
  3269. # Test empty search
  3270. res = await admin.a_get_subgroups(group=main_group, path="/none")
  3271. assert res is None, res
  3272. # Test get group by path
  3273. res = await admin.a_get_group_by_path(path="/main-group/subgroup-1")
  3274. assert res is not None, res
  3275. assert res["id"] == subgroup_id_1, res
  3276. res = await admin.a_get_group_by_path(path="/main-group/subgroup-2/subsubgroup-1/test")
  3277. assert res["error"] == "Group path does not exist"
  3278. res = await admin.a_get_group_by_path(path="/main-group/subgroup-2/subsubgroup-1")
  3279. assert res is not None, res
  3280. assert res["id"] == subsubgroup_id_1
  3281. res = await admin.a_get_group_by_path(path="/main-group")
  3282. assert res is not None, res
  3283. assert res["id"] == group_id, res
  3284. # Test group members
  3285. res = await admin.a_get_group_members(group_id=subgroup_id_2)
  3286. assert len(res) == 0, res
  3287. # Test fail group members
  3288. with pytest.raises(KeycloakGetError) as err:
  3289. await admin.a_get_group_members(group_id="does-not-exist")
  3290. assert err.match('404: b\'{"error":"Could not find group by id".*}\'')
  3291. res = await admin.a_group_user_add(user_id=user, group_id=subgroup_id_2)
  3292. assert res == dict(), res
  3293. res = await admin.a_get_group_members(group_id=subgroup_id_2)
  3294. assert len(res) == 1, res
  3295. assert res[0]["id"] == user
  3296. # Test get group members query
  3297. res = await admin.a_get_group_members(group_id=subgroup_id_2, query={"max": 10})
  3298. assert len(res) == 1, res
  3299. assert res[0]["id"] == user
  3300. with pytest.raises(KeycloakDeleteError) as err:
  3301. await admin.a_group_user_remove(user_id="does-not-exist", group_id=subgroup_id_2)
  3302. assert err.match(USER_NOT_FOUND_REGEX), err
  3303. res = await admin.a_group_user_remove(user_id=user, group_id=subgroup_id_2)
  3304. assert res == dict(), res
  3305. # Test set permissions
  3306. res = await admin.a_group_set_permissions(group_id=subgroup_id_2, enabled=True)
  3307. assert res["enabled"], res
  3308. res = await admin.a_group_set_permissions(group_id=subgroup_id_2, enabled=False)
  3309. assert not res["enabled"], res
  3310. with pytest.raises(KeycloakPutError) as err:
  3311. await admin.a_group_set_permissions(group_id=subgroup_id_2, enabled="blah")
  3312. assert err.match(UNKOWN_ERROR_REGEX), err
  3313. # Test update group
  3314. res = await admin.a_update_group(group_id=subgroup_id_2, payload={"name": "new-subgroup-2"})
  3315. assert res == dict(), res
  3316. assert (await admin.a_get_group(group_id=subgroup_id_2))["name"] == "new-subgroup-2"
  3317. # test update fail
  3318. with pytest.raises(KeycloakPutError) as err:
  3319. await admin.a_update_group(group_id="does-not-exist", payload=dict())
  3320. assert err.match('404: b\'{"error":"Could not find group by id".*}\''), err
  3321. # Test delete
  3322. res = await admin.a_delete_group(group_id=group_id)
  3323. assert res == dict(), res
  3324. res = await admin.a_delete_group(group_id=main_group_id_2)
  3325. assert res == dict(), res
  3326. assert len(await admin.a_get_groups()) == 0
  3327. # Test delete fail
  3328. with pytest.raises(KeycloakDeleteError) as err:
  3329. await admin.a_delete_group(group_id="does-not-exist")
  3330. assert err.match('404: b\'{"error":"Could not find group by id".*}\''), err
  3331. @pytest.mark.asyncio
  3332. async def test_a_clients(admin: KeycloakAdmin, realm: str):
  3333. """Test clients.
  3334. :param admin: Keycloak Admin client
  3335. :type admin: KeycloakAdmin
  3336. :param realm: Keycloak realm
  3337. :type realm: str
  3338. """
  3339. await admin.a_change_current_realm(realm)
  3340. # Test get clients
  3341. clients = await admin.a_get_clients()
  3342. assert len(clients) == 6, clients
  3343. assert {x["name"] for x in clients} == set(
  3344. [
  3345. "${client_admin-cli}",
  3346. "${client_security-admin-console}",
  3347. "${client_account-console}",
  3348. "${client_broker}",
  3349. "${client_account}",
  3350. "${client_realm-management}",
  3351. ],
  3352. ), clients
  3353. # Test create client
  3354. client_id = await admin.a_create_client(
  3355. payload={"name": "test-client", "clientId": "test-client"},
  3356. )
  3357. assert client_id, client_id
  3358. with pytest.raises(KeycloakPostError) as err:
  3359. await admin.a_create_client(payload={"name": "test-client", "clientId": "test-client"})
  3360. assert err.match('409: b\'{"errorMessage":"Client test-client already exists"}\''), err
  3361. client_id_2 = await admin.a_create_client(
  3362. payload={"name": "test-client", "clientId": "test-client"}, skip_exists=True,
  3363. )
  3364. assert client_id == client_id_2, client_id_2
  3365. # Test get client
  3366. res = await admin.a_get_client(client_id=client_id)
  3367. assert res["clientId"] == "test-client", res
  3368. assert res["name"] == "test-client", res
  3369. assert res["id"] == client_id, res
  3370. with pytest.raises(KeycloakGetError) as err:
  3371. await admin.a_get_client(client_id="does-not-exist")
  3372. assert err.match('404: b\'{"error":"Could not find client".*}\'')
  3373. assert len(await admin.a_get_clients()) == 7
  3374. # Test get client id
  3375. assert await admin.a_get_client_id(client_id="test-client") == client_id
  3376. assert await admin.a_get_client_id(client_id="does-not-exist") is None
  3377. # Test update client
  3378. res = await admin.a_update_client(client_id=client_id, payload={"name": "test-client-change"})
  3379. assert res == dict(), res
  3380. with pytest.raises(KeycloakPutError) as err:
  3381. await admin.a_update_client(
  3382. client_id="does-not-exist", payload={"name": "test-client-change"},
  3383. )
  3384. assert err.match('404: b\'{"error":"Could not find client".*}\'')
  3385. # Test client mappers
  3386. res = await admin.a_get_mappers_from_client(client_id=client_id)
  3387. assert len(res) == 0
  3388. with pytest.raises(KeycloakPostError) as err:
  3389. await admin.a_add_mapper_to_client(client_id="does-not-exist", payload=dict())
  3390. assert err.match('404: b\'{"error":"Could not find client".*}\'')
  3391. res = await admin.a_add_mapper_to_client(
  3392. client_id=client_id,
  3393. payload={
  3394. "name": "test-mapper",
  3395. "protocol": "openid-connect",
  3396. "protocolMapper": "oidc-usermodel-attribute-mapper",
  3397. },
  3398. )
  3399. assert res == b""
  3400. assert len(await admin.a_get_mappers_from_client(client_id=client_id)) == 1
  3401. mapper = (await admin.a_get_mappers_from_client(client_id=client_id))[0]
  3402. with pytest.raises(KeycloakPutError) as err:
  3403. await admin.a_update_client_mapper(
  3404. client_id=client_id, mapper_id="does-not-exist", payload=dict(),
  3405. )
  3406. assert err.match('404: b\'{"error":"Model not found".*}\'')
  3407. mapper["config"]["user.attribute"] = "test"
  3408. res = await admin.a_update_client_mapper(
  3409. client_id=client_id, mapper_id=mapper["id"], payload=mapper,
  3410. )
  3411. assert res == dict()
  3412. res = await admin.a_remove_client_mapper(client_id=client_id, client_mapper_id=mapper["id"])
  3413. assert res == dict()
  3414. with pytest.raises(KeycloakDeleteError) as err:
  3415. await admin.a_remove_client_mapper(client_id=client_id, client_mapper_id=mapper["id"])
  3416. assert err.match('404: b\'{"error":"Model not found".*}\'')
  3417. # Test client sessions
  3418. with pytest.raises(KeycloakGetError) as err:
  3419. await admin.a_get_client_all_sessions(client_id="does-not-exist")
  3420. assert err.match('404: b\'{"error":"Could not find client".*}\'')
  3421. assert await admin.a_get_client_all_sessions(client_id=client_id) == list()
  3422. assert await admin.a_get_client_sessions_stats() == list()
  3423. # Test authz
  3424. auth_client_id = await admin.a_create_client(
  3425. payload={
  3426. "name": "authz-client",
  3427. "clientId": "authz-client",
  3428. "authorizationServicesEnabled": True,
  3429. "serviceAccountsEnabled": True,
  3430. },
  3431. )
  3432. res = await admin.a_get_client_authz_settings(client_id=auth_client_id)
  3433. assert res["allowRemoteResourceManagement"]
  3434. assert res["decisionStrategy"] == "UNANIMOUS"
  3435. assert len(res["policies"]) >= 0
  3436. with pytest.raises(KeycloakGetError) as err:
  3437. await admin.a_get_client_authz_settings(client_id=client_id)
  3438. assert err.match(HTTP_404_REGEX)
  3439. # Authz resources
  3440. res = await admin.a_get_client_authz_resources(client_id=auth_client_id)
  3441. assert len(res) == 1
  3442. assert res[0]["name"] == "Default Resource"
  3443. with pytest.raises(KeycloakGetError) as err:
  3444. await admin.a_get_client_authz_resources(client_id=client_id)
  3445. assert err.match(HTTP_404_REGEX)
  3446. res = await admin.a_create_client_authz_resource(
  3447. client_id=auth_client_id, payload={"name": "test-resource"},
  3448. )
  3449. assert res["name"] == "test-resource", res
  3450. test_resource_id = res["_id"]
  3451. res = await admin.a_get_client_authz_resource(
  3452. client_id=auth_client_id, resource_id=test_resource_id,
  3453. )
  3454. assert res["_id"] == test_resource_id, res
  3455. assert res["name"] == "test-resource", res
  3456. with pytest.raises(KeycloakPostError) as err:
  3457. await admin.a_create_client_authz_resource(
  3458. client_id=auth_client_id, payload={"name": "test-resource"},
  3459. )
  3460. assert err.match('409: b\'{"error":"invalid_request"')
  3461. assert await admin.a_create_client_authz_resource(
  3462. client_id=auth_client_id, payload={"name": "test-resource"}, skip_exists=True,
  3463. ) == {"msg": "Already exists"}
  3464. res = await admin.a_get_client_authz_resources(client_id=auth_client_id)
  3465. assert len(res) == 2
  3466. assert {x["name"] for x in res} == {"Default Resource", "test-resource"}
  3467. res = await admin.a_create_client_authz_resource(
  3468. client_id=auth_client_id, payload={"name": "temp-resource"},
  3469. )
  3470. assert res["name"] == "temp-resource", res
  3471. temp_resource_id: str = res["_id"]
  3472. # Test update authz resources
  3473. await admin.a_update_client_authz_resource(
  3474. client_id=auth_client_id,
  3475. resource_id=temp_resource_id,
  3476. payload={"name": "temp-updated-resource"},
  3477. )
  3478. res = await admin.a_get_client_authz_resource(
  3479. client_id=auth_client_id, resource_id=temp_resource_id,
  3480. )
  3481. assert res["name"] == "temp-updated-resource", res
  3482. with pytest.raises(KeycloakPutError) as err:
  3483. await admin.a_update_client_authz_resource(
  3484. client_id=auth_client_id,
  3485. resource_id="invalid_resource_id",
  3486. payload={"name": "temp-updated-resource"},
  3487. )
  3488. assert err.match("404: b''"), err
  3489. await admin.a_delete_client_authz_resource(
  3490. client_id=auth_client_id, resource_id=temp_resource_id,
  3491. )
  3492. with pytest.raises(KeycloakGetError) as err:
  3493. await admin.a_get_client_authz_resource(
  3494. client_id=auth_client_id, resource_id=temp_resource_id,
  3495. )
  3496. assert err.match("404: b''")
  3497. # Authz policies
  3498. res = await admin.a_get_client_authz_policies(client_id=auth_client_id)
  3499. assert len(res) == 1, res
  3500. assert res[0]["name"] == "Default Policy"
  3501. with pytest.raises(KeycloakGetError) as err:
  3502. await admin.a_get_client_authz_policies(client_id="does-not-exist")
  3503. assert err.match('404: b\'{"error":"Could not find client".*}\'')
  3504. role_id = (await admin.a_get_realm_role(role_name="offline_access"))["id"]
  3505. res = await admin.a_create_client_authz_role_based_policy(
  3506. client_id=auth_client_id,
  3507. payload={"name": "test-authz-rb-policy", "roles": [{"id": role_id}]},
  3508. )
  3509. assert res["name"] == "test-authz-rb-policy", res
  3510. with pytest.raises(KeycloakPostError) as err:
  3511. await admin.a_create_client_authz_role_based_policy(
  3512. client_id=auth_client_id,
  3513. payload={"name": "test-authz-rb-policy", "roles": [{"id": role_id}]},
  3514. )
  3515. assert err.match('409: b\'{"error":"Policy with name')
  3516. assert await admin.a_create_client_authz_role_based_policy(
  3517. client_id=auth_client_id,
  3518. payload={"name": "test-authz-rb-policy", "roles": [{"id": role_id}]},
  3519. skip_exists=True,
  3520. ) == {"msg": "Already exists"}
  3521. assert len(await admin.a_get_client_authz_policies(client_id=auth_client_id)) == 2
  3522. role_based_policy_id = res["id"]
  3523. role_based_policy_name = res["name"]
  3524. res = await admin.a_create_client_authz_role_based_policy(
  3525. client_id=auth_client_id,
  3526. payload={"name": "test-authz-rb-policy-delete", "roles": [{"id": role_id}]},
  3527. )
  3528. res2 = await admin.a_get_client_authz_policy(client_id=auth_client_id, policy_id=res["id"])
  3529. assert res["id"] == res2["id"]
  3530. await admin.a_delete_client_authz_policy(client_id=auth_client_id, policy_id=res["id"])
  3531. with pytest.raises(KeycloakGetError) as err:
  3532. await admin.a_get_client_authz_policy(client_id=auth_client_id, policy_id=res["id"])
  3533. assert err.match("404: b''")
  3534. res = await admin.a_create_client_authz_policy(
  3535. client_id=auth_client_id,
  3536. payload={
  3537. "name": "test-authz-policy",
  3538. "type": "time",
  3539. "config": {"hourEnd": "18", "hour": "9"},
  3540. },
  3541. )
  3542. assert res["name"] == "test-authz-policy", res
  3543. with pytest.raises(KeycloakPostError) as err:
  3544. await admin.a_create_client_authz_policy(
  3545. client_id=auth_client_id,
  3546. payload={
  3547. "name": "test-authz-policy",
  3548. "type": "time",
  3549. "config": {"hourEnd": "18", "hour": "9"},
  3550. },
  3551. )
  3552. assert err.match('409: b\'{"error":"Policy with name')
  3553. assert await admin.a_create_client_authz_policy(
  3554. client_id=auth_client_id,
  3555. payload={
  3556. "name": "test-authz-policy",
  3557. "type": "time",
  3558. "config": {"hourEnd": "18", "hour": "9"},
  3559. },
  3560. skip_exists=True,
  3561. ) == {"msg": "Already exists"}
  3562. assert len(await admin.a_get_client_authz_policies(client_id=auth_client_id)) == 3
  3563. # Test authz permissions
  3564. res = await admin.a_get_client_authz_permissions(client_id=auth_client_id)
  3565. assert len(res) == 1, res
  3566. assert res[0]["name"] == "Default Permission"
  3567. with pytest.raises(KeycloakGetError) as err:
  3568. await admin.a_get_client_authz_permissions(client_id="does-not-exist")
  3569. assert err.match('404: b\'{"error":"Could not find client".*}\'')
  3570. res = await admin.a_create_client_authz_resource_based_permission(
  3571. client_id=auth_client_id,
  3572. payload={"name": "test-permission-rb", "resources": [test_resource_id]},
  3573. )
  3574. assert res, res
  3575. assert res["name"] == "test-permission-rb"
  3576. assert res["resources"] == [test_resource_id]
  3577. resource_based_permission_id = res["id"]
  3578. resource_based_permission_name = res["name"]
  3579. with pytest.raises(KeycloakPostError) as err:
  3580. await admin.a_create_client_authz_resource_based_permission(
  3581. client_id=auth_client_id,
  3582. payload={"name": "test-permission-rb", "resources": [test_resource_id]},
  3583. )
  3584. assert err.match('409: b\'{"error":"Policy with name')
  3585. assert await admin.a_create_client_authz_resource_based_permission(
  3586. client_id=auth_client_id,
  3587. payload={"name": "test-permission-rb", "resources": [test_resource_id]},
  3588. skip_exists=True,
  3589. ) == {"msg": "Already exists"}
  3590. assert len(await admin.a_get_client_authz_permissions(client_id=auth_client_id)) == 2
  3591. # Test associating client policy with resource based permission
  3592. res = await admin.a_update_client_authz_resource_permission(
  3593. client_id=auth_client_id,
  3594. resource_id=resource_based_permission_id,
  3595. payload={
  3596. "id": resource_based_permission_id,
  3597. "name": resource_based_permission_name,
  3598. "type": "resource",
  3599. "logic": "POSITIVE",
  3600. "decisionStrategy": "UNANIMOUS",
  3601. "resources": [test_resource_id],
  3602. "scopes": [],
  3603. "policies": [role_based_policy_id],
  3604. },
  3605. )
  3606. # Test getting associated policies for a permission
  3607. associated_policies = await admin.a_get_client_authz_permission_associated_policies(
  3608. client_id=auth_client_id, policy_id=resource_based_permission_id,
  3609. )
  3610. assert len(associated_policies) == 1
  3611. assert associated_policies[0]["name"].startswith(role_based_policy_name)
  3612. # Test authz scopes
  3613. res = await admin.a_get_client_authz_scopes(client_id=auth_client_id)
  3614. assert len(res) == 0, res
  3615. with pytest.raises(KeycloakGetError) as err:
  3616. await admin.a_get_client_authz_scopes(client_id=client_id)
  3617. assert err.match(HTTP_404_REGEX)
  3618. res = await admin.a_create_client_authz_scopes(
  3619. client_id=auth_client_id, payload={"name": "test-authz-scope"},
  3620. )
  3621. assert res["name"] == "test-authz-scope", res
  3622. with pytest.raises(KeycloakPostError) as err:
  3623. await admin.a_create_client_authz_scopes(
  3624. client_id="invalid_client_id", payload={"name": "test-authz-scope"},
  3625. )
  3626. assert err.match('404: b\'{"error":"Could not find client".*}\'')
  3627. assert await admin.a_create_client_authz_scopes(
  3628. client_id=auth_client_id, payload={"name": "test-authz-scope"},
  3629. )
  3630. res = await admin.a_get_client_authz_scopes(client_id=auth_client_id)
  3631. assert len(res) == 1
  3632. assert {x["name"] for x in res} == {"test-authz-scope"}
  3633. # Test service account user
  3634. res = await admin.a_get_client_service_account_user(client_id=auth_client_id)
  3635. assert res["username"] == "service-account-authz-client", res
  3636. with pytest.raises(KeycloakGetError) as err:
  3637. await admin.a_get_client_service_account_user(client_id=client_id)
  3638. assert ('b\'{"error":"Service account not enabled for the client' in str(err)) or err.match(
  3639. UNKOWN_ERROR_REGEX,
  3640. )
  3641. # Test delete client
  3642. res = await admin.a_delete_client(client_id=auth_client_id)
  3643. assert res == dict(), res
  3644. with pytest.raises(KeycloakDeleteError) as err:
  3645. await admin.a_delete_client(client_id=auth_client_id)
  3646. assert err.match('404: b\'{"error":"Could not find client".*}\'')
  3647. # Test client credentials
  3648. await admin.a_create_client(
  3649. payload={
  3650. "name": "test-confidential",
  3651. "enabled": True,
  3652. "protocol": "openid-connect",
  3653. "publicClient": False,
  3654. "redirectUris": ["http://localhost/*"],
  3655. "webOrigins": ["+"],
  3656. "clientId": "test-confidential",
  3657. "secret": "test-secret",
  3658. "clientAuthenticatorType": "client-secret",
  3659. },
  3660. )
  3661. with pytest.raises(KeycloakGetError) as err:
  3662. await admin.a_get_client_secrets(client_id="does-not-exist")
  3663. assert err.match('404: b\'{"error":"Could not find client".*}\'')
  3664. secrets = await admin.a_get_client_secrets(
  3665. client_id=await admin.a_get_client_id(client_id="test-confidential"),
  3666. )
  3667. assert secrets == {"type": "secret", "value": "test-secret"}
  3668. with pytest.raises(KeycloakPostError) as err:
  3669. await admin.a_generate_client_secrets(client_id="does-not-exist")
  3670. assert err.match('404: b\'{"error":"Could not find client".*}\'')
  3671. res = await admin.a_generate_client_secrets(
  3672. client_id=await admin.a_get_client_id(client_id="test-confidential"),
  3673. )
  3674. assert res
  3675. assert (
  3676. await admin.a_get_client_secrets(
  3677. client_id=await admin.a_get_client_id(client_id="test-confidential"),
  3678. )
  3679. == res
  3680. )
  3681. @pytest.mark.asyncio
  3682. async def test_a_realm_roles(admin: KeycloakAdmin, realm: str):
  3683. """Test realm roles.
  3684. :param admin: Keycloak Admin client
  3685. :type admin: KeycloakAdmin
  3686. :param realm: Keycloak realm
  3687. :type realm: str
  3688. """
  3689. await admin.a_change_current_realm(realm)
  3690. # Test get realm roles
  3691. roles = await admin.a_get_realm_roles()
  3692. assert len(roles) == 3, roles
  3693. role_names = [x["name"] for x in roles]
  3694. assert "uma_authorization" in role_names, role_names
  3695. assert "offline_access" in role_names, role_names
  3696. # Test get realm roles with search text
  3697. searched_roles = await admin.a_get_realm_roles(search_text="uma_a")
  3698. searched_role_names = [x["name"] for x in searched_roles]
  3699. assert "uma_authorization" in searched_role_names, searched_role_names
  3700. assert "offline_access" not in searched_role_names, searched_role_names
  3701. # Test empty members
  3702. with pytest.raises(KeycloakGetError) as err:
  3703. await admin.a_get_realm_role_members(role_name="does-not-exist")
  3704. assert err.match(COULD_NOT_FIND_ROLE_REGEX)
  3705. members = await admin.a_get_realm_role_members(role_name="offline_access")
  3706. assert members == list(), members
  3707. # Test create realm role
  3708. role_id = await admin.a_create_realm_role(
  3709. payload={"name": "test-realm-role"}, skip_exists=True,
  3710. )
  3711. assert role_id, role_id
  3712. with pytest.raises(KeycloakPostError) as err:
  3713. await admin.a_create_realm_role(payload={"name": "test-realm-role"})
  3714. assert err.match('409: b\'{"errorMessage":"Role with name test-realm-role already exists"}\'')
  3715. role_id_2 = await admin.a_create_realm_role(
  3716. payload={"name": "test-realm-role"}, skip_exists=True,
  3717. )
  3718. assert role_id == role_id_2
  3719. # Test get realm role by its id
  3720. role_id = (await admin.a_get_realm_role(role_name="test-realm-role"))["id"]
  3721. res = await admin.a_get_realm_role_by_id(role_id)
  3722. assert res["name"] == "test-realm-role"
  3723. # Test update realm role
  3724. res = await admin.a_update_realm_role(
  3725. role_name="test-realm-role", payload={"name": "test-realm-role-update"},
  3726. )
  3727. assert res == dict(), res
  3728. with pytest.raises(KeycloakPutError) as err:
  3729. await admin.a_update_realm_role(
  3730. role_name="test-realm-role", payload={"name": "test-realm-role-update"},
  3731. )
  3732. assert err.match(COULD_NOT_FIND_ROLE_REGEX)
  3733. # Test realm role user assignment
  3734. user_id = await admin.a_create_user(
  3735. payload={"username": "role-testing", "email": "test@test.test"},
  3736. )
  3737. with pytest.raises(KeycloakPostError) as err:
  3738. await admin.a_assign_realm_roles(user_id=user_id, roles=["bad"])
  3739. assert err.match(UNKOWN_ERROR_REGEX), err
  3740. res = await admin.a_assign_realm_roles(
  3741. user_id=user_id,
  3742. roles=[
  3743. await admin.a_get_realm_role(role_name="offline_access"),
  3744. await admin.a_get_realm_role(role_name="test-realm-role-update"),
  3745. ],
  3746. )
  3747. assert res == dict(), res
  3748. assert admin.get_user(user_id=user_id)["username"] in [
  3749. x["username"] for x in await admin.a_get_realm_role_members(role_name="offline_access")
  3750. ]
  3751. assert admin.get_user(user_id=user_id)["username"] in [
  3752. x["username"]
  3753. for x in await admin.a_get_realm_role_members(role_name="test-realm-role-update")
  3754. ]
  3755. roles = await admin.a_get_realm_roles_of_user(user_id=user_id)
  3756. assert len(roles) == 3
  3757. assert "offline_access" in [x["name"] for x in roles]
  3758. assert "test-realm-role-update" in [x["name"] for x in roles]
  3759. with pytest.raises(KeycloakDeleteError) as err:
  3760. admin.delete_realm_roles_of_user(user_id=user_id, roles=["bad"])
  3761. assert err.match(UNKOWN_ERROR_REGEX), err
  3762. res = await admin.a_delete_realm_roles_of_user(
  3763. user_id=user_id, roles=[await admin.a_get_realm_role(role_name="offline_access")],
  3764. )
  3765. assert res == dict(), res
  3766. assert await admin.a_get_realm_role_members(role_name="offline_access") == list()
  3767. roles = await admin.a_get_realm_roles_of_user(user_id=user_id)
  3768. assert len(roles) == 2
  3769. assert "offline_access" not in [x["name"] for x in roles]
  3770. assert "test-realm-role-update" in [x["name"] for x in roles]
  3771. roles = await admin.a_get_available_realm_roles_of_user(user_id=user_id)
  3772. assert len(roles) == 2
  3773. assert "offline_access" in [x["name"] for x in roles]
  3774. assert "uma_authorization" in [x["name"] for x in roles]
  3775. # Test realm role group assignment
  3776. group_id = await admin.a_create_group(payload={"name": "test-group"})
  3777. with pytest.raises(KeycloakPostError) as err:
  3778. await admin.a_assign_group_realm_roles(group_id=group_id, roles=["bad"])
  3779. assert err.match(UNKOWN_ERROR_REGEX), err
  3780. res = await admin.a_assign_group_realm_roles(
  3781. group_id=group_id,
  3782. roles=[
  3783. await admin.a_get_realm_role(role_name="offline_access"),
  3784. await admin.a_get_realm_role(role_name="test-realm-role-update"),
  3785. ],
  3786. )
  3787. assert res == dict(), res
  3788. roles = await admin.a_get_group_realm_roles(group_id=group_id)
  3789. assert len(roles) == 2
  3790. assert "offline_access" in [x["name"] for x in roles]
  3791. assert "test-realm-role-update" in [x["name"] for x in roles]
  3792. with pytest.raises(KeycloakDeleteError) as err:
  3793. await admin.a_delete_group_realm_roles(group_id=group_id, roles=["bad"])
  3794. assert err.match(UNKOWN_ERROR_REGEX)
  3795. res = await admin.a_delete_group_realm_roles(
  3796. group_id=group_id, roles=[admin.get_realm_role(role_name="offline_access")],
  3797. )
  3798. assert res == dict(), res
  3799. roles = await admin.a_get_group_realm_roles(group_id=group_id)
  3800. assert len(roles) == 1
  3801. assert "test-realm-role-update" in [x["name"] for x in roles]
  3802. # Test composite realm roles
  3803. composite_role = await admin.a_create_realm_role(payload={"name": "test-composite-role"})
  3804. with pytest.raises(KeycloakPostError) as err:
  3805. await admin.a_add_composite_realm_roles_to_role(role_name=composite_role, roles=["bad"])
  3806. assert err.match(UNKOWN_ERROR_REGEX), err
  3807. res = await admin.a_add_composite_realm_roles_to_role(
  3808. role_name=composite_role, roles=[admin.get_realm_role(role_name="test-realm-role-update")],
  3809. )
  3810. assert res == dict(), res
  3811. res = await admin.a_get_composite_realm_roles_of_role(role_name=composite_role)
  3812. assert len(res) == 1
  3813. assert "test-realm-role-update" in res[0]["name"]
  3814. with pytest.raises(KeycloakGetError) as err:
  3815. await admin.a_get_composite_realm_roles_of_role(role_name="bad")
  3816. assert err.match(COULD_NOT_FIND_ROLE_REGEX)
  3817. res = await admin.a_get_composite_realm_roles_of_user(user_id=user_id)
  3818. assert len(res) == 4
  3819. assert "offline_access" in {x["name"] for x in res}
  3820. assert "test-realm-role-update" in {x["name"] for x in res}
  3821. assert "uma_authorization" in {x["name"] for x in res}
  3822. with pytest.raises(KeycloakGetError) as err:
  3823. await admin.a_get_composite_realm_roles_of_user(user_id="bad")
  3824. assert err.match(USER_NOT_FOUND_REGEX), err
  3825. with pytest.raises(KeycloakDeleteError) as err:
  3826. await admin.a_remove_composite_realm_roles_to_role(role_name=composite_role, roles=["bad"])
  3827. assert err.match(UNKOWN_ERROR_REGEX), err
  3828. res = await admin.a_remove_composite_realm_roles_to_role(
  3829. role_name=composite_role, roles=[admin.get_realm_role(role_name="test-realm-role-update")],
  3830. )
  3831. assert res == dict(), res
  3832. res = await admin.a_get_composite_realm_roles_of_role(role_name=composite_role)
  3833. assert len(res) == 0
  3834. # Test realm role group list
  3835. res = await admin.a_get_realm_role_groups(role_name="test-realm-role-update")
  3836. assert len(res) == 1
  3837. assert res[0]["id"] == group_id
  3838. with pytest.raises(KeycloakGetError) as err:
  3839. await admin.a_get_realm_role_groups(role_name="non-existent-role")
  3840. assert err.match(COULD_NOT_FIND_ROLE_REGEX)
  3841. # Test with query params
  3842. res = await admin.a_get_realm_role_groups(role_name="test-realm-role-update", query={"max": 1})
  3843. assert len(res) == 1
  3844. # Test delete realm role
  3845. res = await admin.a_delete_realm_role(role_name=composite_role)
  3846. assert res == dict(), res
  3847. with pytest.raises(KeycloakDeleteError) as err:
  3848. await admin.a_delete_realm_role(role_name=composite_role)
  3849. assert err.match(COULD_NOT_FIND_ROLE_REGEX)
  3850. @pytest.mark.asyncio
  3851. @pytest.mark.parametrize(
  3852. "testcase, arg_brief_repr, includes_attributes",
  3853. [
  3854. ("brief True", {"brief_representation": True}, False),
  3855. ("brief False", {"brief_representation": False}, True),
  3856. ("default", {}, False),
  3857. ],
  3858. )
  3859. async def test_a_role_attributes(
  3860. admin: KeycloakAdmin,
  3861. realm: str,
  3862. client: str,
  3863. arg_brief_repr: dict,
  3864. includes_attributes: bool,
  3865. testcase: str,
  3866. ):
  3867. """Test getting role attributes for bulk calls.
  3868. :param admin: Keycloak admin
  3869. :type admin: KeycloakAdmin
  3870. :param realm: Keycloak realm
  3871. :type realm: str
  3872. :param client: Keycloak client
  3873. :type client: str
  3874. :param arg_brief_repr: Brief representation
  3875. :type arg_brief_repr: dict
  3876. :param includes_attributes: Indicator whether to include attributes
  3877. :type includes_attributes: bool
  3878. :param testcase: Test case
  3879. :type testcase: str
  3880. """
  3881. # setup
  3882. attribute_role = "test-realm-role-w-attr"
  3883. test_attrs = {"attr1": ["val1"], "attr2": ["val2-1", "val2-2"]}
  3884. role_id = await admin.a_create_realm_role(
  3885. payload={"name": attribute_role, "attributes": test_attrs}, skip_exists=True,
  3886. )
  3887. assert role_id, role_id
  3888. cli_role_id = await admin.a_create_client_role(
  3889. client, payload={"name": attribute_role, "attributes": test_attrs}, skip_exists=True,
  3890. )
  3891. assert cli_role_id, cli_role_id
  3892. if not includes_attributes:
  3893. test_attrs = None
  3894. # tests
  3895. roles = await admin.a_get_realm_roles(**arg_brief_repr)
  3896. roles_filtered = [role for role in roles if role["name"] == role_id]
  3897. assert roles_filtered, roles_filtered
  3898. role = roles_filtered[0]
  3899. assert role.get("attributes") == test_attrs, testcase
  3900. roles = await admin.a_get_client_roles(client, **arg_brief_repr)
  3901. roles_filtered = [role for role in roles if role["name"] == cli_role_id]
  3902. assert roles_filtered, roles_filtered
  3903. role = roles_filtered[0]
  3904. assert role.get("attributes") == test_attrs, testcase
  3905. # cleanup
  3906. res = await admin.a_delete_realm_role(role_name=attribute_role)
  3907. assert res == dict(), res
  3908. res = await admin.a_delete_client_role(client, role_name=attribute_role)
  3909. assert res == dict(), res
  3910. @pytest.mark.asyncio
  3911. async def test_a_client_scope_realm_roles(admin: KeycloakAdmin, realm: str):
  3912. """Test client realm roles.
  3913. :param admin: Keycloak admin
  3914. :type admin: KeycloakAdmin
  3915. :param realm: Keycloak realm
  3916. :type realm: str
  3917. """
  3918. await admin.a_change_current_realm(realm)
  3919. # Test get realm roles
  3920. roles = await admin.a_get_realm_roles()
  3921. assert len(roles) == 3, roles
  3922. role_names = [x["name"] for x in roles]
  3923. assert "uma_authorization" in role_names, role_names
  3924. assert "offline_access" in role_names, role_names
  3925. # create realm role for test
  3926. role_id = await admin.a_create_realm_role(
  3927. payload={"name": "test-realm-role"}, skip_exists=True,
  3928. )
  3929. assert role_id, role_id
  3930. # Test realm role client assignment
  3931. client_id = await admin.a_create_client(
  3932. payload={"name": "role-testing-client", "clientId": "role-testing-client"},
  3933. )
  3934. with pytest.raises(KeycloakPostError) as err:
  3935. await admin.a_assign_realm_roles_to_client_scope(client_id=client_id, roles=["bad"])
  3936. assert err.match(UNKOWN_ERROR_REGEX), err
  3937. res = await admin.a_assign_realm_roles_to_client_scope(
  3938. client_id=client_id,
  3939. roles=[
  3940. await admin.a_get_realm_role(role_name="offline_access"),
  3941. await admin.a_get_realm_role(role_name="test-realm-role"),
  3942. ],
  3943. )
  3944. assert res == dict(), res
  3945. roles = await admin.a_get_realm_roles_of_client_scope(client_id=client_id)
  3946. assert len(roles) == 2
  3947. client_role_names = [x["name"] for x in roles]
  3948. assert "offline_access" in client_role_names, client_role_names
  3949. assert "test-realm-role" in client_role_names, client_role_names
  3950. assert "uma_authorization" not in client_role_names, client_role_names
  3951. # Test remove realm role of client
  3952. with pytest.raises(KeycloakDeleteError) as err:
  3953. await admin.a_delete_realm_roles_of_client_scope(client_id=client_id, roles=["bad"])
  3954. assert err.match(UNKOWN_ERROR_REGEX), err
  3955. res = await admin.a_delete_realm_roles_of_client_scope(
  3956. client_id=client_id, roles=[await admin.a_get_realm_role(role_name="offline_access")],
  3957. )
  3958. assert res == dict(), res
  3959. roles = await admin.a_get_realm_roles_of_client_scope(client_id=client_id)
  3960. assert len(roles) == 1
  3961. assert "test-realm-role" in [x["name"] for x in roles]
  3962. res = await admin.a_delete_realm_roles_of_client_scope(
  3963. client_id=client_id, roles=[await admin.a_get_realm_role(role_name="test-realm-role")],
  3964. )
  3965. assert res == dict(), res
  3966. roles = await admin.a_get_realm_roles_of_client_scope(client_id=client_id)
  3967. assert len(roles) == 0
  3968. @pytest.mark.asyncio
  3969. async def test_a_client_scope_client_roles(admin: KeycloakAdmin, realm: str, client: str):
  3970. """Test client assignment of other client roles.
  3971. :param admin: Keycloak admin
  3972. :type admin: KeycloakAdmin
  3973. :param realm: Keycloak realm
  3974. :type realm: str
  3975. :param client: Keycloak client
  3976. :type client: str
  3977. """
  3978. await admin.a_change_current_realm(realm)
  3979. client_id = await admin.a_create_client(
  3980. payload={"name": "role-testing-client", "clientId": "role-testing-client"},
  3981. )
  3982. # Test get client roles
  3983. roles = await admin.a_get_client_roles_of_client_scope(client_id, client)
  3984. assert len(roles) == 0, roles
  3985. # create client role for test
  3986. client_role_id = await admin.a_create_client_role(
  3987. client_role_id=client, payload={"name": "client-role-test"}, skip_exists=True,
  3988. )
  3989. assert client_role_id, client_role_id
  3990. # Test client role assignment to other client
  3991. with pytest.raises(KeycloakPostError) as err:
  3992. await admin.a_assign_client_roles_to_client_scope(
  3993. client_id=client_id, client_roles_owner_id=client, roles=["bad"],
  3994. )
  3995. assert err.match(UNKOWN_ERROR_REGEX), err
  3996. res = await admin.a_assign_client_roles_to_client_scope(
  3997. client_id=client_id,
  3998. client_roles_owner_id=client,
  3999. roles=[await admin.a_get_client_role(client_id=client, role_name="client-role-test")],
  4000. )
  4001. assert res == dict(), res
  4002. roles = await admin.a_get_client_roles_of_client_scope(
  4003. client_id=client_id, client_roles_owner_id=client,
  4004. )
  4005. assert len(roles) == 1
  4006. client_role_names = [x["name"] for x in roles]
  4007. assert "client-role-test" in client_role_names, client_role_names
  4008. # Test remove realm role of client
  4009. with pytest.raises(KeycloakDeleteError) as err:
  4010. await admin.a_delete_client_roles_of_client_scope(
  4011. client_id=client_id, client_roles_owner_id=client, roles=["bad"],
  4012. )
  4013. assert err.match(UNKOWN_ERROR_REGEX), err
  4014. res = await admin.a_delete_client_roles_of_client_scope(
  4015. client_id=client_id,
  4016. client_roles_owner_id=client,
  4017. roles=[await admin.a_get_client_role(client_id=client, role_name="client-role-test")],
  4018. )
  4019. assert res == dict(), res
  4020. roles = await admin.a_get_client_roles_of_client_scope(
  4021. client_id=client_id, client_roles_owner_id=client,
  4022. )
  4023. assert len(roles) == 0
  4024. @pytest.mark.asyncio
  4025. async def test_a_client_scope_mapping_client_roles(admin: KeycloakAdmin, realm: str, client: str):
  4026. """Test client scope assignment of client roles.
  4027. :param admin: Keycloak admin
  4028. :type admin: KeycloakAdmin
  4029. :param realm: Keycloak realm
  4030. :type realm: str
  4031. :param client: Keycloak client owning roles
  4032. :type client: str
  4033. """
  4034. CLIENT_ROLE_NAME = "some-client-role"
  4035. await admin.a_change_current_realm(realm)
  4036. client_obj = await admin.a_get_client(client)
  4037. client_name = client_obj["name"]
  4038. client_scope = {
  4039. "name": "test_client_scope",
  4040. "description": "Test Client Scope",
  4041. "protocol": "openid-connect",
  4042. "attributes": {},
  4043. }
  4044. client_scope_id = await admin.a_create_client_scope(client_scope, skip_exists=False)
  4045. # Test get client roles
  4046. client_specific_roles = await admin.a_get_client_specific_roles_of_client_scope(
  4047. client_scope_id, client,
  4048. )
  4049. assert len(client_specific_roles) == 0, client_specific_roles
  4050. all_roles = await admin.a_get_all_roles_of_client_scope(client_scope_id)
  4051. assert len(all_roles) == 0, all_roles
  4052. # create client role for test
  4053. client_role_name = await admin.a_create_client_role(
  4054. client_role_id=client, payload={"name": CLIENT_ROLE_NAME}, skip_exists=True,
  4055. )
  4056. assert client_role_name, client_role_name
  4057. # Test client role assignment to other client
  4058. with pytest.raises(KeycloakPostError) as err:
  4059. await admin.a_add_client_specific_roles_to_client_scope(
  4060. client_scope_id=client_scope_id, client_roles_owner_id=client, roles=["bad"],
  4061. )
  4062. assert err.match(UNKOWN_ERROR_REGEX), err
  4063. res = await admin.a_add_client_specific_roles_to_client_scope(
  4064. client_scope_id=client_scope_id,
  4065. client_roles_owner_id=client,
  4066. roles=[await admin.a_get_client_role(client_id=client, role_name=CLIENT_ROLE_NAME)],
  4067. )
  4068. assert res == dict(), res
  4069. # Test when getting roles for the specific owner client
  4070. client_specific_roles = await admin.a_get_client_specific_roles_of_client_scope(
  4071. client_scope_id=client_scope_id, client_roles_owner_id=client,
  4072. )
  4073. assert len(client_specific_roles) == 1
  4074. client_role_names = [x["name"] for x in client_specific_roles]
  4075. assert CLIENT_ROLE_NAME in client_role_names, client_role_names
  4076. # Test when getting all roles for the client scope
  4077. all_roles = await admin.a_get_all_roles_of_client_scope(client_scope_id=client_scope_id)
  4078. assert "clientMappings" in all_roles, all_roles
  4079. all_roles_clients = all_roles["clientMappings"]
  4080. assert client_name in all_roles_clients, all_roles_clients
  4081. mappings = all_roles_clients[client_name]["mappings"]
  4082. client_role_names = [x["name"] for x in mappings]
  4083. assert CLIENT_ROLE_NAME in client_role_names, client_role_names
  4084. # Test remove realm role of client
  4085. with pytest.raises(KeycloakDeleteError) as err:
  4086. await admin.a_remove_client_specific_roles_of_client_scope(
  4087. client_scope_id=client_scope_id, client_roles_owner_id=client, roles=["bad"],
  4088. )
  4089. assert err.match(UNKOWN_ERROR_REGEX), err
  4090. res = await admin.a_remove_client_specific_roles_of_client_scope(
  4091. client_scope_id=client_scope_id,
  4092. client_roles_owner_id=client,
  4093. roles=[await admin.a_get_client_role(client_id=client, role_name=CLIENT_ROLE_NAME)],
  4094. )
  4095. assert res == dict(), res
  4096. all_roles = await admin.a_get_all_roles_of_client_scope(client_scope_id=client_scope_id)
  4097. assert len(all_roles) == 0
  4098. @pytest.mark.asyncio
  4099. async def test_a_client_default_client_scopes(admin: KeycloakAdmin, realm: str, client: str):
  4100. """Test client assignment of default client scopes.
  4101. :param admin: Keycloak admin
  4102. :type admin: KeycloakAdmin
  4103. :param realm: Keycloak realm
  4104. :type realm: str
  4105. :param client: Keycloak client
  4106. :type client: str
  4107. """
  4108. await admin.a_change_current_realm(realm)
  4109. client_id = await admin.a_create_client(
  4110. payload={"name": "role-testing-client", "clientId": "role-testing-client"},
  4111. )
  4112. # Test get client default scopes
  4113. # keycloak default roles: web-origins, acr, profile, roles, email
  4114. default_client_scopes = await admin.a_get_client_default_client_scopes(client_id)
  4115. assert len(default_client_scopes) in [6, 5], default_client_scopes
  4116. # Test add a client scope to client default scopes
  4117. default_client_scope = "test-client-default-scope"
  4118. new_client_scope = {
  4119. "name": default_client_scope,
  4120. "description": f"Test Client Scope: {default_client_scope}",
  4121. "protocol": "openid-connect",
  4122. "attributes": {},
  4123. }
  4124. new_client_scope_id = await admin.a_create_client_scope(new_client_scope, skip_exists=False)
  4125. new_default_client_scope_data = {
  4126. "realm": realm,
  4127. "client": client_id,
  4128. "clientScopeId": new_client_scope_id,
  4129. }
  4130. await admin.a_add_client_default_client_scope(
  4131. client_id, new_client_scope_id, new_default_client_scope_data,
  4132. )
  4133. default_client_scopes = await admin.a_get_client_default_client_scopes(client_id)
  4134. assert len(default_client_scopes) in [6, 7], default_client_scopes
  4135. # Test remove a client default scope
  4136. await admin.a_delete_client_default_client_scope(client_id, new_client_scope_id)
  4137. default_client_scopes = await admin.a_get_client_default_client_scopes(client_id)
  4138. assert len(default_client_scopes) in [5, 6], default_client_scopes
  4139. @pytest.mark.asyncio
  4140. async def test_a_client_optional_client_scopes(admin: KeycloakAdmin, realm: str, client: str):
  4141. """Test client assignment of optional client scopes.
  4142. :param admin: Keycloak admin
  4143. :type admin: KeycloakAdmin
  4144. :param realm: Keycloak realm
  4145. :type realm: str
  4146. :param client: Keycloak client
  4147. :type client: str
  4148. """
  4149. await admin.a_change_current_realm(realm)
  4150. client_id = await admin.a_create_client(
  4151. payload={"name": "role-testing-client", "clientId": "role-testing-client"},
  4152. )
  4153. # Test get client optional scopes
  4154. # keycloak optional roles: microprofile-jwt, offline_access, address, --> for versions < 26.0.0
  4155. # starting with Keycloak version 26.0.0 a new optional role is added: organization
  4156. optional_client_scopes = await admin.a_get_client_optional_client_scopes(client_id)
  4157. assert len(optional_client_scopes) in [4, 5], optional_client_scopes
  4158. # Test add a client scope to client optional scopes
  4159. optional_client_scope = "test-client-optional-scope"
  4160. new_client_scope = {
  4161. "name": optional_client_scope,
  4162. "description": f"Test Client Scope: {optional_client_scope}",
  4163. "protocol": "openid-connect",
  4164. "attributes": {},
  4165. }
  4166. new_client_scope_id = await admin.a_create_client_scope(new_client_scope, skip_exists=False)
  4167. new_optional_client_scope_data = {
  4168. "realm": realm,
  4169. "client": client_id,
  4170. "clientScopeId": new_client_scope_id,
  4171. }
  4172. await admin.a_add_client_optional_client_scope(
  4173. client_id, new_client_scope_id, new_optional_client_scope_data,
  4174. )
  4175. optional_client_scopes = await admin.a_get_client_optional_client_scopes(client_id)
  4176. assert len(optional_client_scopes) in [5, 6], optional_client_scopes
  4177. # Test remove a client optional scope
  4178. await admin.a_delete_client_optional_client_scope(client_id, new_client_scope_id)
  4179. optional_client_scopes = await admin.a_get_client_optional_client_scopes(client_id)
  4180. assert len(optional_client_scopes) in [4, 5], optional_client_scopes
  4181. @pytest.mark.asyncio
  4182. async def test_a_client_roles(admin: KeycloakAdmin, client: str):
  4183. """Test client roles.
  4184. :param admin: Keycloak Admin client
  4185. :type admin: KeycloakAdmin
  4186. :param client: Keycloak client
  4187. :type client: str
  4188. """
  4189. # Test get client roles
  4190. res = await admin.a_get_client_roles(client_id=client)
  4191. assert len(res) == 0
  4192. with pytest.raises(KeycloakGetError) as err:
  4193. await admin.a_get_client_roles(client_id="bad")
  4194. assert err.match('404: b\'{"error":"Could not find client".*}\'')
  4195. # Test create client role
  4196. client_role_id = await admin.a_create_client_role(
  4197. client_role_id=client, payload={"name": "client-role-test"}, skip_exists=True,
  4198. )
  4199. with pytest.raises(KeycloakPostError) as err:
  4200. await admin.a_create_client_role(
  4201. client_role_id=client, payload={"name": "client-role-test"},
  4202. )
  4203. assert err.match('409: b\'{"errorMessage":"Role with name client-role-test already exists"}\'')
  4204. client_role_id_2 = await admin.a_create_client_role(
  4205. client_role_id=client, payload={"name": "client-role-test"}, skip_exists=True,
  4206. )
  4207. assert client_role_id == client_role_id_2
  4208. # Test get client role
  4209. res = await admin.a_get_client_role(client_id=client, role_name="client-role-test")
  4210. assert res["name"] == client_role_id
  4211. with pytest.raises(KeycloakGetError) as err:
  4212. await admin.a_get_client_role(client_id=client, role_name="bad")
  4213. assert err.match(COULD_NOT_FIND_ROLE_REGEX)
  4214. res_ = await admin.a_get_client_role_id(client_id=client, role_name="client-role-test")
  4215. assert res_ == res["id"]
  4216. with pytest.raises(KeycloakGetError) as err:
  4217. await admin.a_get_client_role_id(client_id=client, role_name="bad")
  4218. assert err.match(COULD_NOT_FIND_ROLE_REGEX)
  4219. assert len(await admin.a_get_client_roles(client_id=client)) == 1
  4220. # Test update client role
  4221. res = await admin.a_update_client_role(
  4222. client_id=client, role_name="client-role-test", payload={"name": "client-role-test-update"},
  4223. )
  4224. assert res == dict()
  4225. with pytest.raises(KeycloakPutError) as err:
  4226. res = await admin.a_update_client_role(
  4227. client_id=client,
  4228. role_name="client-role-test",
  4229. payload={"name": "client-role-test-update"},
  4230. )
  4231. assert err.match(COULD_NOT_FIND_ROLE_REGEX)
  4232. # Test user with client role
  4233. res = await admin.a_get_client_role_members(
  4234. client_id=client, role_name="client-role-test-update",
  4235. )
  4236. assert len(res) == 0
  4237. with pytest.raises(KeycloakGetError) as err:
  4238. await admin.a_get_client_role_members(client_id=client, role_name="bad")
  4239. assert err.match(COULD_NOT_FIND_ROLE_REGEX)
  4240. user_id = await admin.a_create_user(payload={"username": "test", "email": "test@test.test"})
  4241. with pytest.raises(KeycloakPostError) as err:
  4242. await admin.a_assign_client_role(user_id=user_id, client_id=client, roles=["bad"])
  4243. assert err.match(UNKOWN_ERROR_REGEX), err
  4244. res = await admin.a_assign_client_role(
  4245. user_id=user_id,
  4246. client_id=client,
  4247. roles=[
  4248. await admin.a_get_client_role(client_id=client, role_name="client-role-test-update"),
  4249. ],
  4250. )
  4251. assert res == dict()
  4252. assert (
  4253. len(
  4254. await admin.a_get_client_role_members(
  4255. client_id=client, role_name="client-role-test-update",
  4256. ),
  4257. )
  4258. == 1
  4259. )
  4260. roles = await admin.a_get_client_roles_of_user(user_id=user_id, client_id=client)
  4261. assert len(roles) == 1, roles
  4262. with pytest.raises(KeycloakGetError) as err:
  4263. await admin.a_get_client_roles_of_user(user_id=user_id, client_id="bad")
  4264. assert err.match(CLIENT_NOT_FOUND_REGEX)
  4265. roles = await admin.a_get_composite_client_roles_of_user(user_id=user_id, client_id=client)
  4266. assert len(roles) == 1, roles
  4267. with pytest.raises(KeycloakGetError) as err:
  4268. await admin.a_get_composite_client_roles_of_user(user_id=user_id, client_id="bad")
  4269. assert err.match(CLIENT_NOT_FOUND_REGEX)
  4270. roles = await admin.a_get_available_client_roles_of_user(user_id=user_id, client_id=client)
  4271. assert len(roles) == 0, roles
  4272. with pytest.raises(KeycloakGetError) as err:
  4273. await admin.a_get_composite_client_roles_of_user(user_id=user_id, client_id="bad")
  4274. assert err.match(CLIENT_NOT_FOUND_REGEX)
  4275. with pytest.raises(KeycloakDeleteError) as err:
  4276. await admin.a_delete_client_roles_of_user(user_id=user_id, client_id=client, roles=["bad"])
  4277. assert err.match(UNKOWN_ERROR_REGEX), err
  4278. await admin.a_delete_client_roles_of_user(
  4279. user_id=user_id,
  4280. client_id=client,
  4281. roles=[
  4282. await admin.a_get_client_role(client_id=client, role_name="client-role-test-update"),
  4283. ],
  4284. )
  4285. assert len(await admin.a_get_client_roles_of_user(user_id=user_id, client_id=client)) == 0
  4286. # Test groups and client roles
  4287. res = await admin.a_get_client_role_groups(
  4288. client_id=client, role_name="client-role-test-update",
  4289. )
  4290. assert len(res) == 0
  4291. with pytest.raises(KeycloakGetError) as err:
  4292. await admin.a_get_client_role_groups(client_id=client, role_name="bad")
  4293. assert err.match(COULD_NOT_FIND_ROLE_REGEX)
  4294. group_id = await admin.a_create_group(payload={"name": "test-group"})
  4295. res = await admin.a_get_group_client_roles(group_id=group_id, client_id=client)
  4296. assert len(res) == 0
  4297. with pytest.raises(KeycloakGetError) as err:
  4298. await admin.a_get_group_client_roles(group_id=group_id, client_id="bad")
  4299. assert err.match(CLIENT_NOT_FOUND_REGEX)
  4300. with pytest.raises(KeycloakPostError) as err:
  4301. await admin.a_assign_group_client_roles(group_id=group_id, client_id=client, roles=["bad"])
  4302. assert err.match(UNKOWN_ERROR_REGEX), err
  4303. res = await admin.a_assign_group_client_roles(
  4304. group_id=group_id,
  4305. client_id=client,
  4306. roles=[
  4307. await admin.a_get_client_role(client_id=client, role_name="client-role-test-update"),
  4308. ],
  4309. )
  4310. assert res == dict()
  4311. assert (
  4312. len(
  4313. await admin.a_get_client_role_groups(
  4314. client_id=client, role_name="client-role-test-update",
  4315. ),
  4316. )
  4317. == 1
  4318. )
  4319. assert len(await admin.a_get_group_client_roles(group_id=group_id, client_id=client)) == 1
  4320. with pytest.raises(KeycloakDeleteError) as err:
  4321. await admin.a_delete_group_client_roles(group_id=group_id, client_id=client, roles=["bad"])
  4322. assert err.match(UNKOWN_ERROR_REGEX), err
  4323. res = await admin.a_delete_group_client_roles(
  4324. group_id=group_id,
  4325. client_id=client,
  4326. roles=[
  4327. await admin.a_get_client_role(client_id=client, role_name="client-role-test-update"),
  4328. ],
  4329. )
  4330. assert res == dict()
  4331. # Test composite client roles
  4332. with pytest.raises(KeycloakPostError) as err:
  4333. await admin.a_add_composite_client_roles_to_role(
  4334. client_role_id=client, role_name="client-role-test-update", roles=["bad"],
  4335. )
  4336. assert err.match(UNKOWN_ERROR_REGEX), err
  4337. res = await admin.a_add_composite_client_roles_to_role(
  4338. client_role_id=client,
  4339. role_name="client-role-test-update",
  4340. roles=[await admin.a_get_realm_role(role_name="offline_access")],
  4341. )
  4342. assert res == dict()
  4343. assert (await admin.a_get_client_role(client_id=client, role_name="client-role-test-update"))[
  4344. "composite"
  4345. ]
  4346. # Test removal of composite client roles
  4347. with pytest.raises(KeycloakDeleteError) as err:
  4348. await admin.a_remove_composite_client_roles_from_role(
  4349. client_role_id=client, role_name="client-role-test-update", roles=["bad"],
  4350. )
  4351. assert err.match(UNKOWN_ERROR_REGEX), err
  4352. res = await admin.a_remove_composite_client_roles_from_role(
  4353. client_role_id=client,
  4354. role_name="client-role-test-update",
  4355. roles=[await admin.a_get_realm_role(role_name="offline_access")],
  4356. )
  4357. assert res == dict()
  4358. assert not (
  4359. await admin.a_get_client_role(client_id=client, role_name="client-role-test-update")
  4360. )["composite"]
  4361. # Test delete of client role
  4362. res = await admin.a_delete_client_role(
  4363. client_role_id=client, role_name="client-role-test-update",
  4364. )
  4365. assert res == dict()
  4366. with pytest.raises(KeycloakDeleteError) as err:
  4367. await admin.a_delete_client_role(
  4368. client_role_id=client, role_name="client-role-test-update",
  4369. )
  4370. assert err.match(COULD_NOT_FIND_ROLE_REGEX)
  4371. # Test of roles by id - Get role
  4372. await admin.a_create_client_role(
  4373. client_role_id=client, payload={"name": "client-role-by-id-test"}, skip_exists=True,
  4374. )
  4375. role = await admin.a_get_client_role(client_id=client, role_name="client-role-by-id-test")
  4376. res = await admin.a_get_role_by_id(role_id=role["id"])
  4377. assert res["name"] == "client-role-by-id-test"
  4378. with pytest.raises(KeycloakGetError) as err:
  4379. await admin.a_get_role_by_id(role_id="bad")
  4380. assert err.match(COULD_NOT_FIND_ROLE_WITH_ID_REGEX)
  4381. # Test of roles by id - Update role
  4382. res = await admin.a_update_role_by_id(
  4383. role_id=role["id"], payload={"name": "client-role-by-id-test-update"},
  4384. )
  4385. assert res == dict()
  4386. with pytest.raises(KeycloakPutError) as err:
  4387. res = await admin.a_update_role_by_id(
  4388. role_id="bad", payload={"name": "client-role-by-id-test-update"},
  4389. )
  4390. assert err.match(COULD_NOT_FIND_ROLE_WITH_ID_REGEX)
  4391. # Test of roles by id - Delete role
  4392. res = await admin.a_delete_role_by_id(role_id=role["id"])
  4393. assert res == dict()
  4394. with pytest.raises(KeycloakDeleteError) as err:
  4395. await admin.a_delete_role_by_id(role_id="bad")
  4396. assert err.match(COULD_NOT_FIND_ROLE_WITH_ID_REGEX)
  4397. @pytest.mark.asyncio
  4398. async def test_a_enable_token_exchange(admin: KeycloakAdmin, realm: str):
  4399. """Test enable token exchange.
  4400. :param admin: Keycloak Admin client
  4401. :type admin: KeycloakAdmin
  4402. :param realm: Keycloak realm
  4403. :type realm: str
  4404. :raises AssertionError: In case of bad configuration
  4405. """
  4406. # Test enabling token exchange between two confidential clients
  4407. await admin.a_change_current_realm(realm)
  4408. # Create test clients
  4409. source_client_id = await admin.a_create_client(
  4410. payload={"name": "Source Client", "clientId": "source-client"},
  4411. )
  4412. target_client_id = await admin.a_create_client(
  4413. payload={"name": "Target Client", "clientId": "target-client"},
  4414. )
  4415. for c in await admin.a_get_clients():
  4416. if c["clientId"] == "realm-management":
  4417. realm_management_id = c["id"]
  4418. break
  4419. else:
  4420. raise AssertionError("Missing realm management client")
  4421. # Enable permissions on the Superset client
  4422. await admin.a_update_client_management_permissions(
  4423. payload={"enabled": True}, client_id=target_client_id,
  4424. )
  4425. # Fetch various IDs and strings needed when creating the permission
  4426. token_exchange_permission_id = (
  4427. await admin.a_get_client_management_permissions(client_id=target_client_id)
  4428. )["scopePermissions"]["token-exchange"]
  4429. scopes = await admin.a_get_client_authz_policy_scopes(
  4430. client_id=realm_management_id, policy_id=token_exchange_permission_id,
  4431. )
  4432. for s in scopes:
  4433. if s["name"] == "token-exchange":
  4434. token_exchange_scope_id = s["id"]
  4435. break
  4436. else:
  4437. raise AssertionError("Missing token-exchange scope")
  4438. resources = await admin.a_get_client_authz_policy_resources(
  4439. client_id=realm_management_id, policy_id=token_exchange_permission_id,
  4440. )
  4441. for r in resources:
  4442. if r["name"] == f"client.resource.{target_client_id}":
  4443. token_exchange_resource_id = r["_id"]
  4444. break
  4445. else:
  4446. raise AssertionError("Missing client resource")
  4447. # Create a client policy for source client
  4448. policy_name = "Exchange source client token with target client token"
  4449. client_policy_id = (
  4450. await admin.a_create_client_authz_client_policy(
  4451. payload={
  4452. "type": "client",
  4453. "logic": "POSITIVE",
  4454. "decisionStrategy": "UNANIMOUS",
  4455. "name": policy_name,
  4456. "clients": [source_client_id],
  4457. },
  4458. client_id=realm_management_id,
  4459. )
  4460. )["id"]
  4461. policies = await admin.a_get_client_authz_client_policies(client_id=realm_management_id)
  4462. for policy in policies:
  4463. if policy["name"] == policy_name:
  4464. assert policy["clients"] == [source_client_id]
  4465. break
  4466. else:
  4467. raise AssertionError("Missing client policy")
  4468. # Update permissions on the target client to reference this policy
  4469. permission_name = (
  4470. await admin.a_get_client_authz_scope_permission(
  4471. client_id=realm_management_id, scope_id=token_exchange_permission_id,
  4472. )
  4473. )["name"]
  4474. await admin.a_update_client_authz_scope_permission(
  4475. payload={
  4476. "id": token_exchange_permission_id,
  4477. "name": permission_name,
  4478. "type": "scope",
  4479. "logic": "POSITIVE",
  4480. "decisionStrategy": "UNANIMOUS",
  4481. "resources": [token_exchange_resource_id],
  4482. "scopes": [token_exchange_scope_id],
  4483. "policies": [client_policy_id],
  4484. },
  4485. client_id=realm_management_id,
  4486. scope_id=token_exchange_permission_id,
  4487. )
  4488. # Create permissions on the target client to reference this policy
  4489. await admin.a_create_client_authz_scope_permission(
  4490. payload={
  4491. "id": "some-id",
  4492. "name": "test-permission",
  4493. "type": "scope",
  4494. "logic": "POSITIVE",
  4495. "decisionStrategy": "UNANIMOUS",
  4496. "resources": [token_exchange_resource_id],
  4497. "scopes": [token_exchange_scope_id],
  4498. "policies": [client_policy_id],
  4499. },
  4500. client_id=realm_management_id,
  4501. )
  4502. permission_name = (
  4503. await admin.a_get_client_authz_scope_permission(
  4504. client_id=realm_management_id, scope_id=token_exchange_permission_id,
  4505. )
  4506. )["name"]
  4507. assert permission_name.startswith("token-exchange.permission.client.")
  4508. with pytest.raises(KeycloakPostError) as err:
  4509. await admin.a_create_client_authz_scope_permission(
  4510. payload={"name": "test-permission", "scopes": [token_exchange_scope_id]},
  4511. client_id="realm_management_id",
  4512. )
  4513. assert err.match('404: b\'{"error":"Could not find client".*}\'')
  4514. @pytest.mark.asyncio
  4515. async def test_a_email(admin: KeycloakAdmin, user: str):
  4516. """Test email.
  4517. :param admin: Keycloak Admin client
  4518. :type admin: KeycloakAdmin
  4519. :param user: Keycloak user
  4520. :type user: str
  4521. """
  4522. # Emails will fail as we don't have SMTP test setup
  4523. with pytest.raises(KeycloakPutError) as err:
  4524. await admin.a_send_update_account(user_id=user, payload=dict())
  4525. assert err.match(UNKOWN_ERROR_REGEX), err
  4526. admin.update_user(user_id=user, payload={"enabled": True})
  4527. with pytest.raises(KeycloakPutError) as err:
  4528. await admin.a_send_verify_email(user_id=user)
  4529. assert err.match('500: b\'{"errorMessage":"Failed to send .*"}\'')
  4530. @pytest.mark.asyncio
  4531. async def test_a_email_query_param_handling(admin: KeycloakAdmin, user: str):
  4532. """Test that the optional parameters are correctly transformed into query params.
  4533. :param admin: Keycloak Admin client
  4534. :type admin: KeycloakAdmin
  4535. :param user: Keycloak user
  4536. :type user: str
  4537. """
  4538. with (
  4539. patch.object(
  4540. admin.connection.async_s, "put", side_effect=Exception("An expected error"),
  4541. ) as mock_put,
  4542. pytest.raises(KeycloakConnectionError),
  4543. ):
  4544. await admin.a_send_update_account(
  4545. user_id=user,
  4546. payload=["UPDATE_PASSWORD"],
  4547. client_id="update-account-client-id",
  4548. redirect_uri="https://example.com",
  4549. )
  4550. mock_put.assert_awaited_once_with(
  4551. ANY,
  4552. data='["UPDATE_PASSWORD"]',
  4553. params={"client_id": "update-account-client-id", "redirect_uri": "https://example.com"},
  4554. headers=ANY,
  4555. timeout=60,
  4556. )
  4557. with (
  4558. patch.object(
  4559. admin.connection.async_s, "put", side_effect=Exception("An expected error"),
  4560. ) as mock_put,
  4561. pytest.raises(KeycloakConnectionError),
  4562. ):
  4563. await admin.a_send_verify_email(
  4564. user_id=user, client_id="verify-client-id", redirect_uri="https://example.com",
  4565. )
  4566. mock_put.assert_awaited_once_with(
  4567. ANY,
  4568. data=ANY,
  4569. params={"client_id": "verify-client-id", "redirect_uri": "https://example.com"},
  4570. headers=ANY,
  4571. timeout=60,
  4572. )
  4573. @pytest.mark.asyncio
  4574. async def test_a_get_sessions(admin: KeycloakAdmin):
  4575. """Test get sessions.
  4576. :param admin: Keycloak Admin client
  4577. :type admin: KeycloakAdmin
  4578. """
  4579. sessions = await admin.a_get_sessions(
  4580. user_id=admin.get_user_id(username=admin.connection.username),
  4581. )
  4582. assert len(sessions) >= 1
  4583. with pytest.raises(KeycloakGetError) as err:
  4584. await admin.a_get_sessions(user_id="bad")
  4585. assert err.match(USER_NOT_FOUND_REGEX)
  4586. @pytest.mark.asyncio
  4587. async def test_a_get_client_installation_provider(admin: KeycloakAdmin, client: str):
  4588. """Test get client installation provider.
  4589. :param admin: Keycloak Admin client
  4590. :type admin: KeycloakAdmin
  4591. :param client: Keycloak client
  4592. :type client: str
  4593. """
  4594. with pytest.raises(KeycloakGetError) as err:
  4595. await admin.a_get_client_installation_provider(client_id=client, provider_id="bad")
  4596. assert err.match('404: b\'{"error":"Unknown Provider".*}\'')
  4597. installation = await admin.a_get_client_installation_provider(
  4598. client_id=client, provider_id="keycloak-oidc-keycloak-json",
  4599. )
  4600. assert set(installation.keys()) == {
  4601. "auth-server-url",
  4602. "confidential-port",
  4603. "credentials",
  4604. "realm",
  4605. "resource",
  4606. "ssl-required",
  4607. }
  4608. @pytest.mark.asyncio
  4609. async def test_a_auth_flows(admin: KeycloakAdmin, realm: str):
  4610. """Test auth flows.
  4611. :param admin: Keycloak Admin client
  4612. :type admin: KeycloakAdmin
  4613. :param realm: Keycloak realm
  4614. :type realm: str
  4615. """
  4616. await admin.a_change_current_realm(realm)
  4617. res = await admin.a_get_authentication_flows()
  4618. assert len(res) <= 8, res
  4619. default_flows = len(res)
  4620. assert {x["alias"] for x in res}.issubset(
  4621. {
  4622. "reset credentials",
  4623. "browser",
  4624. "registration",
  4625. "http challenge",
  4626. "docker auth",
  4627. "direct grant",
  4628. "first broker login",
  4629. "clients",
  4630. },
  4631. )
  4632. assert set(res[0].keys()) == {
  4633. "alias",
  4634. "authenticationExecutions",
  4635. "builtIn",
  4636. "description",
  4637. "id",
  4638. "providerId",
  4639. "topLevel",
  4640. }
  4641. assert {x["alias"] for x in res}.issubset(
  4642. {
  4643. "reset credentials",
  4644. "browser",
  4645. "registration",
  4646. "docker auth",
  4647. "direct grant",
  4648. "first broker login",
  4649. "clients",
  4650. "http challenge",
  4651. },
  4652. )
  4653. with pytest.raises(KeycloakGetError) as err:
  4654. await admin.a_get_authentication_flow_for_id(flow_id="bad")
  4655. assert err.match('404: b\'{"error":"Could not find flow with id".*}\'')
  4656. browser_flow_id = [x for x in res if x["alias"] == "browser"][0]["id"]
  4657. res = await admin.a_get_authentication_flow_for_id(flow_id=browser_flow_id)
  4658. assert res["alias"] == "browser"
  4659. # Test copying
  4660. with pytest.raises(KeycloakPostError) as err:
  4661. await admin.a_copy_authentication_flow(payload=dict(), flow_alias="bad")
  4662. assert ('b\'{"error":"Flow not found"' in str(err)) or err.match("404: b''")
  4663. res = await admin.a_copy_authentication_flow(
  4664. payload={"newName": "test-browser"}, flow_alias="browser",
  4665. )
  4666. assert res == b"", res
  4667. assert len(await admin.a_get_authentication_flows()) == (default_flows + 1)
  4668. # Test create
  4669. res = await admin.a_create_authentication_flow(
  4670. payload={"alias": "test-create", "providerId": "basic-flow"},
  4671. )
  4672. assert res == b""
  4673. with pytest.raises(KeycloakPostError) as err:
  4674. await admin.a_create_authentication_flow(
  4675. payload={"alias": "test-create", "builtIn": False},
  4676. )
  4677. assert err.match('409: b\'{"errorMessage":"Flow test-create already exists"}\'')
  4678. assert await admin.a_create_authentication_flow(
  4679. payload={"alias": "test-create"}, skip_exists=True,
  4680. ) == {"msg": "Already exists"}
  4681. # Test flow executions
  4682. res = await admin.a_get_authentication_flow_executions(flow_alias="browser")
  4683. assert len(res) in [8, 12], res
  4684. with pytest.raises(KeycloakGetError) as err:
  4685. await admin.a_get_authentication_flow_executions(flow_alias="bad")
  4686. assert ('b\'{"error":"Flow not found"' in str(err)) or err.match("404: b''")
  4687. exec_id = res[0]["id"]
  4688. res = await admin.a_get_authentication_flow_execution(execution_id=exec_id)
  4689. assert set(res.keys()).issubset(
  4690. {
  4691. "alternative",
  4692. "authenticator",
  4693. "authenticatorFlow",
  4694. "autheticatorFlow",
  4695. "conditional",
  4696. "disabled",
  4697. "enabled",
  4698. "id",
  4699. "parentFlow",
  4700. "priority",
  4701. "required",
  4702. "requirement",
  4703. },
  4704. ), res.keys()
  4705. with pytest.raises(KeycloakGetError) as err:
  4706. await admin.a_get_authentication_flow_execution(execution_id="bad")
  4707. assert err.match(ILLEGAL_EXECUTION_REGEX)
  4708. with pytest.raises(KeycloakPostError) as err:
  4709. await admin.a_create_authentication_flow_execution(payload=dict(), flow_alias="browser")
  4710. assert err.match('400: b\'{"error":"It is illegal to add execution to a built in flow".*}\'')
  4711. res = await admin.a_create_authentication_flow_execution(
  4712. payload={"provider": "auth-cookie"}, flow_alias="test-create",
  4713. )
  4714. assert res == b""
  4715. assert len(await admin.a_get_authentication_flow_executions(flow_alias="test-create")) == 1
  4716. with pytest.raises(KeycloakPutError) as err:
  4717. await admin.a_update_authentication_flow_executions(
  4718. payload={"required": "yes"}, flow_alias="test-create",
  4719. )
  4720. assert err.match("Unrecognized field")
  4721. payload = (await admin.a_get_authentication_flow_executions(flow_alias="test-create"))[0]
  4722. payload["displayName"] = "test"
  4723. res = await admin.a_update_authentication_flow_executions(
  4724. payload=payload, flow_alias="test-create",
  4725. )
  4726. assert res or (res == {})
  4727. exec_id = (await admin.a_get_authentication_flow_executions(flow_alias="test-create"))[0]["id"]
  4728. res = await admin.a_delete_authentication_flow_execution(execution_id=exec_id)
  4729. assert res == dict()
  4730. with pytest.raises(KeycloakDeleteError) as err:
  4731. await admin.a_delete_authentication_flow_execution(execution_id=exec_id)
  4732. assert err.match(ILLEGAL_EXECUTION_REGEX)
  4733. # Test subflows
  4734. res = await admin.a_create_authentication_flow_subflow(
  4735. payload={
  4736. "alias": "test-subflow",
  4737. "provider": "basic-flow",
  4738. "type": "something",
  4739. "description": "something",
  4740. },
  4741. flow_alias="test-browser",
  4742. )
  4743. assert res == b""
  4744. with pytest.raises(KeycloakPostError) as err:
  4745. await admin.a_create_authentication_flow_subflow(
  4746. payload={"alias": "test-subflow", "providerId": "basic-flow"},
  4747. flow_alias="test-browser",
  4748. )
  4749. assert err.match('409: b\'{"errorMessage":"New flow alias name already exists"}\'')
  4750. res = await admin.a_create_authentication_flow_subflow(
  4751. payload={
  4752. "alias": "test-subflow",
  4753. "provider": "basic-flow",
  4754. "type": "something",
  4755. "description": "something",
  4756. },
  4757. flow_alias="test-create",
  4758. skip_exists=True,
  4759. )
  4760. assert res == {"msg": "Already exists"}
  4761. # Test delete auth flow
  4762. flow_id = [
  4763. x for x in await admin.a_get_authentication_flows() if x["alias"] == "test-browser"
  4764. ][0]["id"]
  4765. res = await admin.a_delete_authentication_flow(flow_id=flow_id)
  4766. assert res == dict()
  4767. with pytest.raises(KeycloakDeleteError) as err:
  4768. await admin.a_delete_authentication_flow(flow_id=flow_id)
  4769. assert ('b\'{"error":"Could not find flow with id"' in str(err)) or (
  4770. 'b\'{"error":"Flow not found"' in str(err)
  4771. )
  4772. @pytest.mark.asyncio
  4773. async def test_a_authentication_configs(admin: KeycloakAdmin, realm: str):
  4774. """Test authentication configs.
  4775. :param admin: Keycloak Admin client
  4776. :type admin: KeycloakAdmin
  4777. :param realm: Keycloak realm
  4778. :type realm: str
  4779. """
  4780. admin.change_current_realm(realm)
  4781. # Test list of auth providers
  4782. res = await admin.a_get_authenticator_providers()
  4783. assert len(res) <= 38
  4784. res = await admin.a_get_authenticator_provider_config_description(provider_id="auth-cookie")
  4785. assert res == {
  4786. "helpText": "Validates the SSO cookie set by the auth server.",
  4787. "name": "Cookie",
  4788. "properties": [],
  4789. "providerId": "auth-cookie",
  4790. }
  4791. # Test authenticator config
  4792. # Currently unable to find a sustainable way to fetch the config id,
  4793. # therefore testing only failures
  4794. with pytest.raises(KeycloakGetError) as err:
  4795. await admin.a_get_authenticator_config(config_id="bad")
  4796. assert err.match('404: b\'{"error":"Could not find authenticator config".*}\'')
  4797. with pytest.raises(KeycloakPutError) as err:
  4798. await admin.a_update_authenticator_config(payload=dict(), config_id="bad")
  4799. assert err.match('404: b\'{"error":"Could not find authenticator config".*}\'')
  4800. with pytest.raises(KeycloakDeleteError) as err:
  4801. await admin.a_delete_authenticator_config(config_id="bad")
  4802. assert err.match('404: b\'{"error":"Could not find authenticator config".*}\'')
  4803. @pytest.mark.asyncio
  4804. async def test_a_sync_users(admin: KeycloakAdmin, realm: str):
  4805. """Test sync users.
  4806. :param admin: Keycloak Admin client
  4807. :type admin: KeycloakAdmin
  4808. :param realm: Keycloak realm
  4809. :type realm: str
  4810. """
  4811. await admin.a_change_current_realm(realm)
  4812. # Only testing the error message
  4813. with pytest.raises(KeycloakPostError) as err:
  4814. await admin.a_sync_users(storage_id="does-not-exist", action="triggerFullSync")
  4815. assert err.match('404: b\'{"error":"Could not find component".*}\'')
  4816. @pytest.mark.asyncio
  4817. async def test_a_client_scopes(admin: KeycloakAdmin, realm: str):
  4818. """Test client scopes.
  4819. :param admin: Keycloak Admin client
  4820. :type admin: KeycloakAdmin
  4821. :param realm: Keycloak realm
  4822. :type realm: str
  4823. """
  4824. await admin.a_change_current_realm(realm)
  4825. # Test get client scopes
  4826. res = await admin.a_get_client_scopes()
  4827. scope_names = {x["name"] for x in res}
  4828. assert len(res) in [10, 11, 13]
  4829. assert "email" in scope_names
  4830. assert "profile" in scope_names
  4831. assert "offline_access" in scope_names
  4832. with pytest.raises(KeycloakGetError) as err:
  4833. await admin.a_get_client_scope(client_scope_id="does-not-exist")
  4834. assert err.match(NO_CLIENT_SCOPE_REGEX)
  4835. scope = await admin.a_get_client_scope(client_scope_id=res[0]["id"])
  4836. assert res[0] == scope
  4837. scope = await admin.a_get_client_scope_by_name(client_scope_name=res[0]["name"])
  4838. assert res[0] == scope
  4839. # Test create client scope
  4840. res = await admin.a_create_client_scope(
  4841. payload={"name": "test-scope", "protocol": "openid-connect"}, skip_exists=True,
  4842. )
  4843. assert res
  4844. res2 = await admin.a_create_client_scope(
  4845. payload={"name": "test-scope", "protocol": "openid-connect"}, skip_exists=True,
  4846. )
  4847. assert res == res2
  4848. with pytest.raises(KeycloakPostError) as err:
  4849. await admin.a_create_client_scope(
  4850. payload={"name": "test-scope", "protocol": "openid-connect"}, skip_exists=False,
  4851. )
  4852. assert err.match('409: b\'{"errorMessage":"Client Scope test-scope already exists"}\'')
  4853. # Test update client scope
  4854. with pytest.raises(KeycloakPutError) as err:
  4855. await admin.a_update_client_scope(client_scope_id="does-not-exist", payload=dict())
  4856. assert err.match(NO_CLIENT_SCOPE_REGEX)
  4857. res_update = await admin.a_update_client_scope(
  4858. client_scope_id=res, payload={"name": "test-scope-update"},
  4859. )
  4860. assert res_update == dict()
  4861. assert (await admin.a_get_client_scope(client_scope_id=res))["name"] == "test-scope-update"
  4862. # Test get mappers
  4863. mappers = await admin.a_get_mappers_from_client_scope(client_scope_id=res)
  4864. assert mappers == list()
  4865. # Test add mapper
  4866. with pytest.raises(KeycloakPostError) as err:
  4867. await admin.a_add_mapper_to_client_scope(client_scope_id=res, payload=dict())
  4868. assert err.match('404: b\'{"error":"ProtocolMapper provider not found".*}\'')
  4869. res_add = await admin.a_add_mapper_to_client_scope(
  4870. client_scope_id=res,
  4871. payload={
  4872. "name": "test-mapper",
  4873. "protocol": "openid-connect",
  4874. "protocolMapper": "oidc-usermodel-attribute-mapper",
  4875. },
  4876. )
  4877. assert res_add == b""
  4878. assert len(await admin.a_get_mappers_from_client_scope(client_scope_id=res)) == 1
  4879. # Test update mapper
  4880. test_mapper = (await admin.a_get_mappers_from_client_scope(client_scope_id=res))[0]
  4881. with pytest.raises(KeycloakPutError) as err:
  4882. await admin.a_update_mapper_in_client_scope(
  4883. client_scope_id="does-not-exist", protocol_mapper_id=test_mapper["id"], payload=dict(),
  4884. )
  4885. assert err.match(NO_CLIENT_SCOPE_REGEX)
  4886. test_mapper["config"]["user.attribute"] = "test"
  4887. res_update = await admin.a_update_mapper_in_client_scope(
  4888. client_scope_id=res, protocol_mapper_id=test_mapper["id"], payload=test_mapper,
  4889. )
  4890. assert res_update == dict()
  4891. assert (await admin.a_get_mappers_from_client_scope(client_scope_id=res))[0]["config"][
  4892. "user.attribute"
  4893. ] == "test"
  4894. # Test delete mapper
  4895. res_del = await admin.a_delete_mapper_from_client_scope(
  4896. client_scope_id=res, protocol_mapper_id=test_mapper["id"],
  4897. )
  4898. assert res_del == dict()
  4899. with pytest.raises(KeycloakDeleteError) as err:
  4900. await admin.a_delete_mapper_from_client_scope(
  4901. client_scope_id=res, protocol_mapper_id=test_mapper["id"],
  4902. )
  4903. assert err.match('404: b\'{"error":"Model not found".*}\'')
  4904. # Test default default scopes
  4905. res_defaults = await admin.a_get_default_default_client_scopes()
  4906. assert len(res_defaults) in [6, 7, 8]
  4907. with pytest.raises(KeycloakPutError) as err:
  4908. await admin.a_add_default_default_client_scope(scope_id="does-not-exist")
  4909. assert err.match(CLIENT_SCOPE_NOT_FOUND_REGEX)
  4910. res_add = await admin.a_add_default_default_client_scope(scope_id=res)
  4911. assert res_add == dict()
  4912. assert len(admin.get_default_default_client_scopes()) in [7, 8, 9]
  4913. with pytest.raises(KeycloakDeleteError) as err:
  4914. await admin.a_delete_default_default_client_scope(scope_id="does-not-exist")
  4915. assert err.match(CLIENT_SCOPE_NOT_FOUND_REGEX)
  4916. res_del = await admin.a_delete_default_default_client_scope(scope_id=res)
  4917. assert res_del == dict()
  4918. assert len(admin.get_default_default_client_scopes()) in [6, 7, 8]
  4919. # Test default optional scopes
  4920. res_defaults = await admin.a_get_default_optional_client_scopes()
  4921. assert len(res_defaults) in [4, 5]
  4922. with pytest.raises(KeycloakPutError) as err:
  4923. await admin.a_add_default_optional_client_scope(scope_id="does-not-exist")
  4924. assert err.match(CLIENT_SCOPE_NOT_FOUND_REGEX)
  4925. res_add = await admin.a_add_default_optional_client_scope(scope_id=res)
  4926. assert res_add == dict()
  4927. assert len(await admin.a_get_default_optional_client_scopes()) in [5, 6]
  4928. with pytest.raises(KeycloakDeleteError) as err:
  4929. await admin.a_delete_default_optional_client_scope(scope_id="does-not-exist")
  4930. assert err.match(CLIENT_SCOPE_NOT_FOUND_REGEX)
  4931. res_del = await admin.a_delete_default_optional_client_scope(scope_id=res)
  4932. assert res_del == dict()
  4933. assert len(await admin.a_get_default_optional_client_scopes()) in [4, 5]
  4934. # Test client scope delete
  4935. res_del = await admin.a_delete_client_scope(client_scope_id=res)
  4936. assert res_del == dict()
  4937. with pytest.raises(KeycloakDeleteError) as err:
  4938. await admin.a_delete_client_scope(client_scope_id=res)
  4939. assert err.match(NO_CLIENT_SCOPE_REGEX)
  4940. @pytest.mark.asyncio
  4941. async def test_a_components(admin: KeycloakAdmin, realm: str):
  4942. """Test components.
  4943. :param admin: Keycloak Admin client
  4944. :type admin: KeycloakAdmin
  4945. :param realm: Keycloak realm
  4946. :type realm: str
  4947. """
  4948. await admin.a_change_current_realm(realm)
  4949. # Test get components
  4950. res = await admin.a_get_components()
  4951. assert len(res) == 12
  4952. with pytest.raises(KeycloakGetError) as err:
  4953. await admin.a_get_component(component_id="does-not-exist")
  4954. assert err.match('404: b\'{"error":"Could not find component".*}\'')
  4955. res_get = await admin.a_get_component(component_id=res[0]["id"])
  4956. assert res_get == res[0]
  4957. # Test create component
  4958. with pytest.raises(KeycloakPostError) as err:
  4959. await admin.a_create_component(payload={"bad": "dict"})
  4960. assert err.match("Unrecognized field")
  4961. res = await admin.a_create_component(
  4962. payload={
  4963. "name": "Test Component",
  4964. "providerId": "max-clients",
  4965. "providerType": "org.keycloak.services.clientregistration."
  4966. + "policy.ClientRegistrationPolicy",
  4967. "config": {"max-clients": ["1000"]},
  4968. },
  4969. )
  4970. assert res
  4971. assert (await admin.a_get_component(component_id=res))["name"] == "Test Component"
  4972. # Test update component
  4973. component = await admin.a_get_component(component_id=res)
  4974. component["name"] = "Test Component Update"
  4975. with pytest.raises(KeycloakPutError) as err:
  4976. await admin.a_update_component(component_id="does-not-exist", payload=dict())
  4977. assert err.match('404: b\'{"error":"Could not find component".*}\'')
  4978. res_upd = await admin.a_update_component(component_id=res, payload=component)
  4979. assert res_upd == dict()
  4980. assert (await admin.a_get_component(component_id=res))["name"] == "Test Component Update"
  4981. # Test delete component
  4982. res_del = await admin.a_delete_component(component_id=res)
  4983. assert res_del == dict()
  4984. with pytest.raises(KeycloakDeleteError) as err:
  4985. await admin.a_delete_component(component_id=res)
  4986. assert err.match('404: b\'{"error":"Could not find component".*}\'')
  4987. @pytest.mark.asyncio
  4988. async def test_a_keys(admin: KeycloakAdmin, realm: str):
  4989. """Test keys.
  4990. :param admin: Keycloak Admin client
  4991. :type admin: KeycloakAdmin
  4992. :param realm: Keycloak realm
  4993. :type realm: str
  4994. """
  4995. await admin.a_change_current_realm(realm)
  4996. assert set((await admin.a_get_keys())["active"].keys()) == {
  4997. "AES",
  4998. "HS256",
  4999. "RS256",
  5000. "RSA-OAEP",
  5001. } or set((await admin.a_get_keys())["active"].keys()) == {"RSA-OAEP", "RS256", "HS512", "AES"}
  5002. assert {k["algorithm"] for k in (await admin.a_get_keys())["keys"]} == {
  5003. "HS256",
  5004. "RSA-OAEP",
  5005. "AES",
  5006. "RS256",
  5007. } or {k["algorithm"] for k in (await admin.a_get_keys())["keys"]} == {
  5008. "HS512",
  5009. "RSA-OAEP",
  5010. "AES",
  5011. "RS256",
  5012. }
  5013. @pytest.mark.asyncio
  5014. async def test_a_admin_events(admin: KeycloakAdmin, realm: str):
  5015. """Test events.
  5016. :param admin: Keycloak Admin client
  5017. :type admin: KeycloakAdmin
  5018. :param realm: Keycloak realm
  5019. :type realm: str
  5020. """
  5021. await admin.a_change_current_realm(realm)
  5022. await admin.a_create_client(payload={"name": "test", "clientId": "test"})
  5023. events = await admin.a_get_admin_events()
  5024. assert events == list()
  5025. @pytest.mark.asyncio
  5026. async def test_a_user_events(admin: KeycloakAdmin, realm: str):
  5027. """Test events.
  5028. :param admin: Keycloak Admin client
  5029. :type admin: KeycloakAdmin
  5030. :param realm: Keycloak realm
  5031. :type realm: str
  5032. """
  5033. await admin.a_change_current_realm(realm)
  5034. events = await admin.a_get_events()
  5035. assert events == list()
  5036. with pytest.raises(KeycloakPutError) as err:
  5037. await admin.a_set_events(payload={"bad": "conf"})
  5038. assert err.match("Unrecognized field")
  5039. res = await admin.a_set_events(
  5040. payload={"adminEventsDetailsEnabled": True, "adminEventsEnabled": True},
  5041. )
  5042. assert res == dict()
  5043. await admin.a_create_client(payload={"name": "test", "clientId": "test"})
  5044. events = await admin.a_get_events()
  5045. assert events == list()
  5046. @pytest.mark.asyncio
  5047. @freezegun.freeze_time("2023-02-25 10:00:00")
  5048. async def test_a_auto_refresh(admin_frozen: KeycloakAdmin, realm: str):
  5049. """Test auto refresh token.
  5050. :param admin_frozen: Keycloak Admin client with time frozen in place
  5051. :type admin_frozen: KeycloakAdmin
  5052. :param realm: Keycloak realm
  5053. :type realm: str
  5054. """
  5055. admin = admin_frozen
  5056. admin.get_realm(realm)
  5057. # Test get refresh
  5058. admin.connection.custom_headers = {
  5059. "Authorization": "Bearer bad",
  5060. "Content-Type": "application/json",
  5061. }
  5062. res = await admin.a_get_realm(realm_name=realm)
  5063. assert res["realm"] == realm
  5064. # Freeze time to simulate the access token expiring
  5065. with freezegun.freeze_time("2023-02-25 10:05:00"):
  5066. assert admin.connection.expires_at < datetime_parser.parse("2023-02-25 10:05:00")
  5067. assert await admin.a_get_realm(realm_name=realm)
  5068. assert admin.connection.expires_at > datetime_parser.parse("2023-02-25 10:05:00")
  5069. # Test bad refresh token, but first make sure access token has expired again
  5070. with freezegun.freeze_time("2023-02-25 10:10:00"):
  5071. admin.connection.custom_headers = {"Content-Type": "application/json"}
  5072. admin.connection.token["refresh_token"] = "bad"
  5073. with pytest.raises(KeycloakPostError) as err:
  5074. await admin.a_get_realm(realm_name="test-refresh")
  5075. assert err.match(
  5076. '400: b\'{"error":"invalid_grant","error_description":"Invalid refresh token"}\'',
  5077. )
  5078. admin.connection.get_token()
  5079. # Test post refresh
  5080. with freezegun.freeze_time("2023-02-25 10:15:00"):
  5081. assert admin.connection.expires_at < datetime_parser.parse("2023-02-25 10:15:00")
  5082. admin.connection.token = None
  5083. assert await admin.a_create_realm(payload={"realm": "test-refresh"}) == b""
  5084. assert admin.connection.expires_at > datetime_parser.parse("2023-02-25 10:15:00")
  5085. # Test update refresh
  5086. with freezegun.freeze_time("2023-02-25 10:25:00"):
  5087. assert admin.connection.expires_at < datetime_parser.parse("2023-02-25 10:25:00")
  5088. admin.connection.token = None
  5089. assert (
  5090. await admin.a_update_realm(realm_name="test-refresh", payload={"accountTheme": "test"})
  5091. == dict()
  5092. )
  5093. assert admin.connection.expires_at > datetime_parser.parse("2023-02-25 10:25:00")
  5094. # Test delete refresh
  5095. with freezegun.freeze_time("2023-02-25 10:35:00"):
  5096. assert admin.connection.expires_at < datetime_parser.parse("2023-02-25 10:35:00")
  5097. admin.connection.token = None
  5098. assert await admin.a_delete_realm(realm_name="test-refresh") == dict()
  5099. assert admin.connection.expires_at > datetime_parser.parse("2023-02-25 10:35:00")
  5100. @pytest.mark.asyncio
  5101. async def test_a_get_required_actions(admin: KeycloakAdmin, realm: str):
  5102. """Test required actions.
  5103. :param admin: Keycloak Admin client
  5104. :type admin: KeycloakAdmin
  5105. :param realm: Keycloak realm
  5106. :type realm: str
  5107. """
  5108. await admin.a_change_current_realm(realm)
  5109. ractions = await admin.a_get_required_actions()
  5110. assert isinstance(ractions, list)
  5111. for ra in ractions:
  5112. for key in [
  5113. "alias",
  5114. "name",
  5115. "providerId",
  5116. "enabled",
  5117. "defaultAction",
  5118. "priority",
  5119. "config",
  5120. ]:
  5121. assert key in ra
  5122. @pytest.mark.asyncio
  5123. async def test_a_get_required_action_by_alias(admin: KeycloakAdmin, realm: str):
  5124. """Test get required action by alias.
  5125. :param admin: Keycloak Admin client
  5126. :type admin: KeycloakAdmin
  5127. :param realm: Keycloak realm
  5128. :type realm: str
  5129. """
  5130. await admin.a_change_current_realm(realm)
  5131. ractions = await admin.a_get_required_actions()
  5132. ra = await admin.a_get_required_action_by_alias("UPDATE_PASSWORD")
  5133. assert ra in ractions
  5134. assert ra["alias"] == "UPDATE_PASSWORD"
  5135. assert await admin.a_get_required_action_by_alias("does-not-exist") is None
  5136. @pytest.mark.asyncio
  5137. async def test_a_update_required_action(admin: KeycloakAdmin, realm: str):
  5138. """Test update required action.
  5139. :param admin: Keycloak Admin client
  5140. :type admin: KeycloakAdmin
  5141. :param realm: Keycloak realm
  5142. :type realm: str
  5143. """
  5144. await admin.a_change_current_realm(realm)
  5145. ra = await admin.a_get_required_action_by_alias("UPDATE_PASSWORD")
  5146. old = copy.deepcopy(ra)
  5147. ra["enabled"] = False
  5148. admin.update_required_action("UPDATE_PASSWORD", ra)
  5149. newra = await admin.a_get_required_action_by_alias("UPDATE_PASSWORD")
  5150. assert old != newra
  5151. assert newra["enabled"] is False
  5152. @pytest.mark.asyncio
  5153. async def test_a_get_composite_client_roles_of_group(
  5154. admin: KeycloakAdmin, realm: str, client: str, group: str, composite_client_role: str,
  5155. ):
  5156. """Test get composite client roles of group.
  5157. :param admin: Keycloak Admin client
  5158. :type admin: KeycloakAdmin
  5159. :param realm: Keycloak realm
  5160. :type realm: str
  5161. :param client: Keycloak client
  5162. :type client: str
  5163. :param group: Keycloak group
  5164. :type group: str
  5165. :param composite_client_role: Composite client role
  5166. :type composite_client_role: str
  5167. """
  5168. await admin.a_change_current_realm(realm)
  5169. role = await admin.a_get_client_role(client, composite_client_role)
  5170. await admin.a_assign_group_client_roles(group_id=group, client_id=client, roles=[role])
  5171. result = await admin.a_get_composite_client_roles_of_group(client, group)
  5172. assert role["id"] in [x["id"] for x in result]
  5173. @pytest.mark.asyncio
  5174. async def test_a_get_role_client_level_children(
  5175. admin: KeycloakAdmin, realm: str, client: str, composite_client_role: str, client_role: str,
  5176. ):
  5177. """Test get children of composite client role.
  5178. :param admin: Keycloak Admin client
  5179. :type admin: KeycloakAdmin
  5180. :param realm: Keycloak realm
  5181. :type realm: str
  5182. :param client: Keycloak client
  5183. :type client: str
  5184. :param composite_client_role: Composite client role
  5185. :type composite_client_role: str
  5186. :param client_role: Client role
  5187. :type client_role: str
  5188. """
  5189. await admin.a_change_current_realm(realm)
  5190. child = await admin.a_get_client_role(client, client_role)
  5191. parent = await admin.a_get_client_role(client, composite_client_role)
  5192. res = await admin.a_get_role_client_level_children(client, parent["id"])
  5193. assert child["id"] in [x["id"] for x in res]
  5194. @pytest.mark.asyncio
  5195. async def test_a_upload_certificate(
  5196. admin: KeycloakAdmin, realm: str, client: str, selfsigned_cert: tuple,
  5197. ):
  5198. """Test upload certificate.
  5199. :param admin: Keycloak Admin client
  5200. :type admin: KeycloakAdmin
  5201. :param realm: Keycloak realm
  5202. :type realm: str
  5203. :param client: Keycloak client
  5204. :type client: str
  5205. :param selfsigned_cert: Selfsigned certificates
  5206. :type selfsigned_cert: tuple
  5207. """
  5208. await admin.a_change_current_realm(realm)
  5209. cert, _ = selfsigned_cert
  5210. cert = cert.decode("utf-8").strip()
  5211. admin.upload_certificate(client, cert)
  5212. cl = await admin.a_get_client(client)
  5213. assert cl["attributes"]["jwt.credential.certificate"] == "".join(cert.splitlines()[1:-1])
  5214. @pytest.mark.asyncio
  5215. async def test_a_get_bruteforce_status_for_user(
  5216. admin: KeycloakAdmin, oid_with_credentials: Tuple[KeycloakOpenID, str, str], realm: str,
  5217. ):
  5218. """Test users.
  5219. :param admin: Keycloak Admin client
  5220. :type admin: KeycloakAdmin
  5221. :param oid_with_credentials: Keycloak OpenID client with pre-configured user credentials
  5222. :type oid_with_credentials: Tuple[KeycloakOpenID, str, str]
  5223. :param realm: Keycloak realm
  5224. :type realm: str
  5225. """
  5226. oid, username, password = oid_with_credentials
  5227. await admin.a_change_current_realm(realm)
  5228. # Turn on bruteforce protection
  5229. res = await admin.a_update_realm(realm_name=realm, payload={"bruteForceProtected": True})
  5230. res = await admin.a_get_realm(realm_name=realm)
  5231. assert res["bruteForceProtected"] is True
  5232. # Test login user with wrong credentials
  5233. try:
  5234. oid.token(username=username, password="wrongpassword")
  5235. except KeycloakAuthenticationError:
  5236. pass
  5237. user_id = await admin.a_get_user_id(username)
  5238. bruteforce_status = await admin.a_get_bruteforce_detection_status(user_id)
  5239. assert bruteforce_status["numFailures"] == 1
  5240. # Cleanup
  5241. res = await admin.a_update_realm(realm_name=realm, payload={"bruteForceProtected": False})
  5242. res = await admin.a_get_realm(realm_name=realm)
  5243. assert res["bruteForceProtected"] is False
  5244. @pytest.mark.asyncio
  5245. async def test_a_clear_bruteforce_attempts_for_user(
  5246. admin: KeycloakAdmin, oid_with_credentials: Tuple[KeycloakOpenID, str, str], realm: str,
  5247. ):
  5248. """Test users.
  5249. :param admin: Keycloak Admin client
  5250. :type admin: KeycloakAdmin
  5251. :param oid_with_credentials: Keycloak OpenID client with pre-configured user credentials
  5252. :type oid_with_credentials: Tuple[KeycloakOpenID, str, str]
  5253. :param realm: Keycloak realm
  5254. :type realm: str
  5255. """
  5256. oid, username, password = oid_with_credentials
  5257. await admin.a_change_current_realm(realm)
  5258. # Turn on bruteforce protection
  5259. res = await admin.a_update_realm(realm_name=realm, payload={"bruteForceProtected": True})
  5260. res = await admin.a_get_realm(realm_name=realm)
  5261. assert res["bruteForceProtected"] is True
  5262. # Test login user with wrong credentials
  5263. try:
  5264. oid.token(username=username, password="wrongpassword")
  5265. except KeycloakAuthenticationError:
  5266. pass
  5267. user_id = await admin.a_get_user_id(username)
  5268. bruteforce_status = await admin.a_get_bruteforce_detection_status(user_id)
  5269. assert bruteforce_status["numFailures"] == 1
  5270. res = await admin.a_clear_bruteforce_attempts_for_user(user_id)
  5271. bruteforce_status = await admin.a_get_bruteforce_detection_status(user_id)
  5272. assert bruteforce_status["numFailures"] == 0
  5273. # Cleanup
  5274. res = await admin.a_update_realm(realm_name=realm, payload={"bruteForceProtected": False})
  5275. res = await admin.a_get_realm(realm_name=realm)
  5276. assert res["bruteForceProtected"] is False
  5277. @pytest.mark.asyncio
  5278. async def test_a_clear_bruteforce_attempts_for_all_users(
  5279. admin: KeycloakAdmin, oid_with_credentials: Tuple[KeycloakOpenID, str, str], realm: str,
  5280. ):
  5281. """Test users.
  5282. :param admin: Keycloak Admin client
  5283. :type admin: KeycloakAdmin
  5284. :param oid_with_credentials: Keycloak OpenID client with pre-configured user credentials
  5285. :type oid_with_credentials: Tuple[KeycloakOpenID, str, str]
  5286. :param realm: Keycloak realm
  5287. :type realm: str
  5288. """
  5289. oid, username, password = oid_with_credentials
  5290. await admin.a_change_current_realm(realm)
  5291. # Turn on bruteforce protection
  5292. res = await admin.a_update_realm(realm_name=realm, payload={"bruteForceProtected": True})
  5293. res = await admin.a_get_realm(realm_name=realm)
  5294. assert res["bruteForceProtected"] is True
  5295. # Test login user with wrong credentials
  5296. try:
  5297. oid.token(username=username, password="wrongpassword")
  5298. except KeycloakAuthenticationError:
  5299. pass
  5300. user_id = await admin.a_get_user_id(username)
  5301. bruteforce_status = await admin.a_get_bruteforce_detection_status(user_id)
  5302. assert bruteforce_status["numFailures"] == 1
  5303. res = await admin.a_clear_all_bruteforce_attempts()
  5304. bruteforce_status = await admin.a_get_bruteforce_detection_status(user_id)
  5305. assert bruteforce_status["numFailures"] == 0
  5306. # Cleanup
  5307. res = await admin.a_update_realm(realm_name=realm, payload={"bruteForceProtected": False})
  5308. res = await admin.a_get_realm(realm_name=realm)
  5309. assert res["bruteForceProtected"] is False
  5310. @pytest.mark.asyncio
  5311. async def test_a_default_realm_role_present(realm: str, admin: KeycloakAdmin) -> None:
  5312. """Test that the default realm role is present in a brand new realm.
  5313. :param realm: Realm name
  5314. :type realm: str
  5315. :param admin: Keycloak admin
  5316. :type admin: KeycloakAdmin
  5317. """
  5318. await admin.a_change_current_realm(realm)
  5319. assert f"default-roles-{realm}" in [x["name"] for x in admin.get_realm_roles()]
  5320. assert (
  5321. len(
  5322. [
  5323. x["name"]
  5324. for x in await admin.a_get_realm_roles()
  5325. if x["name"] == f"default-roles-{realm}"
  5326. ],
  5327. )
  5328. == 1
  5329. )
  5330. @pytest.mark.asyncio
  5331. async def test_a_get_default_realm_role_id(realm: str, admin: KeycloakAdmin) -> None:
  5332. """Test getter for the ID of the default realm role.
  5333. :param realm: Realm name
  5334. :type realm: str
  5335. :param admin: Keycloak admin
  5336. :type admin: KeycloakAdmin
  5337. """
  5338. await admin.a_change_current_realm(realm)
  5339. assert (
  5340. await admin.a_get_default_realm_role_id()
  5341. == [
  5342. x["id"]
  5343. for x in await admin.a_get_realm_roles()
  5344. if x["name"] == f"default-roles-{realm}"
  5345. ][0]
  5346. )
  5347. @pytest.mark.asyncio
  5348. async def test_a_realm_default_roles(admin: KeycloakAdmin, realm: str) -> None:
  5349. """Test getting, adding and deleting default realm roles.
  5350. :param realm: Realm name
  5351. :type realm: str
  5352. :param admin: Keycloak admin
  5353. :type admin: KeycloakAdmin
  5354. """
  5355. await admin.a_change_current_realm(realm)
  5356. # Test listing all default realm roles
  5357. roles = await admin.a_get_realm_default_roles()
  5358. assert len(roles) == 2
  5359. assert {x["name"] for x in roles} == {"offline_access", "uma_authorization"}
  5360. with pytest.raises(KeycloakGetError) as err:
  5361. await admin.a_change_current_realm("doesnotexist")
  5362. await admin.a_get_realm_default_roles()
  5363. assert err.match('404: b\'{"error":"Realm not found.".*}\'')
  5364. await admin.a_change_current_realm(realm)
  5365. # Test removing a default realm role
  5366. res = await admin.a_remove_realm_default_roles(payload=[roles[0]])
  5367. assert res == {}
  5368. assert roles[0] not in await admin.a_get_realm_default_roles()
  5369. assert len(await admin.a_get_realm_default_roles()) == 1
  5370. with pytest.raises(KeycloakDeleteError) as err:
  5371. await admin.a_remove_realm_default_roles(payload=[{"id": "bad id"}])
  5372. assert err.match('404: b\'{"error":"Could not find composite role".*}\'')
  5373. # Test adding a default realm role
  5374. res = await admin.a_add_realm_default_roles(payload=[roles[0]])
  5375. assert res == {}
  5376. assert roles[0] in await admin.a_get_realm_default_roles()
  5377. assert len(await admin.a_get_realm_default_roles()) == 2
  5378. with pytest.raises(KeycloakPostError) as err:
  5379. await admin.a_add_realm_default_roles(payload=[{"id": "bad id"}])
  5380. assert err.match('404: b\'{"error":"Could not find composite role".*}\'')
  5381. @pytest.mark.asyncio
  5382. async def test_a_clear_keys_cache(realm: str, admin: KeycloakAdmin) -> None:
  5383. """Test clearing the keys cache.
  5384. :param realm: Realm name
  5385. :type realm: str
  5386. :param admin: Keycloak admin
  5387. :type admin: KeycloakAdmin
  5388. """
  5389. await admin.a_change_current_realm(realm)
  5390. res = await admin.a_clear_keys_cache()
  5391. assert res == {}
  5392. @pytest.mark.asyncio
  5393. async def test_a_clear_realm_cache(realm: str, admin: KeycloakAdmin) -> None:
  5394. """Test clearing the realm cache.
  5395. :param realm: Realm name
  5396. :type realm: str
  5397. :param admin: Keycloak admin
  5398. :type admin: KeycloakAdmin
  5399. """
  5400. await admin.a_change_current_realm(realm)
  5401. res = await admin.a_clear_realm_cache()
  5402. assert res == {}
  5403. @pytest.mark.asyncio
  5404. async def test_a_clear_user_cache(realm: str, admin: KeycloakAdmin) -> None:
  5405. """Test clearing the user cache.
  5406. :param realm: Realm name
  5407. :type realm: str
  5408. :param admin: Keycloak admin
  5409. :type admin: KeycloakAdmin
  5410. """
  5411. await admin.a_change_current_realm(realm)
  5412. res = await admin.a_clear_user_cache()
  5413. assert res == {}
  5414. @pytest.mark.asyncio
  5415. async def test_a_initial_access_token(
  5416. admin: KeycloakAdmin, oid_with_credentials: Tuple[KeycloakOpenID, str, str],
  5417. ) -> None:
  5418. """Test initial access token and client creation.
  5419. :param admin: Keycloak admin
  5420. :type admin: KeycloakAdmin
  5421. :param oid_with_credentials: Keycloak OpenID client with pre-configured user credentials
  5422. :type oid_with_credentials: Tuple[KeycloakOpenID, str, str]
  5423. """
  5424. res = await admin.a_create_initial_access_token(2, 3)
  5425. assert "token" in res
  5426. assert res["count"] == 2
  5427. assert res["expiration"] == 3
  5428. oid, username, password = oid_with_credentials
  5429. client = str(uuid.uuid4())
  5430. secret = str(uuid.uuid4())
  5431. res = await oid.a_register_client(
  5432. token=res["token"],
  5433. payload={
  5434. "name": "DynamicRegisteredClient",
  5435. "clientId": client,
  5436. "enabled": True,
  5437. "publicClient": False,
  5438. "protocol": "openid-connect",
  5439. "secret": secret,
  5440. "clientAuthenticatorType": "client-secret",
  5441. },
  5442. )
  5443. assert res["clientId"] == client
  5444. new_secret = str(uuid.uuid4())
  5445. res = await oid.a_update_client(
  5446. res["registrationAccessToken"], client, payload={"secret": new_secret},
  5447. )
  5448. assert res["secret"] == new_secret
  5449. @pytest.mark.asyncio
  5450. async def test_a_refresh_token(admin: KeycloakAdmin):
  5451. """Test refresh token on connection even if it is expired.
  5452. :param admin: Keycloak admin
  5453. :type admin: KeycloakAdmin
  5454. """
  5455. admin.get_realms()
  5456. assert admin.connection.token is not None
  5457. await admin.a_user_logout(await admin.a_get_user_id(admin.connection.username))
  5458. admin.connection.refresh_token()
  5459. def test_counter_part():
  5460. """Test that each function has its async counter part."""
  5461. admin_methods = [func for func in dir(KeycloakAdmin) if callable(getattr(KeycloakAdmin, func))]
  5462. sync_methods = [
  5463. method
  5464. for method in admin_methods
  5465. if not method.startswith("a_") and not method.startswith("_")
  5466. ]
  5467. async_methods = [
  5468. method for method in admin_methods if iscoroutinefunction(getattr(KeycloakAdmin, method))
  5469. ]
  5470. for method in sync_methods:
  5471. async_method = f"a_{method}"
  5472. assert (async_method in admin_methods) is True
  5473. sync_sign = signature(getattr(KeycloakAdmin, method))
  5474. async_sign = signature(getattr(KeycloakAdmin, async_method))
  5475. assert sync_sign.parameters == async_sign.parameters
  5476. for async_method in async_methods:
  5477. if async_method[2:].startswith("_"):
  5478. continue
  5479. assert async_method[2:] in sync_methods