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.

3064 lines
109 KiB

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