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.

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