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.

280 lines
8.7 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
6 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
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. # The MIT License (MIT)
  4. #
  5. # Copyright (C) 2017 Marcos Pereira <marcospereira.mpj@gmail.com>
  6. #
  7. # Permission is hereby granted, free of charge, to any person obtaining a copy of
  8. # this software and associated documentation files (the "Software"), to deal in
  9. # the Software without restriction, including without limitation the rights to
  10. # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  11. # the Software, and to permit persons to whom the Software is furnished to do so,
  12. # subject to the following conditions:
  13. #
  14. # The above copyright notice and this permission notice shall be included in all
  15. # copies or substantial portions of the Software.
  16. #
  17. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  19. # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  20. # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  21. # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  22. # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  23. """Connection manager module."""
  24. try:
  25. from urllib.parse import urljoin
  26. except ImportError: # pragma: no cover
  27. from urlparse import urljoin
  28. import requests
  29. from requests.adapters import HTTPAdapter
  30. from .exceptions import KeycloakConnectionError
  31. class ConnectionManager(object):
  32. """Represents a simple server connection.
  33. :param base_url: The server URL.
  34. :type base_url: str
  35. :param headers: The header parameters of the requests to the server.
  36. :type headers: dict
  37. :param timeout: Timeout to use for requests to the server.
  38. :type timeout: int
  39. :param verify: Verify server SSL.
  40. :type verify: bool
  41. :param proxies: The proxies servers requests is sent by.
  42. :type proxies: dict
  43. """
  44. def __init__(self, base_url, headers={}, timeout=60, verify=True, proxies=None):
  45. """Init method.
  46. :param base_url: The server URL.
  47. :type base_url: str
  48. :param headers: The header parameters of the requests to the server.
  49. :type headers: dict
  50. :param timeout: Timeout to use for requests to the server.
  51. :type timeout: int
  52. :param verify: Verify server SSL.
  53. :type verify: bool
  54. :param proxies: The proxies servers requests is sent by.
  55. :type proxies: dict
  56. """
  57. self.base_url = base_url
  58. self.headers = headers
  59. self.timeout = timeout
  60. self.verify = verify
  61. self._s = requests.Session()
  62. self._s.auth = lambda x: x # don't let requests add auth headers
  63. # retry once to reset connection with Keycloak after tomcat's ConnectionTimeout
  64. # see https://github.com/marcospereirampj/python-keycloak/issues/36
  65. for protocol in ("https://", "http://"):
  66. adapter = HTTPAdapter(max_retries=1)
  67. # adds POST to retry whitelist
  68. allowed_methods = set(adapter.max_retries.allowed_methods)
  69. allowed_methods.add("POST")
  70. adapter.max_retries.allowed_methods = frozenset(allowed_methods)
  71. self._s.mount(protocol, adapter)
  72. if proxies:
  73. self._s.proxies.update(proxies)
  74. def __del__(self):
  75. """Del method."""
  76. self._s.close()
  77. @property
  78. def base_url(self):
  79. """Return base url in use for requests to the server.
  80. :returns: Base URL
  81. :rtype: str
  82. """
  83. return self._base_url
  84. @base_url.setter
  85. def base_url(self, value):
  86. self._base_url = value
  87. @property
  88. def timeout(self):
  89. """Return timeout in use for request to the server.
  90. :returns: Timeout
  91. :rtype: int
  92. """
  93. return self._timeout
  94. @timeout.setter
  95. def timeout(self, value):
  96. self._timeout = value
  97. @property
  98. def verify(self):
  99. """Return verify in use for request to the server.
  100. :returns: Verify indicator
  101. :rtype: bool
  102. """
  103. return self._verify
  104. @verify.setter
  105. def verify(self, value):
  106. self._verify = value
  107. @property
  108. def headers(self):
  109. """Return header request to the server.
  110. :returns: Request headers
  111. :rtype: dict
  112. """
  113. return self._headers
  114. @headers.setter
  115. def headers(self, value):
  116. self._headers = value
  117. def param_headers(self, key):
  118. """Return a specific header parameter.
  119. :param key: Header parameters key.
  120. :type key: str
  121. :returns: If the header parameters exist, return its value.
  122. :rtype: str
  123. """
  124. return self.headers.get(key)
  125. def clean_headers(self):
  126. """Clear header parameters."""
  127. self.headers = {}
  128. def exist_param_headers(self, key):
  129. """Check if the parameter exists in the header.
  130. :param key: Header parameters key.
  131. :type key: str
  132. :returns: If the header parameters exist, return True.
  133. :rtype: bool
  134. """
  135. return self.param_headers(key) is not None
  136. def add_param_headers(self, key, value):
  137. """Add a single parameter inside the header.
  138. :param key: Header parameters key.
  139. :type key: str
  140. :param value: Value to be added.
  141. :type value: str
  142. """
  143. self.headers[key] = value
  144. def del_param_headers(self, key):
  145. """Remove a specific parameter.
  146. :param key: Key of the header parameters.
  147. :type key: str
  148. """
  149. self.headers.pop(key, None)
  150. def raw_get(self, path, **kwargs):
  151. """Submit get request to the path.
  152. :param path: Path for request.
  153. :type path: str
  154. :param kwargs: Additional arguments
  155. :type kwargs: dict
  156. :returns: Response the request.
  157. :rtype: Response
  158. :raises KeycloakConnectionError: HttpError Can't connect to server.
  159. """
  160. try:
  161. return self._s.get(
  162. urljoin(self.base_url, path),
  163. params=kwargs,
  164. headers=self.headers,
  165. timeout=self.timeout,
  166. verify=self.verify,
  167. )
  168. except Exception as e:
  169. raise KeycloakConnectionError("Can't connect to server (%s)" % e)
  170. def raw_post(self, path, data, **kwargs):
  171. """Submit post request to the path.
  172. :param path: Path for request.
  173. :type path: str
  174. :param data: Payload for request.
  175. :type data: dict
  176. :param kwargs: Additional arguments
  177. :type kwargs: dict
  178. :returns: Response the request.
  179. :rtype: Response
  180. :raises KeycloakConnectionError: HttpError Can't connect to server.
  181. """
  182. try:
  183. return self._s.post(
  184. urljoin(self.base_url, path),
  185. params=kwargs,
  186. data=data,
  187. headers=self.headers,
  188. timeout=self.timeout,
  189. verify=self.verify,
  190. )
  191. except Exception as e:
  192. raise KeycloakConnectionError("Can't connect to server (%s)" % e)
  193. def raw_put(self, path, data, **kwargs):
  194. """Submit put request to the path.
  195. :param path: Path for request.
  196. :type path: str
  197. :param data: Payload for request.
  198. :type data: dict
  199. :param kwargs: Additional arguments
  200. :type kwargs: dict
  201. :returns: Response the request.
  202. :rtype: Response
  203. :raises KeycloakConnectionError: HttpError Can't connect to server.
  204. """
  205. try:
  206. return self._s.put(
  207. urljoin(self.base_url, path),
  208. params=kwargs,
  209. data=data,
  210. headers=self.headers,
  211. timeout=self.timeout,
  212. verify=self.verify,
  213. )
  214. except Exception as e:
  215. raise KeycloakConnectionError("Can't connect to server (%s)" % e)
  216. def raw_delete(self, path, data=None, **kwargs):
  217. """Submit delete request to the path.
  218. :param path: Path for request.
  219. :type path: str
  220. :param data: Payload for request.
  221. :type data: dict | None
  222. :param kwargs: Additional arguments
  223. :type kwargs: dict
  224. :returns: Response the request.
  225. :rtype: Response
  226. :raises KeycloakConnectionError: HttpError Can't connect to server.
  227. """
  228. try:
  229. return self._s.delete(
  230. urljoin(self.base_url, path),
  231. params=kwargs,
  232. data=data or dict(),
  233. headers=self.headers,
  234. timeout=self.timeout,
  235. verify=self.verify,
  236. )
  237. except Exception as e:
  238. raise KeycloakConnectionError("Can't connect to server (%s)" % e)