]> git.proxmox.com Git - ceph.git/blame - ceph/qa/tasks/keycloak.py
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / qa / tasks / keycloak.py
CommitLineData
f67539c2
TL
1"""
2Deploy and configure Keycloak for Teuthology
3"""
4import contextlib
5import logging
6import os
7
8from teuthology import misc as teuthology
9from teuthology import contextutil
10from teuthology.orchestra import run
11from teuthology.exceptions import ConfigError
12
13log = logging.getLogger(__name__)
14
15def get_keycloak_version(config):
16 for client, client_config in config.items():
17 if 'keycloak_version' in client_config:
18 keycloak_version = client_config.get('keycloak_version')
19 return keycloak_version
20
21def get_keycloak_dir(ctx, config):
22 keycloak_version = get_keycloak_version(config)
23 current_version = 'keycloak-'+keycloak_version
24 return '{tdir}/{ver}'.format(tdir=teuthology.get_testdir(ctx),ver=current_version)
25
26def run_in_keycloak_dir(ctx, client, config, args, **kwargs):
27 return ctx.cluster.only(client).run(
28 args=[ 'cd', get_keycloak_dir(ctx,config), run.Raw('&&'), ] + args,
29 **kwargs
30 )
31
32def get_toxvenv_dir(ctx):
33 return ctx.tox.venv_path
34
35def toxvenv_sh(ctx, remote, args, **kwargs):
36 activate = get_toxvenv_dir(ctx) + '/bin/activate'
37 return remote.sh(['source', activate, run.Raw('&&')] + args, **kwargs)
38
39@contextlib.contextmanager
40def install_packages(ctx, config):
41 """
42 Downloading the two required tar files
43 1. Keycloak
44 2. Wildfly (Application Server)
45 """
46 assert isinstance(config, dict)
47 log.info('Installing packages for Keycloak...')
48
49 for (client, _) in config.items():
50 (remote,) = ctx.cluster.only(client).remotes.keys()
51 test_dir=teuthology.get_testdir(ctx)
52 current_version = get_keycloak_version(config)
53 link1 = 'https://downloads.jboss.org/keycloak/'+current_version+'/keycloak-'+current_version+'.tar.gz'
54 toxvenv_sh(ctx, remote, ['wget', link1])
55
56 file1 = 'keycloak-'+current_version+'.tar.gz'
57 toxvenv_sh(ctx, remote, ['tar', '-C', test_dir, '-xvzf', file1])
58
59 link2 ='https://downloads.jboss.org/keycloak/'+current_version+'/adapters/keycloak-oidc/keycloak-wildfly-adapter-dist-'+current_version+'.tar.gz'
60 toxvenv_sh(ctx, remote, ['cd', '{tdir}'.format(tdir=get_keycloak_dir(ctx,config)), run.Raw('&&'), 'wget', link2])
61
62 file2 = 'keycloak-wildfly-adapter-dist-'+current_version+'.tar.gz'
63 toxvenv_sh(ctx, remote, ['tar', '-C', '{tdir}'.format(tdir=get_keycloak_dir(ctx,config)), '-xvzf', '{tdr}/{file}'.format(tdr=get_keycloak_dir(ctx,config),file=file2)])
64
65 try:
66 yield
67 finally:
68 log.info('Removing packaged dependencies of Keycloak...')
69 for client in config:
70 ctx.cluster.only(client).run(
71 args=['rm', '-rf', '{tdir}'.format(tdir=get_keycloak_dir(ctx,config))],
72 )
73
74@contextlib.contextmanager
75def build(ctx,config):
76 """
77 Build process which needs to be done before starting a server.
78 """
79 assert isinstance(config, dict)
80 log.info('Building Keycloak...')
81 for (client,_) in config.items():
82 run_in_keycloak_dir(ctx, client, config,['cd', 'bin', run.Raw('&&'), './jboss-cli.sh', '--file=adapter-elytron-install-offline.cli'])
83 try:
84 yield
85 finally:
86 pass
87
88@contextlib.contextmanager
89def run_keycloak(ctx,config):
90 """
91 This includes two parts:
92 1. Adding a user to keycloak which is actually used to log in when we start the server and check in browser.
93 2. Starting the server.
94 """
95 assert isinstance(config, dict)
96 log.info('Bringing up Keycloak...')
97 for (client,_) in config.items():
98 (remote,) = ctx.cluster.only(client).remotes.keys()
99
100 ctx.cluster.only(client).run(
101 args=[
102 '{tdir}/bin/add-user-keycloak.sh'.format(tdir=get_keycloak_dir(ctx,config)),
103 '-r', 'master',
104 '-u', 'admin',
105 '-p', 'admin',
106 ],
107 )
108
109 toxvenv_sh(ctx, remote, ['cd', '{tdir}/bin'.format(tdir=get_keycloak_dir(ctx,config)), run.Raw('&&'), './standalone.sh', run.Raw('&'), 'exit'])
110 try:
111 yield
112 finally:
113 log.info('Stopping Keycloak Server...')
114
115 for (client, _) in config.items():
116 (remote,) = ctx.cluster.only(client).remotes.keys()
117 toxvenv_sh(ctx, remote, ['cd', '{tdir}/bin'.format(tdir=get_keycloak_dir(ctx,config)), run.Raw('&&'), './jboss-cli.sh', '--connect', 'command=:shutdown'])
118
119@contextlib.contextmanager
120def run_admin_cmds(ctx,config):
121 """
122 Running Keycloak Admin commands(kcadm commands) in order to get the token, aud value, thumbprint and realm name.
123 """
124 assert isinstance(config, dict)
125 log.info('Running admin commands...')
126 for (client,_) in config.items():
127 (remote,) = ctx.cluster.only(client).remotes.keys()
128
129 remote.run(
130 args=[
131 '{tdir}/bin/kcadm.sh'.format(tdir=get_keycloak_dir(ctx,config)),
132 'config', 'credentials',
133 '--server', 'http://localhost:8080/auth',
134 '--realm', 'master',
135 '--user', 'admin',
136 '--password', 'admin',
137 '--client', 'admin-cli',
138 ],
139 )
140
141 realm_name='demorealm'
142 realm='realm={}'.format(realm_name)
143
144 remote.run(
145 args=[
146 '{tdir}/bin/kcadm.sh'.format(tdir=get_keycloak_dir(ctx,config)),
147 'create', 'realms',
148 '-s', realm,
149 '-s', 'enabled=true',
150 '-s', 'accessTokenLifespan=1800',
151 '-o',
152 ],
153 )
154
155 client_name='my_client'
156 client='clientId={}'.format(client_name)
157
158 remote.run(
159 args=[
160 '{tdir}/bin/kcadm.sh'.format(tdir=get_keycloak_dir(ctx,config)),
161 'create', 'clients',
162 '-r', realm_name,
163 '-s', client,
164 '-s', 'redirectUris=["http://localhost:8080/myapp/*"]',
165 ],
166 )
167
168 ans1= toxvenv_sh(ctx, remote,
169 [
170 'cd', '{tdir}/bin'.format(tdir=get_keycloak_dir(ctx,config)), run.Raw('&&'),
171 './kcadm.sh', 'get', 'clients',
172 '-r', realm_name,
173 '-F', 'id,clientId', run.Raw('|'),
174 'jq', '-r', '.[] | select (.clientId == "my_client") | .id'
175 ])
176
177 pre0=ans1.rstrip()
178 pre1="clients/{}".format(pre0)
179
180 remote.run(
181 args=[
182 '{tdir}/bin/kcadm.sh'.format(tdir=get_keycloak_dir(ctx,config)),
183 'update', pre1,
184 '-r', realm_name,
185 '-s', 'enabled=true',
186 '-s', 'serviceAccountsEnabled=true',
187 '-s', 'redirectUris=["http://localhost:8080/myapp/*"]',
188 ],
189 )
190
191 ans2= pre1+'/client-secret'
192
193 out2= toxvenv_sh(ctx, remote,
194 [
195 'cd', '{tdir}/bin'.format(tdir=get_keycloak_dir(ctx,config)), run.Raw('&&'),
196 './kcadm.sh', 'get', ans2,
197 '-r', realm_name,
198 '-F', 'value'
199 ])
200
201 ans0= '{client}:{secret}'.format(client=client_name,secret=out2[15:51])
202 ans3= 'client_secret={}'.format(out2[15:51])
203 clientid='client_id={}'.format(client_name)
204
205 out3= toxvenv_sh(ctx, remote,
206 [
207 'curl', '-k', '-v',
208 '-X', 'POST',
209 '-H', 'Content-Type:application/x-www-form-urlencoded',
210 '-d', 'scope=openid',
211 '-d', 'grant_type=client_credentials',
212 '-d', clientid,
213 '-d', ans3,
214 'http://localhost:8080/auth/realms/'+realm_name+'/protocol/openid-connect/token', run.Raw('|'),
215 'jq', '-r', '.access_token'
216 ])
217
218 pre2=out3.rstrip()
219 acc_token= 'token={}'.format(pre2)
220 ans4= '{}'.format(pre2)
221
222 out4= toxvenv_sh(ctx, remote,
223 [
224 'curl', '-k', '-v',
225 '-X', 'GET',
226 '-H', 'Content-Type:application/x-www-form-urlencoded',
227 'http://localhost:8080/auth/realms/'+realm_name+'/protocol/openid-connect/certs', run.Raw('|'),
228 'jq', '-r', '.keys[].x5c[]'
229 ])
230
231 pre3=out4.rstrip()
232 cert_value='{}'.format(pre3)
233 start_value= "-----BEGIN CERTIFICATE-----\n"
234 end_value= "\n-----END CERTIFICATE-----"
235 user_data=""
236 user_data+=start_value
237 user_data+=cert_value
238 user_data+=end_value
239
240 remote.write_file(
241 path='{tdir}/bin/certificate.crt'.format(tdir=get_keycloak_dir(ctx,config)),
242 data=user_data
243 )
244
245 out5= toxvenv_sh(ctx, remote,
246 [
247 'openssl', 'x509',
248 '-in', '{tdir}/bin/certificate.crt'.format(tdir=get_keycloak_dir(ctx,config)),
249 '--fingerprint', '--noout', '-sha1'
250 ])
251
252 pre_ans= '{}'.format(out5[17:76])
253 ans5=""
254
255 for character in pre_ans:
256 if(character!=':'):
257 ans5+=character
258
259 out6= toxvenv_sh(ctx, remote,
260 [
261 'curl', '-k', '-v',
262 '-X', 'POST',
263 '-u', ans0,
264 '-d', acc_token,
265 'http://localhost:8080/auth/realms/'+realm_name+'/protocol/openid-connect/token/introspect', run.Raw('|'),
266 'jq', '-r', '.aud'
267 ])
268
269 ans6=out6.rstrip()
270
271 os.environ['TOKEN']=ans4
272 os.environ['THUMBPRINT']=ans5
273 os.environ['AUD']=ans6
274 os.environ['KC_REALM']=realm_name
275
276 try:
277 yield
278 finally:
279 log.info('Removing certificate.crt file...')
280 for (client,_) in config.items():
281 (remote,) = ctx.cluster.only(client).remotes.keys()
282 remote.run(
283 args=['rm', '-f',
284 '{tdir}/bin/certificate.crt'.format(tdir=get_keycloak_dir(ctx,config)),
285 ],
286 )
287
288@contextlib.contextmanager
289def task(ctx,config):
290 """
291 To run keycloak the prerequisite is to run the tox task. Following is the way how to run
292 tox and then keycloak::
293
294 tasks:
295 - tox: [ client.0 ]
296 - keycloak:
297 client.0:
298 keycloak_version: 11.0.0
299
300 To pass extra arguments to nose (e.g. to run a certain test)::
301
302 tasks:
303 - tox: [ client.0 ]
304 - keycloak:
305 client.0:
306 keycloak_version: 11.0.0
307 - s3tests:
308 client.0:
309 extra_attrs: ['webidentity_test']
310
311 """
312 assert config is None or isinstance(config, list) \
313 or isinstance(config, dict), \
314 "task keycloak only supports a list or dictionary for configuration"
315
316 if not hasattr(ctx, 'tox'):
317 raise ConfigError('keycloak must run after the tox task')
318
319 all_clients = ['client.{id}'.format(id=id_)
320 for id_ in teuthology.all_roles_of_type(ctx.cluster, 'client')]
321 if config is None:
322 config = all_clients
323 if isinstance(config, list):
324 config = dict.fromkeys(config)
325
326 log.debug('Keycloak config is %s', config)
327
328 with contextutil.nested(
329 lambda: install_packages(ctx=ctx, config=config),
330 lambda: build(ctx=ctx, config=config),
331 lambda: run_keycloak(ctx=ctx, config=config),
332 lambda: run_admin_cmds(ctx=ctx, config=config),
333 ):
334 yield
335