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.

2625 lines
93 KiB

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