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.

2650 lines
94 KiB

  1. """Test the keycloak admin object."""
  2. import copy
  3. import uuid
  4. from typing import Tuple
  5. import freezegun
  6. import pytest
  7. from dateutil import parser as datetime_parser
  8. import keycloak
  9. from keycloak import KeycloakAdmin, KeycloakOpenID, KeycloakOpenIDConnection
  10. from keycloak.connection import ConnectionManager
  11. from keycloak.exceptions import (
  12. KeycloakAuthenticationError,
  13. KeycloakDeleteError,
  14. KeycloakGetError,
  15. KeycloakPostError,
  16. KeycloakPutError,
  17. )
  18. def test_keycloak_version():
  19. """Test version."""
  20. assert keycloak.__version__, keycloak.__version__
  21. def test_keycloak_admin_init(env):
  22. """Test keycloak admin init.
  23. :param env: Environment fixture
  24. :type env: KeycloakTestEnv
  25. """
  26. admin = KeycloakAdmin(
  27. server_url=f"http://{env.KEYCLOAK_HOST}:{env.KEYCLOAK_PORT}",
  28. username=env.KEYCLOAK_ADMIN,
  29. password=env.KEYCLOAK_ADMIN_PASSWORD,
  30. )
  31. assert admin.server_url == f"http://{env.KEYCLOAK_HOST}:{env.KEYCLOAK_PORT}", admin.server_url
  32. assert admin.realm_name == "master", admin.realm_name
  33. assert isinstance(admin.connection, ConnectionManager), type(admin.connection)
  34. assert admin.client_id == "admin-cli", admin.client_id
  35. assert admin.client_secret_key is None, admin.client_secret_key
  36. assert admin.verify, admin.verify
  37. assert admin.username == env.KEYCLOAK_ADMIN, admin.username
  38. assert admin.password == env.KEYCLOAK_ADMIN_PASSWORD, admin.password
  39. assert admin.totp is None, admin.totp
  40. assert admin.token is not None, admin.token
  41. assert admin.user_realm_name is None, admin.user_realm_name
  42. assert admin.custom_headers is None, admin.custom_headers
  43. assert admin.token
  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. realm_name=None,
  49. user_realm_name="master",
  50. )
  51. assert admin.token
  52. admin = KeycloakAdmin(
  53. server_url=f"http://{env.KEYCLOAK_HOST}:{env.KEYCLOAK_PORT}",
  54. username=env.KEYCLOAK_ADMIN,
  55. password=env.KEYCLOAK_ADMIN_PASSWORD,
  56. realm_name=None,
  57. user_realm_name=None,
  58. )
  59. assert admin.token
  60. token = admin.token
  61. admin = KeycloakAdmin(
  62. server_url=f"http://{env.KEYCLOAK_HOST}:{env.KEYCLOAK_PORT}",
  63. token=token,
  64. realm_name=None,
  65. user_realm_name=None,
  66. )
  67. assert admin.token == token
  68. admin.create_realm(payload={"realm": "authz", "enabled": True})
  69. admin.realm_name = "authz"
  70. admin.create_client(
  71. payload={
  72. "name": "authz-client",
  73. "clientId": "authz-client",
  74. "authorizationServicesEnabled": True,
  75. "serviceAccountsEnabled": True,
  76. "clientAuthenticatorType": "client-secret",
  77. "directAccessGrantsEnabled": False,
  78. "enabled": True,
  79. "implicitFlowEnabled": False,
  80. "publicClient": False,
  81. }
  82. )
  83. secret = admin.generate_client_secrets(client_id=admin.get_client_id("authz-client"))
  84. assert KeycloakAdmin(
  85. server_url=f"http://{env.KEYCLOAK_HOST}:{env.KEYCLOAK_PORT}",
  86. user_realm_name="authz",
  87. client_id="authz-client",
  88. client_secret_key=secret["value"],
  89. ).token
  90. admin.delete_realm(realm_name="authz")
  91. assert (
  92. KeycloakAdmin(
  93. server_url=f"http://{env.KEYCLOAK_HOST}:{env.KEYCLOAK_PORT}",
  94. username=None,
  95. password=None,
  96. client_secret_key=None,
  97. custom_headers={"custom": "header"},
  98. ).token
  99. is None
  100. )
  101. keycloak_connection = KeycloakOpenIDConnection(
  102. server_url=f"http://{env.KEYCLOAK_HOST}:{env.KEYCLOAK_PORT}",
  103. username=env.KEYCLOAK_ADMIN,
  104. password=env.KEYCLOAK_ADMIN_PASSWORD,
  105. realm_name="master",
  106. client_id="admin-cli",
  107. verify=True,
  108. )
  109. keycloak_admin = KeycloakAdmin(connection=keycloak_connection)
  110. assert keycloak_admin.token
  111. def test_realms(admin: KeycloakAdmin):
  112. """Test realms.
  113. :param admin: Keycloak Admin client
  114. :type admin: KeycloakAdmin
  115. """
  116. # Get realms
  117. realms = admin.get_realms()
  118. assert len(realms) == 1, realms
  119. assert "master" == realms[0]["realm"]
  120. # Create a test realm
  121. res = admin.create_realm(payload={"realm": "test"})
  122. assert res == b"", res
  123. # Create the same realm, should fail
  124. with pytest.raises(KeycloakPostError) as err:
  125. res = admin.create_realm(payload={"realm": "test"})
  126. assert err.match('409: b\'{"errorMessage":"Conflict detected. See logs for details"}\'')
  127. # Create the same realm, skip_exists true
  128. res = admin.create_realm(payload={"realm": "test"}, skip_exists=True)
  129. assert res == {"msg": "Already exists"}, res
  130. # Get a single realm
  131. res = admin.get_realm(realm_name="test")
  132. assert res["realm"] == "test"
  133. # Get non-existing realm
  134. with pytest.raises(KeycloakGetError) as err:
  135. admin.get_realm(realm_name="non-existent")
  136. assert err.match('404: b\'{"error":"Realm not found."}\'')
  137. # Update realm
  138. res = admin.update_realm(realm_name="test", payload={"accountTheme": "test"})
  139. assert res == dict(), res
  140. # Check that the update worked
  141. res = admin.get_realm(realm_name="test")
  142. assert res["realm"] == "test"
  143. assert res["accountTheme"] == "test"
  144. # Update wrong payload
  145. with pytest.raises(KeycloakPutError) as err:
  146. admin.update_realm(realm_name="test", payload={"wrong": "payload"})
  147. assert err.match('400: b\'{"error":"Unrecognized field')
  148. # Check that get realms returns both realms
  149. realms = admin.get_realms()
  150. realm_names = [x["realm"] for x in realms]
  151. assert len(realms) == 2, realms
  152. assert "master" in realm_names, realm_names
  153. assert "test" in realm_names, realm_names
  154. # Delete the realm
  155. res = admin.delete_realm(realm_name="test")
  156. assert res == dict(), res
  157. # Check that the realm does not exist anymore
  158. with pytest.raises(KeycloakGetError) as err:
  159. admin.get_realm(realm_name="test")
  160. assert err.match('404: b\'{"error":"Realm not found."}\'')
  161. # Delete non-existing realm
  162. with pytest.raises(KeycloakDeleteError) as err:
  163. admin.delete_realm(realm_name="non-existent")
  164. assert err.match('404: b\'{"error":"Realm not found."}\'')
  165. def test_import_export_realms(admin: KeycloakAdmin, realm: str):
  166. """Test import and export of realms.
  167. :param admin: Keycloak Admin client
  168. :type admin: KeycloakAdmin
  169. :param realm: Keycloak realm
  170. :type realm: str
  171. """
  172. admin.realm_name = realm
  173. realm_export = admin.export_realm(export_clients=True, export_groups_and_role=True)
  174. assert realm_export != dict(), realm_export
  175. admin.delete_realm(realm_name=realm)
  176. admin.realm_name = "master"
  177. res = admin.import_realm(payload=realm_export)
  178. assert res == b"", res
  179. # Test bad import
  180. with pytest.raises(KeycloakPostError) as err:
  181. admin.import_realm(payload=dict())
  182. assert err.match('500: b\'{"error":"unknown_error"}\'')
  183. def test_users(admin: KeycloakAdmin, realm: str):
  184. """Test users.
  185. :param admin: Keycloak Admin client
  186. :type admin: KeycloakAdmin
  187. :param realm: Keycloak realm
  188. :type realm: str
  189. """
  190. admin.realm_name = realm
  191. # Check no users present
  192. users = admin.get_users()
  193. assert users == list(), users
  194. # Test create user
  195. user_id = admin.create_user(payload={"username": "test", "email": "test@test.test"})
  196. assert user_id is not None, user_id
  197. # Test create the same user
  198. with pytest.raises(KeycloakPostError) as err:
  199. admin.create_user(payload={"username": "test", "email": "test@test.test"})
  200. assert err.match('409: b\'{"errorMessage":"User exists with same username"}\'')
  201. # Test create the same user, exists_ok true
  202. user_id_2 = admin.create_user(
  203. payload={"username": "test", "email": "test@test.test"}, exist_ok=True
  204. )
  205. assert user_id == user_id_2
  206. # Test get user
  207. user = admin.get_user(user_id=user_id)
  208. assert user["username"] == "test", user["username"]
  209. assert user["email"] == "test@test.test", user["email"]
  210. # Test update user
  211. res = admin.update_user(user_id=user_id, payload={"firstName": "Test"})
  212. assert res == dict(), res
  213. user = admin.get_user(user_id=user_id)
  214. assert user["firstName"] == "Test"
  215. # Test update user fail
  216. with pytest.raises(KeycloakPutError) as err:
  217. admin.update_user(user_id=user_id, payload={"wrong": "payload"})
  218. assert err.match('400: b\'{"error":"Unrecognized field')
  219. # Test get users again
  220. users = admin.get_users()
  221. usernames = [x["username"] for x in users]
  222. assert "test" in usernames
  223. # Test users counts
  224. count = admin.users_count()
  225. assert count == 1, count
  226. # Test users count with query
  227. count = admin.users_count(query={"username": "notpresent"})
  228. assert count == 0
  229. # Test user groups
  230. groups = admin.get_user_groups(user_id=user["id"])
  231. assert len(groups) == 0
  232. # Test user groups bad id
  233. with pytest.raises(KeycloakGetError) as err:
  234. admin.get_user_groups(user_id="does-not-exist")
  235. assert err.match('404: b\'{"error":"User not found"}\'')
  236. # Test logout
  237. res = admin.user_logout(user_id=user["id"])
  238. assert res == dict(), res
  239. # Test logout fail
  240. with pytest.raises(KeycloakPostError) as err:
  241. admin.user_logout(user_id="non-existent-id")
  242. assert err.match('404: b\'{"error":"User not found"}\'')
  243. # Test consents
  244. res = admin.user_consents(user_id=user["id"])
  245. assert len(res) == 0, res
  246. # Test consents fail
  247. with pytest.raises(KeycloakGetError) as err:
  248. admin.user_consents(user_id="non-existent-id")
  249. assert err.match('404: b\'{"error":"User not found"}\'')
  250. # Test delete user
  251. res = admin.delete_user(user_id=user_id)
  252. assert res == dict(), res
  253. with pytest.raises(KeycloakGetError) as err:
  254. admin.get_user(user_id=user_id)
  255. err.match('404: b\'{"error":"User not found"}\'')
  256. # Test delete fail
  257. with pytest.raises(KeycloakDeleteError) as err:
  258. admin.delete_user(user_id="non-existent-id")
  259. assert err.match('404: b\'{"error":"User not found"}\'')
  260. def test_users_pagination(admin: KeycloakAdmin, realm: str):
  261. """Test user pagination.
  262. :param admin: Keycloak Admin client
  263. :type admin: KeycloakAdmin
  264. :param realm: Keycloak realm
  265. :type realm: str
  266. """
  267. admin.realm_name = realm
  268. for ind in range(admin.PAGE_SIZE + 50):
  269. username = f"user_{ind}"
  270. admin.create_user(payload={"username": username, "email": f"{username}@test.test"})
  271. users = admin.get_users()
  272. assert len(users) == admin.PAGE_SIZE + 50, len(users)
  273. users = admin.get_users(query={"first": 100})
  274. assert len(users) == 50, len(users)
  275. users = admin.get_users(query={"max": 20})
  276. assert len(users) == 20, len(users)
  277. def test_idps(admin: KeycloakAdmin, realm: str):
  278. """Test IDPs.
  279. :param admin: Keycloak Admin client
  280. :type admin: KeycloakAdmin
  281. :param realm: Keycloak realm
  282. :type realm: str
  283. """
  284. admin.realm_name = realm
  285. # Create IDP
  286. res = admin.create_idp(
  287. payload=dict(
  288. providerId="github", alias="github", config=dict(clientId="test", clientSecret="test")
  289. )
  290. )
  291. assert res == b"", res
  292. # Test create idp fail
  293. with pytest.raises(KeycloakPostError) as err:
  294. admin.create_idp(payload={"providerId": "does-not-exist", "alias": "something"})
  295. assert err.match("Invalid identity provider id"), err
  296. # Test listing
  297. idps = admin.get_idps()
  298. assert len(idps) == 1
  299. assert "github" == idps[0]["alias"]
  300. # Test IdP update
  301. res = admin.update_idp(idp_alias="github", payload=idps[0])
  302. assert res == {}, res
  303. # Test adding a mapper
  304. res = admin.add_mapper_to_idp(
  305. idp_alias="github",
  306. payload={
  307. "identityProviderAlias": "github",
  308. "identityProviderMapper": "github-user-attribute-mapper",
  309. "name": "test",
  310. },
  311. )
  312. assert res == b"", res
  313. # Test mapper fail
  314. with pytest.raises(KeycloakPostError) as err:
  315. admin.add_mapper_to_idp(idp_alias="does-no-texist", payload=dict())
  316. assert err.match('404: b\'{"error":"HTTP 404 Not Found"}\'')
  317. # Test IdP mappers listing
  318. idp_mappers = admin.get_idp_mappers(idp_alias="github")
  319. assert len(idp_mappers) == 1
  320. # Test IdP mapper update
  321. res = admin.update_mapper_in_idp(
  322. idp_alias="github",
  323. mapper_id=idp_mappers[0]["id"],
  324. # For an obscure reason, keycloak expect all fields
  325. payload={
  326. "id": idp_mappers[0]["id"],
  327. "identityProviderAlias": "github-alias",
  328. "identityProviderMapper": "github-user-attribute-mapper",
  329. "name": "test",
  330. "config": idp_mappers[0]["config"],
  331. },
  332. )
  333. assert res == dict(), res
  334. # Test delete
  335. res = admin.delete_idp(idp_alias="github")
  336. assert res == dict(), res
  337. # Test delete fail
  338. with pytest.raises(KeycloakDeleteError) as err:
  339. admin.delete_idp(idp_alias="does-not-exist")
  340. assert err.match('404: b\'{"error":"HTTP 404 Not Found"}\'')
  341. def test_user_credentials(admin: KeycloakAdmin, user: str):
  342. """Test user credentials.
  343. :param admin: Keycloak Admin client
  344. :type admin: KeycloakAdmin
  345. :param user: Keycloak user
  346. :type user: str
  347. """
  348. res = admin.set_user_password(user_id=user, password="booya", temporary=True)
  349. assert res == dict(), res
  350. # Test user password set fail
  351. with pytest.raises(KeycloakPutError) as err:
  352. admin.set_user_password(user_id="does-not-exist", password="")
  353. assert err.match('404: b\'{"error":"User not found"}\'')
  354. credentials = admin.get_credentials(user_id=user)
  355. assert len(credentials) == 1
  356. assert credentials[0]["type"] == "password", credentials
  357. # Test get credentials fail
  358. with pytest.raises(KeycloakGetError) as err:
  359. admin.get_credentials(user_id="does-not-exist")
  360. assert err.match('404: b\'{"error":"User not found"}\'')
  361. res = admin.delete_credential(user_id=user, credential_id=credentials[0]["id"])
  362. assert res == dict(), res
  363. # Test delete fail
  364. with pytest.raises(KeycloakDeleteError) as err:
  365. admin.delete_credential(user_id=user, credential_id="does-not-exist")
  366. assert err.match('404: b\'{"error":"Credential not found"}\'')
  367. def test_social_logins(admin: KeycloakAdmin, user: str):
  368. """Test social logins.
  369. :param admin: Keycloak Admin client
  370. :type admin: KeycloakAdmin
  371. :param user: Keycloak user
  372. :type user: str
  373. """
  374. res = admin.add_user_social_login(
  375. user_id=user, provider_id="gitlab", provider_userid="test", provider_username="test"
  376. )
  377. assert res == dict(), res
  378. admin.add_user_social_login(
  379. user_id=user, provider_id="github", provider_userid="test", provider_username="test"
  380. )
  381. assert res == dict(), res
  382. # Test add social login fail
  383. with pytest.raises(KeycloakPostError) as err:
  384. admin.add_user_social_login(
  385. user_id="does-not-exist",
  386. provider_id="does-not-exist",
  387. provider_userid="test",
  388. provider_username="test",
  389. )
  390. assert err.match('404: b\'{"error":"User not found"}\'')
  391. res = admin.get_user_social_logins(user_id=user)
  392. assert res == list(), res
  393. # Test get social logins fail
  394. with pytest.raises(KeycloakGetError) as err:
  395. admin.get_user_social_logins(user_id="does-not-exist")
  396. assert err.match('404: b\'{"error":"User not found"}\'')
  397. res = admin.delete_user_social_login(user_id=user, provider_id="gitlab")
  398. assert res == {}, res
  399. res = admin.delete_user_social_login(user_id=user, provider_id="github")
  400. assert res == {}, res
  401. with pytest.raises(KeycloakDeleteError) as err:
  402. admin.delete_user_social_login(user_id=user, provider_id="instagram")
  403. assert err.match('404: b\'{"error":"Link not found"}\''), err
  404. def test_server_info(admin: KeycloakAdmin):
  405. """Test server info.
  406. :param admin: Keycloak Admin client
  407. :type admin: KeycloakAdmin
  408. """
  409. info = admin.get_server_info()
  410. assert set(info.keys()).issubset(
  411. {
  412. "systemInfo",
  413. "memoryInfo",
  414. "profileInfo",
  415. "themes",
  416. "socialProviders",
  417. "identityProviders",
  418. "providers",
  419. "protocolMapperTypes",
  420. "builtinProtocolMappers",
  421. "clientInstallations",
  422. "componentTypes",
  423. "passwordPolicies",
  424. "enums",
  425. "cryptoInfo",
  426. }
  427. ), info.keys()
  428. def test_groups(admin: KeycloakAdmin, user: str):
  429. """Test groups.
  430. :param admin: Keycloak Admin client
  431. :type admin: KeycloakAdmin
  432. :param user: Keycloak user
  433. :type user: str
  434. """
  435. # Test get groups
  436. groups = admin.get_groups()
  437. assert len(groups) == 0
  438. # Test create group
  439. group_id = admin.create_group(payload={"name": "main-group"})
  440. assert group_id is not None, group_id
  441. # Test create subgroups
  442. subgroup_id_1 = admin.create_group(payload={"name": "subgroup-1"}, parent=group_id)
  443. subgroup_id_2 = admin.create_group(payload={"name": "subgroup-2"}, parent=group_id)
  444. # Test create group fail
  445. with pytest.raises(KeycloakPostError) as err:
  446. admin.create_group(payload={"name": "subgroup-1"}, parent=group_id)
  447. assert err.match("409"), err
  448. # Test skip exists OK
  449. subgroup_id_1_eq = admin.create_group(
  450. payload={"name": "subgroup-1"}, parent=group_id, skip_exists=True
  451. )
  452. assert subgroup_id_1_eq is None
  453. # Test get groups again
  454. groups = admin.get_groups()
  455. assert len(groups) == 1, groups
  456. assert len(groups[0]["subGroups"]) == 2, groups["subGroups"]
  457. assert groups[0]["id"] == group_id
  458. assert {x["id"] for x in groups[0]["subGroups"]} == {subgroup_id_1, subgroup_id_2}
  459. # Test get groups query
  460. groups = admin.get_groups(query={"max": 10})
  461. assert len(groups) == 1, groups
  462. assert len(groups[0]["subGroups"]) == 2, groups["subGroups"]
  463. assert groups[0]["id"] == group_id
  464. assert {x["id"] for x in groups[0]["subGroups"]} == {subgroup_id_1, subgroup_id_2}
  465. # Test get group
  466. res = admin.get_group(group_id=subgroup_id_1)
  467. assert res["id"] == subgroup_id_1, res
  468. assert res["name"] == "subgroup-1"
  469. assert res["path"] == "/main-group/subgroup-1"
  470. # Test get group fail
  471. with pytest.raises(KeycloakGetError) as err:
  472. admin.get_group(group_id="does-not-exist")
  473. assert err.match('404: b\'{"error":"Could not find group by id"}\''), err
  474. # Create 1 more subgroup
  475. subsubgroup_id_1 = admin.create_group(payload={"name": "subsubgroup-1"}, parent=subgroup_id_2)
  476. main_group = admin.get_group(group_id=group_id)
  477. # Test nested searches
  478. res = admin.get_subgroups(group=main_group, path="/main-group/subgroup-2/subsubgroup-1")
  479. assert res is not None, res
  480. assert res["id"] == subsubgroup_id_1
  481. # Test empty search
  482. res = admin.get_subgroups(group=main_group, path="/none")
  483. assert res is None, res
  484. # Test get group by path
  485. res = admin.get_group_by_path(path="/main-group/subgroup-1")
  486. assert res is not None, res
  487. assert res["id"] == subgroup_id_1, res
  488. with pytest.raises(KeycloakGetError) as err:
  489. admin.get_group_by_path(path="/main-group/subgroup-2/subsubgroup-1/test")
  490. assert err.match('404: b\'{"error":"Group path does not exist"}\'')
  491. res = admin.get_group_by_path(path="/main-group/subgroup-2/subsubgroup-1")
  492. assert res is not None, res
  493. assert res["id"] == subsubgroup_id_1
  494. res = admin.get_group_by_path(path="/main-group")
  495. assert res is not None, res
  496. assert res["id"] == group_id, res
  497. # Test group members
  498. res = admin.get_group_members(group_id=subgroup_id_2)
  499. assert len(res) == 0, res
  500. # Test fail group members
  501. with pytest.raises(KeycloakGetError) as err:
  502. admin.get_group_members(group_id="does-not-exist")
  503. assert err.match('404: b\'{"error":"Could not find group by id"}\'')
  504. res = admin.group_user_add(user_id=user, group_id=subgroup_id_2)
  505. assert res == dict(), res
  506. res = admin.get_group_members(group_id=subgroup_id_2)
  507. assert len(res) == 1, res
  508. assert res[0]["id"] == user
  509. # Test get group members query
  510. res = admin.get_group_members(group_id=subgroup_id_2, query={"max": 10})
  511. assert len(res) == 1, res
  512. assert res[0]["id"] == user
  513. with pytest.raises(KeycloakDeleteError) as err:
  514. admin.group_user_remove(user_id="does-not-exist", group_id=subgroup_id_2)
  515. assert err.match('404: b\'{"error":"User not found"}\''), err
  516. res = admin.group_user_remove(user_id=user, group_id=subgroup_id_2)
  517. assert res == dict(), res
  518. # Test set permissions
  519. res = admin.group_set_permissions(group_id=subgroup_id_2, enabled=True)
  520. assert res["enabled"], res
  521. res = admin.group_set_permissions(group_id=subgroup_id_2, enabled=False)
  522. assert not res["enabled"], res
  523. with pytest.raises(KeycloakPutError) as err:
  524. admin.group_set_permissions(group_id=subgroup_id_2, enabled="blah")
  525. assert err.match('b\'{"error":"unknown_error"}\''), err
  526. # Test update group
  527. res = admin.update_group(group_id=subgroup_id_2, payload={"name": "new-subgroup-2"})
  528. assert res == dict(), res
  529. assert admin.get_group(group_id=subgroup_id_2)["name"] == "new-subgroup-2"
  530. # test update fail
  531. with pytest.raises(KeycloakPutError) as err:
  532. admin.update_group(group_id="does-not-exist", payload=dict())
  533. assert err.match('404: b\'{"error":"Could not find group by id"}\''), err
  534. # Test delete
  535. res = admin.delete_group(group_id=group_id)
  536. assert res == dict(), res
  537. assert len(admin.get_groups()) == 0
  538. # Test delete fail
  539. with pytest.raises(KeycloakDeleteError) as err:
  540. admin.delete_group(group_id="does-not-exist")
  541. assert err.match('404: b\'{"error":"Could not find group by id"}\''), err
  542. def test_clients(admin: KeycloakAdmin, realm: str):
  543. """Test clients.
  544. :param admin: Keycloak Admin client
  545. :type admin: KeycloakAdmin
  546. :param realm: Keycloak realm
  547. :type realm: str
  548. """
  549. admin.realm_name = realm
  550. # Test get clients
  551. clients = admin.get_clients()
  552. assert len(clients) == 6, clients
  553. assert {x["name"] for x in clients} == set(
  554. [
  555. "${client_admin-cli}",
  556. "${client_security-admin-console}",
  557. "${client_account-console}",
  558. "${client_broker}",
  559. "${client_account}",
  560. "${client_realm-management}",
  561. ]
  562. ), clients
  563. # Test create client
  564. client_id = admin.create_client(payload={"name": "test-client", "clientId": "test-client"})
  565. assert client_id, client_id
  566. with pytest.raises(KeycloakPostError) as err:
  567. admin.create_client(payload={"name": "test-client", "clientId": "test-client"})
  568. assert err.match('409: b\'{"errorMessage":"Client test-client already exists"}\''), err
  569. client_id_2 = admin.create_client(
  570. payload={"name": "test-client", "clientId": "test-client"}, skip_exists=True
  571. )
  572. assert client_id == client_id_2, client_id_2
  573. # Test get client
  574. res = admin.get_client(client_id=client_id)
  575. assert res["clientId"] == "test-client", res
  576. assert res["name"] == "test-client", res
  577. assert res["id"] == client_id, res
  578. with pytest.raises(KeycloakGetError) as err:
  579. admin.get_client(client_id="does-not-exist")
  580. assert err.match('404: b\'{"error":"Could not find client"}\'')
  581. assert len(admin.get_clients()) == 7
  582. # Test get client id
  583. assert admin.get_client_id(client_id="test-client") == client_id
  584. assert admin.get_client_id(client_id="does-not-exist") is None
  585. # Test update client
  586. res = admin.update_client(client_id=client_id, payload={"name": "test-client-change"})
  587. assert res == dict(), res
  588. with pytest.raises(KeycloakPutError) as err:
  589. admin.update_client(client_id="does-not-exist", payload={"name": "test-client-change"})
  590. assert err.match('404: b\'{"error":"Could not find client"}\'')
  591. # Test client mappers
  592. res = admin.get_mappers_from_client(client_id=client_id)
  593. assert len(res) == 0
  594. with pytest.raises(KeycloakPostError) as err:
  595. admin.add_mapper_to_client(client_id="does-not-exist", payload=dict())
  596. assert err.match('404: b\'{"error":"Could not find client"}\'')
  597. res = admin.add_mapper_to_client(
  598. client_id=client_id,
  599. payload={
  600. "name": "test-mapper",
  601. "protocol": "openid-connect",
  602. "protocolMapper": "oidc-usermodel-attribute-mapper",
  603. },
  604. )
  605. assert res == b""
  606. assert len(admin.get_mappers_from_client(client_id=client_id)) == 1
  607. mapper = admin.get_mappers_from_client(client_id=client_id)[0]
  608. with pytest.raises(KeycloakPutError) as err:
  609. admin.update_client_mapper(client_id=client_id, mapper_id="does-not-exist", payload=dict())
  610. assert err.match('404: b\'{"error":"Model not found"}\'')
  611. mapper["config"]["user.attribute"] = "test"
  612. res = admin.update_client_mapper(client_id=client_id, mapper_id=mapper["id"], payload=mapper)
  613. assert res == dict()
  614. res = admin.remove_client_mapper(client_id=client_id, client_mapper_id=mapper["id"])
  615. assert res == dict()
  616. with pytest.raises(KeycloakDeleteError) as err:
  617. admin.remove_client_mapper(client_id=client_id, client_mapper_id=mapper["id"])
  618. assert err.match('404: b\'{"error":"Model not found"}\'')
  619. # Test client sessions
  620. with pytest.raises(KeycloakGetError) as err:
  621. admin.get_client_all_sessions(client_id="does-not-exist")
  622. assert err.match('404: b\'{"error":"Could not find client"}\'')
  623. assert admin.get_client_all_sessions(client_id=client_id) == list()
  624. assert admin.get_client_sessions_stats() == list()
  625. # Test authz
  626. auth_client_id = admin.create_client(
  627. payload={
  628. "name": "authz-client",
  629. "clientId": "authz-client",
  630. "authorizationServicesEnabled": True,
  631. "serviceAccountsEnabled": True,
  632. }
  633. )
  634. res = admin.get_client_authz_settings(client_id=auth_client_id)
  635. assert res["allowRemoteResourceManagement"]
  636. assert res["decisionStrategy"] == "UNANIMOUS"
  637. assert len(res["policies"]) >= 0
  638. with pytest.raises(KeycloakGetError) as err:
  639. admin.get_client_authz_settings(client_id=client_id)
  640. assert err.match('404: b\'{"error":"HTTP 404 Not Found"}\'')
  641. # Authz resources
  642. res = admin.get_client_authz_resources(client_id=auth_client_id)
  643. assert len(res) == 1
  644. assert res[0]["name"] == "Default Resource"
  645. with pytest.raises(KeycloakGetError) as err:
  646. admin.get_client_authz_resources(client_id=client_id)
  647. assert err.match('404: b\'{"error":"HTTP 404 Not Found"}\'')
  648. res = admin.create_client_authz_resource(
  649. client_id=auth_client_id, payload={"name": "test-resource"}
  650. )
  651. assert res["name"] == "test-resource", res
  652. test_resource_id = res["_id"]
  653. res = admin.get_client_authz_resource(client_id=auth_client_id, resource_id=test_resource_id)
  654. assert res["_id"] == test_resource_id, res
  655. assert res["name"] == "test-resource", res
  656. with pytest.raises(KeycloakPostError) as err:
  657. admin.create_client_authz_resource(
  658. client_id=auth_client_id, payload={"name": "test-resource"}
  659. )
  660. assert err.match('409: b\'{"error":"invalid_request"')
  661. assert admin.create_client_authz_resource(
  662. client_id=auth_client_id, payload={"name": "test-resource"}, skip_exists=True
  663. ) == {"msg": "Already exists"}
  664. res = admin.get_client_authz_resources(client_id=auth_client_id)
  665. assert len(res) == 2
  666. assert {x["name"] for x in res} == {"Default Resource", "test-resource"}
  667. res = admin.create_client_authz_resource(
  668. client_id=auth_client_id, payload={"name": "temp-resource"}
  669. )
  670. assert res["name"] == "temp-resource", res
  671. temp_resource_id = res["_id"]
  672. admin.delete_client_authz_resource(client_id=auth_client_id, resource_id=temp_resource_id)
  673. with pytest.raises(KeycloakGetError) as err:
  674. admin.get_client_authz_resource(client_id=auth_client_id, resource_id=temp_resource_id)
  675. assert err.match("404: b''")
  676. # Authz policies
  677. res = admin.get_client_authz_policies(client_id=auth_client_id)
  678. assert len(res) == 1, res
  679. assert res[0]["name"] == "Default Policy"
  680. with pytest.raises(KeycloakGetError) as err:
  681. admin.get_client_authz_policies(client_id="does-not-exist")
  682. assert err.match('404: b\'{"error":"Could not find client"}\'')
  683. role_id = admin.get_realm_role(role_name="offline_access")["id"]
  684. res = admin.create_client_authz_role_based_policy(
  685. client_id=auth_client_id,
  686. payload={"name": "test-authz-rb-policy", "roles": [{"id": role_id}]},
  687. )
  688. assert res["name"] == "test-authz-rb-policy", res
  689. with pytest.raises(KeycloakPostError) as err:
  690. admin.create_client_authz_role_based_policy(
  691. client_id=auth_client_id,
  692. payload={"name": "test-authz-rb-policy", "roles": [{"id": role_id}]},
  693. )
  694. assert err.match('409: b\'{"error":"Policy with name')
  695. assert admin.create_client_authz_role_based_policy(
  696. client_id=auth_client_id,
  697. payload={"name": "test-authz-rb-policy", "roles": [{"id": role_id}]},
  698. skip_exists=True,
  699. ) == {"msg": "Already exists"}
  700. assert len(admin.get_client_authz_policies(client_id=auth_client_id)) == 2
  701. res = admin.create_client_authz_role_based_policy(
  702. client_id=auth_client_id,
  703. payload={"name": "test-authz-rb-policy-delete", "roles": [{"id": role_id}]},
  704. )
  705. res2 = admin.get_client_authz_policy(client_id=auth_client_id, policy_id=res["id"])
  706. assert res["id"] == res2["id"]
  707. admin.delete_client_authz_policy(client_id=auth_client_id, policy_id=res["id"])
  708. with pytest.raises(KeycloakGetError) as err:
  709. admin.get_client_authz_policy(client_id=auth_client_id, policy_id=res["id"])
  710. assert err.match("404: b''")
  711. # Test authz permissions
  712. res = admin.get_client_authz_permissions(client_id=auth_client_id)
  713. assert len(res) == 1, res
  714. assert res[0]["name"] == "Default Permission"
  715. with pytest.raises(KeycloakGetError) as err:
  716. admin.get_client_authz_permissions(client_id="does-not-exist")
  717. assert err.match('404: b\'{"error":"Could not find client"}\'')
  718. res = admin.create_client_authz_resource_based_permission(
  719. client_id=auth_client_id,
  720. payload={"name": "test-permission-rb", "resources": [test_resource_id]},
  721. )
  722. assert res, res
  723. assert res["name"] == "test-permission-rb"
  724. assert res["resources"] == [test_resource_id]
  725. with pytest.raises(KeycloakPostError) as err:
  726. admin.create_client_authz_resource_based_permission(
  727. client_id=auth_client_id,
  728. payload={"name": "test-permission-rb", "resources": [test_resource_id]},
  729. )
  730. assert err.match('409: b\'{"error":"Policy with name')
  731. assert admin.create_client_authz_resource_based_permission(
  732. client_id=auth_client_id,
  733. payload={"name": "test-permission-rb", "resources": [test_resource_id]},
  734. skip_exists=True,
  735. ) == {"msg": "Already exists"}
  736. assert len(admin.get_client_authz_permissions(client_id=auth_client_id)) == 2
  737. # Test authz scopes
  738. res = admin.get_client_authz_scopes(client_id=auth_client_id)
  739. assert len(res) == 0, res
  740. with pytest.raises(KeycloakGetError) as err:
  741. admin.get_client_authz_scopes(client_id=client_id)
  742. assert err.match('404: b\'{"error":"HTTP 404 Not Found"}\'')
  743. res = admin.create_client_authz_scopes(
  744. client_id=auth_client_id, payload={"name": "test-authz-scope"}
  745. )
  746. assert res["name"] == "test-authz-scope", res
  747. with pytest.raises(KeycloakPostError) as err:
  748. admin.create_client_authz_scopes(
  749. client_id="invalid_client_id", payload={"name": "test-authz-scope"}
  750. )
  751. assert err.match('404: b\'{"error":"Could not find client"')
  752. assert admin.create_client_authz_scopes(
  753. client_id=auth_client_id, payload={"name": "test-authz-scope"}
  754. )
  755. res = admin.get_client_authz_scopes(client_id=auth_client_id)
  756. assert len(res) == 1
  757. assert {x["name"] for x in res} == {"test-authz-scope"}
  758. # Test service account user
  759. res = admin.get_client_service_account_user(client_id=auth_client_id)
  760. assert res["username"] == "service-account-authz-client", res
  761. with pytest.raises(KeycloakGetError) as err:
  762. admin.get_client_service_account_user(client_id=client_id)
  763. assert err.match('400: b\'{"error":"unknown_error"}\'')
  764. # Test delete client
  765. res = admin.delete_client(client_id=auth_client_id)
  766. assert res == dict(), res
  767. with pytest.raises(KeycloakDeleteError) as err:
  768. admin.delete_client(client_id=auth_client_id)
  769. assert err.match('404: b\'{"error":"Could not find client"}\'')
  770. # Test client credentials
  771. admin.create_client(
  772. payload={
  773. "name": "test-confidential",
  774. "enabled": True,
  775. "protocol": "openid-connect",
  776. "publicClient": False,
  777. "redirectUris": ["http://localhost/*"],
  778. "webOrigins": ["+"],
  779. "clientId": "test-confidential",
  780. "secret": "test-secret",
  781. "clientAuthenticatorType": "client-secret",
  782. }
  783. )
  784. with pytest.raises(KeycloakGetError) as err:
  785. admin.get_client_secrets(client_id="does-not-exist")
  786. assert err.match('404: b\'{"error":"Could not find client"}\'')
  787. secrets = admin.get_client_secrets(
  788. client_id=admin.get_client_id(client_id="test-confidential")
  789. )
  790. assert secrets == {"type": "secret", "value": "test-secret"}
  791. with pytest.raises(KeycloakPostError) as err:
  792. admin.generate_client_secrets(client_id="does-not-exist")
  793. assert err.match('404: b\'{"error":"Could not find client"}\'')
  794. res = admin.generate_client_secrets(
  795. client_id=admin.get_client_id(client_id="test-confidential")
  796. )
  797. assert res
  798. assert (
  799. admin.get_client_secrets(client_id=admin.get_client_id(client_id="test-confidential"))
  800. == res
  801. )
  802. def test_realm_roles(admin: KeycloakAdmin, realm: str):
  803. """Test realm roles.
  804. :param admin: Keycloak Admin client
  805. :type admin: KeycloakAdmin
  806. :param realm: Keycloak realm
  807. :type realm: str
  808. """
  809. admin.realm_name = realm
  810. # Test get realm roles
  811. roles = admin.get_realm_roles()
  812. assert len(roles) == 3, roles
  813. role_names = [x["name"] for x in roles]
  814. assert "uma_authorization" in role_names, role_names
  815. assert "offline_access" in role_names, role_names
  816. # Test empty members
  817. with pytest.raises(KeycloakGetError) as err:
  818. admin.get_realm_role_members(role_name="does-not-exist")
  819. assert err.match('404: b\'{"error":"Could not find role"}\'')
  820. members = admin.get_realm_role_members(role_name="offline_access")
  821. assert members == list(), members
  822. # Test create realm role
  823. role_id = admin.create_realm_role(payload={"name": "test-realm-role"}, skip_exists=True)
  824. assert role_id, role_id
  825. with pytest.raises(KeycloakPostError) as err:
  826. admin.create_realm_role(payload={"name": "test-realm-role"})
  827. assert err.match('409: b\'{"errorMessage":"Role with name test-realm-role already exists"}\'')
  828. role_id_2 = admin.create_realm_role(payload={"name": "test-realm-role"}, skip_exists=True)
  829. assert role_id == role_id_2
  830. # Test update realm role
  831. res = admin.update_realm_role(
  832. role_name="test-realm-role", payload={"name": "test-realm-role-update"}
  833. )
  834. assert res == dict(), res
  835. with pytest.raises(KeycloakPutError) as err:
  836. admin.update_realm_role(
  837. role_name="test-realm-role", payload={"name": "test-realm-role-update"}
  838. )
  839. assert err.match('404: b\'{"error":"Could not find role"}\''), err
  840. # Test realm role user assignment
  841. user_id = admin.create_user(payload={"username": "role-testing", "email": "test@test.test"})
  842. with pytest.raises(KeycloakPostError) as err:
  843. admin.assign_realm_roles(user_id=user_id, roles=["bad"])
  844. assert err.match('b\'{"error":"unknown_error"}\''), err
  845. res = admin.assign_realm_roles(
  846. user_id=user_id,
  847. roles=[
  848. admin.get_realm_role(role_name="offline_access"),
  849. admin.get_realm_role(role_name="test-realm-role-update"),
  850. ],
  851. )
  852. assert res == dict(), res
  853. assert admin.get_user(user_id=user_id)["username"] in [
  854. x["username"] for x in admin.get_realm_role_members(role_name="offline_access")
  855. ]
  856. assert admin.get_user(user_id=user_id)["username"] in [
  857. x["username"] for x in admin.get_realm_role_members(role_name="test-realm-role-update")
  858. ]
  859. roles = admin.get_realm_roles_of_user(user_id=user_id)
  860. assert len(roles) == 3
  861. assert "offline_access" in [x["name"] for x in roles]
  862. assert "test-realm-role-update" in [x["name"] for x in roles]
  863. with pytest.raises(KeycloakDeleteError) as err:
  864. admin.delete_realm_roles_of_user(user_id=user_id, roles=["bad"])
  865. assert err.match('b\'{"error":"unknown_error"}\''), err
  866. res = admin.delete_realm_roles_of_user(
  867. user_id=user_id, roles=[admin.get_realm_role(role_name="offline_access")]
  868. )
  869. assert res == dict(), res
  870. assert admin.get_realm_role_members(role_name="offline_access") == list()
  871. roles = admin.get_realm_roles_of_user(user_id=user_id)
  872. assert len(roles) == 2
  873. assert "offline_access" not in [x["name"] for x in roles]
  874. assert "test-realm-role-update" in [x["name"] for x in roles]
  875. roles = admin.get_available_realm_roles_of_user(user_id=user_id)
  876. assert len(roles) == 2
  877. assert "offline_access" in [x["name"] for x in roles]
  878. assert "uma_authorization" in [x["name"] for x in roles]
  879. # Test realm role group assignment
  880. group_id = admin.create_group(payload={"name": "test-group"})
  881. with pytest.raises(KeycloakPostError) as err:
  882. admin.assign_group_realm_roles(group_id=group_id, roles=["bad"])
  883. assert err.match('b\'{"error":"unknown_error"}\''), err
  884. res = admin.assign_group_realm_roles(
  885. group_id=group_id,
  886. roles=[
  887. admin.get_realm_role(role_name="offline_access"),
  888. admin.get_realm_role(role_name="test-realm-role-update"),
  889. ],
  890. )
  891. assert res == dict(), res
  892. roles = admin.get_group_realm_roles(group_id=group_id)
  893. assert len(roles) == 2
  894. assert "offline_access" in [x["name"] for x in roles]
  895. assert "test-realm-role-update" in [x["name"] for x in roles]
  896. with pytest.raises(KeycloakDeleteError) as err:
  897. admin.delete_group_realm_roles(group_id=group_id, roles=["bad"])
  898. assert err.match('b\'{"error":"unknown_error"}\''), err
  899. res = admin.delete_group_realm_roles(
  900. group_id=group_id, roles=[admin.get_realm_role(role_name="offline_access")]
  901. )
  902. assert res == dict(), res
  903. roles = admin.get_group_realm_roles(group_id=group_id)
  904. assert len(roles) == 1
  905. assert "test-realm-role-update" in [x["name"] for x in roles]
  906. # Test composite realm roles
  907. composite_role = admin.create_realm_role(payload={"name": "test-composite-role"})
  908. with pytest.raises(KeycloakPostError) as err:
  909. admin.add_composite_realm_roles_to_role(role_name=composite_role, roles=["bad"])
  910. assert err.match('b\'{"error":"unknown_error"}\''), err
  911. res = admin.add_composite_realm_roles_to_role(
  912. role_name=composite_role, roles=[admin.get_realm_role(role_name="test-realm-role-update")]
  913. )
  914. assert res == dict(), res
  915. res = admin.get_composite_realm_roles_of_role(role_name=composite_role)
  916. assert len(res) == 1
  917. assert "test-realm-role-update" in res[0]["name"]
  918. with pytest.raises(KeycloakGetError) as err:
  919. admin.get_composite_realm_roles_of_role(role_name="bad")
  920. assert err.match('404: b\'{"error":"Could not find role"}\'')
  921. res = admin.get_composite_realm_roles_of_user(user_id=user_id)
  922. assert len(res) == 4
  923. assert "offline_access" in {x["name"] for x in res}
  924. assert "test-realm-role-update" in {x["name"] for x in res}
  925. assert "uma_authorization" in {x["name"] for x in res}
  926. with pytest.raises(KeycloakGetError) as err:
  927. admin.get_composite_realm_roles_of_user(user_id="bad")
  928. assert err.match('b\'{"error":"User not found"}\''), err
  929. with pytest.raises(KeycloakDeleteError) as err:
  930. admin.remove_composite_realm_roles_to_role(role_name=composite_role, roles=["bad"])
  931. assert err.match('b\'{"error":"unknown_error"}\''), err
  932. res = admin.remove_composite_realm_roles_to_role(
  933. role_name=composite_role, roles=[admin.get_realm_role(role_name="test-realm-role-update")]
  934. )
  935. assert res == dict(), res
  936. res = admin.get_composite_realm_roles_of_role(role_name=composite_role)
  937. assert len(res) == 0
  938. # Test delete realm role
  939. res = admin.delete_realm_role(role_name=composite_role)
  940. assert res == dict(), res
  941. with pytest.raises(KeycloakDeleteError) as err:
  942. admin.delete_realm_role(role_name=composite_role)
  943. assert err.match('404: b\'{"error":"Could not find role"}\'')
  944. @pytest.mark.parametrize(
  945. "testcase, arg_brief_repr, includes_attributes",
  946. [
  947. ("brief True", {"brief_representation": True}, False),
  948. ("brief False", {"brief_representation": False}, True),
  949. ("default", {}, False),
  950. ],
  951. )
  952. def test_role_attributes(
  953. admin: KeycloakAdmin,
  954. realm: str,
  955. client: str,
  956. arg_brief_repr: dict,
  957. includes_attributes: bool,
  958. testcase: str,
  959. ):
  960. """Test getting role attributes for bulk calls.
  961. :param admin: Keycloak admin
  962. :type admin: KeycloakAdmin
  963. :param realm: Keycloak realm
  964. :type realm: str
  965. :param client: Keycloak client
  966. :type client: str
  967. :param arg_brief_repr: Brief representation
  968. :type arg_brief_repr: dict
  969. :param includes_attributes: Indicator whether to include attributes
  970. :type includes_attributes: bool
  971. :param testcase: Test case
  972. :type testcase: str
  973. """
  974. # setup
  975. attribute_role = "test-realm-role-w-attr"
  976. test_attrs = {"attr1": ["val1"], "attr2": ["val2-1", "val2-2"]}
  977. role_id = admin.create_realm_role(
  978. payload={"name": attribute_role, "attributes": test_attrs}, skip_exists=True
  979. )
  980. assert role_id, role_id
  981. cli_role_id = admin.create_client_role(
  982. client, payload={"name": attribute_role, "attributes": test_attrs}, skip_exists=True
  983. )
  984. assert cli_role_id, cli_role_id
  985. if not includes_attributes:
  986. test_attrs = None
  987. # tests
  988. roles = admin.get_realm_roles(**arg_brief_repr)
  989. roles_filtered = [role for role in roles if role["name"] == role_id]
  990. assert roles_filtered, roles_filtered
  991. role = roles_filtered[0]
  992. assert role.get("attributes") == test_attrs, testcase
  993. roles = admin.get_client_roles(client, **arg_brief_repr)
  994. roles_filtered = [role for role in roles if role["name"] == cli_role_id]
  995. assert roles_filtered, roles_filtered
  996. role = roles_filtered[0]
  997. assert role.get("attributes") == test_attrs, testcase
  998. # cleanup
  999. res = admin.delete_realm_role(role_name=attribute_role)
  1000. assert res == dict(), res
  1001. res = admin.delete_client_role(client, role_name=attribute_role)
  1002. assert res == dict(), res
  1003. def test_client_scope_realm_roles(admin: KeycloakAdmin, realm: str):
  1004. """Test client realm roles.
  1005. :param admin: Keycloak admin
  1006. :type admin: KeycloakAdmin
  1007. :param realm: Keycloak realm
  1008. :type realm: str
  1009. """
  1010. admin.realm_name = realm
  1011. # Test get realm roles
  1012. roles = admin.get_realm_roles()
  1013. assert len(roles) == 3, roles
  1014. role_names = [x["name"] for x in roles]
  1015. assert "uma_authorization" in role_names, role_names
  1016. assert "offline_access" in role_names, role_names
  1017. # create realm role for test
  1018. role_id = admin.create_realm_role(payload={"name": "test-realm-role"}, skip_exists=True)
  1019. assert role_id, role_id
  1020. # Test realm role client assignment
  1021. client_id = admin.create_client(
  1022. payload={"name": "role-testing-client", "clientId": "role-testing-client"}
  1023. )
  1024. with pytest.raises(KeycloakPostError) as err:
  1025. admin.assign_realm_roles_to_client_scope(client_id=client_id, roles=["bad"])
  1026. assert err.match('b\'{"error":"unknown_error"}\''), err
  1027. res = admin.assign_realm_roles_to_client_scope(
  1028. client_id=client_id,
  1029. roles=[
  1030. admin.get_realm_role(role_name="offline_access"),
  1031. admin.get_realm_role(role_name="test-realm-role"),
  1032. ],
  1033. )
  1034. assert res == dict(), res
  1035. roles = admin.get_realm_roles_of_client_scope(client_id=client_id)
  1036. assert len(roles) == 2
  1037. client_role_names = [x["name"] for x in roles]
  1038. assert "offline_access" in client_role_names, client_role_names
  1039. assert "test-realm-role" in client_role_names, client_role_names
  1040. assert "uma_authorization" not in client_role_names, client_role_names
  1041. # Test remove realm role of client
  1042. with pytest.raises(KeycloakDeleteError) as err:
  1043. admin.delete_realm_roles_of_client_scope(client_id=client_id, roles=["bad"])
  1044. assert err.match('b\'{"error":"unknown_error"}\''), err
  1045. res = admin.delete_realm_roles_of_client_scope(
  1046. client_id=client_id, roles=[admin.get_realm_role(role_name="offline_access")]
  1047. )
  1048. assert res == dict(), res
  1049. roles = admin.get_realm_roles_of_client_scope(client_id=client_id)
  1050. assert len(roles) == 1
  1051. assert "test-realm-role" in [x["name"] for x in roles]
  1052. res = admin.delete_realm_roles_of_client_scope(
  1053. client_id=client_id, roles=[admin.get_realm_role(role_name="test-realm-role")]
  1054. )
  1055. assert res == dict(), res
  1056. roles = admin.get_realm_roles_of_client_scope(client_id=client_id)
  1057. assert len(roles) == 0
  1058. def test_client_scope_client_roles(admin: KeycloakAdmin, realm: str, client: str):
  1059. """Test client assignment of other client roles.
  1060. :param admin: Keycloak admin
  1061. :type admin: KeycloakAdmin
  1062. :param realm: Keycloak realm
  1063. :type realm: str
  1064. :param client: Keycloak client
  1065. :type client: str
  1066. """
  1067. admin.realm_name = realm
  1068. client_id = admin.create_client(
  1069. payload={"name": "role-testing-client", "clientId": "role-testing-client"}
  1070. )
  1071. # Test get client roles
  1072. roles = admin.get_client_roles_of_client_scope(client_id, client)
  1073. assert len(roles) == 0, roles
  1074. # create client role for test
  1075. client_role_id = admin.create_client_role(
  1076. client_role_id=client, payload={"name": "client-role-test"}, skip_exists=True
  1077. )
  1078. assert client_role_id, client_role_id
  1079. # Test client role assignment to other client
  1080. with pytest.raises(KeycloakPostError) as err:
  1081. admin.assign_client_roles_to_client_scope(
  1082. client_id=client_id, client_roles_owner_id=client, roles=["bad"]
  1083. )
  1084. assert err.match('b\'{"error":"unknown_error"}\''), err
  1085. res = admin.assign_client_roles_to_client_scope(
  1086. client_id=client_id,
  1087. client_roles_owner_id=client,
  1088. roles=[admin.get_client_role(client_id=client, role_name="client-role-test")],
  1089. )
  1090. assert res == dict(), res
  1091. roles = admin.get_client_roles_of_client_scope(
  1092. client_id=client_id, client_roles_owner_id=client
  1093. )
  1094. assert len(roles) == 1
  1095. client_role_names = [x["name"] for x in roles]
  1096. assert "client-role-test" in client_role_names, client_role_names
  1097. # Test remove realm role of client
  1098. with pytest.raises(KeycloakDeleteError) as err:
  1099. admin.delete_client_roles_of_client_scope(
  1100. client_id=client_id, client_roles_owner_id=client, roles=["bad"]
  1101. )
  1102. assert err.match('b\'{"error":"unknown_error"}\''), err
  1103. res = admin.delete_client_roles_of_client_scope(
  1104. client_id=client_id,
  1105. client_roles_owner_id=client,
  1106. roles=[admin.get_client_role(client_id=client, role_name="client-role-test")],
  1107. )
  1108. assert res == dict(), res
  1109. roles = admin.get_client_roles_of_client_scope(
  1110. client_id=client_id, client_roles_owner_id=client
  1111. )
  1112. assert len(roles) == 0
  1113. def test_client_default_client_scopes(admin: KeycloakAdmin, realm: str, client: str):
  1114. """Test client assignment of default client scopes.
  1115. :param admin: Keycloak admin
  1116. :type admin: KeycloakAdmin
  1117. :param realm: Keycloak realm
  1118. :type realm: str
  1119. :param client: Keycloak client
  1120. :type client: str
  1121. """
  1122. admin.realm_name = realm
  1123. client_id = admin.create_client(
  1124. payload={"name": "role-testing-client", "clientId": "role-testing-client"}
  1125. )
  1126. # Test get client default scopes
  1127. # keycloak default roles: web-origins, acr, profile, roles, email
  1128. default_client_scopes = admin.get_client_default_client_scopes(client_id)
  1129. assert len(default_client_scopes) == 5, default_client_scopes
  1130. # Test add a client scope to client default scopes
  1131. default_client_scope = "test-client-default-scope"
  1132. new_client_scope = {
  1133. "name": default_client_scope,
  1134. "description": f"Test Client Scope: {default_client_scope}",
  1135. "protocol": "openid-connect",
  1136. "attributes": {},
  1137. }
  1138. new_client_scope_id = admin.create_client_scope(new_client_scope, skip_exists=False)
  1139. new_default_client_scope_data = {
  1140. "realm": realm,
  1141. "client": client_id,
  1142. "clientScopeId": new_client_scope_id,
  1143. }
  1144. admin.add_client_default_client_scope(
  1145. client_id, new_client_scope_id, new_default_client_scope_data
  1146. )
  1147. default_client_scopes = admin.get_client_default_client_scopes(client_id)
  1148. assert len(default_client_scopes) == 6, default_client_scopes
  1149. # Test remove a client default scope
  1150. admin.delete_client_default_client_scope(client_id, new_client_scope_id)
  1151. default_client_scopes = admin.get_client_default_client_scopes(client_id)
  1152. assert len(default_client_scopes) == 5, default_client_scopes
  1153. def test_client_optional_client_scopes(admin: KeycloakAdmin, realm: str, client: str):
  1154. """Test client assignment of optional client scopes.
  1155. :param admin: Keycloak admin
  1156. :type admin: KeycloakAdmin
  1157. :param realm: Keycloak realm
  1158. :type realm: str
  1159. :param client: Keycloak client
  1160. :type client: str
  1161. """
  1162. admin.realm_name = realm
  1163. client_id = admin.create_client(
  1164. payload={"name": "role-testing-client", "clientId": "role-testing-client"}
  1165. )
  1166. # Test get client optional scopes
  1167. # keycloak optional roles: microprofile-jwt, offline_access, address, phone
  1168. optional_client_scopes = admin.get_client_optional_client_scopes(client_id)
  1169. assert len(optional_client_scopes) == 4, optional_client_scopes
  1170. # Test add a client scope to client optional scopes
  1171. optional_client_scope = "test-client-optional-scope"
  1172. new_client_scope = {
  1173. "name": optional_client_scope,
  1174. "description": f"Test Client Scope: {optional_client_scope}",
  1175. "protocol": "openid-connect",
  1176. "attributes": {},
  1177. }
  1178. new_client_scope_id = admin.create_client_scope(new_client_scope, skip_exists=False)
  1179. new_optional_client_scope_data = {
  1180. "realm": realm,
  1181. "client": client_id,
  1182. "clientScopeId": new_client_scope_id,
  1183. }
  1184. admin.add_client_optional_client_scope(
  1185. client_id, new_client_scope_id, new_optional_client_scope_data
  1186. )
  1187. optional_client_scopes = admin.get_client_optional_client_scopes(client_id)
  1188. assert len(optional_client_scopes) == 5, optional_client_scopes
  1189. # Test remove a client optional scope
  1190. admin.delete_client_optional_client_scope(client_id, new_client_scope_id)
  1191. optional_client_scopes = admin.get_client_optional_client_scopes(client_id)
  1192. assert len(optional_client_scopes) == 4, optional_client_scopes
  1193. def test_client_roles(admin: KeycloakAdmin, client: str):
  1194. """Test client roles.
  1195. :param admin: Keycloak Admin client
  1196. :type admin: KeycloakAdmin
  1197. :param client: Keycloak client
  1198. :type client: str
  1199. """
  1200. # Test get client roles
  1201. res = admin.get_client_roles(client_id=client)
  1202. assert len(res) == 0
  1203. with pytest.raises(KeycloakGetError) as err:
  1204. admin.get_client_roles(client_id="bad")
  1205. assert err.match('404: b\'{"error":"Could not find client"}\'')
  1206. # Test create client role
  1207. client_role_id = admin.create_client_role(
  1208. client_role_id=client, payload={"name": "client-role-test"}, skip_exists=True
  1209. )
  1210. with pytest.raises(KeycloakPostError) as err:
  1211. admin.create_client_role(client_role_id=client, payload={"name": "client-role-test"})
  1212. assert err.match('409: b\'{"errorMessage":"Role with name client-role-test already exists"}\'')
  1213. client_role_id_2 = admin.create_client_role(
  1214. client_role_id=client, payload={"name": "client-role-test"}, skip_exists=True
  1215. )
  1216. assert client_role_id == client_role_id_2
  1217. # Test get client role
  1218. res = admin.get_client_role(client_id=client, role_name="client-role-test")
  1219. assert res["name"] == client_role_id
  1220. with pytest.raises(KeycloakGetError) as err:
  1221. admin.get_client_role(client_id=client, role_name="bad")
  1222. assert err.match('404: b\'{"error":"Could not find role"}\'')
  1223. res_ = admin.get_client_role_id(client_id=client, role_name="client-role-test")
  1224. assert res_ == res["id"]
  1225. with pytest.raises(KeycloakGetError) as err:
  1226. admin.get_client_role_id(client_id=client, role_name="bad")
  1227. assert err.match('404: b\'{"error":"Could not find role"}\'')
  1228. assert len(admin.get_client_roles(client_id=client)) == 1
  1229. # Test update client role
  1230. res = admin.update_client_role(
  1231. client_role_id=client,
  1232. role_name="client-role-test",
  1233. payload={"name": "client-role-test-update"},
  1234. )
  1235. assert res == dict()
  1236. with pytest.raises(KeycloakPutError) as err:
  1237. res = admin.update_client_role(
  1238. client_role_id=client,
  1239. role_name="client-role-test",
  1240. payload={"name": "client-role-test-update"},
  1241. )
  1242. assert err.match('404: b\'{"error":"Could not find role"}\'')
  1243. # Test user with client role
  1244. res = admin.get_client_role_members(client_id=client, role_name="client-role-test-update")
  1245. assert len(res) == 0
  1246. with pytest.raises(KeycloakGetError) as err:
  1247. admin.get_client_role_members(client_id=client, role_name="bad")
  1248. assert err.match('404: b\'{"error":"Could not find role"}\'')
  1249. user_id = admin.create_user(payload={"username": "test", "email": "test@test.test"})
  1250. with pytest.raises(KeycloakPostError) as err:
  1251. admin.assign_client_role(user_id=user_id, client_id=client, roles=["bad"])
  1252. assert err.match('b\'{"error":"unknown_error"}\''), err
  1253. res = admin.assign_client_role(
  1254. user_id=user_id,
  1255. client_id=client,
  1256. roles=[admin.get_client_role(client_id=client, role_name="client-role-test-update")],
  1257. )
  1258. assert res == dict()
  1259. assert (
  1260. len(admin.get_client_role_members(client_id=client, role_name="client-role-test-update"))
  1261. == 1
  1262. )
  1263. roles = admin.get_client_roles_of_user(user_id=user_id, client_id=client)
  1264. assert len(roles) == 1, roles
  1265. with pytest.raises(KeycloakGetError) as err:
  1266. admin.get_client_roles_of_user(user_id=user_id, client_id="bad")
  1267. assert err.match('404: b\'{"error":"Client not found"}\'')
  1268. roles = admin.get_composite_client_roles_of_user(user_id=user_id, client_id=client)
  1269. assert len(roles) == 1, roles
  1270. with pytest.raises(KeycloakGetError) as err:
  1271. admin.get_composite_client_roles_of_user(user_id=user_id, client_id="bad")
  1272. assert err.match('404: b\'{"error":"Client not found"}\'')
  1273. roles = admin.get_available_client_roles_of_user(user_id=user_id, client_id=client)
  1274. assert len(roles) == 0, roles
  1275. with pytest.raises(KeycloakGetError) as err:
  1276. admin.get_composite_client_roles_of_user(user_id=user_id, client_id="bad")
  1277. assert err.match('404: b\'{"error":"Client not found"}\'')
  1278. with pytest.raises(KeycloakDeleteError) as err:
  1279. admin.delete_client_roles_of_user(user_id=user_id, client_id=client, roles=["bad"])
  1280. assert err.match('b\'{"error":"unknown_error"}\''), err
  1281. admin.delete_client_roles_of_user(
  1282. user_id=user_id,
  1283. client_id=client,
  1284. roles=[admin.get_client_role(client_id=client, role_name="client-role-test-update")],
  1285. )
  1286. assert len(admin.get_client_roles_of_user(user_id=user_id, client_id=client)) == 0
  1287. # Test groups and client roles
  1288. res = admin.get_client_role_groups(client_id=client, role_name="client-role-test-update")
  1289. assert len(res) == 0
  1290. with pytest.raises(KeycloakGetError) as err:
  1291. admin.get_client_role_groups(client_id=client, role_name="bad")
  1292. assert err.match('404: b\'{"error":"Could not find role"}\'')
  1293. group_id = admin.create_group(payload={"name": "test-group"})
  1294. res = admin.get_group_client_roles(group_id=group_id, client_id=client)
  1295. assert len(res) == 0
  1296. with pytest.raises(KeycloakGetError) as err:
  1297. admin.get_group_client_roles(group_id=group_id, client_id="bad")
  1298. assert err.match('404: b\'{"error":"Client not found"}\'')
  1299. with pytest.raises(KeycloakPostError) as err:
  1300. admin.assign_group_client_roles(group_id=group_id, client_id=client, roles=["bad"])
  1301. assert err.match('b\'{"error":"unknown_error"}\''), err
  1302. res = admin.assign_group_client_roles(
  1303. group_id=group_id,
  1304. client_id=client,
  1305. roles=[admin.get_client_role(client_id=client, role_name="client-role-test-update")],
  1306. )
  1307. assert res == dict()
  1308. assert (
  1309. len(admin.get_client_role_groups(client_id=client, role_name="client-role-test-update"))
  1310. == 1
  1311. )
  1312. assert len(admin.get_group_client_roles(group_id=group_id, client_id=client)) == 1
  1313. with pytest.raises(KeycloakDeleteError) as err:
  1314. admin.delete_group_client_roles(group_id=group_id, client_id=client, roles=["bad"])
  1315. assert err.match('b\'{"error":"unknown_error"}\''), err
  1316. res = admin.delete_group_client_roles(
  1317. group_id=group_id,
  1318. client_id=client,
  1319. roles=[admin.get_client_role(client_id=client, role_name="client-role-test-update")],
  1320. )
  1321. assert res == dict()
  1322. # Test composite client roles
  1323. with pytest.raises(KeycloakPostError) as err:
  1324. admin.add_composite_client_roles_to_role(
  1325. client_role_id=client, role_name="client-role-test-update", roles=["bad"]
  1326. )
  1327. assert err.match('b\'{"error":"unknown_error"}\''), err
  1328. res = admin.add_composite_client_roles_to_role(
  1329. client_role_id=client,
  1330. role_name="client-role-test-update",
  1331. roles=[admin.get_realm_role(role_name="offline_access")],
  1332. )
  1333. assert res == dict()
  1334. assert admin.get_client_role(client_id=client, role_name="client-role-test-update")[
  1335. "composite"
  1336. ]
  1337. # Test delete of client role
  1338. res = admin.delete_client_role(client_role_id=client, role_name="client-role-test-update")
  1339. assert res == dict()
  1340. with pytest.raises(KeycloakDeleteError) as err:
  1341. admin.delete_client_role(client_role_id=client, role_name="client-role-test-update")
  1342. assert err.match('404: b\'{"error":"Could not find role"}\'')
  1343. def test_enable_token_exchange(admin: KeycloakAdmin, realm: str):
  1344. """Test enable token exchange.
  1345. :param admin: Keycloak Admin client
  1346. :type admin: KeycloakAdmin
  1347. :param realm: Keycloak realm
  1348. :type realm: str
  1349. :raises AssertionError: In case of bad configuration
  1350. """
  1351. # Test enabling token exchange between two confidential clients
  1352. admin.realm_name = realm
  1353. # Create test clients
  1354. source_client_id = admin.create_client(
  1355. payload={"name": "Source Client", "clientId": "source-client"}
  1356. )
  1357. target_client_id = admin.create_client(
  1358. payload={"name": "Target Client", "clientId": "target-client"}
  1359. )
  1360. for c in admin.get_clients():
  1361. if c["clientId"] == "realm-management":
  1362. realm_management_id = c["id"]
  1363. break
  1364. else:
  1365. raise AssertionError("Missing realm management client")
  1366. # Enable permissions on the Superset client
  1367. admin.update_client_management_permissions(
  1368. payload={"enabled": True}, client_id=target_client_id
  1369. )
  1370. # Fetch various IDs and strings needed when creating the permission
  1371. token_exchange_permission_id = admin.get_client_management_permissions(
  1372. client_id=target_client_id
  1373. )["scopePermissions"]["token-exchange"]
  1374. scopes = admin.get_client_authz_policy_scopes(
  1375. client_id=realm_management_id, policy_id=token_exchange_permission_id
  1376. )
  1377. for s in scopes:
  1378. if s["name"] == "token-exchange":
  1379. token_exchange_scope_id = s["id"]
  1380. break
  1381. else:
  1382. raise AssertionError("Missing token-exchange scope")
  1383. resources = admin.get_client_authz_policy_resources(
  1384. client_id=realm_management_id, policy_id=token_exchange_permission_id
  1385. )
  1386. for r in resources:
  1387. if r["name"] == f"client.resource.{target_client_id}":
  1388. token_exchange_resource_id = r["_id"]
  1389. break
  1390. else:
  1391. raise AssertionError("Missing client resource")
  1392. # Create a client policy for source client
  1393. policy_name = "Exchange source client token with target client token"
  1394. client_policy_id = admin.create_client_authz_client_policy(
  1395. payload={
  1396. "type": "client",
  1397. "logic": "POSITIVE",
  1398. "decisionStrategy": "UNANIMOUS",
  1399. "name": policy_name,
  1400. "clients": [source_client_id],
  1401. },
  1402. client_id=realm_management_id,
  1403. )["id"]
  1404. policies = admin.get_client_authz_client_policies(client_id=realm_management_id)
  1405. for policy in policies:
  1406. if policy["name"] == policy_name:
  1407. assert policy["clients"] == [source_client_id]
  1408. break
  1409. else:
  1410. raise AssertionError("Missing client policy")
  1411. # Update permissions on the target client to reference this policy
  1412. permission_name = admin.get_client_authz_scope_permission(
  1413. client_id=realm_management_id, scope_id=token_exchange_permission_id
  1414. )["name"]
  1415. admin.update_client_authz_scope_permission(
  1416. payload={
  1417. "id": token_exchange_permission_id,
  1418. "name": permission_name,
  1419. "type": "scope",
  1420. "logic": "POSITIVE",
  1421. "decisionStrategy": "UNANIMOUS",
  1422. "resources": [token_exchange_resource_id],
  1423. "scopes": [token_exchange_scope_id],
  1424. "policies": [client_policy_id],
  1425. },
  1426. client_id=realm_management_id,
  1427. scope_id=token_exchange_permission_id,
  1428. )
  1429. def test_email(admin: KeycloakAdmin, user: str):
  1430. """Test email.
  1431. :param admin: Keycloak Admin client
  1432. :type admin: KeycloakAdmin
  1433. :param user: Keycloak user
  1434. :type user: str
  1435. """
  1436. # Emails will fail as we don't have SMTP test setup
  1437. with pytest.raises(KeycloakPutError) as err:
  1438. admin.send_update_account(user_id=user, payload=dict())
  1439. assert err.match('b\'{"error":"unknown_error"}\''), err
  1440. admin.update_user(user_id=user, payload={"enabled": True})
  1441. with pytest.raises(KeycloakPutError) as err:
  1442. admin.send_verify_email(user_id=user)
  1443. assert err.match('500: b\'{"errorMessage":"Failed to send execute actions email"}\'')
  1444. def test_get_sessions(admin: KeycloakAdmin):
  1445. """Test get sessions.
  1446. :param admin: Keycloak Admin client
  1447. :type admin: KeycloakAdmin
  1448. """
  1449. sessions = admin.get_sessions(user_id=admin.get_user_id(username=admin.username))
  1450. assert len(sessions) >= 1
  1451. with pytest.raises(KeycloakGetError) as err:
  1452. admin.get_sessions(user_id="bad")
  1453. assert err.match('404: b\'{"error":"User not found"}\'')
  1454. def test_get_client_installation_provider(admin: KeycloakAdmin, client: str):
  1455. """Test get client installation provider.
  1456. :param admin: Keycloak Admin client
  1457. :type admin: KeycloakAdmin
  1458. :param client: Keycloak client
  1459. :type client: str
  1460. """
  1461. with pytest.raises(KeycloakGetError) as err:
  1462. admin.get_client_installation_provider(client_id=client, provider_id="bad")
  1463. assert err.match('404: b\'{"error":"Unknown Provider"}\'')
  1464. installation = admin.get_client_installation_provider(
  1465. client_id=client, provider_id="keycloak-oidc-keycloak-json"
  1466. )
  1467. assert set(installation.keys()) == {
  1468. "auth-server-url",
  1469. "confidential-port",
  1470. "credentials",
  1471. "realm",
  1472. "resource",
  1473. "ssl-required",
  1474. }
  1475. def test_auth_flows(admin: KeycloakAdmin, realm: str):
  1476. """Test auth flows.
  1477. :param admin: Keycloak Admin client
  1478. :type admin: KeycloakAdmin
  1479. :param realm: Keycloak realm
  1480. :type realm: str
  1481. """
  1482. admin.realm_name = realm
  1483. res = admin.get_authentication_flows()
  1484. assert len(res) == 8, res
  1485. assert set(res[0].keys()) == {
  1486. "alias",
  1487. "authenticationExecutions",
  1488. "builtIn",
  1489. "description",
  1490. "id",
  1491. "providerId",
  1492. "topLevel",
  1493. }
  1494. assert {x["alias"] for x in res} == {
  1495. "reset credentials",
  1496. "browser",
  1497. "http challenge",
  1498. "registration",
  1499. "docker auth",
  1500. "direct grant",
  1501. "first broker login",
  1502. "clients",
  1503. }
  1504. with pytest.raises(KeycloakGetError) as err:
  1505. admin.get_authentication_flow_for_id(flow_id="bad")
  1506. assert err.match('404: b\'{"error":"Could not find flow with id"}\'')
  1507. browser_flow_id = [x for x in res if x["alias"] == "browser"][0]["id"]
  1508. res = admin.get_authentication_flow_for_id(flow_id=browser_flow_id)
  1509. assert res["alias"] == "browser"
  1510. # Test copying
  1511. with pytest.raises(KeycloakPostError) as err:
  1512. admin.copy_authentication_flow(payload=dict(), flow_alias="bad")
  1513. assert err.match("404: b''")
  1514. res = admin.copy_authentication_flow(payload={"newName": "test-browser"}, flow_alias="browser")
  1515. assert res == b"", res
  1516. assert len(admin.get_authentication_flows()) == 9
  1517. # Test create
  1518. res = admin.create_authentication_flow(
  1519. payload={"alias": "test-create", "providerId": "basic-flow"}
  1520. )
  1521. assert res == b""
  1522. with pytest.raises(KeycloakPostError) as err:
  1523. admin.create_authentication_flow(payload={"alias": "test-create", "builtIn": False})
  1524. assert err.match('409: b\'{"errorMessage":"Flow test-create already exists"}\'')
  1525. assert admin.create_authentication_flow(
  1526. payload={"alias": "test-create"}, skip_exists=True
  1527. ) == {"msg": "Already exists"}
  1528. # Test flow executions
  1529. res = admin.get_authentication_flow_executions(flow_alias="browser")
  1530. assert len(res) == 8, res
  1531. with pytest.raises(KeycloakGetError) as err:
  1532. admin.get_authentication_flow_executions(flow_alias="bad")
  1533. assert err.match("404: b''")
  1534. exec_id = res[0]["id"]
  1535. res = admin.get_authentication_flow_execution(execution_id=exec_id)
  1536. assert set(res.keys()) == {
  1537. "alternative",
  1538. "authenticator",
  1539. "authenticatorFlow",
  1540. "conditional",
  1541. "disabled",
  1542. "enabled",
  1543. "id",
  1544. "parentFlow",
  1545. "priority",
  1546. "required",
  1547. "requirement",
  1548. }, res
  1549. with pytest.raises(KeycloakGetError) as err:
  1550. admin.get_authentication_flow_execution(execution_id="bad")
  1551. assert err.match('404: b\'{"error":"Illegal execution"}\'')
  1552. with pytest.raises(KeycloakPostError) as err:
  1553. admin.create_authentication_flow_execution(payload=dict(), flow_alias="browser")
  1554. assert err.match('400: b\'{"error":"It is illegal to add execution to a built in flow"}\'')
  1555. res = admin.create_authentication_flow_execution(
  1556. payload={"provider": "auth-cookie"}, flow_alias="test-create"
  1557. )
  1558. assert res == b""
  1559. assert len(admin.get_authentication_flow_executions(flow_alias="test-create")) == 1
  1560. with pytest.raises(KeycloakPutError) as err:
  1561. admin.update_authentication_flow_executions(
  1562. payload={"required": "yes"}, flow_alias="test-create"
  1563. )
  1564. assert err.match('400: b\'{"error":"Unrecognized field')
  1565. payload = admin.get_authentication_flow_executions(flow_alias="test-create")[0]
  1566. payload["displayName"] = "test"
  1567. res = admin.update_authentication_flow_executions(payload=payload, flow_alias="test-create")
  1568. assert res
  1569. exec_id = admin.get_authentication_flow_executions(flow_alias="test-create")[0]["id"]
  1570. res = admin.delete_authentication_flow_execution(execution_id=exec_id)
  1571. assert res == dict()
  1572. with pytest.raises(KeycloakDeleteError) as err:
  1573. admin.delete_authentication_flow_execution(execution_id=exec_id)
  1574. assert err.match('404: b\'{"error":"Illegal execution"}\'')
  1575. # Test subflows
  1576. res = admin.create_authentication_flow_subflow(
  1577. payload={
  1578. "alias": "test-subflow",
  1579. "provider": "basic-flow",
  1580. "type": "something",
  1581. "description": "something",
  1582. },
  1583. flow_alias="test-browser",
  1584. )
  1585. assert res == b""
  1586. with pytest.raises(KeycloakPostError) as err:
  1587. admin.create_authentication_flow_subflow(
  1588. payload={"alias": "test-subflow", "providerId": "basic-flow"},
  1589. flow_alias="test-browser",
  1590. )
  1591. assert err.match('409: b\'{"errorMessage":"New flow alias name already exists"}\'')
  1592. res = admin.create_authentication_flow_subflow(
  1593. payload={
  1594. "alias": "test-subflow",
  1595. "provider": "basic-flow",
  1596. "type": "something",
  1597. "description": "something",
  1598. },
  1599. flow_alias="test-create",
  1600. skip_exists=True,
  1601. )
  1602. assert res == {"msg": "Already exists"}
  1603. # Test delete auth flow
  1604. flow_id = [x for x in admin.get_authentication_flows() if x["alias"] == "test-browser"][0][
  1605. "id"
  1606. ]
  1607. res = admin.delete_authentication_flow(flow_id=flow_id)
  1608. assert res == dict()
  1609. with pytest.raises(KeycloakDeleteError) as err:
  1610. admin.delete_authentication_flow(flow_id=flow_id)
  1611. assert err.match('404: b\'{"error":"Could not find flow with id"}\'')
  1612. def test_authentication_configs(admin: KeycloakAdmin, realm: str):
  1613. """Test authentication configs.
  1614. :param admin: Keycloak Admin client
  1615. :type admin: KeycloakAdmin
  1616. :param realm: Keycloak realm
  1617. :type realm: str
  1618. """
  1619. admin.realm_name = realm
  1620. # Test list of auth providers
  1621. res = admin.get_authenticator_providers()
  1622. assert len(res) == 38
  1623. res = admin.get_authenticator_provider_config_description(provider_id="auth-cookie")
  1624. assert res == {
  1625. "helpText": "Validates the SSO cookie set by the auth server.",
  1626. "name": "Cookie",
  1627. "properties": [],
  1628. "providerId": "auth-cookie",
  1629. }
  1630. # Test authenticator config
  1631. # Currently unable to find a sustainable way to fetch the config id,
  1632. # therefore testing only failures
  1633. with pytest.raises(KeycloakGetError) as err:
  1634. admin.get_authenticator_config(config_id="bad")
  1635. assert err.match('404: b\'{"error":"Could not find authenticator config"}\'')
  1636. with pytest.raises(KeycloakPutError) as err:
  1637. admin.update_authenticator_config(payload=dict(), config_id="bad")
  1638. assert err.match('404: b\'{"error":"Could not find authenticator config"}\'')
  1639. with pytest.raises(KeycloakDeleteError) as err:
  1640. admin.delete_authenticator_config(config_id="bad")
  1641. assert err.match('404: b\'{"error":"Could not find authenticator config"}\'')
  1642. def test_sync_users(admin: KeycloakAdmin, realm: str):
  1643. """Test sync users.
  1644. :param admin: Keycloak Admin client
  1645. :type admin: KeycloakAdmin
  1646. :param realm: Keycloak realm
  1647. :type realm: str
  1648. """
  1649. admin.realm_name = realm
  1650. # Only testing the error message
  1651. with pytest.raises(KeycloakPostError) as err:
  1652. admin.sync_users(storage_id="does-not-exist", action="triggerFullSync")
  1653. assert err.match('404: b\'{"error":"Could not find component"}\'')
  1654. def test_client_scopes(admin: KeycloakAdmin, realm: str):
  1655. """Test client scopes.
  1656. :param admin: Keycloak Admin client
  1657. :type admin: KeycloakAdmin
  1658. :param realm: Keycloak realm
  1659. :type realm: str
  1660. """
  1661. admin.realm_name = realm
  1662. # Test get client scopes
  1663. res = admin.get_client_scopes()
  1664. scope_names = {x["name"] for x in res}
  1665. assert len(res) == 10
  1666. assert "email" in scope_names
  1667. assert "profile" in scope_names
  1668. assert "offline_access" in scope_names
  1669. with pytest.raises(KeycloakGetError) as err:
  1670. admin.get_client_scope(client_scope_id="does-not-exist")
  1671. assert err.match('404: b\'{"error":"Could not find client scope"}\'')
  1672. scope = admin.get_client_scope(client_scope_id=res[0]["id"])
  1673. assert res[0] == scope
  1674. scope = admin.get_client_scope_by_name(client_scope_name=res[0]["name"])
  1675. assert res[0] == scope
  1676. # Test create client scope
  1677. res = admin.create_client_scope(payload={"name": "test-scope"}, skip_exists=True)
  1678. assert res
  1679. res2 = admin.create_client_scope(payload={"name": "test-scope"}, skip_exists=True)
  1680. assert res == res2
  1681. with pytest.raises(KeycloakPostError) as err:
  1682. admin.create_client_scope(payload={"name": "test-scope"}, skip_exists=False)
  1683. assert err.match('409: b\'{"errorMessage":"Client Scope test-scope already exists"}\'')
  1684. # Test update client scope
  1685. with pytest.raises(KeycloakPutError) as err:
  1686. admin.update_client_scope(client_scope_id="does-not-exist", payload=dict())
  1687. assert err.match('404: b\'{"error":"Could not find client scope"}\'')
  1688. res_update = admin.update_client_scope(
  1689. client_scope_id=res, payload={"name": "test-scope-update"}
  1690. )
  1691. assert res_update == dict()
  1692. admin.get_client_scope(client_scope_id=res)["name"] == "test-scope-update"
  1693. # Test get mappers
  1694. mappers = admin.get_mappers_from_client_scope(client_scope_id=res)
  1695. assert mappers == list()
  1696. # Test add mapper
  1697. with pytest.raises(KeycloakPostError) as err:
  1698. admin.add_mapper_to_client_scope(client_scope_id=res, payload=dict())
  1699. assert err.match('404: b\'{"error":"ProtocolMapper provider not found"}\'')
  1700. res_add = admin.add_mapper_to_client_scope(
  1701. client_scope_id=res,
  1702. payload={
  1703. "name": "test-mapper",
  1704. "protocol": "openid-connect",
  1705. "protocolMapper": "oidc-usermodel-attribute-mapper",
  1706. },
  1707. )
  1708. assert res_add == b""
  1709. assert len(admin.get_mappers_from_client_scope(client_scope_id=res)) == 1
  1710. # Test update mapper
  1711. test_mapper = admin.get_mappers_from_client_scope(client_scope_id=res)[0]
  1712. with pytest.raises(KeycloakPutError) as err:
  1713. admin.update_mapper_in_client_scope(
  1714. client_scope_id="does-not-exist", protocol_mapper_id=test_mapper["id"], payload=dict()
  1715. )
  1716. assert err.match('404: b\'{"error":"Could not find client scope"}\'')
  1717. test_mapper["config"]["user.attribute"] = "test"
  1718. res_update = admin.update_mapper_in_client_scope(
  1719. client_scope_id=res, protocol_mapper_id=test_mapper["id"], payload=test_mapper
  1720. )
  1721. assert res_update == dict()
  1722. assert (
  1723. admin.get_mappers_from_client_scope(client_scope_id=res)[0]["config"]["user.attribute"]
  1724. == "test"
  1725. )
  1726. # Test delete mapper
  1727. res_del = admin.delete_mapper_from_client_scope(
  1728. client_scope_id=res, protocol_mapper_id=test_mapper["id"]
  1729. )
  1730. assert res_del == dict()
  1731. with pytest.raises(KeycloakDeleteError) as err:
  1732. admin.delete_mapper_from_client_scope(
  1733. client_scope_id=res, protocol_mapper_id=test_mapper["id"]
  1734. )
  1735. assert err.match('404: b\'{"error":"Model not found"}\'')
  1736. # Test default default scopes
  1737. res_defaults = admin.get_default_default_client_scopes()
  1738. assert len(res_defaults) == 6
  1739. with pytest.raises(KeycloakPutError) as err:
  1740. admin.add_default_default_client_scope(scope_id="does-not-exist")
  1741. assert err.match('404: b\'{"error":"Client scope not found"}\'')
  1742. res_add = admin.add_default_default_client_scope(scope_id=res)
  1743. assert res_add == dict()
  1744. assert len(admin.get_default_default_client_scopes()) == 7
  1745. with pytest.raises(KeycloakDeleteError) as err:
  1746. admin.delete_default_default_client_scope(scope_id="does-not-exist")
  1747. assert err.match('404: b\'{"error":"Client scope not found"}\'')
  1748. res_del = admin.delete_default_default_client_scope(scope_id=res)
  1749. assert res_del == dict()
  1750. assert len(admin.get_default_default_client_scopes()) == 6
  1751. # Test default optional scopes
  1752. res_defaults = admin.get_default_optional_client_scopes()
  1753. assert len(res_defaults) == 4
  1754. with pytest.raises(KeycloakPutError) as err:
  1755. admin.add_default_optional_client_scope(scope_id="does-not-exist")
  1756. assert err.match('404: b\'{"error":"Client scope not found"}\'')
  1757. res_add = admin.add_default_optional_client_scope(scope_id=res)
  1758. assert res_add == dict()
  1759. assert len(admin.get_default_optional_client_scopes()) == 5
  1760. with pytest.raises(KeycloakDeleteError) as err:
  1761. admin.delete_default_optional_client_scope(scope_id="does-not-exist")
  1762. assert err.match('404: b\'{"error":"Client scope not found"}\'')
  1763. res_del = admin.delete_default_optional_client_scope(scope_id=res)
  1764. assert res_del == dict()
  1765. assert len(admin.get_default_optional_client_scopes()) == 4
  1766. # Test client scope delete
  1767. res_del = admin.delete_client_scope(client_scope_id=res)
  1768. assert res_del == dict()
  1769. with pytest.raises(KeycloakDeleteError) as err:
  1770. admin.delete_client_scope(client_scope_id=res)
  1771. assert err.match('404: b\'{"error":"Could not find client scope"}\'')
  1772. def test_components(admin: KeycloakAdmin, realm: str):
  1773. """Test components.
  1774. :param admin: Keycloak Admin client
  1775. :type admin: KeycloakAdmin
  1776. :param realm: Keycloak realm
  1777. :type realm: str
  1778. """
  1779. admin.realm_name = realm
  1780. # Test get components
  1781. res = admin.get_components()
  1782. assert len(res) == 12
  1783. with pytest.raises(KeycloakGetError) as err:
  1784. admin.get_component(component_id="does-not-exist")
  1785. assert err.match('404: b\'{"error":"Could not find component"}\'')
  1786. res_get = admin.get_component(component_id=res[0]["id"])
  1787. assert res_get == res[0]
  1788. # Test create component
  1789. with pytest.raises(KeycloakPostError) as err:
  1790. admin.create_component(payload={"bad": "dict"})
  1791. assert err.match('400: b\'{"error":"Unrecognized field')
  1792. res = admin.create_component(
  1793. payload={
  1794. "name": "Test Component",
  1795. "providerId": "max-clients",
  1796. "providerType": "org.keycloak.services.clientregistration."
  1797. + "policy.ClientRegistrationPolicy",
  1798. "config": {"max-clients": ["1000"]},
  1799. }
  1800. )
  1801. assert res
  1802. assert admin.get_component(component_id=res)["name"] == "Test Component"
  1803. # Test update component
  1804. component = admin.get_component(component_id=res)
  1805. component["name"] = "Test Component Update"
  1806. with pytest.raises(KeycloakPutError) as err:
  1807. admin.update_component(component_id="does-not-exist", payload=dict())
  1808. assert err.match('404: b\'{"error":"Could not find component"}\'')
  1809. res_upd = admin.update_component(component_id=res, payload=component)
  1810. assert res_upd == dict()
  1811. assert admin.get_component(component_id=res)["name"] == "Test Component Update"
  1812. # Test delete component
  1813. res_del = admin.delete_component(component_id=res)
  1814. assert res_del == dict()
  1815. with pytest.raises(KeycloakDeleteError) as err:
  1816. admin.delete_component(component_id=res)
  1817. assert err.match('404: b\'{"error":"Could not find component"}\'')
  1818. def test_keys(admin: KeycloakAdmin, realm: str):
  1819. """Test keys.
  1820. :param admin: Keycloak Admin client
  1821. :type admin: KeycloakAdmin
  1822. :param realm: Keycloak realm
  1823. :type realm: str
  1824. """
  1825. admin.realm_name = realm
  1826. assert set(admin.get_keys()["active"].keys()) == {"AES", "HS256", "RS256", "RSA-OAEP"}
  1827. assert {k["algorithm"] for k in admin.get_keys()["keys"]} == {
  1828. "HS256",
  1829. "RSA-OAEP",
  1830. "AES",
  1831. "RS256",
  1832. }
  1833. def test_events(admin: KeycloakAdmin, realm: str):
  1834. """Test events.
  1835. :param admin: Keycloak Admin client
  1836. :type admin: KeycloakAdmin
  1837. :param realm: Keycloak realm
  1838. :type realm: str
  1839. """
  1840. admin.realm_name = realm
  1841. events = admin.get_events()
  1842. assert events == list()
  1843. with pytest.raises(KeycloakPutError) as err:
  1844. admin.set_events(payload={"bad": "conf"})
  1845. assert err.match('400: b\'{"error":"Unrecognized field')
  1846. res = admin.set_events(payload={"adminEventsDetailsEnabled": True, "adminEventsEnabled": True})
  1847. assert res == dict()
  1848. admin.create_client(payload={"name": "test", "clientId": "test"})
  1849. events = admin.get_events()
  1850. assert events == list()
  1851. @freezegun.freeze_time("2023-02-25 10:00:00")
  1852. def test_auto_refresh(admin_frozen: KeycloakAdmin, realm: str):
  1853. """Test auto refresh token.
  1854. :param admin_frozen: Keycloak Admin client with time frozen in place
  1855. :type admin_frozen: KeycloakAdmin
  1856. :param realm: Keycloak realm
  1857. :type realm: str
  1858. """
  1859. admin = admin_frozen
  1860. # Test get refresh
  1861. admin.connection.custom_headers = {
  1862. "Authorization": "Bearer bad",
  1863. "Content-Type": "application/json",
  1864. }
  1865. with pytest.raises(KeycloakAuthenticationError) as err:
  1866. admin.get_realm(realm_name=realm)
  1867. assert err.match('401: b\'{"error":"HTTP 401 Unauthorized"}\'')
  1868. # Freeze time to simulate the access token expiring
  1869. with freezegun.freeze_time("2023-02-25 10:05:00"):
  1870. assert admin.connection.expires_at < datetime_parser.parse("2023-02-25 10:05:00")
  1871. assert admin.get_realm(realm_name=realm)
  1872. assert admin.connection.expires_at > datetime_parser.parse("2023-02-25 10:05:00")
  1873. # Test bad refresh token, but first make sure access token has expired again
  1874. with freezegun.freeze_time("2023-02-25 10:10:00"):
  1875. admin.connection.custom_headers = {"Content-Type": "application/json"}
  1876. admin.connection.token["refresh_token"] = "bad"
  1877. with pytest.raises(KeycloakPostError) as err:
  1878. admin.get_realm(realm_name="test-refresh")
  1879. assert err.match(
  1880. '400: b\'{"error":"invalid_grant","error_description":"Invalid refresh token"}\''
  1881. )
  1882. admin.connection.get_token()
  1883. # Test post refresh
  1884. with freezegun.freeze_time("2023-02-25 10:15:00"):
  1885. assert admin.connection.expires_at < datetime_parser.parse("2023-02-25 10:15:00")
  1886. admin.connection.token = None
  1887. assert admin.create_realm(payload={"realm": "test-refresh"}) == b""
  1888. assert admin.connection.expires_at > datetime_parser.parse("2023-02-25 10:15:00")
  1889. # Test update refresh
  1890. with freezegun.freeze_time("2023-02-25 10:25:00"):
  1891. assert admin.connection.expires_at < datetime_parser.parse("2023-02-25 10:25:00")
  1892. admin.connection.token = None
  1893. assert (
  1894. admin.update_realm(realm_name="test-refresh", payload={"accountTheme": "test"})
  1895. == dict()
  1896. )
  1897. assert admin.connection.expires_at > datetime_parser.parse("2023-02-25 10:25:00")
  1898. # Test delete refresh
  1899. with freezegun.freeze_time("2023-02-25 10:35:00"):
  1900. assert admin.connection.expires_at < datetime_parser.parse("2023-02-25 10:35:00")
  1901. admin.connection.token = None
  1902. assert admin.delete_realm(realm_name="test-refresh") == dict()
  1903. assert admin.connection.expires_at > datetime_parser.parse("2023-02-25 10:35:00")
  1904. def test_get_required_actions(admin: KeycloakAdmin, realm: str):
  1905. """Test required actions.
  1906. :param admin: Keycloak Admin client
  1907. :type admin: KeycloakAdmin
  1908. :param realm: Keycloak realm
  1909. :type realm: str
  1910. """
  1911. admin.realm_name = realm
  1912. ractions = admin.get_required_actions()
  1913. assert isinstance(ractions, list)
  1914. for ra in ractions:
  1915. for key in [
  1916. "alias",
  1917. "name",
  1918. "providerId",
  1919. "enabled",
  1920. "defaultAction",
  1921. "priority",
  1922. "config",
  1923. ]:
  1924. assert key in ra
  1925. def test_get_required_action_by_alias(admin: KeycloakAdmin, realm: str):
  1926. """Test get required action by alias.
  1927. :param admin: Keycloak Admin client
  1928. :type admin: KeycloakAdmin
  1929. :param realm: Keycloak realm
  1930. :type realm: str
  1931. """
  1932. admin.realm_name = realm
  1933. ractions = admin.get_required_actions()
  1934. ra = admin.get_required_action_by_alias("UPDATE_PASSWORD")
  1935. assert ra in ractions
  1936. assert ra["alias"] == "UPDATE_PASSWORD"
  1937. assert admin.get_required_action_by_alias("does-not-exist") is None
  1938. def test_update_required_action(admin: KeycloakAdmin, realm: str):
  1939. """Test update required action.
  1940. :param admin: Keycloak Admin client
  1941. :type admin: KeycloakAdmin
  1942. :param realm: Keycloak realm
  1943. :type realm: str
  1944. """
  1945. admin.realm_name = realm
  1946. ra = admin.get_required_action_by_alias("UPDATE_PASSWORD")
  1947. old = copy.deepcopy(ra)
  1948. ra["enabled"] = False
  1949. admin.update_required_action("UPDATE_PASSWORD", ra)
  1950. newra = admin.get_required_action_by_alias("UPDATE_PASSWORD")
  1951. assert old != newra
  1952. assert newra["enabled"] is False
  1953. def test_get_composite_client_roles_of_group(
  1954. admin: KeycloakAdmin, realm: str, client: str, group: str, composite_client_role: str
  1955. ):
  1956. """Test get composite client roles of group.
  1957. :param admin: Keycloak Admin client
  1958. :type admin: KeycloakAdmin
  1959. :param realm: Keycloak realm
  1960. :type realm: str
  1961. :param client: Keycloak client
  1962. :type client: str
  1963. :param group: Keycloak group
  1964. :type group: str
  1965. :param composite_client_role: Composite client role
  1966. :type composite_client_role: str
  1967. """
  1968. admin.realm_name = realm
  1969. role = admin.get_client_role(client, composite_client_role)
  1970. admin.assign_group_client_roles(group_id=group, client_id=client, roles=[role])
  1971. result = admin.get_composite_client_roles_of_group(client, group)
  1972. assert role["id"] in [x["id"] for x in result]
  1973. def test_get_role_client_level_children(
  1974. admin: KeycloakAdmin, realm: str, client: str, composite_client_role: str, client_role: str
  1975. ):
  1976. """Test get children of composite client role.
  1977. :param admin: Keycloak Admin client
  1978. :type admin: KeycloakAdmin
  1979. :param realm: Keycloak realm
  1980. :type realm: str
  1981. :param client: Keycloak client
  1982. :type client: str
  1983. :param composite_client_role: Composite client role
  1984. :type composite_client_role: str
  1985. :param client_role: Client role
  1986. :type client_role: str
  1987. """
  1988. admin.realm_name = realm
  1989. child = admin.get_client_role(client, client_role)
  1990. parent = admin.get_client_role(client, composite_client_role)
  1991. res = admin.get_role_client_level_children(client, parent["id"])
  1992. assert child["id"] in [x["id"] for x in res]
  1993. def test_upload_certificate(admin: KeycloakAdmin, realm: str, client: str, selfsigned_cert: tuple):
  1994. """Test upload certificate.
  1995. :param admin: Keycloak Admin client
  1996. :type admin: KeycloakAdmin
  1997. :param realm: Keycloak realm
  1998. :type realm: str
  1999. :param client: Keycloak client
  2000. :type client: str
  2001. :param selfsigned_cert: Selfsigned certificates
  2002. :type selfsigned_cert: tuple
  2003. """
  2004. admin.realm_name = realm
  2005. cert, _ = selfsigned_cert
  2006. cert = cert.decode("utf-8").strip()
  2007. admin.upload_certificate(client, cert)
  2008. cl = admin.get_client(client)
  2009. assert cl["attributes"]["jwt.credential.certificate"] == "".join(cert.splitlines()[1:-1])
  2010. def test_get_bruteforce_status_for_user(
  2011. admin: KeycloakAdmin, oid_with_credentials: Tuple[KeycloakOpenID, str, str], realm: str
  2012. ):
  2013. """Test users.
  2014. :param admin: Keycloak Admin client
  2015. :type admin: KeycloakAdmin
  2016. :param oid_with_credentials: Keycloak OpenID client with pre-configured user credentials
  2017. :type oid_with_credentials: Tuple[KeycloakOpenID, str, str]
  2018. :param realm: Keycloak realm
  2019. :type realm: str
  2020. """
  2021. oid, username, password = oid_with_credentials
  2022. admin.realm_name = realm
  2023. # Turn on bruteforce protection
  2024. res = admin.update_realm(realm_name=realm, payload={"bruteForceProtected": True})
  2025. res = admin.get_realm(realm_name=realm)
  2026. assert res["bruteForceProtected"] is True
  2027. # Test login user with wrong credentials
  2028. try:
  2029. oid.token(username=username, password="wrongpassword")
  2030. except KeycloakAuthenticationError:
  2031. pass
  2032. user_id = admin.get_user_id(username)
  2033. bruteforce_status = admin.get_bruteforce_detection_status(user_id)
  2034. assert bruteforce_status["numFailures"] == 1
  2035. # Cleanup
  2036. res = admin.update_realm(realm_name=realm, payload={"bruteForceProtected": False})
  2037. res = admin.get_realm(realm_name=realm)
  2038. assert res["bruteForceProtected"] is False
  2039. def test_clear_bruteforce_attempts_for_user(
  2040. admin: KeycloakAdmin, oid_with_credentials: Tuple[KeycloakOpenID, str, str], realm: str
  2041. ):
  2042. """Test users.
  2043. :param admin: Keycloak Admin client
  2044. :type admin: KeycloakAdmin
  2045. :param oid_with_credentials: Keycloak OpenID client with pre-configured user credentials
  2046. :type oid_with_credentials: Tuple[KeycloakOpenID, str, str]
  2047. :param realm: Keycloak realm
  2048. :type realm: str
  2049. """
  2050. oid, username, password = oid_with_credentials
  2051. admin.realm_name = realm
  2052. # Turn on bruteforce protection
  2053. res = admin.update_realm(realm_name=realm, payload={"bruteForceProtected": True})
  2054. res = admin.get_realm(realm_name=realm)
  2055. assert res["bruteForceProtected"] is True
  2056. # Test login user with wrong credentials
  2057. try:
  2058. oid.token(username=username, password="wrongpassword")
  2059. except KeycloakAuthenticationError:
  2060. pass
  2061. user_id = admin.get_user_id(username)
  2062. bruteforce_status = admin.get_bruteforce_detection_status(user_id)
  2063. assert bruteforce_status["numFailures"] == 1
  2064. res = admin.clear_bruteforce_attempts_for_user(user_id)
  2065. bruteforce_status = admin.get_bruteforce_detection_status(user_id)
  2066. assert bruteforce_status["numFailures"] == 0
  2067. # Cleanup
  2068. res = admin.update_realm(realm_name=realm, payload={"bruteForceProtected": False})
  2069. res = admin.get_realm(realm_name=realm)
  2070. assert res["bruteForceProtected"] is False
  2071. def test_clear_bruteforce_attempts_for_all_users(
  2072. admin: KeycloakAdmin, oid_with_credentials: Tuple[KeycloakOpenID, str, str], realm: str
  2073. ):
  2074. """Test users.
  2075. :param admin: Keycloak Admin client
  2076. :type admin: KeycloakAdmin
  2077. :param oid_with_credentials: Keycloak OpenID client with pre-configured user credentials
  2078. :type oid_with_credentials: Tuple[KeycloakOpenID, str, str]
  2079. :param realm: Keycloak realm
  2080. :type realm: str
  2081. """
  2082. oid, username, password = oid_with_credentials
  2083. admin.realm_name = realm
  2084. # Turn on bruteforce protection
  2085. res = admin.update_realm(realm_name=realm, payload={"bruteForceProtected": True})
  2086. res = admin.get_realm(realm_name=realm)
  2087. assert res["bruteForceProtected"] is True
  2088. # Test login user with wrong credentials
  2089. try:
  2090. oid.token(username=username, password="wrongpassword")
  2091. except KeycloakAuthenticationError:
  2092. pass
  2093. user_id = admin.get_user_id(username)
  2094. bruteforce_status = admin.get_bruteforce_detection_status(user_id)
  2095. assert bruteforce_status["numFailures"] == 1
  2096. res = admin.clear_all_bruteforce_attempts()
  2097. bruteforce_status = admin.get_bruteforce_detection_status(user_id)
  2098. assert bruteforce_status["numFailures"] == 0
  2099. # Cleanup
  2100. res = admin.update_realm(realm_name=realm, payload={"bruteForceProtected": False})
  2101. res = admin.get_realm(realm_name=realm)
  2102. assert res["bruteForceProtected"] is False
  2103. def test_default_realm_role_present(realm: str, admin: KeycloakAdmin) -> None:
  2104. """Test that the default realm role is present in a brand new realm.
  2105. :param realm: Realm name
  2106. :type realm: str
  2107. :param admin: Keycloak admin
  2108. :type admin: KeycloakAdmin
  2109. """
  2110. admin.realm_name = realm
  2111. assert f"default-roles-{realm}" in [x["name"] for x in admin.get_realm_roles()]
  2112. assert (
  2113. len([x["name"] for x in admin.get_realm_roles() if x["name"] == f"default-roles-{realm}"])
  2114. == 1
  2115. )
  2116. def test_get_default_realm_role_id(realm: str, admin: KeycloakAdmin) -> None:
  2117. """Test getter for the ID of the default realm role.
  2118. :param realm: Realm name
  2119. :type realm: str
  2120. :param admin: Keycloak admin
  2121. :type admin: KeycloakAdmin
  2122. """
  2123. admin.realm_name = realm
  2124. assert (
  2125. admin.get_default_realm_role_id()
  2126. == [x["id"] for x in admin.get_realm_roles() if x["name"] == f"default-roles-{realm}"][0]
  2127. )
  2128. def test_realm_default_roles(admin: KeycloakAdmin, realm: str) -> None:
  2129. """Test getting, adding and deleting default realm roles.
  2130. :param realm: Realm name
  2131. :type realm: str
  2132. :param admin: Keycloak admin
  2133. :type admin: KeycloakAdmin
  2134. """
  2135. admin.realm_name = realm
  2136. # Test listing all default realm roles
  2137. roles = admin.get_realm_default_roles()
  2138. assert len(roles) == 2
  2139. assert {x["name"] for x in roles} == {"offline_access", "uma_authorization"}
  2140. with pytest.raises(KeycloakGetError) as err:
  2141. admin.realm_name = "doesnotexist"
  2142. admin.get_realm_default_roles()
  2143. assert err.match('404: b\'{"error":"Realm not found."}\'')
  2144. admin.realm_name = realm
  2145. # Test removing a default realm role
  2146. res = admin.remove_realm_default_roles(payload=[roles[0]])
  2147. assert res == {}
  2148. assert roles[0] not in admin.get_realm_default_roles()
  2149. assert len(admin.get_realm_default_roles()) == 1
  2150. with pytest.raises(KeycloakDeleteError) as err:
  2151. admin.remove_realm_default_roles(payload=[{"id": "bad id"}])
  2152. assert err.match('404: b\'{"error":"Could not find composite role"}\'')
  2153. # Test adding a default realm role
  2154. res = admin.add_realm_default_roles(payload=[roles[0]])
  2155. assert res == {}
  2156. assert roles[0] in admin.get_realm_default_roles()
  2157. assert len(admin.get_realm_default_roles()) == 2
  2158. with pytest.raises(KeycloakPostError) as err:
  2159. admin.add_realm_default_roles(payload=[{"id": "bad id"}])
  2160. assert err.match('404: b\'{"error":"Could not find composite role"}\'')
  2161. def test_clear_keys_cache(realm: str, admin: KeycloakAdmin) -> None:
  2162. """Test clearing the keys cache.
  2163. :param realm: Realm name
  2164. :type realm: str
  2165. :param admin: Keycloak admin
  2166. :type admin: KeycloakAdmin
  2167. """
  2168. admin.realm_name = realm
  2169. res = admin.clear_keys_cache()
  2170. assert res == {}
  2171. def test_clear_realm_cache(realm: str, admin: KeycloakAdmin) -> None:
  2172. """Test clearing the realm cache.
  2173. :param realm: Realm name
  2174. :type realm: str
  2175. :param admin: Keycloak admin
  2176. :type admin: KeycloakAdmin
  2177. """
  2178. admin.realm_name = realm
  2179. res = admin.clear_realm_cache()
  2180. assert res == {}
  2181. def test_clear_user_cache(realm: str, admin: KeycloakAdmin) -> None:
  2182. """Test clearing the user cache.
  2183. :param realm: Realm name
  2184. :type realm: str
  2185. :param admin: Keycloak admin
  2186. :type admin: KeycloakAdmin
  2187. """
  2188. admin.realm_name = realm
  2189. res = admin.clear_user_cache()
  2190. assert res == {}
  2191. def test_initial_access_token(
  2192. admin: KeycloakAdmin, oid_with_credentials: Tuple[KeycloakOpenID, str, str]
  2193. ) -> None:
  2194. """Test initial access token and client creation.
  2195. :param admin: Keycloak admin
  2196. :type admin: KeycloakAdmin
  2197. :param oid_with_credentials: Keycloak OpenID client with pre-configured user credentials
  2198. :type oid_with_credentials: Tuple[KeycloakOpenID, str, str]
  2199. """
  2200. res = admin.create_initial_access_token(2, 3)
  2201. assert "token" in res
  2202. assert res["count"] == 2
  2203. assert res["expiration"] == 3
  2204. oid, username, password = oid_with_credentials
  2205. client = str(uuid.uuid4())
  2206. secret = str(uuid.uuid4())
  2207. res = oid.register_client(
  2208. token=res["token"],
  2209. payload={
  2210. "name": client,
  2211. "clientId": client,
  2212. "enabled": True,
  2213. "publicClient": False,
  2214. "protocol": "openid-connect",
  2215. "secret": secret,
  2216. "clientAuthenticatorType": "client-secret",
  2217. },
  2218. )
  2219. assert res["clientId"] == client