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.

684 lines
26 KiB

7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
  1. # -*- coding: utf-8 -*-
  2. #
  3. # Copyright (C) 2017 Marcos Pereira <marcospereira.mpj@gmail.com>
  4. #
  5. # This program is free software: you can redistribute it and/or modify
  6. # it under the terms of the GNU Lesser General Public License as published by
  7. # the Free Software Foundation, either version 3 of the License, or
  8. # (at your option) any later version.
  9. #
  10. # This program is distributed in the hope that it will be useful,
  11. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. # GNU Lesser General Public License for more details.
  14. #
  15. # You should have received a copy of the GNU Lesser General Public License
  16. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. # Unless otherwise stated in the comments, "id", in e.g. user_id, refers to the internal Keycloak server ID, usually a uuid string
  18. from .urls_patterns import URL_ADMIN_USERS_COUNT, URL_ADMIN_USER, URL_ADMIN_USER_CONSENTS, \
  19. URL_ADMIN_SEND_UPDATE_ACCOUNT, URL_ADMIN_RESET_PASSWORD, URL_ADMIN_SEND_VERIFY_EMAIL, URL_ADMIN_GET_SESSIONS, \
  20. URL_ADMIN_SERVER_INFO, URL_ADMIN_CLIENTS, URL_ADMIN_CLIENT, URL_ADMIN_CLIENT_ROLES, URL_ADMIN_REALM_ROLES, URL_ADMIN_USER_CLIENT_ROLES, \
  21. URL_ADMIN_GROUP, URL_ADMIN_GROUPS, URL_ADMIN_GROUP_CHILD, URL_ADMIN_USER_GROUP, URL_ADMIN_USER_PASSWORD, URL_ADMIN_GROUP_PERMISSIONS
  22. from .keycloak_openid import KeycloakOpenID
  23. from .exceptions import raise_error_from_response, KeycloakGetError
  24. from .urls_patterns import (
  25. URL_ADMIN_USERS,
  26. )
  27. from .connection import ConnectionManager
  28. import json
  29. class KeycloakAdmin:
  30. def __init__(self, server_url, verify, username, password, realm_name='master', client_id='admin-cli'):
  31. self._username = username
  32. self._password = password
  33. self._client_id = client_id
  34. self._realm_name = realm_name
  35. # Get token Admin
  36. keycloak_openid = KeycloakOpenID(server_url=server_url, client_id=client_id, realm_name=realm_name, verify=verify)
  37. self._token = keycloak_openid.token(username, password)
  38. self._connection = ConnectionManager(base_url=server_url,
  39. headers={'Authorization': 'Bearer ' + self.token.get('access_token'),
  40. 'Content-Type': 'application/json'},
  41. timeout=60,
  42. verify=verify)
  43. @property
  44. def realm_name(self):
  45. return self._realm_name
  46. @realm_name.setter
  47. def realm_name(self, value):
  48. self._realm_name = value
  49. @property
  50. def connection(self):
  51. return self._connection
  52. @connection.setter
  53. def connection(self, value):
  54. self._connection = value
  55. @property
  56. def client_id(self):
  57. return self._client_id
  58. @client_id.setter
  59. def client_id(self, value):
  60. self._client_id = value
  61. @property
  62. def username(self):
  63. return self._username
  64. @username.setter
  65. def username(self, value):
  66. self._username = value
  67. @property
  68. def password(self):
  69. return self._password
  70. @password.setter
  71. def password(self, value):
  72. self._password = value
  73. @property
  74. def token(self):
  75. return self._token
  76. @token.setter
  77. def token(self, value):
  78. self._token = value
  79. def get_users(self, query=None):
  80. """
  81. Get users Returns a list of users, filtered according to query parameters
  82. :return: users list
  83. """
  84. params_path = {"realm-name": self.realm_name}
  85. data_raw = self.connection.raw_get(URL_ADMIN_USERS.format(**params_path), **query)
  86. return raise_error_from_response(data_raw, KeycloakGetError)
  87. def create_user(self, username, email='', firstName='', lastName='', emailVerified=False, enabled=True, password=None, passwordTemp=False, skip_exists=False):
  88. """
  89. Create a new user Username must be unique
  90. UserRepresentation
  91. http://www.keycloak.org/docs-api/3.3/rest-api/index.html#_userrepresentation
  92. :param data: Http response
  93. """
  94. data={}
  95. data["username"]=username
  96. data["email"]=email
  97. data["firstName"]=firstName
  98. data["lastName"]=lastName
  99. data["emailVerified"]=emailVerified
  100. data["enabled"]=enabled
  101. params_path = {"realm-name": self.realm_name}
  102. exists = self.get_user_id(username=username)
  103. if exists is not None:
  104. return str(exists)
  105. data_raw = self.connection.raw_post(URL_ADMIN_USERS.format(**params_path),
  106. data=json.dumps(data))
  107. create_resp = raise_error_from_response(data_raw, KeycloakGetError, expected_code=201, skip_exists=skip_exists)
  108. if password is not None:
  109. user_id = self.get_user_id(username)
  110. data={}
  111. data["value"]=password
  112. data["type"]="password"
  113. data["temporary"]=passwordTemp
  114. params_path = {"realm-name": self.realm_name, "id": user_id}
  115. data_raw = self.connection.raw_put(URL_ADMIN_USER_PASSWORD.format(**params_path),
  116. data=json.dumps(data))
  117. return raise_error_from_response(data_raw, KeycloakGetError, expected_code=204)
  118. else:
  119. return create_resp
  120. def users_count(self):
  121. """
  122. User counter
  123. :return: counter
  124. """
  125. params_path = {"realm-name": self.realm_name}
  126. data_raw = self.connection.raw_get(URL_ADMIN_USERS_COUNT.format(**params_path))
  127. return raise_error_from_response(data_raw, KeycloakGetError)
  128. def get_user_id(self, username):
  129. """
  130. Get internal keycloak user id from username
  131. This is required for further actions against this user.
  132. :param username:
  133. clientId in UserRepresentation
  134. http://www.keycloak.org/docs-api/3.3/rest-api/index.html#_userrepresentation
  135. :return: user_id
  136. """
  137. params_path = {"realm-name": self.realm_name, "username": username}
  138. data_raw = self.connection.raw_get(URL_ADMIN_USERS.format(**params_path))
  139. data_content = raise_error_from_response(data_raw, KeycloakGetError)
  140. for user in data_content:
  141. thisusername = json.dumps(user["username"]).strip('"')
  142. if thisusername == username:
  143. return json.dumps(user["id"]).strip('"')
  144. return None
  145. def get_user(self, user_id):
  146. """
  147. Get representation of the user
  148. :param user_id: User id
  149. UserRepresentation: http://www.keycloak.org/docs-api/3.3/rest-api/index.html#_userrepresentation
  150. :return: UserRepresentation
  151. """
  152. params_path = {"realm-name": self.realm_name, "id": user_id}
  153. data_raw = self.connection.raw_get(URL_ADMIN_USER.format(**params_path))
  154. return raise_error_from_response(data_raw, KeycloakGetError)
  155. def update_user(self, user_id, username, email='', firstName='', lastName='', emailVerified=False, enabled=True, password=None, passwordTemp=False):
  156. """
  157. Update the user
  158. :param user_id: User id
  159. :param data: UserRepresentation
  160. :return: Http response
  161. """
  162. data={}
  163. data["username"]=username
  164. data["email"]=email
  165. data["firstName"]=firstName
  166. data["lastName"]=lastName
  167. data["emailVerified"]=emailVerified
  168. data["enabled"]=enabled
  169. params_path = {"realm-name": self.realm_name, "id": user_id}
  170. data_raw = self.connection.raw_put(URL_ADMIN_USER.format(**params_path),
  171. data=json.dumps(data))
  172. update_resp = raise_error_from_response(data_raw, KeycloakGetError, expected_code=204)
  173. if password is not None:
  174. user_id = self.get_user_id(username)
  175. data={}
  176. data["value"]=password
  177. data["type"]="password"
  178. data["temporary"]=passwordTemp
  179. params_path = {"realm-name": self.realm_name, "id": user_id}
  180. data_raw = self.connection.raw_put(URL_ADMIN_USER_PASSWORD.format(**params_path),
  181. data=json.dumps(data))
  182. return raise_error_from_response(data_raw, KeycloakGetError, expected_code=204)
  183. else:
  184. return update_resp
  185. def delete_user(self, user_id):
  186. """
  187. Delete the user
  188. :param user_id: User id
  189. :return: Http response
  190. """
  191. params_path = {"realm-name": self.realm_name, "id": user_id}
  192. data_raw = self.connection.raw_delete(URL_ADMIN_USER.format(**params_path))
  193. return raise_error_from_response(data_raw, KeycloakGetError, expected_code=204)
  194. def consents_user(self, user_id):
  195. """
  196. Get consents granted by the user
  197. :param user_id: User id
  198. :return: consents
  199. """
  200. params_path = {"realm-name": self.realm_name, "id": user_id}
  201. data_raw = self.connection.raw_get(URL_ADMIN_USER_CONSENTS.format(**params_path))
  202. return raise_error_from_response(data_raw, KeycloakGetError)
  203. def send_update_account(self, user_id, payload, client_id=None, lifespan=None, redirect_uri=None):
  204. """
  205. Send a update account email to the user An email contains a
  206. link the user can click to perform a set of required actions.
  207. :param user_id:
  208. :param payload:
  209. :param client_id:
  210. :param lifespan:
  211. :param redirect_uri:
  212. :return:
  213. """
  214. params_path = {"realm-name": self.realm_name, "id": user_id}
  215. params_query = {"client_id": client_id, "lifespan": lifespan, "redirect_uri": redirect_uri}
  216. data_raw = self.connection.raw_put(URL_ADMIN_SEND_UPDATE_ACCOUNT.format(**params_path),
  217. data=payload, **params_query)
  218. return raise_error_from_response(data_raw, KeycloakGetError)
  219. def send_verify_email(self, user_id, client_id=None, redirect_uri=None):
  220. """
  221. Send a update account email to the user An email contains a
  222. link the user can click to perform a set of required actions.
  223. :param user_id: User id
  224. :param client_id: Client id
  225. :param redirect_uri: Redirect uri
  226. :return:
  227. """
  228. params_path = {"realm-name": self.realm_name, "id": user_id}
  229. params_query = {"client_id": client_id, "redirect_uri": redirect_uri}
  230. data_raw = self.connection.raw_put(URL_ADMIN_SEND_VERIFY_EMAIL.format(**params_path),
  231. data={}, **params_query)
  232. return raise_error_from_response(data_raw, KeycloakGetError)
  233. def get_sessions(self, user_id):
  234. """
  235. Get sessions associated with the user
  236. :param user_id: id of user
  237. UserSessionRepresentation
  238. http://www.keycloak.org/docs-api/3.3/rest-api/index.html#_usersessionrepresentation
  239. :return: UserSessionRepresentation
  240. """
  241. params_path = {"realm-name": self.realm_name, "id": user_id}
  242. data_raw = self.connection.raw_get(URL_ADMIN_GET_SESSIONS.format(**params_path))
  243. return raise_error_from_response(data_raw, KeycloakGetError)
  244. def get_server_info(self):
  245. """
  246. Get themes, social providers, auth providers, and event listeners available on this server
  247. ServerInfoRepresentation
  248. http://www.keycloak.org/docs-api/3.3/rest-api/index.html#_serverinforepresentation
  249. :return: ServerInfoRepresentation
  250. """
  251. data_raw = self.connection.raw_get(URL_ADMIN_SERVER_INFO)
  252. return raise_error_from_response(data_raw, KeycloakGetError)
  253. def get_groups(self):
  254. """
  255. Get groups belonging to the realm. Returns a list of groups belonging to the realm
  256. GroupRepresentation
  257. http://www.keycloak.org/docs-api/3.2/rest-api/#_grouprepresentation
  258. :return: array GroupRepresentation
  259. """
  260. params_path = {"realm-name": self.realm_name}
  261. data_raw = self.connection.raw_get(URL_ADMIN_GROUPS.format(**params_path))
  262. return raise_error_from_response(data_raw, KeycloakGetError)
  263. def get_group(self, group_id):
  264. """
  265. Get group by id. Returns full group details
  266. GroupRepresentation
  267. http://www.keycloak.org/docs-api/3.2/rest-api/#_grouprepresentation
  268. :return: array GroupRepresentation
  269. """
  270. params_path = {"realm-name": self.realm_name, "id": group_id}
  271. data_raw = self.connection.raw_get(URL_ADMIN_GROUP.format(**params_path))
  272. return raise_error_from_response(data_raw, KeycloakGetError)
  273. def get_group_id(self, name=None, path=None, parent=None):
  274. """
  275. Get group id based on name or path.
  276. A straight name or path match with a top-level group will return first.
  277. Subgroups are traversed, the first to match path (or name with path) is returned.
  278. :param name: group name
  279. :param path: group path
  280. :param parent: parent group's id. Required to find a sub-group below level 1.
  281. GroupRepresentation
  282. http://www.keycloak.org/docs-api/3.2/rest-api/#_grouprepresentation
  283. :return: GroupID (string)
  284. """
  285. if parent is not None:
  286. params_path = {"realm-name": self.realm_name, "id": parent}
  287. data_raw = self.connection.raw_get(URL_ADMIN_GROUP.format(**params_path))
  288. res = raise_error_from_response(data_raw, KeycloakGetError)
  289. data_content = []
  290. data_content.append(res)
  291. else:
  292. params_path = {"realm-name": self.realm_name}
  293. data_raw = self.connection.raw_get(URL_ADMIN_GROUPS.format(**params_path))
  294. data_content = raise_error_from_response(data_raw, KeycloakGetError)
  295. for group in data_content:
  296. thisgroupname = json.dumps(group["name"]).strip('"')
  297. thisgrouppath = json.dumps(group["path"]).strip('"')
  298. if (thisgroupname == name and name is not None) or (thisgrouppath == path and path is not None):
  299. return json.dumps(group["id"]).strip('"')
  300. for subgroup in group["subGroups"]:
  301. thisgrouppath = json.dumps(subgroup["path"]).strip('"')
  302. if (thisgrouppath == path and path is not None) or (thisgrouppath == name and name is not None):
  303. return json.dumps(subgroup["id"]).strip('"')
  304. return None
  305. def create_group(self, name=None, client_roles={}, realm_roles=[], sub_groups=[], path=None, parent=None, skip_exists=False):
  306. """
  307. Creates a group in the Realm
  308. :param name: group name
  309. :param client_roles (map): Client roles to include in groupp # Not demonstrated to work
  310. :param realm_roles (array): Realm roles to include in group # Not demonstrated to work
  311. :param sub_groups (array): Subgroups to include in groupp # Not demonstrated to work
  312. :param path: group path
  313. :param parent: parent group's id. Required to create a sub-group.
  314. GroupRepresentation
  315. http://www.keycloak.org/docs-api/3.2/rest-api/#_grouprepresentation
  316. :return: Http response
  317. """
  318. if name is None and path is not None:
  319. name=path
  320. data={}
  321. data["name"]=name
  322. data["path"]=path
  323. data["clientRoles"]=client_roles
  324. data["realmRoles"]=realm_roles
  325. data["subGroups"]=sub_groups
  326. if name is not None:
  327. exists = self.get_group_id(name=name, parent=parent)
  328. elif path is not None:
  329. exists = self.get_group_id(path=path, parent=parent)
  330. if exists is not None:
  331. return str(exists)
  332. if parent is None:
  333. params_path = {"realm-name": self.realm_name}
  334. data_raw = self.connection.raw_post(URL_ADMIN_GROUPS.format(**params_path),
  335. data=json.dumps(data))
  336. else:
  337. params_path = {"realm-name": self.realm_name, "id": parent,}
  338. data_raw = self.connection.raw_post(URL_ADMIN_GROUP_CHILD.format(**params_path),
  339. data=json.dumps(data))
  340. return raise_error_from_response(data_raw, KeycloakGetError, expected_code=201, skip_exists=skip_exists)
  341. def group_set_permissions(self, group_id, enabled=True):
  342. """
  343. Enable/Disable permissions for a group. Cannot delete group if disabled
  344. :param group_id: id of group
  345. :param enabled: boolean
  346. :return: {}
  347. """
  348. data={}
  349. data["enabled"]=enabled
  350. params_path = {"realm-name": self.realm_name, "id": group_id}
  351. data_raw = self.connection.raw_put(URL_ADMIN_GROUP_PERMISSIONS.format(**params_path),
  352. data=json.dumps(data))
  353. return raise_error_from_response(data_raw, KeycloakGetError)
  354. def group_user_add(self, user_id, group_id):
  355. """
  356. Add user to group (user_id and group_id)
  357. :param group_id: id of group
  358. :param user_id: id of user
  359. :param group_id: id of group to add to
  360. :return: {}
  361. """
  362. data={}
  363. data["realm"]=self.realm_name
  364. data["userId"]=user_id
  365. data["groupId"]=group_id
  366. params_path = {"realm-name": self.realm_name, "id": user_id, "group-id": group_id}
  367. data_raw = self.connection.raw_put(URL_ADMIN_USER_GROUP.format(**params_path),
  368. data=json.dumps(data))
  369. return raise_error_from_response(data_raw, KeycloakGetError, expected_code=204)
  370. def group_user_remove(self, user_id, group_id):
  371. """
  372. Remove user from group (user_id and group_id)
  373. :param group_id: id of group
  374. :param user_id: id of user
  375. :param group_id: id of group to add to
  376. :return: {}
  377. """
  378. params_path = {"realm-name": self.realm_name, "id": user_id, "group-id": group_id}
  379. data_raw = self.connection.raw_delete(URL_ADMIN_USER_GROUP.format(**params_path))
  380. return raise_error_from_response(data_raw, KeycloakGetError, expected_code=204)
  381. def delete_group(self, group_id):
  382. """
  383. Deletes a group in the Realm
  384. :param group_id: id of group to delete
  385. :return: Http response
  386. """
  387. params_path = {"realm-name": self.realm_name, "id": group_id}
  388. data_raw = self.connection.raw_delete(URL_ADMIN_GROUP.format(**params_path))
  389. return raise_error_from_response(data_raw, KeycloakGetError, expected_code=204)
  390. def get_clients(self):
  391. """
  392. Get clients belonging to the realm Returns a list of clients belonging to the realm
  393. ClientRepresentation
  394. http://www.keycloak.org/docs-api/3.3/rest-api/index.html#_clientrepresentation
  395. :return: ClientRepresentation
  396. """
  397. params_path = {"realm-name": self.realm_name}
  398. data_raw = self.connection.raw_get(URL_ADMIN_CLIENTS.format(**params_path))
  399. return raise_error_from_response(data_raw, KeycloakGetError)
  400. def get_client_id(self, client_id_name):
  401. """
  402. Get internal keycloak client id from client-id.
  403. This is required for further actions against this client.
  404. :param client_id_name: name in ClientRepresentation
  405. http://www.keycloak.org/docs-api/3.3/rest-api/index.html#_clientrepresentation
  406. :return: client_id (uuid as string)
  407. """
  408. params_path = {"realm-name": self.realm_name, "clientId": client_id_name}
  409. data_raw = self.connection.raw_get(URL_ADMIN_CLIENTS.format(**params_path))
  410. data_content = raise_error_from_response(data_raw, KeycloakGetError)
  411. for client in data_content:
  412. client_id = json.dumps(client["clientId"]).strip('"')
  413. if client_id == client_id_name:
  414. return json.dumps(client["id"]).strip('"')
  415. return None
  416. def get_client(self, client_id):
  417. """
  418. Get representation of the client
  419. ClientRepresentation
  420. http://www.keycloak.org/docs-api/3.3/rest-api/index.html#_clientrepresentation
  421. :param client_id: id of client (not client-id)
  422. :return: ClientRepresentation
  423. """
  424. params_path = {"realm-name": self.realm_name, "id": client_id}
  425. data_raw = self.connection.raw_get(URL_ADMIN_CLIENT.format(**params_path))
  426. return raise_error_from_response(data_raw, KeycloakGetError)
  427. def create_client(self, name, client_id, redirect_uris, protocol="openid-connect", public_client=True, direct_access_grants=True, skip_exists=False):
  428. """
  429. Create a client
  430. :param name: name of client
  431. :param client_id: (oauth client-id)
  432. :param redirect_uris: Valid edirect URIs
  433. :param redirect urls
  434. :param protocol: openid-connect or saml
  435. ClientRepresentation
  436. http://www.keycloak.org/docs-api/3.3/rest-api/index.html#_clientrepresentation
  437. """
  438. data={}
  439. data["name"]=name
  440. data["clientId"]=client_id
  441. data["redirectUris"]=redirect_uris
  442. data["protocol"]=protocol
  443. data["publicClient"]=public_client
  444. data["directAccessGrantsEnabled"]=direct_access_grants
  445. params_path = {"realm-name": self.realm_name}
  446. data_raw = self.connection.raw_post(URL_ADMIN_CLIENTS.format(**params_path),
  447. data=json.dumps(data))
  448. return raise_error_from_response(data_raw, KeycloakGetError, expected_code=201, skip_exists=skip_exists)
  449. def delete_client(self, client_id):
  450. """
  451. Get representation of the client
  452. ClientRepresentation
  453. http://www.keycloak.org/docs-api/3.3/rest-api/index.html#_clientrepresentation
  454. :param client_id: keycloak client id (not oauth client-id)
  455. :return: ClientRepresentation
  456. """
  457. params_path = {"realm-name": self.realm_name, "id": client_id}
  458. data_raw = self.connection.raw_delete(URL_ADMIN_CLIENT.format(**params_path))
  459. return raise_error_from_response(data_raw, KeycloakGetError, expected_code=204)
  460. def get_client_roles(self, client_id):
  461. """
  462. Get all roles for the client
  463. :param client_id: id of client (not client-id)
  464. RoleRepresentation
  465. http://www.keycloak.org/docs-api/3.3/rest-api/index.html#_rolerepresentation
  466. :return: RoleRepresentation
  467. """
  468. params_path = {"realm-name": self.realm_name, "id": client_id}
  469. data_raw = self.connection.raw_get(URL_ADMIN_CLIENT_ROLES.format(**params_path))
  470. return raise_error_from_response(data_raw, KeycloakGetError)
  471. def get_client_role_id(self, client_id, role_name):
  472. """
  473. Get client role id
  474. This is required for further actions with this role.
  475. :param client_id: id of client (not client-id), role_name: name of role
  476. RoleRepresentation
  477. http://www.keycloak.org/docs-api/3.3/rest-api/index.html#_rolerepresentation
  478. :return: role_id
  479. """
  480. params_path = {"realm-name": self.realm_name, "id": client_id}
  481. data_raw = self.connection.raw_get(URL_ADMIN_CLIENT_ROLES.format(**params_path))
  482. data_content = raise_error_from_response(data_raw, KeycloakGetError)
  483. for role in data_content:
  484. this_role_name = json.dumps(role["name"]).strip('"')
  485. if this_role_name == role_name:
  486. return json.dumps(role["id"]).strip('"')
  487. return None
  488. def get_roles(self):
  489. """
  490. Get all roles for the realm or client
  491. RoleRepresentation
  492. http://www.keycloak.org/docs-api/3.3/rest-api/index.html#_rolerepresentation
  493. :return: RoleRepresentation
  494. """
  495. params_path = {"realm-name": self.realm_name}
  496. data_raw = self.connection.raw_get(URL_ADMIN_REALM_ROLES.format(**params_path))
  497. return raise_error_from_response(data_raw, KeycloakGetError)
  498. def create_client_role(self, client_id, role_name, skip_exists=False):
  499. """
  500. Create a client role
  501. :param client_id: id of client (not client-id), role_name: name of role
  502. RoleRepresentation
  503. http://www.keycloak.org/docs-api/3.3/rest-api/index.html#_rolerepresentation
  504. """
  505. data={}
  506. data["name"]=role_name
  507. data["clientRole"]=True
  508. params_path = {"realm-name": self.realm_name, "id": client_id}
  509. data_raw = self.connection.raw_post(URL_ADMIN_CLIENT_ROLES.format(**params_path),
  510. data=json.dumps(data))
  511. return raise_error_from_response(data_raw, KeycloakGetError, expected_code=201, skip_exists=skip_exists)
  512. def delete_client_role(self, client_id, role_name):
  513. """
  514. Create a client role
  515. :param client_id: id of client (not client-id), role_name: name of role
  516. RoleRepresentation
  517. http://www.keycloak.org/docs-api/3.3/rest-api/index.html#_rolerepresentation
  518. """
  519. data={}
  520. data["name"]=role_name
  521. data["clientRole"]=True
  522. params_path = {"realm-name": self.realm_name, "id": client_id}
  523. data_raw = self.connection.raw_delete(URL_ADMIN_CLIENT_ROLES.format(**params_path) + "/" + role_name,
  524. data=json.dumps(data))
  525. return raise_error_from_response(data_raw, KeycloakGetError, expected_code=204)
  526. def assign_client_role(self, user_id, client_id, role_id, role_name):
  527. """
  528. Assign a client role to a user
  529. :param client_id: id of client (not client-id), user_id: id of user, client_id: id of client containing role, role_id: client role id, role_name: client role name)
  530. """
  531. payload=[{}]
  532. payload[0]["id"]=role_id
  533. payload[0]["name"]=role_name
  534. params_path = {"realm-name": self.realm_name, "id": user_id, "client-id": client_id}
  535. data_raw = self.connection.raw_post(URL_ADMIN_USER_CLIENT_ROLES.format(**params_path),
  536. data=json.dumps(payload))
  537. return raise_error_from_response(data_raw, KeycloakGetError, expected_code=204)