Marcos Pereira
7 years ago
7 changed files with 286 additions and 0 deletions
-
3.gitignore
-
35keycloak/__init__.py
-
139keycloak/connection.py
-
105keycloak/exceptions.py
-
0keycloak/tests/__init__.py
-
3keycloak/urls_patterns.py
-
1requirements.txt
@ -0,0 +1,35 @@ |
|||
""" |
|||
|
|||
""" |
|||
|
|||
import json |
|||
|
|||
from keycloak.exceptions import raise_error_from_response, KeycloakGetError |
|||
from .connection import ConnectionManager |
|||
from .urls_patterns import URL_WELL_KNOWN |
|||
|
|||
|
|||
class Keycloak: |
|||
|
|||
def __init__(self, server_url, client_id, realm_name, client_secret_key=None): |
|||
self.__client_id = client_id |
|||
self.__client_secret_key = client_secret_key |
|||
self.__realm_name = realm_name |
|||
|
|||
self.__connection = ConnectionManager(base_url=server_url, |
|||
headers={}, |
|||
timeout=60) |
|||
|
|||
def get_well_know(self): |
|||
params = {"realm-name": self.__realm_name} |
|||
data_raw = self.__connection.raw_get(URL_WELL_KNOWN.format(**params)) |
|||
raise_error_from_response(data_raw, KeycloakGetError) |
|||
return json.loads(data_raw.text) |
|||
|
|||
def auth(self): |
|||
""" |
|||
|
|||
http://openid.net/specs/openid-connect-core-1_0.html#AuthorizationEndpoint |
|||
|
|||
:return: |
|||
""" |
@ -0,0 +1,139 @@ |
|||
""" |
|||
|
|||
""" |
|||
|
|||
import requests |
|||
from urllib.parse import urljoin |
|||
from .exceptions import * |
|||
|
|||
|
|||
class ConnectionManager(object): |
|||
""" Represents a simple server connection. |
|||
Args: |
|||
base_url (str): The URL server |
|||
headers (dict): The header parameters of the requests to the server. |
|||
timeout (int): Timeout to use for requests to the server. |
|||
""" |
|||
|
|||
def __init__(self, base_url, headers={}, timeout=60): |
|||
self.__base_url = base_url |
|||
self.__headers = headers |
|||
self.__timeout = timeout |
|||
|
|||
def get_url(self): |
|||
""" Return base url in use for requests to the server. """ |
|||
return self.__base_url |
|||
|
|||
def get_timeout(self): |
|||
""" Return timeout in use for request to the server. """ |
|||
return self.__timeout |
|||
|
|||
def set_headers(self, params): |
|||
""" Update header request to the server. |
|||
:arg |
|||
params (dict): Parameters header request. |
|||
""" |
|||
self.__headers = params |
|||
|
|||
def get_headers(self): |
|||
""" Return header request to the server. """ |
|||
return self.__headers |
|||
|
|||
def get_param_headers(self, key): |
|||
""" Return a single header parameter. |
|||
:arg |
|||
key (str): Key of the header parameters. |
|||
:return: |
|||
If the header parameters exist, return value him. |
|||
""" |
|||
return self.__headers[key] if key in self.__headers.keys() else None |
|||
|
|||
def clean_headers(self): |
|||
""" Clear header parameters. """ |
|||
self.__headers = {} |
|||
|
|||
def exist_param_headers(self, key): |
|||
""" Check if the parameter exist in header. |
|||
:arg |
|||
key (str): Key of the header parameters. |
|||
:return: |
|||
If the header parameters exist, return True. |
|||
""" |
|||
return True if self.get_param_headers(key) else False |
|||
|
|||
def add_param_headers(self, key, value): |
|||
""" Add a single parameter in header. |
|||
:arg |
|||
key (str): Key of the header parameters. |
|||
value (str): Value for the header parameter. |
|||
""" |
|||
request_headers = self.__headers.copy() |
|||
request_headers.update({key: value}) |
|||
self.set_headers(request_headers) |
|||
|
|||
def del_param_headers(self, key): |
|||
""" Remove a single header parameter. |
|||
:arg |
|||
key (str): Key of the header parameters. |
|||
""" |
|||
if self.get_param_headers(key): |
|||
del self.__headers[key] |
|||
|
|||
def raw_get(self, path, **kwargs): |
|||
""" Submit get request to the path. |
|||
:arg |
|||
path (str): Path for request. |
|||
:return |
|||
Response the request. |
|||
:exception |
|||
HttpError: Can't connect to server. |
|||
""" |
|||
|
|||
try: |
|||
return requests.get(urljoin(self.get_url(), path), |
|||
params=kwargs, |
|||
headers=self.get_headers(), |
|||
timeout=self.get_timeout()) |
|||
except Exception as e: |
|||
raise KeycloakConnectionError( |
|||
"Can't connect to server (%s)" % e) |
|||
|
|||
def raw_post(self, path, data, **kwargs): |
|||
""" Submit post request to the path. |
|||
:arg |
|||
path (str): Path for request. |
|||
data (dict): Payload for request. |
|||
:return |
|||
Response the request. |
|||
:exception |
|||
HttpError: Can't connect to server. |
|||
""" |
|||
try: |
|||
return requests.post(urljoin(self.get_url(), path), |
|||
params=kwargs, |
|||
data=data, |
|||
headers=self.get_headers(), |
|||
timeout=self.get_timeout()) |
|||
except Exception as e: |
|||
raise KeycloakConnectionError( |
|||
"Can't connect to server (%s)" % e) |
|||
|
|||
def raw_put(self, path, data, **kwargs): |
|||
""" Submit put request to the path. |
|||
:arg |
|||
path (str): Path for request. |
|||
data (dict): Payload for request. |
|||
:return |
|||
Response the request. |
|||
:exception |
|||
HttpError: Can't connect to server. |
|||
""" |
|||
try: |
|||
return requests.put(urljoin(self.get_url(), path), |
|||
params=kwargs, |
|||
data=data, |
|||
headers=self.get_headers(), |
|||
timeout=self.get_timeout()) |
|||
except Exception as e: |
|||
raise KeycloakConnectionError( |
|||
"Can't connect to server (%s)" % e) |
@ -0,0 +1,105 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# |
|||
# Copyright (C) 2017 Marcos Pereira <marcospereira.mpj@gmail.com> |
|||
# |
|||
# This program is free software: you can redistribute it and/or modify |
|||
# it under the terms of the GNU Lesser General Public License as published by |
|||
# the Free Software Foundation, either version 3 of the License, or |
|||
# (at your option) any later version. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU Lesser General Public License for more details. |
|||
# |
|||
# You should have received a copy of the GNU Lesser General Public License |
|||
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
|||
|
|||
|
|||
class KeycloakError(Exception): |
|||
def __init__(self, error_message="", response_code=None, |
|||
response_body=None): |
|||
|
|||
Exception.__init__(self, error_message) |
|||
|
|||
self.response_code = response_code |
|||
self.response_body = response_body |
|||
self.error_message = error_message |
|||
|
|||
def __str__(self): |
|||
if self.response_code is not None: |
|||
return "{0}: {1}".format(self.response_code, self.error_message) |
|||
else: |
|||
return "{0}".format(self.error_message) |
|||
|
|||
|
|||
class KeycloakAuthenticationError(KeycloakError): |
|||
pass |
|||
|
|||
|
|||
class KeycloakConnectionError(KeycloakError): |
|||
pass |
|||
|
|||
|
|||
class KeycloakOperationError(KeycloakError): |
|||
pass |
|||
|
|||
|
|||
class KeycloakListError(KeycloakOperationError): |
|||
pass |
|||
|
|||
|
|||
class KeycloakGetError(KeycloakOperationError): |
|||
pass |
|||
|
|||
|
|||
class KeycloakCreateError(KeycloakOperationError): |
|||
pass |
|||
|
|||
|
|||
class KeycloakUpdateError(KeycloakOperationError): |
|||
pass |
|||
|
|||
|
|||
class KeycloakDeleteError(KeycloakOperationError): |
|||
pass |
|||
|
|||
|
|||
class KeycloakProtectError(KeycloakOperationError): |
|||
pass |
|||
|
|||
|
|||
class KeycloakTransferProjectError(KeycloakOperationError): |
|||
pass |
|||
|
|||
|
|||
class KeycloakBuildCancelError(KeycloakOperationError): |
|||
pass |
|||
|
|||
|
|||
class KeycloakBuildRetryError(KeycloakOperationError): |
|||
pass |
|||
|
|||
|
|||
class KeycloakBlockError(KeycloakOperationError): |
|||
pass |
|||
|
|||
|
|||
def raise_error_from_response(response, error, expected_code=200): |
|||
if expected_code == response.status_code: |
|||
return response.json() |
|||
|
|||
try: |
|||
message = response.json()['message'] |
|||
except (KeyError, ValueError): |
|||
message = response.content |
|||
|
|||
if isinstance(error, dict): |
|||
error = error.get(response.status_code, KeycloakOperationError) |
|||
else: |
|||
if response.status_code == 401: |
|||
error = KeycloakAuthenticationError |
|||
|
|||
raise error(error_message=message, |
|||
response_code=response.status_code, |
|||
response_body=response.content) |
@ -0,0 +1,3 @@ |
|||
|
|||
URL_WELL_KNOWN = "realms/{realm-name}/.well-known/openid-configuration" |
|||
URL_WELL_KNOWN = "realms/{realm-name}/protocol/openid-connect/auth" |
@ -0,0 +1 @@ |
|||
requests==2.18.3 |
Write
Preview
Loading…
Cancel
Save
Reference in new issue