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.

283 lines
8.9 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: Boolean value to enable or disable certificate validation or a string
  40. containing a path to a CA bundle to use
  41. :type verify: Union[bool,str]
  42. :param proxies: The proxies servers requests is sent by.
  43. :type proxies: dict
  44. """
  45. def __init__(self, base_url, headers={}, timeout=60, verify=True, proxies=None):
  46. """Init method.
  47. :param base_url: The server URL.
  48. :type base_url: str
  49. :param headers: The header parameters of the requests to the server.
  50. :type headers: dict
  51. :param timeout: Timeout to use for requests to the server.
  52. :type timeout: int
  53. :param verify: Boolean value to enable or disable certificate validation or a string
  54. containing a path to a CA bundle to use
  55. :type verify: Union[bool,str]
  56. :param proxies: The proxies servers requests is sent by.
  57. :type proxies: dict
  58. """
  59. self.base_url = base_url
  60. self.headers = headers
  61. self.timeout = timeout
  62. self.verify = verify
  63. self._s = requests.Session()
  64. self._s.auth = lambda x: x # don't let requests add auth headers
  65. # retry once to reset connection with Keycloak after tomcat's ConnectionTimeout
  66. # see https://github.com/marcospereirampj/python-keycloak/issues/36
  67. for protocol in ("https://", "http://"):
  68. adapter = HTTPAdapter(max_retries=1)
  69. # adds POST to retry whitelist
  70. allowed_methods = set(adapter.max_retries.allowed_methods)
  71. allowed_methods.add("POST")
  72. adapter.max_retries.allowed_methods = frozenset(allowed_methods)
  73. self._s.mount(protocol, adapter)
  74. if proxies:
  75. self._s.proxies.update(proxies)
  76. def __del__(self):
  77. """Del method."""
  78. if hasattr(self, "_s"):
  79. self._s.close()
  80. @property
  81. def base_url(self):
  82. """Return base url in use for requests to the server.
  83. :returns: Base URL
  84. :rtype: str
  85. """
  86. return self._base_url
  87. @base_url.setter
  88. def base_url(self, value):
  89. self._base_url = value
  90. @property
  91. def timeout(self):
  92. """Return timeout in use for request to the server.
  93. :returns: Timeout
  94. :rtype: int
  95. """
  96. return self._timeout
  97. @timeout.setter
  98. def timeout(self, value):
  99. self._timeout = value
  100. @property
  101. def verify(self):
  102. """Return verify in use for request to the server.
  103. :returns: Verify indicator
  104. :rtype: bool
  105. """
  106. return self._verify
  107. @verify.setter
  108. def verify(self, value):
  109. self._verify = value
  110. @property
  111. def headers(self):
  112. """Return header request to the server.
  113. :returns: Request headers
  114. :rtype: dict
  115. """
  116. return self._headers
  117. @headers.setter
  118. def headers(self, value):
  119. self._headers = value
  120. def param_headers(self, key):
  121. """Return a specific header parameter.
  122. :param key: Header parameters key.
  123. :type key: str
  124. :returns: If the header parameters exist, return its value.
  125. :rtype: str
  126. """
  127. return self.headers.get(key)
  128. def clean_headers(self):
  129. """Clear header parameters."""
  130. self.headers = {}
  131. def exist_param_headers(self, key):
  132. """Check if the parameter exists in the header.
  133. :param key: Header parameters key.
  134. :type key: str
  135. :returns: If the header parameters exist, return True.
  136. :rtype: bool
  137. """
  138. return self.param_headers(key) is not None
  139. def add_param_headers(self, key, value):
  140. """Add a single parameter inside the header.
  141. :param key: Header parameters key.
  142. :type key: str
  143. :param value: Value to be added.
  144. :type value: str
  145. """
  146. self.headers[key] = value
  147. def del_param_headers(self, key):
  148. """Remove a specific parameter.
  149. :param key: Key of the header parameters.
  150. :type key: str
  151. """
  152. self.headers.pop(key, None)
  153. def raw_get(self, path, **kwargs):
  154. """Submit get request to the path.
  155. :param path: Path for request.
  156. :type path: str
  157. :param kwargs: Additional arguments
  158. :type kwargs: dict
  159. :returns: Response the request.
  160. :rtype: Response
  161. :raises KeycloakConnectionError: HttpError Can't connect to server.
  162. """
  163. try:
  164. return self._s.get(
  165. urljoin(self.base_url, path),
  166. params=kwargs,
  167. headers=self.headers,
  168. timeout=self.timeout,
  169. verify=self.verify,
  170. )
  171. except Exception as e:
  172. raise KeycloakConnectionError("Can't connect to server (%s)" % e)
  173. def raw_post(self, path, data, **kwargs):
  174. """Submit post request to the path.
  175. :param path: Path for request.
  176. :type path: str
  177. :param data: Payload for request.
  178. :type data: dict
  179. :param kwargs: Additional arguments
  180. :type kwargs: dict
  181. :returns: Response the request.
  182. :rtype: Response
  183. :raises KeycloakConnectionError: HttpError Can't connect to server.
  184. """
  185. try:
  186. return self._s.post(
  187. urljoin(self.base_url, path),
  188. params=kwargs,
  189. data=data,
  190. headers=self.headers,
  191. timeout=self.timeout,
  192. verify=self.verify,
  193. )
  194. except Exception as e:
  195. raise KeycloakConnectionError("Can't connect to server (%s)" % e)
  196. def raw_put(self, path, data, **kwargs):
  197. """Submit put request to the path.
  198. :param path: Path for request.
  199. :type path: str
  200. :param data: Payload for request.
  201. :type data: dict
  202. :param kwargs: Additional arguments
  203. :type kwargs: dict
  204. :returns: Response the request.
  205. :rtype: Response
  206. :raises KeycloakConnectionError: HttpError Can't connect to server.
  207. """
  208. try:
  209. return self._s.put(
  210. urljoin(self.base_url, path),
  211. params=kwargs,
  212. data=data,
  213. headers=self.headers,
  214. timeout=self.timeout,
  215. verify=self.verify,
  216. )
  217. except Exception as e:
  218. raise KeycloakConnectionError("Can't connect to server (%s)" % e)
  219. def raw_delete(self, path, data=None, **kwargs):
  220. """Submit delete request to the path.
  221. :param path: Path for request.
  222. :type path: str
  223. :param data: Payload for request.
  224. :type data: dict | None
  225. :param kwargs: Additional arguments
  226. :type kwargs: dict
  227. :returns: Response the request.
  228. :rtype: Response
  229. :raises KeycloakConnectionError: HttpError Can't connect to server.
  230. """
  231. try:
  232. return self._s.delete(
  233. urljoin(self.base_url, path),
  234. params=kwargs,
  235. data=data or dict(),
  236. headers=self.headers,
  237. timeout=self.timeout,
  238. verify=self.verify,
  239. )
  240. except Exception as e:
  241. raise KeycloakConnectionError("Can't connect to server (%s)" % e)