Skip to content

Commit ad5e7a9

Browse files
Merge branch 'master' into patch-1
2 parents bf30c0a + 1a46182 commit ad5e7a9

File tree

4 files changed

+99
-7
lines changed

4 files changed

+99
-7
lines changed

docs/source/index.rst

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,14 @@ Main methods::
9292
client_secret_key="secret",
9393
verify=True)
9494

95+
# Optionally, you can pass custom headers that will be added to all HTTP calls
96+
# keycloak_openid = KeycloakOpenID(server_url="http://localhost:8080/auth/",
97+
# client_id="example_client",
98+
# realm_name="example_realm",
99+
# client_secret_key="secret",
100+
# verify=True,
101+
# custom_headers={'CustomHeader': 'value'})
102+
95103
# Get WellKnow
96104
config_well_know = keycloak_openid.well_know()
97105

@@ -143,6 +151,14 @@ Main methods::
143151
realm_name="example_realm",
144152
verify=True)
145153

154+
# Optionally, you can pass custom headers that will be added to all HTTP calls
155+
#keycloak_admin = KeycloakAdmin(server_url="http://localhost:8080/auth/",
156+
# username='example-admin',
157+
# password='secret',
158+
# realm_name="example_realm",
159+
# verify=True,
160+
# custom_headers={'CustomHeader': 'value'})
161+
146162
# Add user
147163
new_user = keycloak_admin.create_user({"email": "[email protected]",
148164
"username": "[email protected]",

keycloak/keycloak_admin.py

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ class KeycloakAdmin:
4545

4646
PAGE_SIZE = 100
4747

48-
def __init__(self, server_url, username, password, realm_name='master', client_id='admin-cli', verify=True, client_secret_key=None, user_realm_name=None):
48+
def __init__(self, server_url, username, password, realm_name='master', client_id='admin-cli', verify=True,
49+
client_secret_key=None, custom_headers=None, user_realm_name=None):
4950
"""
5051
5152
:param server_url: Keycloak server url
@@ -55,6 +56,7 @@ def __init__(self, server_url, username, password, realm_name='master', client_i
5556
:param client_id: client id
5657
:param verify: True if want check connection SSL
5758
:param client_secret_key: client secret key
59+
:param custom_headers: dict of custom header to pass to each HTML request
5860
"""
5961
self._username = username
6062
self._password = password
@@ -63,15 +65,23 @@ def __init__(self, server_url, username, password, realm_name='master', client_i
6365

6466
# Get token Admin
6567
keycloak_openid = KeycloakOpenID(server_url=server_url, client_id=client_id, realm_name=user_realm_name or realm_name,
66-
verify=verify, client_secret_key=client_secret_key)
67-
68+
verify=verify, client_secret_key=client_secret_key,
69+
custom_headers=custom_headers)
70+
6871
grant_type = ["password"]
6972
if client_secret_key:
7073
grant_type = ["client_credentials"]
7174
self._token = keycloak_openid.token(username, password, grant_type=grant_type)
75+
headers = {
76+
'Authorization': 'Bearer ' + self.token.get('access_token'),
77+
'Content-Type': 'application/json'
78+
}
79+
if custom_headers is not None:
80+
# merge custom headers to main headers
81+
headers.update(custom_headers)
82+
7283
self._connection = ConnectionManager(base_url=server_url,
73-
headers={'Authorization': 'Bearer ' + self.token.get('access_token'),
74-
'Content-Type': 'application/json'},
84+
headers=headers,
7585
timeout=60,
7686
verify=verify)
7787

@@ -827,6 +837,21 @@ def assign_client_role(self, user_id, client_id, roles):
827837
data=json.dumps(payload))
828838
return raise_error_from_response(data_raw, KeycloakGetError, expected_code=204)
829839

840+
def create_realm_role(self, payload, skip_exists=False):
841+
"""
842+
Create a new role for the realm or client
843+
844+
:param realm: realm name (not id)
845+
:param rep: RoleRepresentation https://www.keycloak.org/docs-api/5.0/rest-api/index.html#_rolerepresentation
846+
:return Keycloak server response
847+
"""
848+
849+
params_path = {"realm-name": self.realm_name}
850+
data_raw = self.connection.raw_post(URL_ADMIN_REALM_ROLES.format(**params_path),
851+
data=json.dumps(payload))
852+
return raise_error_from_response(data_raw, KeycloakGetError, expected_code=201, skip_exists=skip_exists)
853+
854+
830855
def assign_realm_roles(self, user_id, client_id, roles):
831856
"""
832857
Assign realm roles to a user

keycloak/keycloak_openid.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,20 +43,25 @@
4343

4444
class KeycloakOpenID:
4545

46-
def __init__(self, server_url, realm_name, client_id, client_secret_key=None, verify=True):
46+
def __init__(self, server_url, realm_name, client_id, client_secret_key=None, verify=True, custom_headers=None):
4747
"""
4848
4949
:param server_url: Keycloak server url
5050
:param client_id: client id
5151
:param realm_name: realm name
5252
:param client_secret_key: client secret key
5353
:param verify: True if want check connection SSL
54+
:param custom_headers: dict of custom header to pass to each HTML request
5455
"""
5556
self._client_id = client_id
5657
self._client_secret_key = client_secret_key
5758
self._realm_name = realm_name
59+
headers = dict()
60+
if custom_headers is not None:
61+
# merge custom headers to main headers
62+
headers.update(custom_headers)
5863
self._connection = ConnectionManager(base_url=server_url,
59-
headers={},
64+
headers=headers,
6065
timeout=60,
6166
verify=verify)
6267

keycloak/tests/test_connection.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@
1414
#
1515
# You should have received a copy of the GNU Lesser General Public License
1616
# along with this program. If not, see <http://www.gnu.org/licenses/>.
17+
from unittest import mock
1718

1819
from httmock import urlmatch, response, HTTMock, all_requests
1920

21+
from keycloak import KeycloakAdmin, KeycloakOpenID
2022
from ..connection import ConnectionManager
2123

2224
try:
@@ -141,3 +143,47 @@ def test_get_headers(self):
141143
self._conn.add_param_headers("test", "value")
142144
self.assertEqual(self._conn.headers,
143145
{"test": "value"})
146+
147+
def test_KeycloakAdmin_custom_header(self):
148+
149+
class FakeToken:
150+
@staticmethod
151+
def get(string_val):
152+
return "faketoken"
153+
154+
fake_token = FakeToken()
155+
156+
with mock.patch.object(KeycloakOpenID, "__init__", return_value=None) as mock_keycloak_open_id:
157+
with mock.patch("keycloak.keycloak_openid.KeycloakOpenID.token", return_value=fake_token):
158+
with mock.patch("keycloak.connection.ConnectionManager.__init__", return_value=None) as mock_connection_manager:
159+
server_url = "https://localhost/auth/"
160+
username = "admin"
161+
password = "secret"
162+
realm_name = "master"
163+
164+
headers = {
165+
'Custom': 'test-custom-header'
166+
}
167+
KeycloakAdmin(server_url=server_url,
168+
username=username,
169+
password=password,
170+
realm_name=realm_name,
171+
verify=False,
172+
custom_headers=headers)
173+
174+
mock_keycloak_open_id.assert_called_with(server_url=server_url,
175+
realm_name=realm_name,
176+
client_id='admin-cli',
177+
client_secret_key=None,
178+
verify=False,
179+
custom_headers=headers)
180+
181+
expected_header = {'Authorization': 'Bearer faketoken',
182+
'Content-Type': 'application/json',
183+
'Custom': 'test-custom-header'
184+
}
185+
186+
mock_connection_manager.assert_called_with(base_url=server_url,
187+
headers=expected_header,
188+
timeout=60,
189+
verify=False)

0 commit comments

Comments
 (0)