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.

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