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.

1453 lines
55 KiB

  1. import pytest
  2. import keycloak
  3. from keycloak import KeycloakAdmin
  4. from keycloak.connection import ConnectionManager
  5. from keycloak.exceptions import (
  6. KeycloakDeleteError,
  7. KeycloakGetError,
  8. KeycloakPostError,
  9. KeycloakPutError,
  10. )
  11. def test_keycloak_version():
  12. assert keycloak.__version__, keycloak.__version__
  13. def test_keycloak_admin_bad_init(env):
  14. with pytest.raises(TypeError) as err:
  15. KeycloakAdmin(
  16. server_url=f"http://{env.KEYCLOAK_HOST}:{env.KEYCLOAK_PORT}",
  17. username=env.KEYCLOAK_ADMIN,
  18. password=env.KEYCLOAK_ADMIN_PASSWORD,
  19. auto_refresh_token=1,
  20. )
  21. assert err.match("Expected a list of strings")
  22. with pytest.raises(TypeError) as err:
  23. KeycloakAdmin(
  24. server_url=f"http://{env.KEYCLOAK_HOST}:{env.KEYCLOAK_PORT}",
  25. username=env.KEYCLOAK_ADMIN,
  26. password=env.KEYCLOAK_ADMIN_PASSWORD,
  27. auto_refresh_token=["patch"],
  28. )
  29. assert err.match("Unexpected method in auto_refresh_token")
  30. def test_keycloak_admin_init(env):
  31. admin = KeycloakAdmin(
  32. server_url=f"http://{env.KEYCLOAK_HOST}:{env.KEYCLOAK_PORT}",
  33. username=env.KEYCLOAK_ADMIN,
  34. password=env.KEYCLOAK_ADMIN_PASSWORD,
  35. )
  36. assert admin.server_url == f"http://{env.KEYCLOAK_HOST}:{env.KEYCLOAK_PORT}", admin.server_url
  37. assert admin.realm_name == "master", admin.realm_name
  38. assert isinstance(admin.connection, ConnectionManager), type(admin.connection)
  39. assert admin.client_id == "admin-cli", admin.client_id
  40. assert admin.client_secret_key is None, admin.client_secret_key
  41. assert admin.verify, admin.verify
  42. assert admin.username == env.KEYCLOAK_ADMIN, admin.username
  43. assert admin.password == env.KEYCLOAK_ADMIN_PASSWORD, admin.password
  44. assert admin.totp is None, admin.totp
  45. assert admin.token is not None, admin.token
  46. assert admin.auto_refresh_token == list(), admin.auto_refresh_token
  47. assert admin.user_realm_name is None, admin.user_realm_name
  48. assert admin.custom_headers is None, admin.custom_headers
  49. def test_realms(admin: KeycloakAdmin):
  50. # Get realms
  51. realms = admin.get_realms()
  52. assert len(realms) == 1, realms
  53. assert "master" == realms[0]["realm"]
  54. # Create a test realm
  55. res = admin.create_realm(payload={"realm": "test"})
  56. assert res == b"", res
  57. # Create the same realm, should fail
  58. with pytest.raises(KeycloakPostError) as err:
  59. res = admin.create_realm(payload={"realm": "test"})
  60. assert err.match('409: b\'{"errorMessage":"Conflict detected. See logs for details"}\'')
  61. # Create the same realm, skip_exists true
  62. res = admin.create_realm(payload={"realm": "test"}, skip_exists=True)
  63. assert res == {"msg": "Already exists"}, res
  64. # Get a single realm
  65. res = admin.get_realm(realm_name="test")
  66. assert res["realm"] == "test"
  67. # Get non-existing realm
  68. with pytest.raises(KeycloakGetError) as err:
  69. admin.get_realm(realm_name="non-existent")
  70. assert err.match('404: b\'{"error":"Realm not found."}\'')
  71. # Update realm
  72. res = admin.update_realm(realm_name="test", payload={"accountTheme": "test"})
  73. assert res == dict(), res
  74. # Check that the update worked
  75. res = admin.get_realm(realm_name="test")
  76. assert res["realm"] == "test"
  77. assert res["accountTheme"] == "test"
  78. # Update wrong payload
  79. with pytest.raises(KeycloakPutError) as err:
  80. admin.update_realm(realm_name="test", payload={"wrong": "payload"})
  81. assert err.match('400: b\'{"error":"Unrecognized field')
  82. # Check that get realms returns both realms
  83. realms = admin.get_realms()
  84. realm_names = [x["realm"] for x in realms]
  85. assert len(realms) == 2, realms
  86. assert "master" in realm_names, realm_names
  87. assert "test" in realm_names, realm_names
  88. # Delete the realm
  89. res = admin.delete_realm(realm_name="test")
  90. assert res == dict(), res
  91. # Check that the realm does not exist anymore
  92. with pytest.raises(KeycloakGetError) as err:
  93. admin.get_realm(realm_name="test")
  94. assert err.match('404: b\'{"error":"Realm not found."}\'')
  95. # Delete non-existing realm
  96. with pytest.raises(KeycloakDeleteError) as err:
  97. admin.delete_realm(realm_name="non-existent")
  98. assert err.match('404: b\'{"error":"Realm not found."}\'')
  99. def test_import_export_realms(admin: KeycloakAdmin, realm: str):
  100. admin.realm_name = realm
  101. realm_export = admin.export_realm(export_clients=True, export_groups_and_role=True)
  102. assert realm_export != dict(), realm_export
  103. admin.delete_realm(realm_name=realm)
  104. admin.realm_name = "master"
  105. res = admin.import_realm(payload=realm_export)
  106. assert res == b"", res
  107. # Test bad import
  108. with pytest.raises(KeycloakPostError) as err:
  109. admin.import_realm(payload=dict())
  110. assert err.match('500: b\'{"error":"unknown_error"}\'')
  111. def test_users(admin: KeycloakAdmin, realm: str):
  112. admin.realm_name = realm
  113. # Check no users present
  114. users = admin.get_users()
  115. assert users == list(), users
  116. # Test create user
  117. user_id = admin.create_user(payload={"username": "test", "email": "test@test.test"})
  118. assert user_id is not None, user_id
  119. # Test create the same user
  120. with pytest.raises(KeycloakPostError) as err:
  121. admin.create_user(payload={"username": "test", "email": "test@test.test"})
  122. assert err.match('409: b\'{"errorMessage":"User exists with same username"}\'')
  123. # Test create the same user, exists_ok true
  124. user_id_2 = admin.create_user(
  125. payload={"username": "test", "email": "test@test.test"}, exist_ok=True
  126. )
  127. assert user_id == user_id_2
  128. # Test get user
  129. user = admin.get_user(user_id=user_id)
  130. assert user["username"] == "test", user["username"]
  131. assert user["email"] == "test@test.test", user["email"]
  132. # Test update user
  133. res = admin.update_user(user_id=user_id, payload={"firstName": "Test"})
  134. assert res == dict(), res
  135. user = admin.get_user(user_id=user_id)
  136. assert user["firstName"] == "Test"
  137. # Test update user fail
  138. with pytest.raises(KeycloakPutError) as err:
  139. admin.update_user(user_id=user_id, payload={"wrong": "payload"})
  140. assert err.match('400: b\'{"error":"Unrecognized field')
  141. # Test get users again
  142. users = admin.get_users()
  143. usernames = [x["username"] for x in users]
  144. assert "test" in usernames
  145. # Test users counts
  146. count = admin.users_count()
  147. assert count == 1, count
  148. # Test users count with query
  149. count = admin.users_count(query={"username": "notpresent"})
  150. assert count == 0
  151. # Test user groups
  152. groups = admin.get_user_groups(user_id=user["id"])
  153. assert len(groups) == 0
  154. # Test user groups bad id
  155. with pytest.raises(KeycloakGetError) as err:
  156. admin.get_user_groups(user_id="does-not-exist")
  157. assert err.match('404: b\'{"error":"User not found"}\'')
  158. # Test logout
  159. res = admin.user_logout(user_id=user["id"])
  160. assert res == dict(), res
  161. # Test logout fail
  162. with pytest.raises(KeycloakPostError) as err:
  163. admin.user_logout(user_id="non-existent-id")
  164. assert err.match('404: b\'{"error":"User not found"}\'')
  165. # Test consents
  166. res = admin.user_consents(user_id=user["id"])
  167. assert len(res) == 0, res
  168. # Test consents fail
  169. with pytest.raises(KeycloakGetError) as err:
  170. admin.user_consents(user_id="non-existent-id")
  171. assert err.match('404: b\'{"error":"User not found"}\'')
  172. # Test delete user
  173. res = admin.delete_user(user_id=user_id)
  174. assert res == dict(), res
  175. with pytest.raises(KeycloakGetError) as err:
  176. admin.get_user(user_id=user_id)
  177. err.match('404: b\'{"error":"User not found"}\'')
  178. # Test delete fail
  179. with pytest.raises(KeycloakDeleteError) as err:
  180. admin.delete_user(user_id="non-existent-id")
  181. assert err.match('404: b\'{"error":"User not found"}\'')
  182. def test_users_pagination(admin: KeycloakAdmin, realm: str):
  183. admin.realm_name = realm
  184. for ind in range(admin.PAGE_SIZE + 50):
  185. username = f"user_{ind}"
  186. admin.create_user(payload={"username": username, "email": f"{username}@test.test"})
  187. users = admin.get_users()
  188. assert len(users) == admin.PAGE_SIZE + 50, len(users)
  189. users = admin.get_users(query={"first": 100})
  190. assert len(users) == 50, len(users)
  191. users = admin.get_users(query={"max": 20})
  192. assert len(users) == 20, len(users)
  193. def test_idps(admin: KeycloakAdmin, realm: str):
  194. admin.realm_name = realm
  195. # Create IDP
  196. res = admin.create_idp(
  197. payload=dict(
  198. providerId="github", alias="github", config=dict(clientId="test", clientSecret="test")
  199. )
  200. )
  201. assert res == b"", res
  202. # Test create idp fail
  203. with pytest.raises(KeycloakPostError) as err:
  204. admin.create_idp(payload={"providerId": "does-not-exist", "alias": "something"})
  205. assert err.match("Invalid identity provider id"), err
  206. # Test listing
  207. idps = admin.get_idps()
  208. assert len(idps) == 1
  209. assert "github" == idps[0]["alias"]
  210. # Test adding a mapper
  211. res = admin.add_mapper_to_idp(
  212. idp_alias="github",
  213. payload={
  214. "identityProviderAlias": "github",
  215. "identityProviderMapper": "github-user-attribute-mapper",
  216. "name": "test",
  217. },
  218. )
  219. assert res == b"", res
  220. # Test mapper fail
  221. with pytest.raises(KeycloakPostError) as err:
  222. admin.add_mapper_to_idp(idp_alias="does-no-texist", payload=dict())
  223. assert err.match('404: b\'{"error":"HTTP 404 Not Found"}\'')
  224. # Test delete
  225. res = admin.delete_idp(idp_alias="github")
  226. assert res == dict(), res
  227. # Test delete fail
  228. with pytest.raises(KeycloakDeleteError) as err:
  229. admin.delete_idp(idp_alias="does-not-exist")
  230. assert err.match('404: b\'{"error":"HTTP 404 Not Found"}\'')
  231. def test_user_credentials(admin: KeycloakAdmin, user: str):
  232. res = admin.set_user_password(user_id=user, password="booya", temporary=True)
  233. assert res == dict(), res
  234. # Test user password set fail
  235. with pytest.raises(KeycloakPutError) as err:
  236. admin.set_user_password(user_id="does-not-exist", password="")
  237. assert err.match('404: b\'{"error":"User not found"}\'')
  238. credentials = admin.get_credentials(user_id=user)
  239. assert len(credentials) == 1
  240. assert credentials[0]["type"] == "password", credentials
  241. # Test get credentials fail
  242. with pytest.raises(KeycloakGetError) as err:
  243. admin.get_credentials(user_id="does-not-exist")
  244. assert err.match('404: b\'{"error":"User not found"}\'')
  245. res = admin.delete_credential(user_id=user, credential_id=credentials[0]["id"])
  246. assert res == dict(), res
  247. # Test delete fail
  248. with pytest.raises(KeycloakDeleteError) as err:
  249. admin.delete_credential(user_id=user, credential_id="does-not-exist")
  250. assert err.match('404: b\'{"error":"Credential not found"}\'')
  251. def test_social_logins(admin: KeycloakAdmin, user: str):
  252. res = admin.add_user_social_login(
  253. user_id=user, provider_id="gitlab", provider_userid="test", provider_username="test"
  254. )
  255. assert res == dict(), res
  256. admin.add_user_social_login(
  257. user_id=user, provider_id="github", provider_userid="test", provider_username="test"
  258. )
  259. assert res == dict(), res
  260. # Test add social login fail
  261. with pytest.raises(KeycloakPostError) as err:
  262. admin.add_user_social_login(
  263. user_id="does-not-exist",
  264. provider_id="does-not-exist",
  265. provider_userid="test",
  266. provider_username="test",
  267. )
  268. assert err.match('404: b\'{"error":"User not found"}\'')
  269. res = admin.get_user_social_logins(user_id=user)
  270. assert res == list(), res
  271. # Test get social logins fail
  272. with pytest.raises(KeycloakGetError) as err:
  273. admin.get_user_social_logins(user_id="does-not-exist")
  274. assert err.match('404: b\'{"error":"User not found"}\'')
  275. res = admin.delete_user_social_login(user_id=user, provider_id="gitlab")
  276. assert res == {}, res
  277. res = admin.delete_user_social_login(user_id=user, provider_id="github")
  278. assert res == {}, res
  279. with pytest.raises(KeycloakDeleteError) as err:
  280. admin.delete_user_social_login(user_id=user, provider_id="instagram")
  281. assert err.match('404: b\'{"error":"Link not found"}\''), err
  282. def test_server_info(admin: KeycloakAdmin):
  283. info = admin.get_server_info()
  284. assert set(info.keys()) == {
  285. "systemInfo",
  286. "memoryInfo",
  287. "profileInfo",
  288. "themes",
  289. "socialProviders",
  290. "identityProviders",
  291. "providers",
  292. "protocolMapperTypes",
  293. "builtinProtocolMappers",
  294. "clientInstallations",
  295. "componentTypes",
  296. "passwordPolicies",
  297. "enums",
  298. }, info.keys()
  299. def test_groups(admin: KeycloakAdmin, user: str):
  300. # Test get groups
  301. groups = admin.get_groups()
  302. assert len(groups) == 0
  303. # Test create group
  304. group_id = admin.create_group(payload={"name": "main-group"})
  305. assert group_id is not None, group_id
  306. # Test create subgroups
  307. subgroup_id_1 = admin.create_group(payload={"name": "subgroup-1"}, parent=group_id)
  308. subgroup_id_2 = admin.create_group(payload={"name": "subgroup-2"}, parent=group_id)
  309. # Test create group fail
  310. with pytest.raises(KeycloakPostError) as err:
  311. admin.create_group(payload={"name": "subgroup-1"}, parent=group_id)
  312. assert err.match('409: b\'{"error":"unknown_error"}\''), err
  313. # Test skip exists OK
  314. subgroup_id_1_eq = admin.create_group(
  315. payload={"name": "subgroup-1"}, parent=group_id, skip_exists=True
  316. )
  317. assert subgroup_id_1_eq is None
  318. # Test get groups again
  319. groups = admin.get_groups()
  320. assert len(groups) == 1, groups
  321. assert len(groups[0]["subGroups"]) == 2, groups["subGroups"]
  322. assert groups[0]["id"] == group_id
  323. assert {x["id"] for x in groups[0]["subGroups"]} == {subgroup_id_1, subgroup_id_2}
  324. # Test get groups query
  325. groups = admin.get_groups(query={"max": 10})
  326. assert len(groups) == 1, groups
  327. assert len(groups[0]["subGroups"]) == 2, groups["subGroups"]
  328. assert groups[0]["id"] == group_id
  329. assert {x["id"] for x in groups[0]["subGroups"]} == {subgroup_id_1, subgroup_id_2}
  330. # Test get group
  331. res = admin.get_group(group_id=subgroup_id_1)
  332. assert res["id"] == subgroup_id_1, res
  333. assert res["name"] == "subgroup-1"
  334. assert res["path"] == "/main-group/subgroup-1"
  335. # Test get group fail
  336. with pytest.raises(KeycloakGetError) as err:
  337. admin.get_group(group_id="does-not-exist")
  338. assert err.match('404: b\'{"error":"Could not find group by id"}\''), err
  339. # Create 1 more subgroup
  340. subsubgroup_id_1 = admin.create_group(payload={"name": "subsubgroup-1"}, parent=subgroup_id_2)
  341. main_group = admin.get_group(group_id=group_id)
  342. # Test nested searches
  343. res = admin.get_subgroups(group=main_group, path="/main-group/subgroup-2/subsubgroup-1")
  344. assert res is not None, res
  345. assert res["id"] == subsubgroup_id_1
  346. # Test empty search
  347. res = admin.get_subgroups(group=main_group, path="/none")
  348. assert res is None, res
  349. # Test get group by path
  350. res = admin.get_group_by_path(path="/main-group/subgroup-1")
  351. assert res is None, res
  352. res = admin.get_group_by_path(path="/main-group/subgroup-1", search_in_subgroups=True)
  353. assert res is not None, res
  354. assert res["id"] == subgroup_id_1, res
  355. res = admin.get_group_by_path(
  356. path="/main-group/subgroup-2/subsubgroup-1/test", search_in_subgroups=True
  357. )
  358. assert res is None, res
  359. res = admin.get_group_by_path(
  360. path="/main-group/subgroup-2/subsubgroup-1", search_in_subgroups=True
  361. )
  362. assert res is not None, res
  363. assert res["id"] == subsubgroup_id_1
  364. res = admin.get_group_by_path(path="/main-group")
  365. assert res is not None, res
  366. assert res["id"] == group_id, res
  367. # Test group members
  368. res = admin.get_group_members(group_id=subgroup_id_2)
  369. assert len(res) == 0, res
  370. # Test fail group members
  371. with pytest.raises(KeycloakGetError) as err:
  372. admin.get_group_members(group_id="does-not-exist")
  373. assert err.match('404: b\'{"error":"Could not find group by id"}\'')
  374. res = admin.group_user_add(user_id=user, group_id=subgroup_id_2)
  375. assert res == dict(), res
  376. res = admin.get_group_members(group_id=subgroup_id_2)
  377. assert len(res) == 1, res
  378. assert res[0]["id"] == user
  379. # Test get group members query
  380. res = admin.get_group_members(group_id=subgroup_id_2, query={"max": 10})
  381. assert len(res) == 1, res
  382. assert res[0]["id"] == user
  383. with pytest.raises(KeycloakDeleteError) as err:
  384. admin.group_user_remove(user_id="does-not-exist", group_id=subgroup_id_2)
  385. assert err.match('404: b\'{"error":"User not found"}\''), err
  386. res = admin.group_user_remove(user_id=user, group_id=subgroup_id_2)
  387. assert res == dict(), res
  388. # Test set permissions
  389. res = admin.group_set_permissions(group_id=subgroup_id_2, enabled=True)
  390. assert res["enabled"], res
  391. res = admin.group_set_permissions(group_id=subgroup_id_2, enabled=False)
  392. assert not res["enabled"], res
  393. with pytest.raises(KeycloakPutError) as err:
  394. admin.group_set_permissions(group_id=subgroup_id_2, enabled="blah")
  395. assert err.match('500: b\'{"error":"unknown_error"}\''), err
  396. # Test update group
  397. res = admin.update_group(group_id=subgroup_id_2, payload={"name": "new-subgroup-2"})
  398. assert res == dict(), res
  399. assert admin.get_group(group_id=subgroup_id_2)["name"] == "new-subgroup-2"
  400. # test update fail
  401. with pytest.raises(KeycloakPutError) as err:
  402. admin.update_group(group_id="does-not-exist", payload=dict())
  403. assert err.match('404: b\'{"error":"Could not find group by id"}\''), err
  404. # Test delete
  405. res = admin.delete_group(group_id=group_id)
  406. assert res == dict(), res
  407. assert len(admin.get_groups()) == 0
  408. # Test delete fail
  409. with pytest.raises(KeycloakDeleteError) as err:
  410. admin.delete_group(group_id="does-not-exist")
  411. assert err.match('404: b\'{"error":"Could not find group by id"}\''), err
  412. def test_clients(admin: KeycloakAdmin, realm: str):
  413. admin.realm_name = realm
  414. # Test get clients
  415. clients = admin.get_clients()
  416. assert len(clients) == 6, clients
  417. assert {x["name"] for x in clients} == set(
  418. [
  419. "${client_admin-cli}",
  420. "${client_security-admin-console}",
  421. "${client_account-console}",
  422. "${client_broker}",
  423. "${client_account}",
  424. "${client_realm-management}",
  425. ]
  426. ), clients
  427. # Test create client
  428. client_id = admin.create_client(payload={"name": "test-client", "clientId": "test-client"})
  429. assert client_id, client_id
  430. with pytest.raises(KeycloakPostError) as err:
  431. admin.create_client(payload={"name": "test-client", "clientId": "test-client"})
  432. assert err.match('409: b\'{"errorMessage":"Client test-client already exists"}\''), err
  433. client_id_2 = admin.create_client(
  434. payload={"name": "test-client", "clientId": "test-client"}, skip_exists=True
  435. )
  436. assert client_id == client_id_2, client_id_2
  437. # Test get client
  438. res = admin.get_client(client_id=client_id)
  439. assert res["clientId"] == "test-client", res
  440. assert res["name"] == "test-client", res
  441. assert res["id"] == client_id, res
  442. with pytest.raises(KeycloakGetError) as err:
  443. admin.get_client(client_id="does-not-exist")
  444. assert err.match('404: b\'{"error":"Could not find client"}\'')
  445. assert len(admin.get_clients()) == 7
  446. # Test get client id
  447. assert admin.get_client_id(client_name="test-client") == client_id
  448. assert admin.get_client_id(client_name="does-not-exist") is None
  449. # Test update client
  450. res = admin.update_client(client_id=client_id, payload={"name": "test-client-change"})
  451. assert res == dict(), res
  452. with pytest.raises(KeycloakPutError) as err:
  453. admin.update_client(client_id="does-not-exist", payload={"name": "test-client-change"})
  454. assert err.match('404: b\'{"error":"Could not find client"}\'')
  455. # Test client mappers
  456. res = admin.get_mappers_from_client(client_id=client_id)
  457. assert len(res) == 0
  458. with pytest.raises(KeycloakPostError) as err:
  459. admin.add_mapper_to_client(client_id="does-not-exist", payload=dict())
  460. assert err.match('404: b\'{"error":"Could not find client"}\'')
  461. res = admin.add_mapper_to_client(
  462. client_id=client_id,
  463. payload={
  464. "name": "test-mapper",
  465. "protocol": "openid-connect",
  466. "protocolMapper": "oidc-usermodel-attribute-mapper",
  467. },
  468. )
  469. assert res == b""
  470. assert len(admin.get_mappers_from_client(client_id=client_id)) == 1
  471. mapper = admin.get_mappers_from_client(client_id=client_id)[0]
  472. with pytest.raises(KeycloakPutError) as err:
  473. admin.update_client_mapper(client_id=client_id, mapper_id="does-not-exist", payload=dict())
  474. assert err.match('404: b\'{"error":"Model not found"}\'')
  475. mapper["config"]["user.attribute"] = "test"
  476. res = admin.update_client_mapper(client_id=client_id, mapper_id=mapper["id"], payload=mapper)
  477. assert res == dict()
  478. res = admin.remove_client_mapper(client_id=client_id, client_mapper_id=mapper["id"])
  479. assert res == dict()
  480. with pytest.raises(KeycloakDeleteError) as err:
  481. admin.remove_client_mapper(client_id=client_id, client_mapper_id=mapper["id"])
  482. assert err.match('404: b\'{"error":"Model not found"}\'')
  483. # Test authz
  484. auth_client_id = admin.create_client(
  485. payload={
  486. "name": "authz-client",
  487. "clientId": "authz-client",
  488. "authorizationServicesEnabled": True,
  489. "serviceAccountsEnabled": True,
  490. }
  491. )
  492. res = admin.get_client_authz_settings(client_id=auth_client_id)
  493. assert res["allowRemoteResourceManagement"]
  494. assert res["decisionStrategy"] == "UNANIMOUS"
  495. assert len(res["policies"]) >= 0
  496. with pytest.raises(KeycloakGetError) as err:
  497. admin.get_client_authz_settings(client_id=client_id)
  498. assert err.match('500: b\'{"error":"HTTP 500 Internal Server Error"}\'')
  499. # Authz resources
  500. res = admin.get_client_authz_resources(client_id=auth_client_id)
  501. assert len(res) == 1
  502. assert res[0]["name"] == "Default Resource"
  503. with pytest.raises(KeycloakGetError) as err:
  504. admin.get_client_authz_resources(client_id=client_id)
  505. assert err.match('500: b\'{"error":"unknown_error"}\'')
  506. res = admin.create_client_authz_resource(
  507. client_id=auth_client_id, payload={"name": "test-resource"}
  508. )
  509. assert res["name"] == "test-resource", res
  510. test_resource_id = res["_id"]
  511. with pytest.raises(KeycloakPostError) as err:
  512. admin.create_client_authz_resource(
  513. client_id=auth_client_id, payload={"name": "test-resource"}
  514. )
  515. assert err.match('409: b\'{"error":"invalid_request"')
  516. assert admin.create_client_authz_resource(
  517. client_id=auth_client_id, payload={"name": "test-resource"}, skip_exists=True
  518. ) == {"msg": "Already exists"}
  519. res = admin.get_client_authz_resources(client_id=auth_client_id)
  520. assert len(res) == 2
  521. assert {x["name"] for x in res} == {"Default Resource", "test-resource"}
  522. # Authz policies
  523. res = admin.get_client_authz_policies(client_id=auth_client_id)
  524. assert len(res) == 1, res
  525. assert res[0]["name"] == "Default Policy"
  526. assert len(admin.get_client_authz_policies(client_id=client_id)) == 1
  527. with pytest.raises(KeycloakGetError) as err:
  528. admin.get_client_authz_policies(client_id="does-not-exist")
  529. assert err.match('404: b\'{"error":"Could not find client"}\'')
  530. role_id = admin.get_realm_role(role_name="offline_access")["id"]
  531. res = admin.create_client_authz_role_based_policy(
  532. client_id=auth_client_id,
  533. payload={"name": "test-authz-rb-policy", "roles": [{"id": role_id}]},
  534. )
  535. assert res["name"] == "test-authz-rb-policy", res
  536. with pytest.raises(KeycloakPostError) as err:
  537. admin.create_client_authz_role_based_policy(
  538. client_id=auth_client_id,
  539. payload={"name": "test-authz-rb-policy", "roles": [{"id": role_id}]},
  540. )
  541. assert err.match('409: b\'{"error":"Policy with name')
  542. assert admin.create_client_authz_role_based_policy(
  543. client_id=auth_client_id,
  544. payload={"name": "test-authz-rb-policy", "roles": [{"id": role_id}]},
  545. skip_exists=True,
  546. ) == {"msg": "Already exists"}
  547. assert len(admin.get_client_authz_policies(client_id=auth_client_id)) == 2
  548. # Test authz permissions
  549. res = admin.get_client_authz_permissions(client_id=auth_client_id)
  550. assert len(res) == 1, res
  551. assert res[0]["name"] == "Default Permission"
  552. assert len(admin.get_client_authz_permissions(client_id=client_id)) == 1
  553. with pytest.raises(KeycloakGetError) as err:
  554. admin.get_client_authz_permissions(client_id="does-not-exist")
  555. assert err.match('404: b\'{"error":"Could not find client"}\'')
  556. res = admin.create_client_authz_resource_based_permission(
  557. client_id=auth_client_id,
  558. payload={"name": "test-permission-rb", "resources": [test_resource_id]},
  559. )
  560. assert res, res
  561. assert res["name"] == "test-permission-rb"
  562. assert res["resources"] == [test_resource_id]
  563. with pytest.raises(KeycloakPostError) as err:
  564. admin.create_client_authz_resource_based_permission(
  565. client_id=auth_client_id,
  566. payload={"name": "test-permission-rb", "resources": [test_resource_id]},
  567. )
  568. assert err.match('409: b\'{"error":"Policy with name')
  569. assert admin.create_client_authz_resource_based_permission(
  570. client_id=auth_client_id,
  571. payload={"name": "test-permission-rb", "resources": [test_resource_id]},
  572. skip_exists=True,
  573. ) == {"msg": "Already exists"}
  574. assert len(admin.get_client_authz_permissions(client_id=auth_client_id)) == 2
  575. # Test authz scopes
  576. res = admin.get_client_authz_scopes(client_id=auth_client_id)
  577. assert len(res) == 0, res
  578. with pytest.raises(KeycloakGetError) as err:
  579. admin.get_client_authz_scopes(client_id=client_id)
  580. assert err.match('500: b\'{"error":"unknown_error"}\'')
  581. # Test service account user
  582. res = admin.get_client_service_account_user(client_id=auth_client_id)
  583. assert res["username"] == "service-account-authz-client", res
  584. with pytest.raises(KeycloakGetError) as err:
  585. admin.get_client_service_account_user(client_id=client_id)
  586. assert err.match('400: b\'{"error":"unknown_error"}\'')
  587. # Test delete client
  588. res = admin.delete_client(client_id=auth_client_id)
  589. assert res == dict(), res
  590. with pytest.raises(KeycloakDeleteError) as err:
  591. admin.delete_client(client_id=auth_client_id)
  592. assert err.match('404: b\'{"error":"Could not find client"}\'')
  593. # Test client credentials
  594. admin.create_client(
  595. payload={
  596. "name": "test-confidential",
  597. "enabled": True,
  598. "protocol": "openid-connect",
  599. "publicClient": False,
  600. "redirectUris": ["http://localhost/*"],
  601. "webOrigins": ["+"],
  602. "clientId": "test-confidential",
  603. "secret": "test-secret",
  604. "clientAuthenticatorType": "client-secret",
  605. }
  606. )
  607. with pytest.raises(KeycloakGetError) as err:
  608. admin.get_client_secrets(client_id="does-not-exist")
  609. assert err.match('404: b\'{"error":"Could not find client"}\'')
  610. secrets = admin.get_client_secrets(
  611. client_id=admin.get_client_id(client_name="test-confidential")
  612. )
  613. assert secrets == {"type": "secret", "value": "test-secret"}
  614. with pytest.raises(KeycloakPostError) as err:
  615. admin.generate_client_secrets(client_id="does-not-exist")
  616. assert err.match('404: b\'{"error":"Could not find client"}\'')
  617. res = admin.generate_client_secrets(
  618. client_id=admin.get_client_id(client_name="test-confidential")
  619. )
  620. assert res
  621. assert (
  622. admin.get_client_secrets(client_id=admin.get_client_id(client_name="test-confidential"))
  623. == res
  624. )
  625. def test_realm_roles(admin: KeycloakAdmin, realm: str):
  626. admin.realm_name = realm
  627. # Test get realm roles
  628. roles = admin.get_realm_roles()
  629. assert len(roles) == 3, roles
  630. role_names = [x["name"] for x in roles]
  631. assert "uma_authorization" in role_names, role_names
  632. assert "offline_access" in role_names, role_names
  633. # Test empty members
  634. with pytest.raises(KeycloakGetError) as err:
  635. admin.get_realm_role_members(role_name="does-not-exist")
  636. assert err.match('404: b\'{"error":"Could not find role"}\'')
  637. members = admin.get_realm_role_members(role_name="offline_access")
  638. assert members == list(), members
  639. # Test create realm role
  640. role_id = admin.create_realm_role(payload={"name": "test-realm-role"}, skip_exists=True)
  641. assert role_id, role_id
  642. with pytest.raises(KeycloakPostError) as err:
  643. admin.create_realm_role(payload={"name": "test-realm-role"})
  644. assert err.match('409: b\'{"errorMessage":"Role with name test-realm-role already exists"}\'')
  645. role_id_2 = admin.create_realm_role(payload={"name": "test-realm-role"}, skip_exists=True)
  646. assert role_id == role_id_2
  647. # Test update realm role
  648. res = admin.update_realm_role(
  649. role_name="test-realm-role", payload={"name": "test-realm-role-update"}
  650. )
  651. assert res == dict(), res
  652. with pytest.raises(KeycloakPutError) as err:
  653. admin.update_realm_role(
  654. role_name="test-realm-role", payload={"name": "test-realm-role-update"}
  655. )
  656. assert err.match('404: b\'{"error":"Could not find role"}\''), err
  657. # Test realm role user assignment
  658. user_id = admin.create_user(payload={"username": "role-testing", "email": "test@test.test"})
  659. with pytest.raises(KeycloakPostError) as err:
  660. admin.assign_realm_roles(user_id=user_id, roles=["bad"])
  661. assert err.match('500: b\'{"error":"unknown_error"}\'')
  662. res = admin.assign_realm_roles(
  663. user_id=user_id,
  664. roles=[
  665. admin.get_realm_role(role_name="offline_access"),
  666. admin.get_realm_role(role_name="test-realm-role-update"),
  667. ],
  668. )
  669. assert res == dict(), res
  670. assert admin.get_user(user_id=user_id)["username"] in [
  671. x["username"] for x in admin.get_realm_role_members(role_name="offline_access")
  672. ]
  673. assert admin.get_user(user_id=user_id)["username"] in [
  674. x["username"] for x in admin.get_realm_role_members(role_name="test-realm-role-update")
  675. ]
  676. roles = admin.get_realm_roles_of_user(user_id=user_id)
  677. assert len(roles) == 3
  678. assert "offline_access" in [x["name"] for x in roles]
  679. assert "test-realm-role-update" in [x["name"] for x in roles]
  680. with pytest.raises(KeycloakDeleteError) as err:
  681. admin.delete_realm_roles_of_user(user_id=user_id, roles=["bad"])
  682. assert err.match('500: b\'{"error":"unknown_error"}\'')
  683. res = admin.delete_realm_roles_of_user(
  684. user_id=user_id, roles=[admin.get_realm_role(role_name="offline_access")]
  685. )
  686. assert res == dict(), res
  687. assert admin.get_realm_role_members(role_name="offline_access") == list()
  688. roles = admin.get_realm_roles_of_user(user_id=user_id)
  689. assert len(roles) == 2
  690. assert "offline_access" not in [x["name"] for x in roles]
  691. assert "test-realm-role-update" in [x["name"] for x in roles]
  692. roles = admin.get_available_realm_roles_of_user(user_id=user_id)
  693. assert len(roles) == 2
  694. assert "offline_access" in [x["name"] for x in roles]
  695. assert "uma_authorization" in [x["name"] for x in roles]
  696. # Test realm role group assignment
  697. group_id = admin.create_group(payload={"name": "test-group"})
  698. with pytest.raises(KeycloakPostError) as err:
  699. admin.assign_group_realm_roles(group_id=group_id, roles=["bad"])
  700. assert err.match('500: b\'{"error":"unknown_error"}\'')
  701. res = admin.assign_group_realm_roles(
  702. group_id=group_id,
  703. roles=[
  704. admin.get_realm_role(role_name="offline_access"),
  705. admin.get_realm_role(role_name="test-realm-role-update"),
  706. ],
  707. )
  708. assert res == dict(), res
  709. roles = admin.get_group_realm_roles(group_id=group_id)
  710. assert len(roles) == 2
  711. assert "offline_access" in [x["name"] for x in roles]
  712. assert "test-realm-role-update" in [x["name"] for x in roles]
  713. with pytest.raises(KeycloakDeleteError) as err:
  714. admin.delete_group_realm_roles(group_id=group_id, roles=["bad"])
  715. assert err.match('500: b\'{"error":"unknown_error"}\'')
  716. res = admin.delete_group_realm_roles(
  717. group_id=group_id, roles=[admin.get_realm_role(role_name="offline_access")]
  718. )
  719. assert res == dict(), res
  720. roles = admin.get_group_realm_roles(group_id=group_id)
  721. assert len(roles) == 1
  722. assert "test-realm-role-update" in [x["name"] for x in roles]
  723. # Test composite realm roles
  724. composite_role = admin.create_realm_role(payload={"name": "test-composite-role"})
  725. with pytest.raises(KeycloakPostError) as err:
  726. admin.add_composite_realm_roles_to_role(role_name=composite_role, roles=["bad"])
  727. assert err.match('500: b\'{"error":"unknown_error"}\'')
  728. res = admin.add_composite_realm_roles_to_role(
  729. role_name=composite_role, roles=[admin.get_realm_role(role_name="test-realm-role-update")]
  730. )
  731. assert res == dict(), res
  732. res = admin.get_composite_realm_roles_of_role(role_name=composite_role)
  733. assert len(res) == 1
  734. assert "test-realm-role-update" in res[0]["name"]
  735. with pytest.raises(KeycloakGetError) as err:
  736. admin.get_composite_realm_roles_of_role(role_name="bad")
  737. assert err.match('404: b\'{"error":"Could not find role"}\'')
  738. res = admin.get_composite_realm_roles_of_user(user_id=user_id)
  739. assert len(res) == 4
  740. assert "offline_access" in {x["name"] for x in res}
  741. assert "test-realm-role-update" in {x["name"] for x in res}
  742. assert "uma_authorization" in {x["name"] for x in res}
  743. with pytest.raises(KeycloakGetError) as err:
  744. admin.get_composite_realm_roles_of_user(user_id="bad")
  745. assert err.match('404: b\'{"error":"User not found"}\'')
  746. with pytest.raises(KeycloakDeleteError) as err:
  747. admin.remove_composite_realm_roles_to_role(role_name=composite_role, roles=["bad"])
  748. assert err.match('500: b\'{"error":"unknown_error"}\'')
  749. res = admin.remove_composite_realm_roles_to_role(
  750. role_name=composite_role, roles=[admin.get_realm_role(role_name="test-realm-role-update")]
  751. )
  752. assert res == dict(), res
  753. res = admin.get_composite_realm_roles_of_role(role_name=composite_role)
  754. assert len(res) == 0
  755. # Test delete realm role
  756. res = admin.delete_realm_role(role_name=composite_role)
  757. assert res == dict(), res
  758. with pytest.raises(KeycloakDeleteError) as err:
  759. admin.delete_realm_role(role_name=composite_role)
  760. assert err.match('404: b\'{"error":"Could not find role"}\'')
  761. def test_client_roles(admin: KeycloakAdmin, client: str):
  762. # Test get client roles
  763. res = admin.get_client_roles(client_id=client)
  764. assert len(res) == 0
  765. with pytest.raises(KeycloakGetError) as err:
  766. admin.get_client_roles(client_id="bad")
  767. assert err.match('404: b\'{"error":"Could not find client"}\'')
  768. # Test create client role
  769. client_role_id = admin.create_client_role(
  770. client_role_id=client, payload={"name": "client-role-test"}, skip_exists=True
  771. )
  772. with pytest.raises(KeycloakPostError) as err:
  773. admin.create_client_role(client_role_id=client, payload={"name": "client-role-test"})
  774. assert err.match('409: b\'{"errorMessage":"Role with name client-role-test already exists"}\'')
  775. client_role_id_2 = admin.create_client_role(
  776. client_role_id=client, payload={"name": "client-role-test"}, skip_exists=True
  777. )
  778. assert client_role_id == client_role_id_2
  779. # Test get client role
  780. res = admin.get_client_role(client_id=client, role_name="client-role-test")
  781. assert res["name"] == client_role_id
  782. with pytest.raises(KeycloakGetError) as err:
  783. admin.get_client_role(client_id=client, role_name="bad")
  784. assert err.match('404: b\'{"error":"Could not find role"}\'')
  785. res_ = admin.get_client_role_id(client_id=client, role_name="client-role-test")
  786. assert res_ == res["id"]
  787. with pytest.raises(KeycloakGetError) as err:
  788. admin.get_client_role_id(client_id=client, role_name="bad")
  789. assert err.match('404: b\'{"error":"Could not find role"}\'')
  790. assert len(admin.get_client_roles(client_id=client)) == 1
  791. # Test update client role
  792. res = admin.update_client_role(
  793. client_role_id=client,
  794. role_name="client-role-test",
  795. payload={"name": "client-role-test-update"},
  796. )
  797. assert res == dict()
  798. with pytest.raises(KeycloakPutError) as err:
  799. res = admin.update_client_role(
  800. client_role_id=client,
  801. role_name="client-role-test",
  802. payload={"name": "client-role-test-update"},
  803. )
  804. assert err.match('404: b\'{"error":"Could not find role"}\'')
  805. # Test user with client role
  806. res = admin.get_client_role_members(client_id=client, role_name="client-role-test-update")
  807. assert len(res) == 0
  808. with pytest.raises(KeycloakGetError) as err:
  809. admin.get_client_role_members(client_id=client, role_name="bad")
  810. assert err.match('404: b\'{"error":"Could not find role"}\'')
  811. user_id = admin.create_user(payload={"username": "test", "email": "test@test.test"})
  812. with pytest.raises(KeycloakPostError) as err:
  813. admin.assign_client_role(user_id=user_id, client_id=client, roles=["bad"])
  814. assert err.match('500: b\'{"error":"unknown_error"}\'')
  815. res = admin.assign_client_role(
  816. user_id=user_id,
  817. client_id=client,
  818. roles=[admin.get_client_role(client_id=client, role_name="client-role-test-update")],
  819. )
  820. assert res == dict()
  821. assert (
  822. len(admin.get_client_role_members(client_id=client, role_name="client-role-test-update"))
  823. == 1
  824. )
  825. roles = admin.get_client_roles_of_user(user_id=user_id, client_id=client)
  826. assert len(roles) == 1, roles
  827. with pytest.raises(KeycloakGetError) as err:
  828. admin.get_client_roles_of_user(user_id=user_id, client_id="bad")
  829. assert err.match('404: b\'{"error":"Client not found"}\'')
  830. roles = admin.get_composite_client_roles_of_user(user_id=user_id, client_id=client)
  831. assert len(roles) == 1, roles
  832. with pytest.raises(KeycloakGetError) as err:
  833. admin.get_composite_client_roles_of_user(user_id=user_id, client_id="bad")
  834. assert err.match('404: b\'{"error":"Client not found"}\'')
  835. roles = admin.get_available_client_roles_of_user(user_id=user_id, client_id=client)
  836. assert len(roles) == 0, roles
  837. with pytest.raises(KeycloakGetError) as err:
  838. admin.get_composite_client_roles_of_user(user_id=user_id, client_id="bad")
  839. assert err.match('404: b\'{"error":"Client not found"}\'')
  840. with pytest.raises(KeycloakDeleteError) as err:
  841. admin.delete_client_roles_of_user(user_id=user_id, client_id=client, roles=["bad"])
  842. assert err.match('500: b\'{"error":"unknown_error"}\'')
  843. admin.delete_client_roles_of_user(
  844. user_id=user_id,
  845. client_id=client,
  846. roles=[admin.get_client_role(client_id=client, role_name="client-role-test-update")],
  847. )
  848. assert len(admin.get_client_roles_of_user(user_id=user_id, client_id=client)) == 0
  849. # Test groups and client roles
  850. res = admin.get_client_role_groups(client_id=client, role_name="client-role-test-update")
  851. assert len(res) == 0
  852. with pytest.raises(KeycloakGetError) as err:
  853. admin.get_client_role_groups(client_id=client, role_name="bad")
  854. assert err.match('404: b\'{"error":"Could not find role"}\'')
  855. group_id = admin.create_group(payload={"name": "test-group"})
  856. res = admin.get_group_client_roles(group_id=group_id, client_id=client)
  857. assert len(res) == 0
  858. with pytest.raises(KeycloakGetError) as err:
  859. admin.get_group_client_roles(group_id=group_id, client_id="bad")
  860. assert err.match('404: b\'{"error":"Client not found"}\'')
  861. with pytest.raises(KeycloakPostError) as err:
  862. admin.assign_group_client_roles(group_id=group_id, client_id=client, roles=["bad"])
  863. assert err.match('500: b\'{"error":"unknown_error"}\'')
  864. res = admin.assign_group_client_roles(
  865. group_id=group_id,
  866. client_id=client,
  867. roles=[admin.get_client_role(client_id=client, role_name="client-role-test-update")],
  868. )
  869. assert res == dict()
  870. assert (
  871. len(admin.get_client_role_groups(client_id=client, role_name="client-role-test-update"))
  872. == 1
  873. )
  874. assert len(admin.get_group_client_roles(group_id=group_id, client_id=client)) == 1
  875. with pytest.raises(KeycloakDeleteError) as err:
  876. admin.delete_group_client_roles(group_id=group_id, client_id=client, roles=["bad"])
  877. assert err.match('500: b\'{"error":"unknown_error"}\'')
  878. res = admin.delete_group_client_roles(
  879. group_id=group_id,
  880. client_id=client,
  881. roles=[admin.get_client_role(client_id=client, role_name="client-role-test-update")],
  882. )
  883. assert res == dict()
  884. # Test composite client roles
  885. with pytest.raises(KeycloakPostError) as err:
  886. admin.add_composite_client_roles_to_role(
  887. client_role_id=client, role_name="client-role-test-update", roles=["bad"]
  888. )
  889. assert err.match('500: b\'{"error":"unknown_error"}\'')
  890. res = admin.add_composite_client_roles_to_role(
  891. client_role_id=client,
  892. role_name="client-role-test-update",
  893. roles=[admin.get_realm_role(role_name="offline_access")],
  894. )
  895. assert res == dict()
  896. assert admin.get_client_role(client_id=client, role_name="client-role-test-update")[
  897. "composite"
  898. ]
  899. # Test delete of client role
  900. res = admin.delete_client_role(client_role_id=client, role_name="client-role-test-update")
  901. assert res == dict()
  902. with pytest.raises(KeycloakDeleteError) as err:
  903. admin.delete_client_role(client_role_id=client, role_name="client-role-test-update")
  904. assert err.match('404: b\'{"error":"Could not find role"}\'')
  905. def test_email(admin: KeycloakAdmin, user: str):
  906. # Emails will fail as we don't have SMTP test setup
  907. with pytest.raises(KeycloakPutError) as err:
  908. admin.send_update_account(user_id=user, payload=dict())
  909. assert err.match('500: b\'{"error":"unknown_error"}\'')
  910. admin.update_user(user_id=user, payload={"enabled": True})
  911. with pytest.raises(KeycloakPutError) as err:
  912. admin.send_verify_email(user_id=user)
  913. assert err.match('500: b\'{"errorMessage":"Failed to send execute actions email"}\'')
  914. def test_get_sessions(admin: KeycloakAdmin):
  915. sessions = admin.get_sessions(user_id=admin.get_user_id(username=admin.username))
  916. assert len(sessions) >= 1
  917. with pytest.raises(KeycloakGetError) as err:
  918. admin.get_sessions(user_id="bad")
  919. assert err.match('404: b\'{"error":"User not found"}\'')
  920. def test_get_client_installation_provider(admin: KeycloakAdmin, client: str):
  921. with pytest.raises(KeycloakGetError) as err:
  922. admin.get_client_installation_provider(client_id=client, provider_id="bad")
  923. assert err.match('404: b\'{"error":"Unknown Provider"}\'')
  924. installation = admin.get_client_installation_provider(
  925. client_id=client, provider_id="keycloak-oidc-keycloak-json"
  926. )
  927. assert set(installation.keys()) == {
  928. "auth-server-url",
  929. "confidential-port",
  930. "credentials",
  931. "realm",
  932. "resource",
  933. "ssl-required",
  934. }
  935. def test_auth_flows(admin: KeycloakAdmin, realm: str):
  936. admin.realm_name = realm
  937. res = admin.get_authentication_flows()
  938. assert len(res) == 8, res
  939. assert set(res[0].keys()) == {
  940. "alias",
  941. "authenticationExecutions",
  942. "builtIn",
  943. "description",
  944. "id",
  945. "providerId",
  946. "topLevel",
  947. }
  948. assert {x["alias"] for x in res} == {
  949. "reset credentials",
  950. "browser",
  951. "http challenge",
  952. "registration",
  953. "docker auth",
  954. "direct grant",
  955. "first broker login",
  956. "clients",
  957. }
  958. with pytest.raises(KeycloakGetError) as err:
  959. admin.get_authentication_flow_for_id(flow_id="bad")
  960. assert err.match('404: b\'{"error":"Could not find flow with id"}\'')
  961. browser_flow_id = [x for x in res if x["alias"] == "browser"][0]["id"]
  962. res = admin.get_authentication_flow_for_id(flow_id=browser_flow_id)
  963. assert res["alias"] == "browser"
  964. # Test copying
  965. with pytest.raises(KeycloakPostError) as err:
  966. admin.copy_authentication_flow(payload=dict(), flow_alias="bad")
  967. assert err.match("404: b''")
  968. res = admin.copy_authentication_flow(payload={"newName": "test-browser"}, flow_alias="browser")
  969. assert res == b"", res
  970. assert len(admin.get_authentication_flows()) == 9
  971. # Test create
  972. res = admin.create_authentication_flow(
  973. payload={"alias": "test-create", "providerId": "basic-flow"}
  974. )
  975. assert res == b""
  976. with pytest.raises(KeycloakPostError) as err:
  977. admin.create_authentication_flow(payload={"alias": "test-create", "builtIn": False})
  978. assert err.match('409: b\'{"errorMessage":"Flow test-create already exists"}\'')
  979. assert admin.create_authentication_flow(
  980. payload={"alias": "test-create"}, skip_exists=True
  981. ) == {"msg": "Already exists"}
  982. # Test flow executions
  983. res = admin.get_authentication_flow_executions(flow_alias="browser")
  984. assert len(res) == 8, res
  985. with pytest.raises(KeycloakGetError) as err:
  986. admin.get_authentication_flow_executions(flow_alias="bad")
  987. assert err.match("404: b''")
  988. exec_id = res[0]["id"]
  989. res = admin.get_authentication_flow_execution(execution_id=exec_id)
  990. assert set(res.keys()) == {
  991. "alternative",
  992. "authenticator",
  993. "authenticatorFlow",
  994. "conditional",
  995. "disabled",
  996. "enabled",
  997. "id",
  998. "parentFlow",
  999. "priority",
  1000. "required",
  1001. "requirement",
  1002. }, res
  1003. with pytest.raises(KeycloakGetError) as err:
  1004. admin.get_authentication_flow_execution(execution_id="bad")
  1005. assert err.match('404: b\'{"error":"Illegal execution"}\'')
  1006. with pytest.raises(KeycloakPostError) as err:
  1007. admin.create_authentication_flow_execution(payload=dict(), flow_alias="browser")
  1008. assert err.match('400: b\'{"error":"It is illegal to add execution to a built in flow"}\'')
  1009. res = admin.create_authentication_flow_execution(
  1010. payload={"provider": "auth-cookie"}, flow_alias="test-create"
  1011. )
  1012. assert res == b""
  1013. assert len(admin.get_authentication_flow_executions(flow_alias="test-create")) == 1
  1014. with pytest.raises(KeycloakPutError) as err:
  1015. admin.update_authentication_flow_executions(
  1016. payload={"required": "yes"}, flow_alias="test-create"
  1017. )
  1018. assert err.match('400: b\'{"error":"Unrecognized field')
  1019. payload = admin.get_authentication_flow_executions(flow_alias="test-create")[0]
  1020. payload["displayName"] = "test"
  1021. res = admin.update_authentication_flow_executions(payload=payload, flow_alias="test-create")
  1022. assert res
  1023. exec_id = admin.get_authentication_flow_executions(flow_alias="test-create")[0]["id"]
  1024. res = admin.delete_authentication_flow_execution(execution_id=exec_id)
  1025. assert res == dict()
  1026. with pytest.raises(KeycloakDeleteError) as err:
  1027. admin.delete_authentication_flow_execution(execution_id=exec_id)
  1028. assert err.match('404: b\'{"error":"Illegal execution"}\'')
  1029. # Test subflows
  1030. res = admin.create_authentication_flow_subflow(
  1031. payload={
  1032. "alias": "test-subflow",
  1033. "provider": "basic-flow",
  1034. "type": "something",
  1035. "description": "something",
  1036. },
  1037. flow_alias="test-browser",
  1038. )
  1039. assert res == b""
  1040. with pytest.raises(KeycloakPostError) as err:
  1041. admin.create_authentication_flow_subflow(
  1042. payload={"alias": "test-subflow", "providerId": "basic-flow"},
  1043. flow_alias="test-browser",
  1044. )
  1045. assert err.match('409: b\'{"errorMessage":"New flow alias name already exists"}\'')
  1046. res = admin.create_authentication_flow_subflow(
  1047. payload={
  1048. "alias": "test-subflow",
  1049. "provider": "basic-flow",
  1050. "type": "something",
  1051. "description": "something",
  1052. },
  1053. flow_alias="test-create",
  1054. skip_exists=True,
  1055. )
  1056. assert res == {"msg": "Already exists"}
  1057. # Test delete auth flow
  1058. flow_id = [x for x in admin.get_authentication_flows() if x["alias"] == "test-browser"][0][
  1059. "id"
  1060. ]
  1061. res = admin.delete_authentication_flow(flow_id=flow_id)
  1062. assert res == dict()
  1063. with pytest.raises(KeycloakDeleteError) as err:
  1064. admin.delete_authentication_flow(flow_id=flow_id)
  1065. assert err.match('404: b\'{"error":"Could not find flow with id"}\'')
  1066. def test_authentication_configs(admin: KeycloakAdmin, realm: str):
  1067. admin.realm_name = realm
  1068. # Test list of auth providers
  1069. res = admin.get_authenticator_providers()
  1070. assert len(res) == 39
  1071. res = admin.get_authenticator_provider_config_description(provider_id="auth-cookie")
  1072. assert res == {
  1073. "helpText": "Validates the SSO cookie set by the auth server.",
  1074. "name": "Cookie",
  1075. "properties": [],
  1076. "providerId": "auth-cookie",
  1077. }
  1078. # Test authenticator config
  1079. # Currently unable to find a sustainable way to fetch the config id,
  1080. # therefore testing only failures
  1081. with pytest.raises(KeycloakGetError) as err:
  1082. admin.get_authenticator_config(config_id="bad")
  1083. assert err.match('404: b\'{"error":"Could not find authenticator config"}\'')
  1084. with pytest.raises(KeycloakPutError) as err:
  1085. admin.update_authenticator_config(payload=dict(), config_id="bad")
  1086. assert err.match('404: b\'{"error":"Could not find authenticator config"}\'')
  1087. with pytest.raises(KeycloakDeleteError) as err:
  1088. admin.delete_authenticator_config(config_id="bad")
  1089. assert err.match('404: b\'{"error":"Could not find authenticator config"}\'')
  1090. def test_sync_users(admin: KeycloakAdmin, realm: str):
  1091. admin.realm_name = realm
  1092. # Only testing the error message
  1093. with pytest.raises(KeycloakPostError) as err:
  1094. admin.sync_users(storage_id="does-not-exist", action="triggerFullSync")
  1095. assert err.match('404: b\'{"error":"Could not find component"}\'')
  1096. def test_client_scopes(admin: KeycloakAdmin, realm: str):
  1097. admin.realm_name = realm
  1098. # Test get client scopes
  1099. res = admin.get_client_scopes()
  1100. scope_names = {x["name"] for x in res}
  1101. assert len(res) == 10
  1102. assert "email" in scope_names
  1103. assert "profile" in scope_names
  1104. assert "offline_access" in scope_names
  1105. with pytest.raises(KeycloakGetError) as err:
  1106. admin.get_client_scope(client_scope_id="does-not-exist")
  1107. assert err.match('404: b\'{"error":"Could not find client scope"}\'')
  1108. scope = admin.get_client_scope(client_scope_id=res[0]["id"])
  1109. assert res[0] == scope
  1110. scope = admin.get_client_scope_by_name(client_scope_name=res[0]["name"])
  1111. assert res[0] == scope
  1112. # Test create client scope
  1113. res = admin.create_client_scope(payload={"name": "test-scope"}, skip_exists=True)
  1114. assert res
  1115. res2 = admin.create_client_scope(payload={"name": "test-scope"}, skip_exists=True)
  1116. assert res == res2
  1117. with pytest.raises(KeycloakPostError) as err:
  1118. admin.create_client_scope(payload={"name": "test-scope"}, skip_exists=False)
  1119. assert err.match('409: b\'{"errorMessage":"Client Scope test-scope already exists"}\'')
  1120. # Test update client scope
  1121. with pytest.raises(KeycloakPutError) as err:
  1122. admin.update_client_scope(client_scope_id="does-not-exist", payload=dict())
  1123. assert err.match('404: b\'{"error":"Could not find client scope"}\'')
  1124. res_update = admin.update_client_scope(
  1125. client_scope_id=res, payload={"name": "test-scope-update"}
  1126. )
  1127. assert res_update == dict()
  1128. admin.get_client_scope(client_scope_id=res)["name"] == "test-scope-update"
  1129. # Test get mappers
  1130. mappers = admin.get_mappers_from_client_scope(client_scope_id=res)
  1131. assert mappers == list()
  1132. # Test add mapper
  1133. with pytest.raises(KeycloakPostError) as err:
  1134. admin.add_mapper_to_client_scope(client_scope_id=res, payload=dict())
  1135. assert err.match('404: b\'{"error":"ProtocolMapper provider not found"}\'')
  1136. res_add = admin.add_mapper_to_client_scope(
  1137. client_scope_id=res,
  1138. payload={
  1139. "name": "test-mapper",
  1140. "protocol": "openid-connect",
  1141. "protocolMapper": "oidc-usermodel-attribute-mapper",
  1142. },
  1143. )
  1144. assert res_add == b""
  1145. assert len(admin.get_mappers_from_client_scope(client_scope_id=res)) == 1
  1146. # Test update mapper
  1147. test_mapper = admin.get_mappers_from_client_scope(client_scope_id=res)[0]
  1148. with pytest.raises(KeycloakPutError) as err:
  1149. admin.update_mapper_in_client_scope(
  1150. client_scope_id="does-not-exist", protocol_mapper_id=test_mapper["id"], payload=dict()
  1151. )
  1152. assert err.match('404: b\'{"error":"Could not find client scope"}\'')
  1153. test_mapper["config"]["user.attribute"] = "test"
  1154. res_update = admin.update_mapper_in_client_scope(
  1155. client_scope_id=res,
  1156. protocol_mapper_id=test_mapper["id"],
  1157. payload=test_mapper,
  1158. )
  1159. assert res_update == dict()
  1160. assert (
  1161. admin.get_mappers_from_client_scope(client_scope_id=res)[0]["config"]["user.attribute"]
  1162. == "test"
  1163. )
  1164. # Test delete mapper
  1165. res_del = admin.delete_mapper_from_client_scope(
  1166. client_scope_id=res, protocol_mapper_id=test_mapper["id"]
  1167. )
  1168. assert res_del == dict()
  1169. with pytest.raises(KeycloakDeleteError) as err:
  1170. admin.delete_mapper_from_client_scope(
  1171. client_scope_id=res, protocol_mapper_id=test_mapper["id"]
  1172. )
  1173. assert err.match('404: b\'{"error":"Model not found"}\'')
  1174. # Test default default scopes
  1175. res_defaults = admin.get_default_default_client_scopes()
  1176. assert len(res_defaults) == 6
  1177. with pytest.raises(KeycloakPutError) as err:
  1178. admin.add_default_default_client_scope(scope_id="does-not-exist")
  1179. assert err.match('404: b\'{"error":"Client scope not found"}\'')
  1180. res_add = admin.add_default_default_client_scope(scope_id=res)
  1181. assert res_add == dict()
  1182. assert len(admin.get_default_default_client_scopes()) == 7
  1183. with pytest.raises(KeycloakDeleteError) as err:
  1184. admin.delete_default_default_client_scope(scope_id="does-not-exist")
  1185. assert err.match('404: b\'{"error":"Client scope not found"}\'')
  1186. res_del = admin.delete_default_default_client_scope(scope_id=res)
  1187. assert res_del == dict()
  1188. assert len(admin.get_default_default_client_scopes()) == 6
  1189. # Test default optional scopes
  1190. res_defaults = admin.get_default_optional_client_scopes()
  1191. assert len(res_defaults) == 4
  1192. with pytest.raises(KeycloakPutError) as err:
  1193. admin.add_default_optional_client_scope(scope_id="does-not-exist")
  1194. assert err.match('404: b\'{"error":"Client scope not found"}\'')
  1195. res_add = admin.add_default_optional_client_scope(scope_id=res)
  1196. assert res_add == dict()
  1197. assert len(admin.get_default_optional_client_scopes()) == 5
  1198. with pytest.raises(KeycloakDeleteError) as err:
  1199. admin.delete_default_optional_client_scope(scope_id="does-not-exist")
  1200. assert err.match('404: b\'{"error":"Client scope not found"}\'')
  1201. res_del = admin.delete_default_optional_client_scope(scope_id=res)
  1202. assert res_del == dict()
  1203. assert len(admin.get_default_optional_client_scopes()) == 4
  1204. # Test client scope delete
  1205. res_del = admin.delete_client_scope(client_scope_id=res)
  1206. assert res_del == dict()
  1207. with pytest.raises(KeycloakDeleteError) as err:
  1208. admin.delete_client_scope(client_scope_id=res)
  1209. assert err.match('404: b\'{"error":"Could not find client scope"}\'')