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.

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