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.

2597 lines
92 KiB

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