]>
git.proxmox.com Git - ceph.git/blob - ceph/qa/tasks/keycloak.py
0f1fc9d7a38089df13fc3ff33b817ecc93061e00
2 Deploy and configure Keycloak for Teuthology
8 from teuthology
import misc
as teuthology
9 from teuthology
import contextutil
10 from teuthology
.orchestra
import run
11 from teuthology
.exceptions
import ConfigError
13 log
= logging
.getLogger(__name__
)
15 def 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
21 def 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
)
26 def 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
,
32 def get_toxvenv_dir(ctx
):
33 return ctx
.tox
.venv_path
35 def toxvenv_sh(ctx
, remote
, args
, **kwargs
):
36 activate
= get_toxvenv_dir(ctx
) + '/bin/activate'
37 return remote
.sh(['source', activate
, run
.Raw('&&')] + args
, **kwargs
)
39 @contextlib.contextmanager
40 def install_packages(ctx
, config
):
42 Downloading the two required tar files
44 2. Wildfly (Application Server)
46 assert isinstance(config
, dict)
47 log
.info('Installing packages for Keycloak...')
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
])
56 file1
= 'keycloak-'+current_version
+'.tar.gz'
57 toxvenv_sh(ctx
, remote
, ['tar', '-C', test_dir
, '-xvzf', file1
])
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
])
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
)])
68 log
.info('Removing packaged dependencies of Keycloak...')
70 ctx
.cluster
.only(client
).run(
71 args
=['rm', '-rf', '{tdir}'.format(tdir
=get_keycloak_dir(ctx
,config
))],
74 @contextlib.contextmanager
75 def build(ctx
,config
):
77 Build process which needs to be done before starting a server.
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'])
88 @contextlib.contextmanager
89 def run_keycloak(ctx
,config
):
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.
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()
100 ctx
.cluster
.only(client
).run(
102 '{tdir}/bin/add-user-keycloak.sh'.format(tdir
=get_keycloak_dir(ctx
,config
)),
109 toxvenv_sh(ctx
, remote
, ['cd', '{tdir}/bin'.format(tdir
=get_keycloak_dir(ctx
,config
)), run
.Raw('&&'), './standalone.sh', run
.Raw('&'), 'exit'])
113 log
.info('Stopping Keycloak Server...')
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'])
119 @contextlib.contextmanager
120 def run_admin_cmds(ctx
,config
):
122 Running Keycloak Admin commands(kcadm commands) in order to get the token, aud value, thumbprint and realm name.
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()
131 '{tdir}/bin/kcadm.sh'.format(tdir
=get_keycloak_dir(ctx
,config
)),
132 'config', 'credentials',
133 '--server', 'http://localhost:8080/auth',
136 '--password', 'admin',
137 '--client', 'admin-cli',
141 realm_name
='demorealm'
142 realm
='realm={}'.format(realm_name
)
146 '{tdir}/bin/kcadm.sh'.format(tdir
=get_keycloak_dir(ctx
,config
)),
149 '-s', 'enabled=true',
150 '-s', 'accessTokenLifespan=1800',
155 client_name
='my_client'
156 client
='clientId={}'.format(client_name
)
160 '{tdir}/bin/kcadm.sh'.format(tdir
=get_keycloak_dir(ctx
,config
)),
164 '-s', 'redirectUris=["http://localhost:8080/myapp/*"]',
168 ans1
= toxvenv_sh(ctx
, remote
,
170 'cd', '{tdir}/bin'.format(tdir
=get_keycloak_dir(ctx
,config
)), run
.Raw('&&'),
171 './kcadm.sh', 'get', 'clients',
173 '-F', 'id,clientId', run
.Raw('|'),
174 'jq', '-r', '.[] | select (.clientId == "my_client") | .id'
178 pre1
="clients/{}".format(pre0
)
182 '{tdir}/bin/kcadm.sh'.format(tdir
=get_keycloak_dir(ctx
,config
)),
185 '-s', 'enabled=true',
186 '-s', 'serviceAccountsEnabled=true',
187 '-s', 'redirectUris=["http://localhost:8080/myapp/*"]',
191 ans2
= pre1
+'/client-secret'
193 out2
= toxvenv_sh(ctx
, remote
,
195 'cd', '{tdir}/bin'.format(tdir
=get_keycloak_dir(ctx
,config
)), run
.Raw('&&'),
196 './kcadm.sh', 'get', ans2
,
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
)
205 out3
= toxvenv_sh(ctx
, remote
,
209 '-H', 'Content-Type:application/x-www-form-urlencoded',
210 '-d', 'scope=openid',
211 '-d', 'grant_type=client_credentials',
214 'http://localhost:8080/auth/realms/'+realm_name
+'/protocol/openid-connect/token', run
.Raw('|'),
215 'jq', '-r', '.access_token'
219 acc_token
= 'token={}'.format(pre2
)
220 ans4
= '{}'.format(pre2
)
222 out4
= toxvenv_sh(ctx
, remote
,
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[]'
232 cert_value
='{}'.format(pre3
)
233 start_value
= "-----BEGIN CERTIFICATE-----\n"
234 end_value
= "\n-----END CERTIFICATE-----"
236 user_data
+=start_value
237 user_data
+=cert_value
241 path
='{tdir}/bin/certificate.crt'.format(tdir
=get_keycloak_dir(ctx
,config
)),
245 out5
= toxvenv_sh(ctx
, remote
,
248 '-in', '{tdir}/bin/certificate.crt'.format(tdir
=get_keycloak_dir(ctx
,config
)),
249 '--fingerprint', '--noout', '-sha1'
252 pre_ans
= '{}'.format(out5
[17:76])
255 for character
in pre_ans
:
259 out6
= toxvenv_sh(ctx
, remote
,
265 'http://localhost:8080/auth/realms/'+realm_name
+'/protocol/openid-connect/token/introspect', run
.Raw('|'),
271 os
.environ
['TOKEN']=ans4
272 os
.environ
['THUMBPRINT']=ans5
273 os
.environ
['AUD']=ans6
274 os
.environ
['KC_REALM']=realm_name
279 log
.info('Removing certificate.crt file...')
280 for (client
,_
) in config
.items():
281 (remote
,) = ctx
.cluster
.only(client
).remotes
.keys()
284 '{tdir}/bin/certificate.crt'.format(tdir
=get_keycloak_dir(ctx
,config
)),
288 @contextlib.contextmanager
289 def task(ctx
,config
):
291 To run keycloak the prerequisite is to run the tox task. Following is the way how to run
292 tox and then keycloak::
298 keycloak_version: 11.0.0
300 To pass extra arguments to nose (e.g. to run a certain test)::
306 keycloak_version: 11.0.0
309 extra_attrs: ['webidentity_test']
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"
316 if not hasattr(ctx
, 'tox'):
317 raise ConfigError('keycloak must run after the tox task')
319 all_clients
= ['client.{id}'.format(id=id_
)
320 for id_
in teuthology
.all_roles_of_type(ctx
.cluster
, 'client')]
323 if isinstance(config
, list):
324 config
= dict.fromkeys(config
)
326 log
.debug('Keycloak config is %s', config
)
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
),