Skip to content

Commit 709761a

Browse files
Merge pull request #205 from timbmg/keycloak
Add support for Keycloak
2 parents 85bc030 + 492fc07 commit 709761a

File tree

11 files changed

+149
-8
lines changed

11 files changed

+149
-8
lines changed

.github/workflows/main.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ jobs:
2929
- redis.py
3030
- selenium.py
3131
- webdriver.py
32+
- keycloak.py
3233
runs-on: ubuntu-18.04
3334
steps:
3435
- uses: actions/checkout@v2

README.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ Currently available features:
2424
* Generic docker containers
2525
* LocalStack
2626
* RabbitMQ
27+
* Keycloak
2728

2829
Installation
2930
------------

requirements.in

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
-e file:.[docker-compose,mysql,oracle,postgresql,selenium,google-cloud-pubsub,mongo,redis,mssqlserver,neo4j,kafka,rabbitmq,clickhouse]
1+
-e file:.[docker-compose,mysql,oracle,postgresql,selenium,google-cloud-pubsub,mongo,redis,mssqlserver,neo4j,kafka,rabbitmq,clickhouse,keycloak]
22
codecov>=2.1.0
33
cryptography<37
44
flake8<3.8.0 # 3.8.0 adds a dependency on importlib-metadata which conflicts with other packages.

requirements/3.10.txt

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ docopt==0.6.2
7373
# via docker-compose
7474
docutils==0.17.1
7575
# via sphinx
76+
ecdsa==0.17.0
77+
# via python-jose
7678
entrypoints==0.3
7779
# via flake8
7880
flake8==3.7.9
@@ -151,6 +153,7 @@ py==1.11.0
151153
pyasn1==0.4.8
152154
# via
153155
# pyasn1-modules
156+
# python-jose
154157
# rsa
155158
pyasn1-modules==0.2.8
156159
# via google-auth
@@ -186,6 +189,10 @@ pytest-cov==3.0.0
186189
# via -r requirements.in
187190
python-dotenv==0.20.0
188191
# via docker-compose
192+
python-jose==3.3.0
193+
# via python-keycloak
194+
python-keycloak==0.27.0
195+
# via testcontainers
189196
pytz==2022.1
190197
# via
191198
# babel
@@ -195,24 +202,28 @@ pytz-deprecation-shim==0.1.0.post0
195202
# via tzlocal
196203
pyyaml==5.4.1
197204
# via docker-compose
198-
redis==4.2.2
205+
redis==4.3.0
199206
# via testcontainers
200207
requests==2.27.1
201208
# via
202209
# codecov
203210
# docker
204211
# docker-compose
205212
# google-api-core
213+
# python-keycloak
206214
# sphinx
207215
rsa==4.8
208-
# via google-auth
216+
# via
217+
# google-auth
218+
# python-jose
209219
scramp==1.4.1
210220
# via pg8000
211-
selenium==4.1.4
221+
selenium==4.1.5
212222
# via testcontainers
213223
six==1.16.0
214224
# via
215225
# dockerpty
226+
# ecdsa
216227
# google-auth
217228
# grpcio
218229
# jsonschema

requirements/3.6.txt

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ docopt==0.6.2
6969
# via docker-compose
7070
docutils==0.17.1
7171
# via sphinx
72+
ecdsa==0.17.0
73+
# via python-jose
7274
entrypoints==0.3
7375
# via flake8
7476
flake8==3.7.9
@@ -150,6 +152,7 @@ py==1.11.0
150152
pyasn1==0.4.8
151153
# via
152154
# pyasn1-modules
155+
# python-jose
153156
# rsa
154157
pyasn1-modules==0.2.8
155158
# via google-auth
@@ -181,6 +184,10 @@ pytest-cov==3.0.0
181184
# via -r requirements.in
182185
python-dotenv==0.20.0
183186
# via docker-compose
187+
python-jose==3.3.0
188+
# via python-keycloak
189+
python-keycloak==0.27.0
190+
# via testcontainers
184191
pytz==2022.1
185192
# via
186193
# babel
@@ -198,16 +205,20 @@ requests==2.27.1
198205
# docker
199206
# docker-compose
200207
# google-api-core
208+
# python-keycloak
201209
# sphinx
202210
rsa==4.8
203-
# via google-auth
211+
# via
212+
# google-auth
213+
# python-jose
204214
scramp==1.4.1
205215
# via pg8000
206216
selenium==3.141.0
207217
# via testcontainers
208218
six==1.16.0
209219
# via
210220
# dockerpty
221+
# ecdsa
211222
# google-auth
212223
# grpcio
213224
# jsonschema

requirements/3.7.txt

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ docopt==0.6.2
7979
# via docker-compose
8080
docutils==0.17.1
8181
# via sphinx
82+
ecdsa==0.17.0
83+
# via python-jose
8284
entrypoints==0.3
8385
# via flake8
8486
flake8==3.7.9
@@ -165,6 +167,7 @@ py==1.11.0
165167
pyasn1==0.4.8
166168
# via
167169
# pyasn1-modules
170+
# python-jose
168171
# rsa
169172
pyasn1-modules==0.2.8
170173
# via google-auth
@@ -200,6 +203,10 @@ pytest-cov==3.0.0
200203
# via -r requirements.in
201204
python-dotenv==0.20.0
202205
# via docker-compose
206+
python-jose==3.3.0
207+
# via python-keycloak
208+
python-keycloak==0.27.0
209+
# via testcontainers
203210
pytz==2022.1
204211
# via
205212
# babel
@@ -217,16 +224,20 @@ requests==2.27.1
217224
# docker
218225
# docker-compose
219226
# google-api-core
227+
# python-keycloak
220228
# sphinx
221229
rsa==4.8
222-
# via google-auth
230+
# via
231+
# google-auth
232+
# python-jose
223233
scramp==1.4.1
224234
# via pg8000
225235
selenium==4.1.3
226236
# via testcontainers
227237
six==1.16.0
228238
# via
229239
# dockerpty
240+
# ecdsa
230241
# google-auth
231242
# grpcio
232243
# jsonschema

requirements/3.8.txt

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ docopt==0.6.2
7777
# via docker-compose
7878
docutils==0.17.1
7979
# via sphinx
80+
ecdsa==0.17.0
81+
# via python-jose
8082
entrypoints==0.3
8183
# via flake8
8284
flake8==3.7.9
@@ -157,6 +159,7 @@ py==1.11.0
157159
pyasn1==0.4.8
158160
# via
159161
# pyasn1-modules
162+
# python-jose
160163
# rsa
161164
pyasn1-modules==0.2.8
162165
# via google-auth
@@ -192,6 +195,10 @@ pytest-cov==3.0.0
192195
# via -r requirements.in
193196
python-dotenv==0.20.0
194197
# via docker-compose
198+
python-jose==3.3.0
199+
# via python-keycloak
200+
python-keycloak==0.27.0
201+
# via testcontainers
195202
pytz==2022.1
196203
# via
197204
# babel
@@ -209,16 +216,20 @@ requests==2.27.1
209216
# docker
210217
# docker-compose
211218
# google-api-core
219+
# python-keycloak
212220
# sphinx
213221
rsa==4.8
214-
# via google-auth
222+
# via
223+
# google-auth
224+
# python-jose
215225
scramp==1.4.1
216226
# via pg8000
217227
selenium==4.1.3
218228
# via testcontainers
219229
six==1.16.0
220230
# via
221231
# dockerpty
232+
# ecdsa
222233
# google-auth
223234
# grpcio
224235
# jsonschema

requirements/3.9.txt

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ docopt==0.6.2
7373
# via docker-compose
7474
docutils==0.17.1
7575
# via sphinx
76+
ecdsa==0.17.0
77+
# via python-jose
7678
entrypoints==0.3
7779
# via flake8
7880
flake8==3.7.9
@@ -153,6 +155,7 @@ py==1.11.0
153155
pyasn1==0.4.8
154156
# via
155157
# pyasn1-modules
158+
# python-jose
156159
# rsa
157160
pyasn1-modules==0.2.8
158161
# via google-auth
@@ -188,6 +191,10 @@ pytest-cov==3.0.0
188191
# via -r requirements.in
189192
python-dotenv==0.20.0
190193
# via docker-compose
194+
python-jose==3.3.0
195+
# via python-keycloak
196+
python-keycloak==0.27.0
197+
# via testcontainers
191198
pytz==2022.1
192199
# via
193200
# babel
@@ -205,16 +212,20 @@ requests==2.27.1
205212
# docker
206213
# docker-compose
207214
# google-api-core
215+
# python-keycloak
208216
# sphinx
209217
rsa==4.8
210-
# via google-auth
218+
# via
219+
# google-auth
220+
# python-jose
211221
scramp==1.4.1
212222
# via pg8000
213223
selenium==4.1.3
214224
# via testcontainers
215225
six==1.16.0
216226
# via
217227
# dockerpty
228+
# ecdsa
218229
# google-auth
219230
# grpcio
220231
# jsonschema

setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
'kafka': ['kafka-python'],
6767
'rabbitmq': ['pika'],
6868
'clickhouse': ['clickhouse-driver'],
69+
'keycloak': ['python-keycloak'],
6970
},
7071
long_description_content_type="text/x-rst",
7172
long_description=long_description,

testcontainers/keycloak.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
#
2+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
3+
# not use this file except in compliance with the License. You may obtain
4+
# a copy of the License at
5+
#
6+
# http://www.apache.org/licenses/LICENSE-2.0
7+
#
8+
# Unless required by applicable law or agreed to in writing, software
9+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
10+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
11+
# License for the specific language governing permissions and limitations
12+
# under the License.
13+
import os
14+
import requests
15+
16+
from keycloak import KeycloakAdmin
17+
18+
from testcontainers.core.container import DockerContainer
19+
from testcontainers.core.waiting_utils import wait_container_is_ready
20+
21+
22+
class KeycloakContainer(DockerContainer):
23+
"""
24+
Keycloak container.
25+
26+
Example
27+
-------
28+
::
29+
30+
with KeycloakContainer() as kc:
31+
keycloak: KeycloakAdmin = kc.get_client()
32+
"""
33+
KEYCLOAK_USER = os.environ.get("KEYCLOAK_USER", "test")
34+
KEYCLOAK_PASSWORD = os.environ.get("KEYCLOAK_PASSWORD", "test")
35+
36+
def __init__(self, image="jboss/keycloak:latest"):
37+
super(KeycloakContainer, self).__init__(image=image)
38+
self.port_to_expose = 8080
39+
self.with_exposed_ports(self.port_to_expose)
40+
41+
def _configure(self):
42+
self.with_env("KEYCLOAK_USER", self.KEYCLOAK_USER)
43+
self.with_env("KEYCLOAK_PASSWORD", self.KEYCLOAK_PASSWORD)
44+
45+
def get_url(self):
46+
host = self.get_container_host_ip()
47+
port = self.get_exposed_port(self.port_to_expose)
48+
return "http://{}:{}".format(host, port)
49+
50+
@wait_container_is_ready(requests.exceptions.ConnectionError, requests.exceptions.ReadTimeout)
51+
def _connect(self):
52+
url = self.get_url()
53+
response = requests.get("{}/auth".format(url), timeout=1)
54+
response.raise_for_status()
55+
56+
def start(self):
57+
self._configure()
58+
super().start()
59+
self._connect()
60+
return self
61+
62+
def get_client(self, **kwargs):
63+
default_kwargs = dict(
64+
server_url="{}/auth/".format(self.get_url()),
65+
username=self.KEYCLOAK_USER,
66+
password=self.KEYCLOAK_PASSWORD,
67+
realm_name="master",
68+
verify=True,
69+
)
70+
kwargs = {
71+
**default_kwargs,
72+
**kwargs
73+
}
74+
return KeycloakAdmin(**kwargs)

tests/test_keycloak.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import pytest
2+
3+
from testcontainers.keycloak import KeycloakContainer
4+
5+
6+
@pytest.mark.parametrize(["version"], [("16.1.1", )])
7+
def test_docker_run_keycloak(version):
8+
with KeycloakContainer('jboss/keycloak:{}'.format(version)) as kc:
9+
kc.get_client().users_count()

0 commit comments

Comments
 (0)