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.

2630 lines
93 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 not None, res
  496. assert res["id"] == subgroup_id_1, res
  497. with pytest.raises(KeycloakGetError) as err:
  498. admin.get_group_by_path(path="/main-group/subgroup-2/subsubgroup-1/test")
  499. assert err.match('404: b\'{"error":"Group path does not exist"}\'')
  500. res = admin.get_group_by_path(path="/main-group/subgroup-2/subsubgroup-1")
  501. assert res is not None, res
  502. assert res["id"] == subsubgroup_id_1
  503. res = admin.get_group_by_path(path="/main-group")
  504. assert res is not None, res
  505. assert res["id"] == group_id, res
  506. # Test group members
  507. res = admin.get_group_members(group_id=subgroup_id_2)
  508. assert len(res) == 0, res
  509. # Test fail group members
  510. with pytest.raises(KeycloakGetError) as err:
  511. admin.get_group_members(group_id="does-not-exist")
  512. assert err.match('404: b\'{"error":"Could not find group by id"}\'')
  513. res = admin.group_user_add(user_id=user, group_id=subgroup_id_2)
  514. assert res == dict(), res
  515. res = admin.get_group_members(group_id=subgroup_id_2)
  516. assert len(res) == 1, res
  517. assert res[0]["id"] == user
  518. # Test get group members query
  519. res = admin.get_group_members(group_id=subgroup_id_2, query={"max": 10})
  520. assert len(res) == 1, res
  521. assert res[0]["id"] == user
  522. with pytest.raises(KeycloakDeleteError) as err:
  523. admin.group_user_remove(user_id="does-not-exist", group_id=subgroup_id_2)
  524. assert err.match('404: b\'{"error":"User not found"}\''), err
  525. res = admin.group_user_remove(user_id=user, group_id=subgroup_id_2)
  526. assert res == dict(), res
  527. # Test set permissions
  528. res = admin.group_set_permissions(group_id=subgroup_id_2, enabled=True)
  529. assert res["enabled"], res
  530. res = admin.group_set_permissions(group_id=subgroup_id_2, enabled=False)
  531. assert not res["enabled"], res
  532. with pytest.raises(KeycloakPutError) as err:
  533. admin.group_set_permissions(group_id=subgroup_id_2, enabled="blah")
  534. assert err.match('500: b\'{"error":"unknown_error"}\''), err
  535. # Test update group
  536. res = admin.update_group(group_id=subgroup_id_2, payload={"name": "new-subgroup-2"})
  537. assert res == dict(), res
  538. assert admin.get_group(group_id=subgroup_id_2)["name"] == "new-subgroup-2"
  539. # test update fail
  540. with pytest.raises(KeycloakPutError) as err:
  541. admin.update_group(group_id="does-not-exist", payload=dict())
  542. assert err.match('404: b\'{"error":"Could not find group by id"}\''), err
  543. # Test delete
  544. res = admin.delete_group(group_id=group_id)
  545. assert res == dict(), res
  546. assert len(admin.get_groups()) == 0
  547. # Test delete fail
  548. with pytest.raises(KeycloakDeleteError) as err:
  549. admin.delete_group(group_id="does-not-exist")
  550. assert err.match('404: b\'{"error":"Could not find group by id"}\''), err
  551. def test_clients(admin: KeycloakAdmin, realm: str):
  552. """Test clients.
  553. :param admin: Keycloak Admin client
  554. :type admin: KeycloakAdmin
  555. :param realm: Keycloak realm
  556. :type realm: str
  557. """
  558. admin.realm_name = realm
  559. # Test get clients
  560. clients = admin.get_clients()
  561. assert len(clients) == 6, clients
  562. assert {x["name"] for x in clients} == set(
  563. [
  564. "${client_admin-cli}",
  565. "${client_security-admin-console}",
  566. "${client_account-console}",
  567. "${client_broker}",
  568. "${client_account}",
  569. "${client_realm-management}",
  570. ]
  571. ), clients
  572. # Test create client
  573. client_id = admin.create_client(payload={"name": "test-client", "clientId": "test-client"})
  574. assert client_id, client_id
  575. with pytest.raises(KeycloakPostError) as err:
  576. admin.create_client(payload={"name": "test-client", "clientId": "test-client"})
  577. assert err.match('409: b\'{"errorMessage":"Client test-client already exists"}\''), err
  578. client_id_2 = admin.create_client(
  579. payload={"name": "test-client", "clientId": "test-client"}, skip_exists=True
  580. )
  581. assert client_id == client_id_2, client_id_2
  582. # Test get client
  583. res = admin.get_client(client_id=client_id)
  584. assert res["clientId"] == "test-client", res
  585. assert res["name"] == "test-client", res
  586. assert res["id"] == client_id, res
  587. with pytest.raises(KeycloakGetError) as err:
  588. admin.get_client(client_id="does-not-exist")
  589. assert err.match('404: b\'{"error":"Could not find client"}\'')
  590. assert len(admin.get_clients()) == 7
  591. # Test get client id
  592. assert admin.get_client_id(client_id="test-client") == client_id
  593. assert admin.get_client_id(client_id="does-not-exist") is None
  594. # Test update client
  595. res = admin.update_client(client_id=client_id, payload={"name": "test-client-change"})
  596. assert res == dict(), res
  597. with pytest.raises(KeycloakPutError) as err:
  598. admin.update_client(client_id="does-not-exist", payload={"name": "test-client-change"})
  599. assert err.match('404: b\'{"error":"Could not find client"}\'')
  600. # Test client mappers
  601. res = admin.get_mappers_from_client(client_id=client_id)
  602. assert len(res) == 0
  603. with pytest.raises(KeycloakPostError) as err:
  604. admin.add_mapper_to_client(client_id="does-not-exist", payload=dict())
  605. assert err.match('404: b\'{"error":"Could not find client"}\'')
  606. res = admin.add_mapper_to_client(
  607. client_id=client_id,
  608. payload={
  609. "name": "test-mapper",
  610. "protocol": "openid-connect",
  611. "protocolMapper": "oidc-usermodel-attribute-mapper",
  612. },
  613. )
  614. assert res == b""
  615. assert len(admin.get_mappers_from_client(client_id=client_id)) == 1
  616. mapper = admin.get_mappers_from_client(client_id=client_id)[0]
  617. with pytest.raises(KeycloakPutError) as err:
  618. admin.update_client_mapper(client_id=client_id, mapper_id="does-not-exist", payload=dict())
  619. assert err.match('404: b\'{"error":"Model not found"}\'')
  620. mapper["config"]["user.attribute"] = "test"
  621. res = admin.update_client_mapper(client_id=client_id, mapper_id=mapper["id"], payload=mapper)
  622. assert res == dict()
  623. res = admin.remove_client_mapper(client_id=client_id, client_mapper_id=mapper["id"])
  624. assert res == dict()
  625. with pytest.raises(KeycloakDeleteError) as err:
  626. admin.remove_client_mapper(client_id=client_id, client_mapper_id=mapper["id"])
  627. assert err.match('404: b\'{"error":"Model not found"}\'')
  628. # Test client sessions
  629. with pytest.raises(KeycloakGetError) as err:
  630. admin.get_client_all_sessions(client_id="does-not-exist")
  631. assert err.match('404: b\'{"error":"Could not find client"}\'')
  632. assert admin.get_client_all_sessions(client_id=client_id) == list()
  633. assert admin.get_client_sessions_stats() == list()
  634. # Test authz
  635. auth_client_id = admin.create_client(
  636. payload={
  637. "name": "authz-client",
  638. "clientId": "authz-client",
  639. "authorizationServicesEnabled": True,
  640. "serviceAccountsEnabled": True,
  641. }
  642. )
  643. res = admin.get_client_authz_settings(client_id=auth_client_id)
  644. assert res["allowRemoteResourceManagement"]
  645. assert res["decisionStrategy"] == "UNANIMOUS"
  646. assert len(res["policies"]) >= 0
  647. with pytest.raises(KeycloakGetError) as err:
  648. admin.get_client_authz_settings(client_id=client_id)
  649. assert err.match('404: b\'{"error":"HTTP 404 Not Found"}\'')
  650. # Authz resources
  651. res = admin.get_client_authz_resources(client_id=auth_client_id)
  652. assert len(res) == 1
  653. assert res[0]["name"] == "Default Resource"
  654. with pytest.raises(KeycloakGetError) as err:
  655. admin.get_client_authz_resources(client_id=client_id)
  656. assert err.match('404: b\'{"error":"HTTP 404 Not Found"}\'')
  657. res = admin.create_client_authz_resource(
  658. client_id=auth_client_id, payload={"name": "test-resource"}
  659. )
  660. assert res["name"] == "test-resource", res
  661. test_resource_id = res["_id"]
  662. with pytest.raises(KeycloakPostError) as err:
  663. admin.create_client_authz_resource(
  664. client_id=auth_client_id, payload={"name": "test-resource"}
  665. )
  666. assert err.match('409: b\'{"error":"invalid_request"')
  667. assert admin.create_client_authz_resource(
  668. client_id=auth_client_id, payload={"name": "test-resource"}, skip_exists=True
  669. ) == {"msg": "Already exists"}
  670. res = admin.get_client_authz_resources(client_id=auth_client_id)
  671. assert len(res) == 2
  672. assert {x["name"] for x in res} == {"Default Resource", "test-resource"}
  673. # Authz policies
  674. res = admin.get_client_authz_policies(client_id=auth_client_id)
  675. assert len(res) == 1, res
  676. assert res[0]["name"] == "Default Policy"
  677. with pytest.raises(KeycloakGetError) as err:
  678. admin.get_client_authz_policies(client_id="does-not-exist")
  679. assert err.match('404: b\'{"error":"Could not find client"}\'')
  680. role_id = admin.get_realm_role(role_name="offline_access")["id"]
  681. res = admin.create_client_authz_role_based_policy(
  682. client_id=auth_client_id,
  683. payload={"name": "test-authz-rb-policy", "roles": [{"id": role_id}]},
  684. )
  685. assert res["name"] == "test-authz-rb-policy", res
  686. with pytest.raises(KeycloakPostError) as err:
  687. admin.create_client_authz_role_based_policy(
  688. client_id=auth_client_id,
  689. payload={"name": "test-authz-rb-policy", "roles": [{"id": role_id}]},
  690. )
  691. assert err.match('409: b\'{"error":"Policy with name')
  692. assert 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. skip_exists=True,
  696. ) == {"msg": "Already exists"}
  697. assert len(admin.get_client_authz_policies(client_id=auth_client_id)) == 2
  698. # Test authz permissions
  699. res = admin.get_client_authz_permissions(client_id=auth_client_id)
  700. assert len(res) == 1, res
  701. assert res[0]["name"] == "Default Permission"
  702. with pytest.raises(KeycloakGetError) as err:
  703. admin.get_client_authz_permissions(client_id="does-not-exist")
  704. assert err.match('404: b\'{"error":"Could not find client"}\'')
  705. res = admin.create_client_authz_resource_based_permission(
  706. client_id=auth_client_id,
  707. payload={"name": "test-permission-rb", "resources": [test_resource_id]},
  708. )
  709. assert res, res
  710. assert res["name"] == "test-permission-rb"
  711. assert res["resources"] == [test_resource_id]
  712. with pytest.raises(KeycloakPostError) as err:
  713. admin.create_client_authz_resource_based_permission(
  714. client_id=auth_client_id,
  715. payload={"name": "test-permission-rb", "resources": [test_resource_id]},
  716. )
  717. assert err.match('409: b\'{"error":"Policy with name')
  718. assert admin.create_client_authz_resource_based_permission(
  719. client_id=auth_client_id,
  720. payload={"name": "test-permission-rb", "resources": [test_resource_id]},
  721. skip_exists=True,
  722. ) == {"msg": "Already exists"}
  723. assert len(admin.get_client_authz_permissions(client_id=auth_client_id)) == 2
  724. # Test authz scopes
  725. res = admin.get_client_authz_scopes(client_id=auth_client_id)
  726. assert len(res) == 0, res
  727. with pytest.raises(KeycloakGetError) as err:
  728. admin.get_client_authz_scopes(client_id=client_id)
  729. assert err.match('404: b\'{"error":"HTTP 404 Not Found"}\'')
  730. res = admin.create_client_authz_scopes(
  731. client_id=auth_client_id, payload={"name": "test-authz-scope"}
  732. )
  733. assert res["name"] == "test-authz-scope", res
  734. with pytest.raises(KeycloakPostError) as err:
  735. admin.create_client_authz_scopes(
  736. client_id="invalid_client_id", payload={"name": "test-authz-scope"}
  737. )
  738. assert err.match('404: b\'{"error":"Could not find client"')
  739. assert admin.create_client_authz_scopes(
  740. client_id=auth_client_id, payload={"name": "test-authz-scope"}
  741. )
  742. res = admin.get_client_authz_scopes(client_id=auth_client_id)
  743. assert len(res) == 1
  744. assert {x["name"] for x in res} == {"test-authz-scope"}
  745. # Test service account user
  746. res = admin.get_client_service_account_user(client_id=auth_client_id)
  747. assert res["username"] == "service-account-authz-client", res
  748. with pytest.raises(KeycloakGetError) as err:
  749. admin.get_client_service_account_user(client_id=client_id)
  750. assert err.match('400: b\'{"error":"unknown_error"}\'')
  751. # Test delete client
  752. res = admin.delete_client(client_id=auth_client_id)
  753. assert res == dict(), res
  754. with pytest.raises(KeycloakDeleteError) as err:
  755. admin.delete_client(client_id=auth_client_id)
  756. assert err.match('404: b\'{"error":"Could not find client"}\'')
  757. # Test client credentials
  758. admin.create_client(
  759. payload={
  760. "name": "test-confidential",
  761. "enabled": True,
  762. "protocol": "openid-connect",
  763. "publicClient": False,
  764. "redirectUris": ["http://localhost/*"],
  765. "webOrigins": ["+"],
  766. "clientId": "test-confidential",
  767. "secret": "test-secret",
  768. "clientAuthenticatorType": "client-secret",
  769. }
  770. )
  771. with pytest.raises(KeycloakGetError) as err:
  772. admin.get_client_secrets(client_id="does-not-exist")
  773. assert err.match('404: b\'{"error":"Could not find client"}\'')
  774. secrets = admin.get_client_secrets(
  775. client_id=admin.get_client_id(client_id="test-confidential")
  776. )
  777. assert secrets == {"type": "secret", "value": "test-secret"}
  778. with pytest.raises(KeycloakPostError) as err:
  779. admin.generate_client_secrets(client_id="does-not-exist")
  780. assert err.match('404: b\'{"error":"Could not find client"}\'')
  781. res = admin.generate_client_secrets(
  782. client_id=admin.get_client_id(client_id="test-confidential")
  783. )
  784. assert res
  785. assert (
  786. admin.get_client_secrets(client_id=admin.get_client_id(client_id="test-confidential"))
  787. == res
  788. )
  789. def test_realm_roles(admin: KeycloakAdmin, realm: str):
  790. """Test realm roles.
  791. :param admin: Keycloak Admin client
  792. :type admin: KeycloakAdmin
  793. :param realm: Keycloak realm
  794. :type realm: str
  795. """
  796. admin.realm_name = realm
  797. # Test get realm roles
  798. roles = admin.get_realm_roles()
  799. assert len(roles) == 3, roles
  800. role_names = [x["name"] for x in roles]
  801. assert "uma_authorization" in role_names, role_names
  802. assert "offline_access" in role_names, role_names
  803. # Test empty members
  804. with pytest.raises(KeycloakGetError) as err:
  805. admin.get_realm_role_members(role_name="does-not-exist")
  806. assert err.match('404: b\'{"error":"Could not find role"}\'')
  807. members = admin.get_realm_role_members(role_name="offline_access")
  808. assert members == list(), members
  809. # Test create realm role
  810. role_id = admin.create_realm_role(payload={"name": "test-realm-role"}, skip_exists=True)
  811. assert role_id, role_id
  812. with pytest.raises(KeycloakPostError) as err:
  813. admin.create_realm_role(payload={"name": "test-realm-role"})
  814. assert err.match('409: b\'{"errorMessage":"Role with name test-realm-role already exists"}\'')
  815. role_id_2 = admin.create_realm_role(payload={"name": "test-realm-role"}, skip_exists=True)
  816. assert role_id == role_id_2
  817. # Test update realm role
  818. res = admin.update_realm_role(
  819. role_name="test-realm-role", payload={"name": "test-realm-role-update"}
  820. )
  821. assert res == dict(), res
  822. with pytest.raises(KeycloakPutError) as err:
  823. admin.update_realm_role(
  824. role_name="test-realm-role", payload={"name": "test-realm-role-update"}
  825. )
  826. assert err.match('404: b\'{"error":"Could not find role"}\''), err
  827. # Test realm role user assignment
  828. user_id = admin.create_user(payload={"username": "role-testing", "email": "test@test.test"})
  829. with pytest.raises(KeycloakPostError) as err:
  830. admin.assign_realm_roles(user_id=user_id, roles=["bad"])
  831. assert err.match('500: b\'{"error":"unknown_error"}\'')
  832. res = admin.assign_realm_roles(
  833. user_id=user_id,
  834. roles=[
  835. admin.get_realm_role(role_name="offline_access"),
  836. admin.get_realm_role(role_name="test-realm-role-update"),
  837. ],
  838. )
  839. assert res == dict(), res
  840. assert admin.get_user(user_id=user_id)["username"] in [
  841. x["username"] for x in admin.get_realm_role_members(role_name="offline_access")
  842. ]
  843. assert admin.get_user(user_id=user_id)["username"] in [
  844. x["username"] for x in admin.get_realm_role_members(role_name="test-realm-role-update")
  845. ]
  846. roles = admin.get_realm_roles_of_user(user_id=user_id)
  847. assert len(roles) == 3
  848. assert "offline_access" in [x["name"] for x in roles]
  849. assert "test-realm-role-update" in [x["name"] for x in roles]
  850. with pytest.raises(KeycloakDeleteError) as err:
  851. admin.delete_realm_roles_of_user(user_id=user_id, roles=["bad"])
  852. assert err.match('500: b\'{"error":"unknown_error"}\'')
  853. res = admin.delete_realm_roles_of_user(
  854. user_id=user_id, roles=[admin.get_realm_role(role_name="offline_access")]
  855. )
  856. assert res == dict(), res
  857. assert admin.get_realm_role_members(role_name="offline_access") == list()
  858. roles = admin.get_realm_roles_of_user(user_id=user_id)
  859. assert len(roles) == 2
  860. assert "offline_access" not in [x["name"] for x in roles]
  861. assert "test-realm-role-update" in [x["name"] for x in roles]
  862. roles = admin.get_available_realm_roles_of_user(user_id=user_id)
  863. assert len(roles) == 2
  864. assert "offline_access" in [x["name"] for x in roles]
  865. assert "uma_authorization" in [x["name"] for x in roles]
  866. # Test realm role group assignment
  867. group_id = admin.create_group(payload={"name": "test-group"})
  868. with pytest.raises(KeycloakPostError) as err:
  869. admin.assign_group_realm_roles(group_id=group_id, roles=["bad"])
  870. assert err.match('500: b\'{"error":"unknown_error"}\'')
  871. res = admin.assign_group_realm_roles(
  872. group_id=group_id,
  873. roles=[
  874. admin.get_realm_role(role_name="offline_access"),
  875. admin.get_realm_role(role_name="test-realm-role-update"),
  876. ],
  877. )
  878. assert res == dict(), res
  879. roles = admin.get_group_realm_roles(group_id=group_id)
  880. assert len(roles) == 2
  881. assert "offline_access" in [x["name"] for x in roles]
  882. assert "test-realm-role-update" in [x["name"] for x in roles]
  883. with pytest.raises(KeycloakDeleteError) as err:
  884. admin.delete_group_realm_roles(group_id=group_id, roles=["bad"])
  885. assert err.match('500: b\'{"error":"unknown_error"}\'')
  886. res = admin.delete_group_realm_roles(
  887. group_id=group_id, roles=[admin.get_realm_role(role_name="offline_access")]
  888. )
  889. assert res == dict(), res
  890. roles = admin.get_group_realm_roles(group_id=group_id)
  891. assert len(roles) == 1
  892. assert "test-realm-role-update" in [x["name"] for x in roles]
  893. # Test composite realm roles
  894. composite_role = admin.create_realm_role(payload={"name": "test-composite-role"})
  895. with pytest.raises(KeycloakPostError) as err:
  896. admin.add_composite_realm_roles_to_role(role_name=composite_role, roles=["bad"])
  897. assert err.match('500: b\'{"error":"unknown_error"}\'')
  898. res = admin.add_composite_realm_roles_to_role(
  899. role_name=composite_role, roles=[admin.get_realm_role(role_name="test-realm-role-update")]
  900. )
  901. assert res == dict(), res
  902. res = admin.get_composite_realm_roles_of_role(role_name=composite_role)
  903. assert len(res) == 1
  904. assert "test-realm-role-update" in res[0]["name"]
  905. with pytest.raises(KeycloakGetError) as err:
  906. admin.get_composite_realm_roles_of_role(role_name="bad")
  907. assert err.match('404: b\'{"error":"Could not find role"}\'')
  908. res = admin.get_composite_realm_roles_of_user(user_id=user_id)
  909. assert len(res) == 4
  910. assert "offline_access" in {x["name"] for x in res}
  911. assert "test-realm-role-update" in {x["name"] for x in res}
  912. assert "uma_authorization" in {x["name"] for x in res}
  913. with pytest.raises(KeycloakGetError) as err:
  914. admin.get_composite_realm_roles_of_user(user_id="bad")
  915. assert err.match('404: b\'{"error":"User not found"}\'')
  916. with pytest.raises(KeycloakDeleteError) as err:
  917. admin.remove_composite_realm_roles_to_role(role_name=composite_role, roles=["bad"])
  918. assert err.match('500: b\'{"error":"unknown_error"}\'')
  919. res = admin.remove_composite_realm_roles_to_role(
  920. role_name=composite_role, roles=[admin.get_realm_role(role_name="test-realm-role-update")]
  921. )
  922. assert res == dict(), res
  923. res = admin.get_composite_realm_roles_of_role(role_name=composite_role)
  924. assert len(res) == 0
  925. # Test delete realm role
  926. res = admin.delete_realm_role(role_name=composite_role)
  927. assert res == dict(), res
  928. with pytest.raises(KeycloakDeleteError) as err:
  929. admin.delete_realm_role(role_name=composite_role)
  930. assert err.match('404: b\'{"error":"Could not find role"}\'')
  931. @pytest.mark.parametrize(
  932. "testcase, arg_brief_repr, includes_attributes",
  933. [
  934. ("brief True", {"brief_representation": True}, False),
  935. ("brief False", {"brief_representation": False}, True),
  936. ("default", {}, False),
  937. ],
  938. )
  939. def test_role_attributes(
  940. admin: KeycloakAdmin,
  941. realm: str,
  942. client: str,
  943. arg_brief_repr: dict,
  944. includes_attributes: bool,
  945. testcase: str,
  946. ):
  947. """Test getting role attributes for bulk calls.
  948. :param admin: Keycloak admin
  949. :type admin: KeycloakAdmin
  950. :param realm: Keycloak realm
  951. :type realm: str
  952. :param client: Keycloak client
  953. :type client: str
  954. :param arg_brief_repr: Brief representation
  955. :type arg_brief_repr: dict
  956. :param includes_attributes: Indicator whether to include attributes
  957. :type includes_attributes: bool
  958. :param testcase: Test case
  959. :type testcase: str
  960. """
  961. # setup
  962. attribute_role = "test-realm-role-w-attr"
  963. test_attrs = {"attr1": ["val1"], "attr2": ["val2-1", "val2-2"]}
  964. role_id = admin.create_realm_role(
  965. payload={"name": attribute_role, "attributes": test_attrs}, skip_exists=True
  966. )
  967. assert role_id, role_id
  968. cli_role_id = admin.create_client_role(
  969. client, payload={"name": attribute_role, "attributes": test_attrs}, skip_exists=True
  970. )
  971. assert cli_role_id, cli_role_id
  972. if not includes_attributes:
  973. test_attrs = None
  974. # tests
  975. roles = admin.get_realm_roles(**arg_brief_repr)
  976. roles_filtered = [role for role in roles if role["name"] == role_id]
  977. assert roles_filtered, roles_filtered
  978. role = roles_filtered[0]
  979. assert role.get("attributes") == test_attrs, testcase
  980. roles = admin.get_client_roles(client, **arg_brief_repr)
  981. roles_filtered = [role for role in roles if role["name"] == cli_role_id]
  982. assert roles_filtered, roles_filtered
  983. role = roles_filtered[0]
  984. assert role.get("attributes") == test_attrs, testcase
  985. # cleanup
  986. res = admin.delete_realm_role(role_name=attribute_role)
  987. assert res == dict(), res
  988. res = admin.delete_client_role(client, role_name=attribute_role)
  989. assert res == dict(), res
  990. def test_client_scope_realm_roles(admin: KeycloakAdmin, realm: str):
  991. """Test client realm roles.
  992. :param admin: Keycloak admin
  993. :type admin: KeycloakAdmin
  994. :param realm: Keycloak realm
  995. :type realm: str
  996. """
  997. admin.realm_name = realm
  998. # Test get realm roles
  999. roles = admin.get_realm_roles()
  1000. assert len(roles) == 3, roles
  1001. role_names = [x["name"] for x in roles]
  1002. assert "uma_authorization" in role_names, role_names
  1003. assert "offline_access" in role_names, role_names
  1004. # create realm role for test
  1005. role_id = admin.create_realm_role(payload={"name": "test-realm-role"}, skip_exists=True)
  1006. assert role_id, role_id
  1007. # Test realm role client assignment
  1008. client_id = admin.create_client(
  1009. payload={"name": "role-testing-client", "clientId": "role-testing-client"}
  1010. )
  1011. with pytest.raises(KeycloakPostError) as err:
  1012. admin.assign_realm_roles_to_client_scope(client_id=client_id, roles=["bad"])
  1013. assert err.match('500: b\'{"error":"unknown_error"}\'')
  1014. res = admin.assign_realm_roles_to_client_scope(
  1015. client_id=client_id,
  1016. roles=[
  1017. admin.get_realm_role(role_name="offline_access"),
  1018. admin.get_realm_role(role_name="test-realm-role"),
  1019. ],
  1020. )
  1021. assert res == dict(), res
  1022. roles = admin.get_realm_roles_of_client_scope(client_id=client_id)
  1023. assert len(roles) == 2
  1024. client_role_names = [x["name"] for x in roles]
  1025. assert "offline_access" in client_role_names, client_role_names
  1026. assert "test-realm-role" in client_role_names, client_role_names
  1027. assert "uma_authorization" not in client_role_names, client_role_names
  1028. # Test remove realm role of client
  1029. with pytest.raises(KeycloakDeleteError) as err:
  1030. admin.delete_realm_roles_of_client_scope(client_id=client_id, roles=["bad"])
  1031. assert err.match('500: b\'{"error":"unknown_error"}\'')
  1032. res = admin.delete_realm_roles_of_client_scope(
  1033. client_id=client_id, roles=[admin.get_realm_role(role_name="offline_access")]
  1034. )
  1035. assert res == dict(), res
  1036. roles = admin.get_realm_roles_of_client_scope(client_id=client_id)
  1037. assert len(roles) == 1
  1038. assert "test-realm-role" in [x["name"] for x in roles]
  1039. res = admin.delete_realm_roles_of_client_scope(
  1040. client_id=client_id, roles=[admin.get_realm_role(role_name="test-realm-role")]
  1041. )
  1042. assert res == dict(), res
  1043. roles = admin.get_realm_roles_of_client_scope(client_id=client_id)
  1044. assert len(roles) == 0
  1045. def test_client_scope_client_roles(admin: KeycloakAdmin, realm: str, client: str):
  1046. """Test client assignment of other client roles.
  1047. :param admin: Keycloak admin
  1048. :type admin: KeycloakAdmin
  1049. :param realm: Keycloak realm
  1050. :type realm: str
  1051. :param client: Keycloak client
  1052. :type client: str
  1053. """
  1054. admin.realm_name = realm
  1055. client_id = admin.create_client(
  1056. payload={"name": "role-testing-client", "clientId": "role-testing-client"}
  1057. )
  1058. # Test get client roles
  1059. roles = admin.get_client_roles_of_client_scope(client_id, client)
  1060. assert len(roles) == 0, roles
  1061. # create client role for test
  1062. client_role_id = admin.create_client_role(
  1063. client_role_id=client, payload={"name": "client-role-test"}, skip_exists=True
  1064. )
  1065. assert client_role_id, client_role_id
  1066. # Test client role assignment to other client
  1067. with pytest.raises(KeycloakPostError) as err:
  1068. admin.assign_client_roles_to_client_scope(
  1069. client_id=client_id, client_roles_owner_id=client, roles=["bad"]
  1070. )
  1071. assert err.match('500: b\'{"error":"unknown_error"}\'')
  1072. res = admin.assign_client_roles_to_client_scope(
  1073. client_id=client_id,
  1074. client_roles_owner_id=client,
  1075. roles=[admin.get_client_role(client_id=client, role_name="client-role-test")],
  1076. )
  1077. assert res == dict(), res
  1078. roles = admin.get_client_roles_of_client_scope(
  1079. client_id=client_id, client_roles_owner_id=client
  1080. )
  1081. assert len(roles) == 1
  1082. client_role_names = [x["name"] for x in roles]
  1083. assert "client-role-test" in client_role_names, client_role_names
  1084. # Test remove realm role of client
  1085. with pytest.raises(KeycloakDeleteError) as err:
  1086. admin.delete_client_roles_of_client_scope(
  1087. client_id=client_id, client_roles_owner_id=client, roles=["bad"]
  1088. )
  1089. assert err.match('500: b\'{"error":"unknown_error"}\'')
  1090. res = admin.delete_client_roles_of_client_scope(
  1091. client_id=client_id,
  1092. client_roles_owner_id=client,
  1093. roles=[admin.get_client_role(client_id=client, role_name="client-role-test")],
  1094. )
  1095. assert res == dict(), res
  1096. roles = admin.get_client_roles_of_client_scope(
  1097. client_id=client_id, client_roles_owner_id=client
  1098. )
  1099. assert len(roles) == 0
  1100. def test_client_default_client_scopes(admin: KeycloakAdmin, realm: str, client: str):
  1101. """Test client assignment of default client scopes.
  1102. :param admin: Keycloak admin
  1103. :type admin: KeycloakAdmin
  1104. :param realm: Keycloak realm
  1105. :type realm: str
  1106. :param client: Keycloak client
  1107. :type client: str
  1108. """
  1109. admin.realm_name = realm
  1110. client_id = admin.create_client(
  1111. payload={"name": "role-testing-client", "clientId": "role-testing-client"}
  1112. )
  1113. # Test get client default scopes
  1114. # keycloak default roles: web-origins, acr, profile, roles, email
  1115. default_client_scopes = admin.get_client_default_client_scopes(client_id)
  1116. assert len(default_client_scopes) == 5, default_client_scopes
  1117. # Test add a client scope to client default scopes
  1118. default_client_scope = "test-client-default-scope"
  1119. new_client_scope = {
  1120. "name": default_client_scope,
  1121. "description": f"Test Client Scope: {default_client_scope}",
  1122. "protocol": "openid-connect",
  1123. "attributes": {},
  1124. }
  1125. new_client_scope_id = admin.create_client_scope(new_client_scope, skip_exists=False)
  1126. new_default_client_scope_data = {
  1127. "realm": realm,
  1128. "client": client_id,
  1129. "clientScopeId": new_client_scope_id,
  1130. }
  1131. admin.add_client_default_client_scope(
  1132. client_id, new_client_scope_id, new_default_client_scope_data
  1133. )
  1134. default_client_scopes = admin.get_client_default_client_scopes(client_id)
  1135. assert len(default_client_scopes) == 6, default_client_scopes
  1136. # Test remove a client default scope
  1137. admin.delete_client_default_client_scope(client_id, new_client_scope_id)
  1138. default_client_scopes = admin.get_client_default_client_scopes(client_id)
  1139. assert len(default_client_scopes) == 5, default_client_scopes
  1140. def test_client_optional_client_scopes(admin: KeycloakAdmin, realm: str, client: str):
  1141. """Test client assignment of optional client scopes.
  1142. :param admin: Keycloak admin
  1143. :type admin: KeycloakAdmin
  1144. :param realm: Keycloak realm
  1145. :type realm: str
  1146. :param client: Keycloak client
  1147. :type client: str
  1148. """
  1149. admin.realm_name = realm
  1150. client_id = admin.create_client(
  1151. payload={"name": "role-testing-client", "clientId": "role-testing-client"}
  1152. )
  1153. # Test get client optional scopes
  1154. # keycloak optional roles: microprofile-jwt, offline_access, address, phone
  1155. optional_client_scopes = admin.get_client_optional_client_scopes(client_id)
  1156. assert len(optional_client_scopes) == 4, optional_client_scopes
  1157. # Test add a client scope to client optional scopes
  1158. optional_client_scope = "test-client-optional-scope"
  1159. new_client_scope = {
  1160. "name": optional_client_scope,
  1161. "description": f"Test Client Scope: {optional_client_scope}",
  1162. "protocol": "openid-connect",
  1163. "attributes": {},
  1164. }
  1165. new_client_scope_id = admin.create_client_scope(new_client_scope, skip_exists=False)
  1166. new_optional_client_scope_data = {
  1167. "realm": realm,
  1168. "client": client_id,
  1169. "clientScopeId": new_client_scope_id,
  1170. }
  1171. admin.add_client_optional_client_scope(
  1172. client_id, new_client_scope_id, new_optional_client_scope_data
  1173. )
  1174. optional_client_scopes = admin.get_client_optional_client_scopes(client_id)
  1175. assert len(optional_client_scopes) == 5, optional_client_scopes
  1176. # Test remove a client optional scope
  1177. admin.delete_client_optional_client_scope(client_id, new_client_scope_id)
  1178. optional_client_scopes = admin.get_client_optional_client_scopes(client_id)
  1179. assert len(optional_client_scopes) == 4, optional_client_scopes
  1180. def test_client_roles(admin: KeycloakAdmin, client: str):
  1181. """Test client roles.
  1182. :param admin: Keycloak Admin client
  1183. :type admin: KeycloakAdmin
  1184. :param client: Keycloak client
  1185. :type client: str
  1186. """
  1187. # Test get client roles
  1188. res = admin.get_client_roles(client_id=client)
  1189. assert len(res) == 0
  1190. with pytest.raises(KeycloakGetError) as err:
  1191. admin.get_client_roles(client_id="bad")
  1192. assert err.match('404: b\'{"error":"Could not find client"}\'')
  1193. # Test create client role
  1194. client_role_id = admin.create_client_role(
  1195. client_role_id=client, payload={"name": "client-role-test"}, skip_exists=True
  1196. )
  1197. with pytest.raises(KeycloakPostError) as err:
  1198. admin.create_client_role(client_role_id=client, payload={"name": "client-role-test"})
  1199. assert err.match('409: b\'{"errorMessage":"Role with name client-role-test already exists"}\'')
  1200. client_role_id_2 = admin.create_client_role(
  1201. client_role_id=client, payload={"name": "client-role-test"}, skip_exists=True
  1202. )
  1203. assert client_role_id == client_role_id_2
  1204. # Test get client role
  1205. res = admin.get_client_role(client_id=client, role_name="client-role-test")
  1206. assert res["name"] == client_role_id
  1207. with pytest.raises(KeycloakGetError) as err:
  1208. admin.get_client_role(client_id=client, role_name="bad")
  1209. assert err.match('404: b\'{"error":"Could not find role"}\'')
  1210. res_ = admin.get_client_role_id(client_id=client, role_name="client-role-test")
  1211. assert res_ == res["id"]
  1212. with pytest.raises(KeycloakGetError) as err:
  1213. admin.get_client_role_id(client_id=client, role_name="bad")
  1214. assert err.match('404: b\'{"error":"Could not find role"}\'')
  1215. assert len(admin.get_client_roles(client_id=client)) == 1
  1216. # Test update client role
  1217. res = admin.update_client_role(
  1218. client_role_id=client,
  1219. role_name="client-role-test",
  1220. payload={"name": "client-role-test-update"},
  1221. )
  1222. assert res == dict()
  1223. with pytest.raises(KeycloakPutError) as err:
  1224. res = admin.update_client_role(
  1225. client_role_id=client,
  1226. role_name="client-role-test",
  1227. payload={"name": "client-role-test-update"},
  1228. )
  1229. assert err.match('404: b\'{"error":"Could not find role"}\'')
  1230. # Test user with client role
  1231. res = admin.get_client_role_members(client_id=client, role_name="client-role-test-update")
  1232. assert len(res) == 0
  1233. with pytest.raises(KeycloakGetError) as err:
  1234. admin.get_client_role_members(client_id=client, role_name="bad")
  1235. assert err.match('404: b\'{"error":"Could not find role"}\'')
  1236. user_id = admin.create_user(payload={"username": "test", "email": "test@test.test"})
  1237. with pytest.raises(KeycloakPostError) as err:
  1238. admin.assign_client_role(user_id=user_id, client_id=client, roles=["bad"])
  1239. assert err.match('500: b\'{"error":"unknown_error"}\'')
  1240. res = admin.assign_client_role(
  1241. user_id=user_id,
  1242. client_id=client,
  1243. roles=[admin.get_client_role(client_id=client, role_name="client-role-test-update")],
  1244. )
  1245. assert res == dict()
  1246. assert (
  1247. len(admin.get_client_role_members(client_id=client, role_name="client-role-test-update"))
  1248. == 1
  1249. )
  1250. roles = admin.get_client_roles_of_user(user_id=user_id, client_id=client)
  1251. assert len(roles) == 1, roles
  1252. with pytest.raises(KeycloakGetError) as err:
  1253. admin.get_client_roles_of_user(user_id=user_id, client_id="bad")
  1254. assert err.match('404: b\'{"error":"Client not found"}\'')
  1255. roles = admin.get_composite_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_composite_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_available_client_roles_of_user(user_id=user_id, client_id=client)
  1261. assert len(roles) == 0, 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. with pytest.raises(KeycloakDeleteError) as err:
  1266. admin.delete_client_roles_of_user(user_id=user_id, client_id=client, roles=["bad"])
  1267. assert err.match('500: b\'{"error":"unknown_error"}\'')
  1268. admin.delete_client_roles_of_user(
  1269. user_id=user_id,
  1270. client_id=client,
  1271. roles=[admin.get_client_role(client_id=client, role_name="client-role-test-update")],
  1272. )
  1273. assert len(admin.get_client_roles_of_user(user_id=user_id, client_id=client)) == 0
  1274. # Test groups and client roles
  1275. res = admin.get_client_role_groups(client_id=client, role_name="client-role-test-update")
  1276. assert len(res) == 0
  1277. with pytest.raises(KeycloakGetError) as err:
  1278. admin.get_client_role_groups(client_id=client, role_name="bad")
  1279. assert err.match('404: b\'{"error":"Could not find role"}\'')
  1280. group_id = admin.create_group(payload={"name": "test-group"})
  1281. res = admin.get_group_client_roles(group_id=group_id, client_id=client)
  1282. assert len(res) == 0
  1283. with pytest.raises(KeycloakGetError) as err:
  1284. admin.get_group_client_roles(group_id=group_id, client_id="bad")
  1285. assert err.match('404: b\'{"error":"Client not found"}\'')
  1286. with pytest.raises(KeycloakPostError) as err:
  1287. admin.assign_group_client_roles(group_id=group_id, client_id=client, roles=["bad"])
  1288. assert err.match('500: b\'{"error":"unknown_error"}\'')
  1289. res = admin.assign_group_client_roles(
  1290. group_id=group_id,
  1291. client_id=client,
  1292. roles=[admin.get_client_role(client_id=client, role_name="client-role-test-update")],
  1293. )
  1294. assert res == dict()
  1295. assert (
  1296. len(admin.get_client_role_groups(client_id=client, role_name="client-role-test-update"))
  1297. == 1
  1298. )
  1299. assert len(admin.get_group_client_roles(group_id=group_id, client_id=client)) == 1
  1300. with pytest.raises(KeycloakDeleteError) as err:
  1301. admin.delete_group_client_roles(group_id=group_id, client_id=client, roles=["bad"])
  1302. assert err.match('500: b\'{"error":"unknown_error"}\'')
  1303. res = admin.delete_group_client_roles(
  1304. group_id=group_id,
  1305. client_id=client,
  1306. roles=[admin.get_client_role(client_id=client, role_name="client-role-test-update")],
  1307. )
  1308. assert res == dict()
  1309. # Test composite client roles
  1310. with pytest.raises(KeycloakPostError) as err:
  1311. admin.add_composite_client_roles_to_role(
  1312. client_role_id=client, role_name="client-role-test-update", roles=["bad"]
  1313. )
  1314. assert err.match('500: b\'{"error":"unknown_error"}\'')
  1315. res = admin.add_composite_client_roles_to_role(
  1316. client_role_id=client,
  1317. role_name="client-role-test-update",
  1318. roles=[admin.get_realm_role(role_name="offline_access")],
  1319. )
  1320. assert res == dict()
  1321. assert admin.get_client_role(client_id=client, role_name="client-role-test-update")[
  1322. "composite"
  1323. ]
  1324. # Test delete of client role
  1325. res = admin.delete_client_role(client_role_id=client, role_name="client-role-test-update")
  1326. assert res == dict()
  1327. with pytest.raises(KeycloakDeleteError) as err:
  1328. admin.delete_client_role(client_role_id=client, role_name="client-role-test-update")
  1329. assert err.match('404: b\'{"error":"Could not find role"}\'')
  1330. def test_enable_token_exchange(admin: KeycloakAdmin, realm: str):
  1331. """Test enable token exchange.
  1332. :param admin: Keycloak Admin client
  1333. :type admin: KeycloakAdmin
  1334. :param realm: Keycloak realm
  1335. :type realm: str
  1336. :raises AssertionError: In case of bad configuration
  1337. """
  1338. # Test enabling token exchange between two confidential clients
  1339. admin.realm_name = realm
  1340. # Create test clients
  1341. source_client_id = admin.create_client(
  1342. payload={"name": "Source Client", "clientId": "source-client"}
  1343. )
  1344. target_client_id = admin.create_client(
  1345. payload={"name": "Target Client", "clientId": "target-client"}
  1346. )
  1347. for c in admin.get_clients():
  1348. if c["clientId"] == "realm-management":
  1349. realm_management_id = c["id"]
  1350. break
  1351. else:
  1352. raise AssertionError("Missing realm management client")
  1353. # Enable permissions on the Superset client
  1354. admin.update_client_management_permissions(
  1355. payload={"enabled": True}, client_id=target_client_id
  1356. )
  1357. # Fetch various IDs and strings needed when creating the permission
  1358. token_exchange_permission_id = admin.get_client_management_permissions(
  1359. client_id=target_client_id
  1360. )["scopePermissions"]["token-exchange"]
  1361. scopes = admin.get_client_authz_policy_scopes(
  1362. client_id=realm_management_id, policy_id=token_exchange_permission_id
  1363. )
  1364. for s in scopes:
  1365. if s["name"] == "token-exchange":
  1366. token_exchange_scope_id = s["id"]
  1367. break
  1368. else:
  1369. raise AssertionError("Missing token-exchange scope")
  1370. resources = admin.get_client_authz_policy_resources(
  1371. client_id=realm_management_id, policy_id=token_exchange_permission_id
  1372. )
  1373. for r in resources:
  1374. if r["name"] == f"client.resource.{target_client_id}":
  1375. token_exchange_resource_id = r["_id"]
  1376. break
  1377. else:
  1378. raise AssertionError("Missing client resource")
  1379. # Create a client policy for source client
  1380. policy_name = "Exchange source client token with target client token"
  1381. client_policy_id = admin.create_client_authz_client_policy(
  1382. payload={
  1383. "type": "client",
  1384. "logic": "POSITIVE",
  1385. "decisionStrategy": "UNANIMOUS",
  1386. "name": policy_name,
  1387. "clients": [source_client_id],
  1388. },
  1389. client_id=realm_management_id,
  1390. )["id"]
  1391. policies = admin.get_client_authz_client_policies(client_id=realm_management_id)
  1392. for policy in policies:
  1393. if policy["name"] == policy_name:
  1394. assert policy["clients"] == [source_client_id]
  1395. break
  1396. else:
  1397. raise AssertionError("Missing client policy")
  1398. # Update permissions on the target client to reference this policy
  1399. permission_name = admin.get_client_authz_scope_permission(
  1400. client_id=realm_management_id, scope_id=token_exchange_permission_id
  1401. )["name"]
  1402. admin.update_client_authz_scope_permission(
  1403. payload={
  1404. "id": token_exchange_permission_id,
  1405. "name": permission_name,
  1406. "type": "scope",
  1407. "logic": "POSITIVE",
  1408. "decisionStrategy": "UNANIMOUS",
  1409. "resources": [token_exchange_resource_id],
  1410. "scopes": [token_exchange_scope_id],
  1411. "policies": [client_policy_id],
  1412. },
  1413. client_id=realm_management_id,
  1414. scope_id=token_exchange_permission_id,
  1415. )
  1416. def test_email(admin: KeycloakAdmin, user: str):
  1417. """Test email.
  1418. :param admin: Keycloak Admin client
  1419. :type admin: KeycloakAdmin
  1420. :param user: Keycloak user
  1421. :type user: str
  1422. """
  1423. # Emails will fail as we don't have SMTP test setup
  1424. with pytest.raises(KeycloakPutError) as err:
  1425. admin.send_update_account(user_id=user, payload=dict())
  1426. assert err.match('500: b\'{"error":"unknown_error"}\'')
  1427. admin.update_user(user_id=user, payload={"enabled": True})
  1428. with pytest.raises(KeycloakPutError) as err:
  1429. admin.send_verify_email(user_id=user)
  1430. assert err.match('500: b\'{"errorMessage":"Failed to send execute actions email"}\'')
  1431. def test_get_sessions(admin: KeycloakAdmin):
  1432. """Test get sessions.
  1433. :param admin: Keycloak Admin client
  1434. :type admin: KeycloakAdmin
  1435. """
  1436. sessions = admin.get_sessions(user_id=admin.get_user_id(username=admin.username))
  1437. assert len(sessions) >= 1
  1438. with pytest.raises(KeycloakGetError) as err:
  1439. admin.get_sessions(user_id="bad")
  1440. assert err.match('404: b\'{"error":"User not found"}\'')
  1441. def test_get_client_installation_provider(admin: KeycloakAdmin, client: str):
  1442. """Test get client installation provider.
  1443. :param admin: Keycloak Admin client
  1444. :type admin: KeycloakAdmin
  1445. :param client: Keycloak client
  1446. :type client: str
  1447. """
  1448. with pytest.raises(KeycloakGetError) as err:
  1449. admin.get_client_installation_provider(client_id=client, provider_id="bad")
  1450. assert err.match('404: b\'{"error":"Unknown Provider"}\'')
  1451. installation = admin.get_client_installation_provider(
  1452. client_id=client, provider_id="keycloak-oidc-keycloak-json"
  1453. )
  1454. assert set(installation.keys()) == {
  1455. "auth-server-url",
  1456. "confidential-port",
  1457. "credentials",
  1458. "realm",
  1459. "resource",
  1460. "ssl-required",
  1461. }
  1462. def test_auth_flows(admin: KeycloakAdmin, realm: str):
  1463. """Test auth flows.
  1464. :param admin: Keycloak Admin client
  1465. :type admin: KeycloakAdmin
  1466. :param realm: Keycloak realm
  1467. :type realm: str
  1468. """
  1469. admin.realm_name = realm
  1470. res = admin.get_authentication_flows()
  1471. assert len(res) == 8, res
  1472. assert set(res[0].keys()) == {
  1473. "alias",
  1474. "authenticationExecutions",
  1475. "builtIn",
  1476. "description",
  1477. "id",
  1478. "providerId",
  1479. "topLevel",
  1480. }
  1481. assert {x["alias"] for x in res} == {
  1482. "reset credentials",
  1483. "browser",
  1484. "http challenge",
  1485. "registration",
  1486. "docker auth",
  1487. "direct grant",
  1488. "first broker login",
  1489. "clients",
  1490. }
  1491. with pytest.raises(KeycloakGetError) as err:
  1492. admin.get_authentication_flow_for_id(flow_id="bad")
  1493. assert err.match('404: b\'{"error":"Could not find flow with id"}\'')
  1494. browser_flow_id = [x for x in res if x["alias"] == "browser"][0]["id"]
  1495. res = admin.get_authentication_flow_for_id(flow_id=browser_flow_id)
  1496. assert res["alias"] == "browser"
  1497. # Test copying
  1498. with pytest.raises(KeycloakPostError) as err:
  1499. admin.copy_authentication_flow(payload=dict(), flow_alias="bad")
  1500. assert err.match("404: b''")
  1501. res = admin.copy_authentication_flow(payload={"newName": "test-browser"}, flow_alias="browser")
  1502. assert res == b"", res
  1503. assert len(admin.get_authentication_flows()) == 9
  1504. # Test create
  1505. res = admin.create_authentication_flow(
  1506. payload={"alias": "test-create", "providerId": "basic-flow"}
  1507. )
  1508. assert res == b""
  1509. with pytest.raises(KeycloakPostError) as err:
  1510. admin.create_authentication_flow(payload={"alias": "test-create", "builtIn": False})
  1511. assert err.match('409: b\'{"errorMessage":"Flow test-create already exists"}\'')
  1512. assert admin.create_authentication_flow(
  1513. payload={"alias": "test-create"}, skip_exists=True
  1514. ) == {"msg": "Already exists"}
  1515. # Test flow executions
  1516. res = admin.get_authentication_flow_executions(flow_alias="browser")
  1517. assert len(res) == 8, res
  1518. with pytest.raises(KeycloakGetError) as err:
  1519. admin.get_authentication_flow_executions(flow_alias="bad")
  1520. assert err.match("404: b''")
  1521. exec_id = res[0]["id"]
  1522. res = admin.get_authentication_flow_execution(execution_id=exec_id)
  1523. assert set(res.keys()) == {
  1524. "alternative",
  1525. "authenticator",
  1526. "authenticatorFlow",
  1527. "conditional",
  1528. "disabled",
  1529. "enabled",
  1530. "id",
  1531. "parentFlow",
  1532. "priority",
  1533. "required",
  1534. "requirement",
  1535. }, res
  1536. with pytest.raises(KeycloakGetError) as err:
  1537. admin.get_authentication_flow_execution(execution_id="bad")
  1538. assert err.match('404: b\'{"error":"Illegal execution"}\'')
  1539. with pytest.raises(KeycloakPostError) as err:
  1540. admin.create_authentication_flow_execution(payload=dict(), flow_alias="browser")
  1541. assert err.match('400: b\'{"error":"It is illegal to add execution to a built in flow"}\'')
  1542. res = admin.create_authentication_flow_execution(
  1543. payload={"provider": "auth-cookie"}, flow_alias="test-create"
  1544. )
  1545. assert res == b""
  1546. assert len(admin.get_authentication_flow_executions(flow_alias="test-create")) == 1
  1547. with pytest.raises(KeycloakPutError) as err:
  1548. admin.update_authentication_flow_executions(
  1549. payload={"required": "yes"}, flow_alias="test-create"
  1550. )
  1551. assert err.match('400: b\'{"error":"Unrecognized field')
  1552. payload = admin.get_authentication_flow_executions(flow_alias="test-create")[0]
  1553. payload["displayName"] = "test"
  1554. res = admin.update_authentication_flow_executions(payload=payload, flow_alias="test-create")
  1555. assert res
  1556. exec_id = admin.get_authentication_flow_executions(flow_alias="test-create")[0]["id"]
  1557. res = admin.delete_authentication_flow_execution(execution_id=exec_id)
  1558. assert res == dict()
  1559. with pytest.raises(KeycloakDeleteError) as err:
  1560. admin.delete_authentication_flow_execution(execution_id=exec_id)
  1561. assert err.match('404: b\'{"error":"Illegal execution"}\'')
  1562. # Test subflows
  1563. res = admin.create_authentication_flow_subflow(
  1564. payload={
  1565. "alias": "test-subflow",
  1566. "provider": "basic-flow",
  1567. "type": "something",
  1568. "description": "something",
  1569. },
  1570. flow_alias="test-browser",
  1571. )
  1572. assert res == b""
  1573. with pytest.raises(KeycloakPostError) as err:
  1574. admin.create_authentication_flow_subflow(
  1575. payload={"alias": "test-subflow", "providerId": "basic-flow"},
  1576. flow_alias="test-browser",
  1577. )
  1578. assert err.match('409: b\'{"errorMessage":"New flow alias name already exists"}\'')
  1579. res = admin.create_authentication_flow_subflow(
  1580. payload={
  1581. "alias": "test-subflow",
  1582. "provider": "basic-flow",
  1583. "type": "something",
  1584. "description": "something",
  1585. },
  1586. flow_alias="test-create",
  1587. skip_exists=True,
  1588. )
  1589. assert res == {"msg": "Already exists"}
  1590. # Test delete auth flow
  1591. flow_id = [x for x in admin.get_authentication_flows() if x["alias"] == "test-browser"][0][
  1592. "id"
  1593. ]
  1594. res = admin.delete_authentication_flow(flow_id=flow_id)
  1595. assert res == dict()
  1596. with pytest.raises(KeycloakDeleteError) as err:
  1597. admin.delete_authentication_flow(flow_id=flow_id)
  1598. assert err.match('404: b\'{"error":"Could not find flow with id"}\'')
  1599. def test_authentication_configs(admin: KeycloakAdmin, realm: str):
  1600. """Test authentication configs.
  1601. :param admin: Keycloak Admin client
  1602. :type admin: KeycloakAdmin
  1603. :param realm: Keycloak realm
  1604. :type realm: str
  1605. """
  1606. admin.realm_name = realm
  1607. # Test list of auth providers
  1608. res = admin.get_authenticator_providers()
  1609. assert len(res) == 38
  1610. res = admin.get_authenticator_provider_config_description(provider_id="auth-cookie")
  1611. assert res == {
  1612. "helpText": "Validates the SSO cookie set by the auth server.",
  1613. "name": "Cookie",
  1614. "properties": [],
  1615. "providerId": "auth-cookie",
  1616. }
  1617. # Test authenticator config
  1618. # Currently unable to find a sustainable way to fetch the config id,
  1619. # therefore testing only failures
  1620. with pytest.raises(KeycloakGetError) as err:
  1621. admin.get_authenticator_config(config_id="bad")
  1622. assert err.match('404: b\'{"error":"Could not find authenticator config"}\'')
  1623. with pytest.raises(KeycloakPutError) as err:
  1624. admin.update_authenticator_config(payload=dict(), config_id="bad")
  1625. assert err.match('404: b\'{"error":"Could not find authenticator config"}\'')
  1626. with pytest.raises(KeycloakDeleteError) as err:
  1627. admin.delete_authenticator_config(config_id="bad")
  1628. assert err.match('404: b\'{"error":"Could not find authenticator config"}\'')
  1629. def test_sync_users(admin: KeycloakAdmin, realm: str):
  1630. """Test sync users.
  1631. :param admin: Keycloak Admin client
  1632. :type admin: KeycloakAdmin
  1633. :param realm: Keycloak realm
  1634. :type realm: str
  1635. """
  1636. admin.realm_name = realm
  1637. # Only testing the error message
  1638. with pytest.raises(KeycloakPostError) as err:
  1639. admin.sync_users(storage_id="does-not-exist", action="triggerFullSync")
  1640. assert err.match('404: b\'{"error":"Could not find component"}\'')
  1641. def test_client_scopes(admin: KeycloakAdmin, realm: str):
  1642. """Test client scopes.
  1643. :param admin: Keycloak Admin client
  1644. :type admin: KeycloakAdmin
  1645. :param realm: Keycloak realm
  1646. :type realm: str
  1647. """
  1648. admin.realm_name = realm
  1649. # Test get client scopes
  1650. res = admin.get_client_scopes()
  1651. scope_names = {x["name"] for x in res}
  1652. assert len(res) == 10
  1653. assert "email" in scope_names
  1654. assert "profile" in scope_names
  1655. assert "offline_access" in scope_names
  1656. with pytest.raises(KeycloakGetError) as err:
  1657. admin.get_client_scope(client_scope_id="does-not-exist")
  1658. assert err.match('404: b\'{"error":"Could not find client scope"}\'')
  1659. scope = admin.get_client_scope(client_scope_id=res[0]["id"])
  1660. assert res[0] == scope
  1661. scope = admin.get_client_scope_by_name(client_scope_name=res[0]["name"])
  1662. assert res[0] == scope
  1663. # Test create client scope
  1664. res = admin.create_client_scope(payload={"name": "test-scope"}, skip_exists=True)
  1665. assert res
  1666. res2 = admin.create_client_scope(payload={"name": "test-scope"}, skip_exists=True)
  1667. assert res == res2
  1668. with pytest.raises(KeycloakPostError) as err:
  1669. admin.create_client_scope(payload={"name": "test-scope"}, skip_exists=False)
  1670. assert err.match('409: b\'{"errorMessage":"Client Scope test-scope already exists"}\'')
  1671. # Test update client scope
  1672. with pytest.raises(KeycloakPutError) as err:
  1673. admin.update_client_scope(client_scope_id="does-not-exist", payload=dict())
  1674. assert err.match('404: b\'{"error":"Could not find client scope"}\'')
  1675. res_update = admin.update_client_scope(
  1676. client_scope_id=res, payload={"name": "test-scope-update"}
  1677. )
  1678. assert res_update == dict()
  1679. admin.get_client_scope(client_scope_id=res)["name"] == "test-scope-update"
  1680. # Test get mappers
  1681. mappers = admin.get_mappers_from_client_scope(client_scope_id=res)
  1682. assert mappers == list()
  1683. # Test add mapper
  1684. with pytest.raises(KeycloakPostError) as err:
  1685. admin.add_mapper_to_client_scope(client_scope_id=res, payload=dict())
  1686. assert err.match('404: b\'{"error":"ProtocolMapper provider not found"}\'')
  1687. res_add = admin.add_mapper_to_client_scope(
  1688. client_scope_id=res,
  1689. payload={
  1690. "name": "test-mapper",
  1691. "protocol": "openid-connect",
  1692. "protocolMapper": "oidc-usermodel-attribute-mapper",
  1693. },
  1694. )
  1695. assert res_add == b""
  1696. assert len(admin.get_mappers_from_client_scope(client_scope_id=res)) == 1
  1697. # Test update mapper
  1698. test_mapper = admin.get_mappers_from_client_scope(client_scope_id=res)[0]
  1699. with pytest.raises(KeycloakPutError) as err:
  1700. admin.update_mapper_in_client_scope(
  1701. client_scope_id="does-not-exist", protocol_mapper_id=test_mapper["id"], payload=dict()
  1702. )
  1703. assert err.match('404: b\'{"error":"Could not find client scope"}\'')
  1704. test_mapper["config"]["user.attribute"] = "test"
  1705. res_update = admin.update_mapper_in_client_scope(
  1706. client_scope_id=res, protocol_mapper_id=test_mapper["id"], payload=test_mapper
  1707. )
  1708. assert res_update == dict()
  1709. assert (
  1710. admin.get_mappers_from_client_scope(client_scope_id=res)[0]["config"]["user.attribute"]
  1711. == "test"
  1712. )
  1713. # Test delete mapper
  1714. res_del = admin.delete_mapper_from_client_scope(
  1715. client_scope_id=res, protocol_mapper_id=test_mapper["id"]
  1716. )
  1717. assert res_del == dict()
  1718. with pytest.raises(KeycloakDeleteError) as err:
  1719. admin.delete_mapper_from_client_scope(
  1720. client_scope_id=res, protocol_mapper_id=test_mapper["id"]
  1721. )
  1722. assert err.match('404: b\'{"error":"Model not found"}\'')
  1723. # Test default default scopes
  1724. res_defaults = admin.get_default_default_client_scopes()
  1725. assert len(res_defaults) == 6
  1726. with pytest.raises(KeycloakPutError) as err:
  1727. admin.add_default_default_client_scope(scope_id="does-not-exist")
  1728. assert err.match('404: b\'{"error":"Client scope not found"}\'')
  1729. res_add = admin.add_default_default_client_scope(scope_id=res)
  1730. assert res_add == dict()
  1731. assert len(admin.get_default_default_client_scopes()) == 7
  1732. with pytest.raises(KeycloakDeleteError) as err:
  1733. admin.delete_default_default_client_scope(scope_id="does-not-exist")
  1734. assert err.match('404: b\'{"error":"Client scope not found"}\'')
  1735. res_del = admin.delete_default_default_client_scope(scope_id=res)
  1736. assert res_del == dict()
  1737. assert len(admin.get_default_default_client_scopes()) == 6
  1738. # Test default optional scopes
  1739. res_defaults = admin.get_default_optional_client_scopes()
  1740. assert len(res_defaults) == 4
  1741. with pytest.raises(KeycloakPutError) as err:
  1742. admin.add_default_optional_client_scope(scope_id="does-not-exist")
  1743. assert err.match('404: b\'{"error":"Client scope not found"}\'')
  1744. res_add = admin.add_default_optional_client_scope(scope_id=res)
  1745. assert res_add == dict()
  1746. assert len(admin.get_default_optional_client_scopes()) == 5
  1747. with pytest.raises(KeycloakDeleteError) as err:
  1748. admin.delete_default_optional_client_scope(scope_id="does-not-exist")
  1749. assert err.match('404: b\'{"error":"Client scope not found"}\'')
  1750. res_del = admin.delete_default_optional_client_scope(scope_id=res)
  1751. assert res_del == dict()
  1752. assert len(admin.get_default_optional_client_scopes()) == 4
  1753. # Test client scope delete
  1754. res_del = admin.delete_client_scope(client_scope_id=res)
  1755. assert res_del == dict()
  1756. with pytest.raises(KeycloakDeleteError) as err:
  1757. admin.delete_client_scope(client_scope_id=res)
  1758. assert err.match('404: b\'{"error":"Could not find client scope"}\'')
  1759. def test_components(admin: KeycloakAdmin, realm: str):
  1760. """Test components.
  1761. :param admin: Keycloak Admin client
  1762. :type admin: KeycloakAdmin
  1763. :param realm: Keycloak realm
  1764. :type realm: str
  1765. """
  1766. admin.realm_name = realm
  1767. # Test get components
  1768. res = admin.get_components()
  1769. assert len(res) == 12
  1770. with pytest.raises(KeycloakGetError) as err:
  1771. admin.get_component(component_id="does-not-exist")
  1772. assert err.match('404: b\'{"error":"Could not find component"}\'')
  1773. res_get = admin.get_component(component_id=res[0]["id"])
  1774. assert res_get == res[0]
  1775. # Test create component
  1776. with pytest.raises(KeycloakPostError) as err:
  1777. admin.create_component(payload={"bad": "dict"})
  1778. assert err.match('400: b\'{"error":"Unrecognized field')
  1779. res = admin.create_component(
  1780. payload={
  1781. "name": "Test Component",
  1782. "providerId": "max-clients",
  1783. "providerType": "org.keycloak.services.clientregistration."
  1784. + "policy.ClientRegistrationPolicy",
  1785. "config": {"max-clients": ["1000"]},
  1786. }
  1787. )
  1788. assert res
  1789. assert admin.get_component(component_id=res)["name"] == "Test Component"
  1790. # Test update component
  1791. component = admin.get_component(component_id=res)
  1792. component["name"] = "Test Component Update"
  1793. with pytest.raises(KeycloakPutError) as err:
  1794. admin.update_component(component_id="does-not-exist", payload=dict())
  1795. assert err.match('404: b\'{"error":"Could not find component"}\'')
  1796. res_upd = admin.update_component(component_id=res, payload=component)
  1797. assert res_upd == dict()
  1798. assert admin.get_component(component_id=res)["name"] == "Test Component Update"
  1799. # Test delete component
  1800. res_del = admin.delete_component(component_id=res)
  1801. assert res_del == dict()
  1802. with pytest.raises(KeycloakDeleteError) as err:
  1803. admin.delete_component(component_id=res)
  1804. assert err.match('404: b\'{"error":"Could not find component"}\'')
  1805. def test_keys(admin: KeycloakAdmin, realm: str):
  1806. """Test keys.
  1807. :param admin: Keycloak Admin client
  1808. :type admin: KeycloakAdmin
  1809. :param realm: Keycloak realm
  1810. :type realm: str
  1811. """
  1812. admin.realm_name = realm
  1813. assert set(admin.get_keys()["active"].keys()) == {"AES", "HS256", "RS256", "RSA-OAEP"}
  1814. assert {k["algorithm"] for k in admin.get_keys()["keys"]} == {
  1815. "HS256",
  1816. "RSA-OAEP",
  1817. "AES",
  1818. "RS256",
  1819. }
  1820. def test_events(admin: KeycloakAdmin, realm: str):
  1821. """Test events.
  1822. :param admin: Keycloak Admin client
  1823. :type admin: KeycloakAdmin
  1824. :param realm: Keycloak realm
  1825. :type realm: str
  1826. """
  1827. admin.realm_name = realm
  1828. events = admin.get_events()
  1829. assert events == list()
  1830. with pytest.raises(KeycloakPutError) as err:
  1831. admin.set_events(payload={"bad": "conf"})
  1832. assert err.match('400: b\'{"error":"Unrecognized field')
  1833. res = admin.set_events(payload={"adminEventsDetailsEnabled": True, "adminEventsEnabled": True})
  1834. assert res == dict()
  1835. admin.create_client(payload={"name": "test", "clientId": "test"})
  1836. events = admin.get_events()
  1837. assert events == list()
  1838. def test_auto_refresh(admin: KeycloakAdmin, realm: str):
  1839. """Test auto refresh token.
  1840. :param admin: Keycloak Admin client
  1841. :type admin: KeycloakAdmin
  1842. :param realm: Keycloak realm
  1843. :type realm: str
  1844. """
  1845. # Test get refresh
  1846. admin.auto_refresh_token = list()
  1847. admin.connection = ConnectionManager(
  1848. base_url=admin.server_url,
  1849. headers={"Authorization": "Bearer bad", "Content-Type": "application/json"},
  1850. timeout=60,
  1851. verify=admin.verify,
  1852. )
  1853. with pytest.raises(KeycloakAuthenticationError) as err:
  1854. admin.get_realm(realm_name=realm)
  1855. assert err.match('401: b\'{"error":"HTTP 401 Unauthorized"}\'')
  1856. admin.auto_refresh_token = ["get"]
  1857. del admin.token["refresh_token"]
  1858. assert admin.get_realm(realm_name=realm)
  1859. # Test bad refresh token
  1860. admin.connection = ConnectionManager(
  1861. base_url=admin.server_url,
  1862. headers={"Authorization": "Bearer bad", "Content-Type": "application/json"},
  1863. timeout=60,
  1864. verify=admin.verify,
  1865. )
  1866. admin.token["refresh_token"] = "bad"
  1867. with pytest.raises(KeycloakPostError) as err:
  1868. admin.get_realm(realm_name="test-refresh")
  1869. assert err.match(
  1870. '400: b\'{"error":"invalid_grant","error_description":"Invalid refresh token"}\''
  1871. )
  1872. admin.realm_name = "master"
  1873. admin.get_token()
  1874. admin.realm_name = realm
  1875. # Test post refresh
  1876. admin.connection = ConnectionManager(
  1877. base_url=admin.server_url,
  1878. headers={"Authorization": "Bearer bad", "Content-Type": "application/json"},
  1879. timeout=60,
  1880. verify=admin.verify,
  1881. )
  1882. with pytest.raises(KeycloakAuthenticationError) as err:
  1883. admin.create_realm(payload={"realm": "test-refresh"})
  1884. assert err.match('401: b\'{"error":"HTTP 401 Unauthorized"}\'')
  1885. admin.auto_refresh_token = ["get", "post"]
  1886. admin.realm_name = "master"
  1887. admin.user_logout(user_id=admin.get_user_id(username=admin.username))
  1888. assert admin.create_realm(payload={"realm": "test-refresh"}) == b""
  1889. admin.realm_name = realm
  1890. # Test update refresh
  1891. admin.connection = ConnectionManager(
  1892. base_url=admin.server_url,
  1893. headers={"Authorization": "Bearer bad", "Content-Type": "application/json"},
  1894. timeout=60,
  1895. verify=admin.verify,
  1896. )
  1897. with pytest.raises(KeycloakAuthenticationError) as err:
  1898. admin.update_realm(realm_name="test-refresh", payload={"accountTheme": "test"})
  1899. assert err.match('401: b\'{"error":"HTTP 401 Unauthorized"}\'')
  1900. admin.auto_refresh_token = ["get", "post", "put"]
  1901. assert (
  1902. admin.update_realm(realm_name="test-refresh", payload={"accountTheme": "test"}) == dict()
  1903. )
  1904. # Test delete refresh
  1905. admin.connection = ConnectionManager(
  1906. base_url=admin.server_url,
  1907. headers={"Authorization": "Bearer bad", "Content-Type": "application/json"},
  1908. timeout=60,
  1909. verify=admin.verify,
  1910. )
  1911. with pytest.raises(KeycloakAuthenticationError) as err:
  1912. admin.delete_realm(realm_name="test-refresh")
  1913. assert err.match('401: b\'{"error":"HTTP 401 Unauthorized"}\'')
  1914. admin.auto_refresh_token = ["get", "post", "put", "delete"]
  1915. assert admin.delete_realm(realm_name="test-refresh") == dict()
  1916. def test_get_required_actions(admin: KeycloakAdmin, realm: str):
  1917. """Test required actions.
  1918. :param admin: Keycloak Admin client
  1919. :type admin: KeycloakAdmin
  1920. :param realm: Keycloak realm
  1921. :type realm: str
  1922. """
  1923. admin.realm_name = realm
  1924. ractions = admin.get_required_actions()
  1925. assert isinstance(ractions, list)
  1926. for ra in ractions:
  1927. for key in [
  1928. "alias",
  1929. "name",
  1930. "providerId",
  1931. "enabled",
  1932. "defaultAction",
  1933. "priority",
  1934. "config",
  1935. ]:
  1936. assert key in ra
  1937. def test_get_required_action_by_alias(admin: KeycloakAdmin, realm: str):
  1938. """Test get required action by alias.
  1939. :param admin: Keycloak Admin client
  1940. :type admin: KeycloakAdmin
  1941. :param realm: Keycloak realm
  1942. :type realm: str
  1943. """
  1944. admin.realm_name = realm
  1945. ractions = admin.get_required_actions()
  1946. ra = admin.get_required_action_by_alias("UPDATE_PASSWORD")
  1947. assert ra in ractions
  1948. assert ra["alias"] == "UPDATE_PASSWORD"
  1949. assert admin.get_required_action_by_alias("does-not-exist") is None
  1950. def test_update_required_action(admin: KeycloakAdmin, realm: str):
  1951. """Test update required action.
  1952. :param admin: Keycloak Admin client
  1953. :type admin: KeycloakAdmin
  1954. :param realm: Keycloak realm
  1955. :type realm: str
  1956. """
  1957. admin.realm_name = realm
  1958. ra = admin.get_required_action_by_alias("UPDATE_PASSWORD")
  1959. old = copy.deepcopy(ra)
  1960. ra["enabled"] = False
  1961. admin.update_required_action("UPDATE_PASSWORD", ra)
  1962. newra = admin.get_required_action_by_alias("UPDATE_PASSWORD")
  1963. assert old != newra
  1964. assert newra["enabled"] is False
  1965. def test_get_composite_client_roles_of_group(
  1966. admin: KeycloakAdmin, realm: str, client: str, group: str, composite_client_role: str
  1967. ):
  1968. """Test get composite client roles of group.
  1969. :param admin: Keycloak Admin client
  1970. :type admin: KeycloakAdmin
  1971. :param realm: Keycloak realm
  1972. :type realm: str
  1973. :param client: Keycloak client
  1974. :type client: str
  1975. :param group: Keycloak group
  1976. :type group: str
  1977. :param composite_client_role: Composite client role
  1978. :type composite_client_role: str
  1979. """
  1980. admin.realm_name = realm
  1981. role = admin.get_client_role(client, composite_client_role)
  1982. admin.assign_group_client_roles(group_id=group, client_id=client, roles=[role])
  1983. result = admin.get_composite_client_roles_of_group(client, group)
  1984. assert role["id"] in [x["id"] for x in result]
  1985. def test_get_role_client_level_children(
  1986. admin: KeycloakAdmin, realm: str, client: str, composite_client_role: str, client_role: str
  1987. ):
  1988. """Test get children of composite client role.
  1989. :param admin: Keycloak Admin client
  1990. :type admin: KeycloakAdmin
  1991. :param realm: Keycloak realm
  1992. :type realm: str
  1993. :param client: Keycloak client
  1994. :type client: str
  1995. :param composite_client_role: Composite client role
  1996. :type composite_client_role: str
  1997. :param client_role: Client role
  1998. :type client_role: str
  1999. """
  2000. admin.realm_name = realm
  2001. child = admin.get_client_role(client, client_role)
  2002. parent = admin.get_client_role(client, composite_client_role)
  2003. res = admin.get_role_client_level_children(client, parent["id"])
  2004. assert child["id"] in [x["id"] for x in res]
  2005. def test_upload_certificate(admin: KeycloakAdmin, realm: str, client: str, selfsigned_cert: tuple):
  2006. """Test upload certificate.
  2007. :param admin: Keycloak Admin client
  2008. :type admin: KeycloakAdmin
  2009. :param realm: Keycloak realm
  2010. :type realm: str
  2011. :param client: Keycloak client
  2012. :type client: str
  2013. :param selfsigned_cert: Selfsigned certificates
  2014. :type selfsigned_cert: tuple
  2015. """
  2016. admin.realm_name = realm
  2017. cert, _ = selfsigned_cert
  2018. cert = cert.decode("utf-8").strip()
  2019. admin.upload_certificate(client, cert)
  2020. cl = admin.get_client(client)
  2021. assert cl["attributes"]["jwt.credential.certificate"] == "".join(cert.splitlines()[1:-1])
  2022. def test_get_bruteforce_status_for_user(
  2023. admin: KeycloakAdmin, oid_with_credentials: Tuple[KeycloakOpenID, str, str], realm: str
  2024. ):
  2025. """Test users.
  2026. :param admin: Keycloak Admin client
  2027. :type admin: KeycloakAdmin
  2028. :param oid_with_credentials: Keycloak OpenID client with pre-configured user credentials
  2029. :type oid_with_credentials: Tuple[KeycloakOpenID, str, str]
  2030. :param realm: Keycloak realm
  2031. :type realm: str
  2032. """
  2033. oid, username, password = oid_with_credentials
  2034. admin.realm_name = realm
  2035. # Turn on bruteforce protection
  2036. res = admin.update_realm(realm_name=realm, payload={"bruteForceProtected": True})
  2037. res = admin.get_realm(realm_name=realm)
  2038. assert res["bruteForceProtected"] is True
  2039. # Test login user with wrong credentials
  2040. try:
  2041. oid.token(username=username, password="wrongpassword")
  2042. except KeycloakAuthenticationError:
  2043. pass
  2044. user_id = admin.get_user_id(username)
  2045. bruteforce_status = admin.get_bruteforce_detection_status(user_id)
  2046. assert bruteforce_status["numFailures"] == 1
  2047. # Cleanup
  2048. res = admin.update_realm(realm_name=realm, payload={"bruteForceProtected": False})
  2049. res = admin.get_realm(realm_name=realm)
  2050. assert res["bruteForceProtected"] is False
  2051. def test_clear_bruteforce_attempts_for_user(
  2052. admin: KeycloakAdmin, oid_with_credentials: Tuple[KeycloakOpenID, str, str], realm: str
  2053. ):
  2054. """Test users.
  2055. :param admin: Keycloak Admin client
  2056. :type admin: KeycloakAdmin
  2057. :param oid_with_credentials: Keycloak OpenID client with pre-configured user credentials
  2058. :type oid_with_credentials: Tuple[KeycloakOpenID, str, str]
  2059. :param realm: Keycloak realm
  2060. :type realm: str
  2061. """
  2062. oid, username, password = oid_with_credentials
  2063. admin.realm_name = realm
  2064. # Turn on bruteforce protection
  2065. res = admin.update_realm(realm_name=realm, payload={"bruteForceProtected": True})
  2066. res = admin.get_realm(realm_name=realm)
  2067. assert res["bruteForceProtected"] is True
  2068. # Test login user with wrong credentials
  2069. try:
  2070. oid.token(username=username, password="wrongpassword")
  2071. except KeycloakAuthenticationError:
  2072. pass
  2073. user_id = admin.get_user_id(username)
  2074. bruteforce_status = admin.get_bruteforce_detection_status(user_id)
  2075. assert bruteforce_status["numFailures"] == 1
  2076. res = admin.clear_bruteforce_attempts_for_user(user_id)
  2077. bruteforce_status = admin.get_bruteforce_detection_status(user_id)
  2078. assert bruteforce_status["numFailures"] == 0
  2079. # Cleanup
  2080. res = admin.update_realm(realm_name=realm, payload={"bruteForceProtected": False})
  2081. res = admin.get_realm(realm_name=realm)
  2082. assert res["bruteForceProtected"] is False
  2083. def test_clear_bruteforce_attempts_for_all_users(
  2084. admin: KeycloakAdmin, oid_with_credentials: Tuple[KeycloakOpenID, str, str], realm: str
  2085. ):
  2086. """Test users.
  2087. :param admin: Keycloak Admin client
  2088. :type admin: KeycloakAdmin
  2089. :param oid_with_credentials: Keycloak OpenID client with pre-configured user credentials
  2090. :type oid_with_credentials: Tuple[KeycloakOpenID, str, str]
  2091. :param realm: Keycloak realm
  2092. :type realm: str
  2093. """
  2094. oid, username, password = oid_with_credentials
  2095. admin.realm_name = realm
  2096. # Turn on bruteforce protection
  2097. res = admin.update_realm(realm_name=realm, payload={"bruteForceProtected": True})
  2098. res = admin.get_realm(realm_name=realm)
  2099. assert res["bruteForceProtected"] is True
  2100. # Test login user with wrong credentials
  2101. try:
  2102. oid.token(username=username, password="wrongpassword")
  2103. except KeycloakAuthenticationError:
  2104. pass
  2105. user_id = admin.get_user_id(username)
  2106. bruteforce_status = admin.get_bruteforce_detection_status(user_id)
  2107. assert bruteforce_status["numFailures"] == 1
  2108. res = admin.clear_all_bruteforce_attempts()
  2109. bruteforce_status = admin.get_bruteforce_detection_status(user_id)
  2110. assert bruteforce_status["numFailures"] == 0
  2111. # Cleanup
  2112. res = admin.update_realm(realm_name=realm, payload={"bruteForceProtected": False})
  2113. res = admin.get_realm(realm_name=realm)
  2114. assert res["bruteForceProtected"] is False
  2115. def test_default_realm_role_present(realm: str, admin: KeycloakAdmin) -> None:
  2116. """Test that the default realm role is present in a brand new realm.
  2117. :param realm: Realm name
  2118. :type realm: str
  2119. :param admin: Keycloak admin
  2120. :type admin: KeycloakAdmin
  2121. """
  2122. admin.realm_name = realm
  2123. assert f"default-roles-{realm}" in [x["name"] for x in admin.get_realm_roles()]
  2124. assert (
  2125. len([x["name"] for x in admin.get_realm_roles() if x["name"] == f"default-roles-{realm}"])
  2126. == 1
  2127. )
  2128. def test_get_default_realm_role_id(realm: str, admin: KeycloakAdmin) -> None:
  2129. """Test getter for the ID of the default realm role.
  2130. :param realm: Realm name
  2131. :type realm: str
  2132. :param admin: Keycloak admin
  2133. :type admin: KeycloakAdmin
  2134. """
  2135. admin.realm_name = realm
  2136. assert (
  2137. admin.get_default_realm_role_id()
  2138. == [x["id"] for x in admin.get_realm_roles() if x["name"] == f"default-roles-{realm}"][0]
  2139. )
  2140. def test_realm_default_roles(admin: KeycloakAdmin, realm: str) -> None:
  2141. """Test getting, adding and deleting default realm roles.
  2142. :param realm: Realm name
  2143. :type realm: str
  2144. :param admin: Keycloak admin
  2145. :type admin: KeycloakAdmin
  2146. """
  2147. admin.realm_name = realm
  2148. # Test listing all default realm roles
  2149. roles = admin.get_realm_default_roles()
  2150. assert len(roles) == 2
  2151. assert {x["name"] for x in roles} == {"offline_access", "uma_authorization"}
  2152. with pytest.raises(KeycloakGetError) as err:
  2153. admin.realm_name = "doesnotexist"
  2154. admin.get_realm_default_roles()
  2155. assert err.match('404: b\'{"error":"Realm not found."}\'')
  2156. admin.realm_name = realm
  2157. # Test removing a default realm role
  2158. res = admin.remove_realm_default_roles(payload=[roles[0]])
  2159. assert res == {}
  2160. assert roles[0] not in admin.get_realm_default_roles()
  2161. assert len(admin.get_realm_default_roles()) == 1
  2162. with pytest.raises(KeycloakDeleteError) as err:
  2163. admin.remove_realm_default_roles(payload=[{"id": "bad id"}])
  2164. assert err.match('404: b\'{"error":"Could not find composite role"}\'')
  2165. # Test adding a default realm role
  2166. res = admin.add_realm_default_roles(payload=[roles[0]])
  2167. assert res == {}
  2168. assert roles[0] in admin.get_realm_default_roles()
  2169. assert len(admin.get_realm_default_roles()) == 2
  2170. with pytest.raises(KeycloakPostError) as err:
  2171. admin.add_realm_default_roles(payload=[{"id": "bad id"}])
  2172. assert err.match('404: b\'{"error":"Could not find composite role"}\'')
  2173. def test_clear_keys_cache(realm: str, admin: KeycloakAdmin) -> None:
  2174. """Test clearing the keys cache.
  2175. :param realm: Realm name
  2176. :type realm: str
  2177. :param admin: Keycloak admin
  2178. :type admin: KeycloakAdmin
  2179. """
  2180. admin.realm_name = realm
  2181. res = admin.clear_keys_cache()
  2182. assert res == {}
  2183. def test_clear_realm_cache(realm: str, admin: KeycloakAdmin) -> None:
  2184. """Test clearing the realm cache.
  2185. :param realm: Realm name
  2186. :type realm: str
  2187. :param admin: Keycloak admin
  2188. :type admin: KeycloakAdmin
  2189. """
  2190. admin.realm_name = realm
  2191. res = admin.clear_realm_cache()
  2192. assert res == {}
  2193. def test_clear_user_cache(realm: str, admin: KeycloakAdmin) -> None:
  2194. """Test clearing the user cache.
  2195. :param realm: Realm name
  2196. :type realm: str
  2197. :param admin: Keycloak admin
  2198. :type admin: KeycloakAdmin
  2199. """
  2200. admin.realm_name = realm
  2201. res = admin.clear_user_cache()
  2202. assert res == {}