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.

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