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.

2652 lines
95 KiB

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