Updated test env documentation
[nonrtric.git] / test / common / keycloak_api_functions.sh
1 #!/bin/bash
2
3 #  ============LICENSE_START===============================================
4 #  Copyright (C) 2021 Nordix Foundation. All rights reserved.
5 #  ========================================================================
6 #  Licensed under the Apache License, Version 2.0 (the "License");
7 #  you may not use this file except in compliance with the License.
8 #  You may obtain a copy of the License at
9 #
10 #       http://www.apache.org/licenses/LICENSE-2.0
11 #
12 #  Unless required by applicable law or agreed to in writing, software
13 #  distributed under the License is distributed on an "AS IS" BASIS,
14 #  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 #  See the License for the specific language governing permissions and
16 #  limitations under the License.
17 #  ============LICENSE_END=================================================
18 #
19
20 # This is a script that contains container/service management functions and test functions for Keycloak
21
22
23 ################ Test engine functions ################
24
25 # Create the image var used during the test
26 # arg: <image-tag-suffix> (selects staging, snapshot, release etc)
27 # <image-tag-suffix> is present only for images with staging, snapshot,release tags
28 __KEYCLOAK_imagesetup() {
29         __check_and_create_image_var KEYCLOAK "KEYCLOAK_IMAGE" "KEYCLOAK_IMAGE_BASE" "KEYCLOAK_IMAGE_TAG" REMOTE_OTHER "$KEYCLOAK_DISPLAY_NAME" ""
30 }
31
32 # Pull image from remote repo or use locally built image
33 # arg: <pull-policy-override> <pull-policy-original>
34 # <pull-policy-override> Shall be used for images allowing overriding. For example use a local image when test is started to use released images
35 # <pull-policy-original> Shall be used for images that does not allow overriding
36 # Both var may contain: 'remote', 'remote-remove' or 'local'
37 __KEYCLOAK_imagepull() {
38         __check_and_pull_image $2 "$KEYCLOAK_DISPLAY_NAME" $KEYCLOAK_APP_NAME KEYCLOAK_IMAGE
39 }
40
41 # Build image (only for simulator or interfaces stubs owned by the test environment)
42 # arg: <image-tag-suffix> (selects staging, snapshot, release etc)
43 # <image-tag-suffix> is present only for images with staging, snapshot,release tags
44 __KEYCLOAK_imagebuild() {
45         echo -e $RED" Image for app KEYCLOAK shall never be built"$ERED
46 }
47
48 # Generate a string for each included image using the app display name and a docker images format string
49 # If a custom image repo is used then also the source image from the local repo is listed
50 # arg: <docker-images-format-string> <file-to-append>
51 __KEYCLOAK_image_data() {
52         echo -e "$KEYCLOAK_DISPLAY_NAME\t$(docker images --format $1 $KEYCLOAK_IMAGE)" >>   $2
53         if [ ! -z "$KEYCLOAK_IMAGE_SOURCE" ]; then
54                 echo -e "-- source image --\t$(docker images --format $1 $KEYCLOAK_IMAGE_SOURCE)" >>   $2
55         fi
56 }
57
58 # Scale kubernetes resources to zero
59 # All resources shall be ordered to be scaled to 0, if relevant. If not relevant to scale, then do no action.
60 # This function is called for apps fully managed by the test script
61 __KEYCLOAK_kube_scale_zero() {
62         __kube_scale_all_resources $KUBE_KEYCLOAK_NAMESPACE autotest KEYCLOAK
63 }
64
65 # Scale kubernetes resources to zero and wait until this has been accomplished, if relevant. If not relevant to scale, then do no action.
66 # This function is called for pre-started apps not managed by the test script.
67 __KEYCLOAK_kube_scale_zero_and_wait() {
68         echo -e $RED" KEYCLOAK app is not scaled in this state"$ERED
69 }
70
71 # Delete all kube resources for the app
72 # This function is called for apps managed by the test script.
73 __KEYCLOAK_kube_delete_all() {
74         __kube_delete_all_resources $KUBE_KEYCLOAK_NAMESPACE autotest KEYCLOAK
75 }
76
77 # Store docker logs
78 # This function is called for apps managed by the test script.
79 # args: <log-dir> <file-prefix>
80 __KEYCLOAK_store_docker_logs() {
81         if [ $RUNMODE == "KUBE" ]; then
82                 kubectl $KUBECONF  logs -l "autotest=KEYCLOAK" -n $KUBE_KEYCLOAK_NAMESPACE --tail=-1 > $1$2_keycloak.log 2>&1
83         else
84                 docker logs $KEYCLOAK_APP_NAME > $1$2_keycloak.log 2>&1
85         fi
86 }
87
88 # Initial setup of protocol, host and ports
89 # This function is called for apps managed by the test script.
90 # args: -
91 __KEYCLOAK_initial_setup() {
92         use_keycloak_http
93 }
94
95 # Set app short-name, app name and namespace for logging runtime statistics of kubernetes pods or docker containers
96 # For docker, the namespace shall be excluded
97 # This function is called for apps managed by the test script as well as for pre-started apps.
98 # args: -
99 __KEYCLOAK_statistics_setup() {
100         if [ $RUNMODE == "KUBE" ]; then
101                 echo "KEYCLOAK $KEYCLOAK_APP_NAME $KUBE_KEYCLOAK_NAMESPACE"
102         else
103                 echo "KEYCLOAK $KEYCLOAK_APP_NAME"
104         fi
105 }
106
107 # Check application requirements, e.g. helm, the the test needs. Exit 1 if req not satisfied
108 # args: -
109 __KEYCLOAK_test_requirements() {
110         which jq > /dev/null
111         if [ $? -ne 0 ]; then
112                 echo $RED" 'jq' is required to run tests. Pls install 'jq'"
113                 return 1
114         fi
115 }
116
117 #######################################################
118
119 # Set http as the protocol to use for all communication to the Keycloak
120 # args: -
121 # (Function for test scripts)
122 use_keycloak_http() {
123         __keycloak_set_protocoll "http" $KEYCLOAK_INTERNAL_PORT $KEYCLOAK_EXTERNAL_PORT
124 }
125
126 # Set https as the protocol to use for all communication to the Keycloak
127 # args: -
128 # (Function for test scripts)
129 use_keycloak_https() {
130         __keycloak_set_protocoll "https" $KEYCLOAK_INTERNAL_SECURE_PORT $KEYCLOAK_EXTERNAL_SECURE_PORT
131 }
132
133 # Setup paths to svc/container for internal and external access
134 # args: <protocol> <internal-port> <external-port>
135 __keycloak_set_protocoll() {
136         echo -e $BOLD"$KEYCLOAK_DISPLAY_NAME protocol setting"$EBOLD
137         echo -e " Using $BOLD $1 $EBOLD towards $KEYCLOAK_DISPLAY_NAME"
138
139         ## Access to Keycloak
140
141         KEYCLOAK_SERVICE_PATH=$1"://"$KEYCLOAK_APP_NAME":"$2  # docker access, container->container and script->container via proxy
142         KEYCLOAK_SERVICE_PORT=$2
143         KEYCLOAK_SERVICE_HOST=$KEYCLOAK_APP_NAME
144         KEYCLOAK_ISSUER_PATH=$1"://"$KEYCLOAK_APP_NAME
145         if [ $RUNMODE == "KUBE" ]; then
146                 KEYCLOAK_SERVICE_PATH=$1"://"$KEYCLOAK_APP_NAME.$KUBE_KEYCLOAK_NAMESPACE":"$3 # kube access, pod->svc and script->svc via proxy
147                 KEYCLOAK_SERVICE_PORT=$3
148                 KEYCLOAK_SERVICE_HOST=$KEYCLOAK_APP_NAME.$KUBE_KEYCLOAK_NAMESPACE
149                 KEYCLOAK_ISSUER_PATH=$1"://"$KEYCLOAK_APP_NAME.$KUBE_KEYCLOAK_NAMESPACE
150         fi
151         KEYCLOAK_SERVICE_HTTPX=$1
152
153         echo ""
154 }
155
156 ### Admin API functions Keycloak
157
158 ###########################
159 ### Keycloak functions
160 ###########################
161
162 # Export env vars for config files, docker compose and kube resources
163 # args:
164 __keycloak_export_vars() {
165         export KEYCLOAK_APP_NAME
166         export KEYCLOAK_DISPLAY_NAME
167
168         export DOCKER_SIM_NWNAME
169         export KUBE_KEYCLOAK_NAMESPACE
170
171         export KEYCLOAK_IMAGE
172         export KEYCLOAK_INTERNAL_PORT
173         export KEYCLOAK_EXTERNAL_PORT
174
175         export KEYCLOAK_ADMIN_USER
176         export KEYCLOAK_ADMIN_PWD
177         export KEYCLOAK_KC_PROXY
178 }
179
180
181 # Start the Keycloak in the simulator group
182 # args: -
183 # (Function for test scripts)
184 start_keycloak() {
185
186         echo -e $BOLD"Starting $KEYCLOAK_DISPLAY_NAME"$EBOLD
187
188         if [ $RUNMODE == "KUBE" ]; then
189
190                 # Check if app shall be fully managed by the test script
191                 __check_included_image "KEYCLOAK"
192                 retcode_i=$?
193
194                 # Check if app shall only be used by the test script
195                 __check_prestarted_image "KEYCLOAK"
196                 retcode_p=$?
197
198                 if [ $retcode_i -ne 0 ] && [ $retcode_p -ne 0 ]; then
199                         echo -e $RED"The $KEYCLOAK_NAME app is not included as managed nor prestarted in this test script"$ERED
200                         echo -e $RED"The $KEYCLOAK_APP_NAME will not be started"$ERED
201                         exit
202                 fi
203                 if [ $retcode_i -eq 0 ] && [ $retcode_p -eq 0 ]; then
204                         echo -e $RED"The $KEYCLOAK_APP_NAME app is included both as managed and prestarted in this test script"$ERED
205                         echo -e $RED"The $KEYCLOAK_APP_NAME will not be started"$ERED
206                         exit
207                 fi
208
209                 if [ $retcode_p -eq 0 ]; then
210                         echo -e " Using existing $KEYCLOAK_APP_NAME deployment and service"
211                         echo " Setting keycloak replicas=1"
212                         __kube_scale deployment $KEYCLOAK_APP_NAME $KUBE_KEYCLOAK_NAMESPACE 1
213                 fi
214
215                 if [ $retcode_i -eq 0 ]; then
216                         echo -e " Creating $KEYCLOAK_APP_NAME deployment and service"
217
218             __kube_create_namespace $KUBE_KEYCLOAK_NAMESPACE
219
220                         __keycloak_export_vars
221
222                         # Create service and app
223                         input_yaml=$SIM_GROUP"/"$KEYCLOAK_COMPOSE_DIR"/"svc_app.yaml
224                         output_yaml=$PWD/tmp/keycloak_svc_app.yaml
225                         __kube_create_instance "service/app" $KEYCLOAK_APP_NAME $input_yaml $output_yaml
226
227                 fi
228
229                 __check_service_start $KEYCLOAK_APP_NAME $KEYCLOAK_SERVICE_PATH$KEYCLOAK_ALIVE_URL
230         else
231
232                 # Check if docker app shall be fully managed by the test script
233                 __check_included_image 'KEYCLOAK'
234                 if [ $? -eq 1 ]; then
235                         echo -e $RED"The Keycloak app is not included as managed in this test script"$ERED
236                         echo -e $RED"The Keycloak will not be started"$ERED
237                         exit
238                 fi
239
240                 __keycloak_export_vars
241
242                 __start_container $KEYCLOAK_COMPOSE_DIR "" NODOCKERARGS 1 $KEYCLOAK_APP_NAME
243
244         __check_service_start $KEYCLOAK_APP_NAME $KEYCLOAK_SERVICE_PATH$KEYCLOAK_ALIVE_URL
245         fi
246     echo ""
247     return 0
248 }
249
250 # Execute a curl cmd towards the keycloak and check the response code is 2XX.
251 # args: <curl-cmd-string>
252 # resp: <returned-payload> if return code is 0 otherwise <error-info>
253 __execute_curl_to_keycloak() {
254
255         proxyflag=""
256         if [ ! -z "$KUBE_PROXY_PATH" ]; then
257                 if [ $KUBE_PROXY_HTTPX == "http" ]; then
258                         proxyflag=" --proxy $KUBE_PROXY_PATH"
259                 else
260                         proxyflag=" --proxy-insecure --proxy $KUBE_PROXY_PATH"
261                 fi
262         fi
263         __cmd="curl -skw %{http_code} $proxyflag $1"
264         echo " CMD: $__cmd" >> $HTTPLOG
265         res=$($__cmd)
266         echo " RESP: $res" >> $HTTPLOG
267         retcode=$?
268     if [ $retcode -ne 0 ]; then
269         __log_conf_fail_general " Fatal error when executing curl, response: "$retcode
270         echo "$res"
271                 return 1
272     fi
273     status=${res:${#res}-3}
274         if [ $status -lt 200 ] && [ $status -gt 299 ]; then
275                 __log_conf_fail_status_code "2XX" $status
276                 echo "$res"
277                 return 1
278         fi
279         echo ${res:0:${#res}-3}
280         return 0
281 }
282
283 # Execute a curl cmd towards the keycloak and check the response code is 2XX.
284 # args: <operation> <url> <token> <json>
285 # resp: <returned-payload> if return code is 0 otherwise <error-info>
286 __execute_curl_to_keycloak2() {
287         proxyflag=""
288         if [ ! -z "$KUBE_PROXY_PATH" ]; then
289                 if [ $KUBE_PROXY_HTTPX == "http" ]; then
290                         proxyflag=" --proxy $KUBE_PROXY_PATH"
291                 else
292                         proxyflag=" --proxy-insecure --proxy $KUBE_PROXY_PATH"
293                 fi
294         fi
295         if [ $1 == "POST" ]; then
296                 if [ $# -eq 3 ]; then
297                         echo  curl -X POST -skw %{http_code} $proxyflag "$2" -H "Authorization: Bearer $3" >> $HTTPLOG
298                         res=$(curl -X POST -skw %{http_code} $proxyflag "$2" -H "Authorization: Bearer $3")
299                         retcode=$?
300                 else
301                         echo  curl -X POST -skw %{http_code} $proxyflag "$2" -H "Content-Type: application/json" -H "Authorization: Bearer $3" --data-binary "$4" >> $HTTPLOG
302                         res=$(curl -X POST -skw %{http_code} $proxyflag "$2" -H "Content-Type: application/json" -H "Authorization: Bearer $3" --data-binary "$4")
303                         retcode=$?
304                 fi
305         elif [ $1 == "PUT" ]; then
306                 if [ $# -eq 3 ]; then
307                         echo  curl -X PUT -skw %{http_code} $proxyflag "$2" -H "Authorization: Bearer $3" >> $HTTPLOG
308                         res=$(curl -X PUT -skw %{http_code} $proxyflag "$2" -H "Authorization: Bearer $3")
309                         retcode=$?
310                 else
311                         echo  curl -X PUT -skw %{http_code} $proxyflag "$2" -H "Content-Type: application/json" -H "Authorization: Bearer $3" --data-binary "$4" >> $HTTPLOG
312                         res=$(curl -X PUT -skw %{http_code} $proxyflag "$2" -H "Content-Type: application/json" -H "Authorization: Bearer $3" --data-binary "$4")
313                         retcode=$?
314                 fi
315         elif [ $1 == "GET" ]; then
316                 echo  curl -X GET -skw %{http_code} $proxyflag "$2" -H "Authorization: Bearer $3" >> $HTTPLOG
317                 res=$(curl -X GET -skw %{http_code} $proxyflag "$2" -H "Authorization: Bearer $3")
318                 retcode=$?
319         fi
320         echo " RESP: $res" >> $HTTPLOG
321     if [ $retcode -ne 0 ]; then
322         __log_conf_fail_general " Fatal error when executing curl, response: "$retcode
323         echo "$res"
324                 return 1
325     fi
326     status=${res:${#res}-3}
327         if [ $status -lt 200 ] && [ $status -gt 299 ]; then
328                 __log_conf_fail_status_code "2XX" $status
329                 echo "$res"
330                 return 1
331         fi
332         echo ${res:0:${#res}-3}
333         return 0
334 }
335
336 # Extract JWT access token from json structure
337 # args: <json>
338 __keycloak_decode_jwt() {
339     echo $1 | jq -r .access_token | jq -R 'split(".") | .[1] | @base64d | fromjson'
340         return 0
341 }
342
343 # Get the admin token to use for subsequent rest calls to keycloak
344 # args: -
345 keycloak_api_obtain_admin_token() {
346         __log_conf_start $@
347         __curl_string="-X POST $KEYCLOAK_SERVICE_PATH$KEYCLOAK_ADMIN_URL_PREFIX/protocol/openid-connect/token     -H Content-Type:application/x-www-form-urlencoded     -d username="$KEYCLOAK_ADMIN_USER" -d password="$KEYCLOAK_ADMIN_PWD" -d grant_type=password -d client_id="$KEYCLOAK_ADMIN_CLIENT
348         __TMP_TOKEN=$(__execute_curl_to_keycloak "$__curl_string")
349         if [ $? -ne 0 ]; then
350         __log_conf_fail_general " Fatal error when executing curl, response: "$?
351         return 1
352         fi
353
354         __KEYCLOAK_ADMIN_TOKEN=$(echo "$__TMP_TOKEN" | jq  -r '.access_token')
355         if [ $? -ne 0 ]; then
356         __log_conf_fail_general " Fatal error when extracting token, response: "$?
357         return 1
358         fi
359
360         echo "Decoded token:" >> $HTTPLOG
361         __keycloak_decode_jwt "$__TMP_TOKEN" >> $HTTPLOG
362
363         __KEYCLOAK_ADMIN_TOKEN_EXP=$(echo "$__TMP_TOKEN" | jq  -r '.expires_in')
364         if [ $? -ne 0 ]; then
365         __log_conf_fail_general " Fatal error when extracting expiry time, response: "$?
366         return 1
367         fi
368         echo " Admin token obtained. Expires in $__KEYCLOAK_ADMIN_TOKEN_EXP seconds"
369
370         __log_conf_ok
371         return 0
372 }
373
374 # Create a realm, name, enabled, expiry-time
375 # args: <realm-name> true|false <token-expiry>
376 keycloak_api_create_realm() {
377         __log_conf_start $@
378         __json='{"realm":"'$1'","enabled":'$2',"accessTokenLifespan":'$3'}'
379         res=$(__execute_curl_to_keycloak2 POST "$KEYCLOAK_SERVICE_PATH$KEYCLOAK_REALM_URL_PREFIX" "$__KEYCLOAK_ADMIN_TOKEN" "$__json")
380         if [ $? -ne 0 ]; then
381                 __log_conf_fail_general " Fatal error when creating realm, response: "$?
382                 return 1
383         fi
384         __log_conf_ok
385         return 0
386 }
387
388 # Update a realm, name, enabled, expiry-time
389 # args: <realm-name> true|false <token-expiry>
390 keycloak_api_update_realm() {
391         __log_conf_start $@
392         __json='{"realm":"'$1'","enabled":'$2',"accessTokenLifespan":'$3'}'
393         res=$(__execute_curl_to_keycloak2 PUT "$KEYCLOAK_SERVICE_PATH$KEYCLOAK_REALM_URL_PREFIX/$1" "$__KEYCLOAK_ADMIN_TOKEN" "$__json")
394         if [ $? -ne 0 ]; then
395                 __log_conf_fail_general " Fatal error when updating realm, response: "$?
396                 return 1
397         fi
398         __log_conf_ok
399         return 0
400 }
401
402 # Create a client
403 # args: <realm-name> <client-name>
404 keycloak_api_create_confidential_client() {
405         __log_conf_start $@
406         __json='{"clientId":"'$2'","publicClient":false,"serviceAccountsEnabled": true,"rootUrl":"https://example.com/example/","adminUrl":"https://example.com/example/"}'
407         res=$(__execute_curl_to_keycloak2 POST "$KEYCLOAK_SERVICE_PATH$KEYCLOAK_REALM_URL_PREFIX/$1/clients" "$__KEYCLOAK_ADMIN_TOKEN" "$__json")
408         if [ $? -ne 0 ]; then
409                 __log_conf_fail_general " Fatal error when ucreating client, response: "$?
410                 return 1
411         fi
412         __log_conf_ok
413         return 0
414 }
415
416 __keycloak_api_get_client_id() {
417         TIMESTAMP=$(date "+%Y-%m-%d %H:%M:%S")
418         echo "(${BASH_LINENO[0]}) - ${TIMESTAMP}: ${FUNCNAME[0]}" $@ >> $HTTPLOG
419
420         res=$(__execute_curl_to_keycloak2 GET "$KEYCLOAK_SERVICE_PATH$KEYCLOAK_REALM_URL_PREFIX/$1/clients?clientId=$2" "$__KEYCLOAK_ADMIN_TOKEN")
421         if [ $? -ne 0 ]; then
422                 return 1
423         fi
424         echo $res | jq -r '.[0].id'
425         return 0
426 }
427
428 __keycloak_api_get_service_account_id() {
429         TIMESTAMP=$(date "+%Y-%m-%d %H:%M:%S")
430         echo "(${BASH_LINENO[0]}) - ${TIMESTAMP}: ${FUNCNAME[0]}" $@ >> $HTTPLOG
431
432         res=$(__execute_curl_to_keycloak2 GET "$KEYCLOAK_SERVICE_PATH$KEYCLOAK_REALM_URL_PREFIX/$1/clients/$2/service-account-user" "$__KEYCLOAK_ADMIN_TOKEN")
433         if [ $? -ne 0 ]; then
434                 return 1
435         fi
436         echo $res | jq -r '.id'
437         return 0
438 }
439
440 # Generate secret for client
441 # args: <realm-name> <client-name>
442 keycloak_api_generate_client_secret() {
443         __log_conf_start $@
444         __c_id=$(__keycloak_api_get_client_id $1 $2)
445         if [ $? -ne 0 ]; then
446                 __log_conf_fail_general " Fatal error when getting client id, response: "$?
447                 return 1
448         fi
449         res=$(__execute_curl_to_keycloak2 POST "$KEYCLOAK_SERVICE_PATH$KEYCLOAK_REALM_URL_PREFIX/$1/clients/$__c_id/client-secret" "$__KEYCLOAK_ADMIN_TOKEN")
450         if [ $? -ne 0 ]; then
451                 __log_conf_fail_general " Fatal error when generating client secret, response: "$?
452                 return 1
453         fi
454         __c_sec=$(__execute_curl_to_keycloak2 GET "$KEYCLOAK_SERVICE_PATH$KEYCLOAK_REALM_URL_PREFIX/$1/clients/$__c_id/client-secret" "$__KEYCLOAK_ADMIN_TOKEN")
455         if [ $? -ne 0 ]; then
456                 __log_conf_fail_general " Fatal error when getting client secret, response: "$?
457                 return 1
458         fi
459         __c_sec=$(echo $__c_sec | jq -r .value)
460         echo " Client id    : $__c_id"
461         echo " Client secret: $__c_sec"
462         __log_conf_ok
463         return 0
464 }
465
466 # Get secret for client
467 # args: <realm-name> <client-name>
468 keycloak_api_get_client_secret() {
469         __log_conf_start $@
470         __c_id=$(__keycloak_api_get_client_id $1 $2)
471         if [ $? -ne 0 ]; then
472                 __log_conf_fail_general " Fatal error when getting client id, response: "$?
473                 return 1
474         fi
475         __c_sec=$(__execute_curl_to_keycloak2 GET "$KEYCLOAK_SERVICE_PATH$KEYCLOAK_REALM_URL_PREFIX/$1/clients/$__c_id/client-secret" "$__KEYCLOAK_ADMIN_TOKEN")
476         if [ $? -ne 0 ]; then
477                 __log_conf_fail_general " Fatal error when getting client secret, response: "$?
478                 return 1
479         fi
480         __c_sec=$(echo $__c_sec | jq -r .value)
481         echo " Client id    : $__c_id"
482         echo " Client secret: $__c_sec"
483         __log_conf_ok
484         return 0
485 }
486
487 # Create client roles
488 # args: <realm-name> <client-name> <role>+
489 keycloak_api_create_client_roles() {
490         __log_conf_start $@
491         __c_id=$(__keycloak_api_get_client_id $1 $2)
492         if [ $? -ne 0 ]; then
493                 __log_conf_fail_general " Fatal error when getting client id, response: "$?
494                 return 1
495         fi
496         __realm=$1
497         shift; shift;
498     while [ $# -gt 0 ]; do
499                 __json='{"name":"'$1'"}'
500                 res=$(__execute_curl_to_keycloak2 POST "$KEYCLOAK_SERVICE_PATH$KEYCLOAK_REALM_URL_PREFIX/$__realm/clients/$__c_id/roles" "$__KEYCLOAK_ADMIN_TOKEN" "$__json")
501                 if [ $? -ne 0 ]; then
502                         __log_conf_fail_general " Fatal error when creating client role, response: "$?
503                         return 1
504                 fi
505                 shift
506         done
507         __log_conf_ok
508         return 0
509 }
510
511 # Get client role id
512 # args: <realm-name> <service-account-name> <client-name> <role-name>
513 __get_client_available_role_id() {
514         res=$(__execute_curl_to_keycloak2 GET "$KEYCLOAK_SERVICE_PATH$KEYCLOAK_REALM_URL_PREFIX/$1/users/$2/role-mappings/clients/$3/available" "$__KEYCLOAK_ADMIN_TOKEN")
515         if [ $? -ne 0 ]; then
516                 __log_conf_fail_general " Fatal error when getting availiable client role id, response: "$?
517                 return 1
518         fi
519     __client_role_id=$(echo $res | jq  -r '.[] | select(.name=="'$4'") | .id ')
520     echo $__client_role_id
521     return 0
522 }
523
524 # Map roles to a client
525 # args: <realm-name> <client-name> <role>+
526 keycloak_api_map_client_roles() {
527         __log_conf_start $@
528         __c_id=$(__keycloak_api_get_client_id $1 $2)
529         if [ $? -ne 0 ]; then
530                 __log_conf_fail_general " Fatal error when getting client id, response: "$?
531                 return 1
532         fi
533         __sa_id=$(__keycloak_api_get_service_account_id $1 $__c_id)
534         if [ $? -ne 0 ]; then
535                 __log_conf_fail_general " Fatal error when getting service account id, response: "$?
536                 return 1
537         fi
538         __realm=$1
539         shift; shift;
540         __json="["
541         __cntr=0
542     while [ $# -gt 0 ]; do
543         __client_role_id=$(__get_client_available_role_id $__realm $__sa_id $__c_id $1)
544         if [ $? -ne 0 ]; then
545                         __log_conf_fail_general " Fatal error when getting client role id, response: "$?
546                         return 1
547         fi
548         __role='{"name":"'$1'","id":"'$__client_role_id'","composite": false,"clientRole": true}'
549         if [ $__cntr -gt 0 ]; then
550             __json=$__json","
551         fi
552         __json=$__json$__role
553         let __cntr=__cntr+1
554         shift
555     done
556     __json=$__json"]"
557
558         res=$(__execute_curl_to_keycloak2 POST "$KEYCLOAK_SERVICE_PATH$KEYCLOAK_REALM_URL_PREFIX/$__realm/users/$__sa_id/role-mappings/clients/$__c_id" "$__KEYCLOAK_ADMIN_TOKEN" "$__json")
559         if [ $? -ne 0 ]; then
560                 __log_conf_fail_general " Fatal error when mapping client roles, response: "$?
561                 return 1
562         fi
563
564         __log_conf_ok
565         return 0
566 }
567
568 # Get a client token
569 # args: <realm-name> <client-name>
570 keycloak_api_get_client_token() {
571         __log_conf_start $@
572         __c_id=$(__keycloak_api_get_client_id $1 $2)
573         if [ $? -ne 0 ]; then
574                 __log_conf_fail_general " Fatal error when getting client id, response: "$?
575                 return 1
576         fi
577         __c_sec=$(__execute_curl_to_keycloak2 GET "$KEYCLOAK_SERVICE_PATH$KEYCLOAK_REALM_URL_PREFIX/$1/clients/$__c_id/client-secret" "$__KEYCLOAK_ADMIN_TOKEN")
578         if [ $? -ne 0 ]; then
579                 __log_conf_fail_general " Fatal error when getting client secret, response: "$?
580                 return 1
581         fi
582         __c_sec=$(echo $__c_sec | jq -r .value)
583         __curl_string="-X POST $KEYCLOAK_SERVICE_PATH$KEYCLOAK_TOKEN_URL_PREFIX/$1/protocol/openid-connect/token     -H Content-Type:application/x-www-form-urlencoded     -d client_id="$2" -d client_secret="$__c_sec" -d grant_type=client_credentials"
584         __TMP_TOKEN=$(__execute_curl_to_keycloak "$__curl_string")
585         if [ $? -ne 0 ]; then
586                 __log_conf_fail_general " Fatal error when getting client token, response: "$?
587                 return 1
588         fi
589         echo $__TMP_TOKEN| jq -r .access_token
590         __log_conf_ok
591         return 0
592 }
593
594 # Read a client token
595 # args: <realm-name> <client-name>
596 keycloak_api_read_client_token() {
597         TIMESTAMP=$(date "+%Y-%m-%d %H:%M:%S")
598         echo "(${BASH_LINENO[0]}) - ${TIMESTAMP}: ${FUNCNAME[0]}" $@ >> $HTTPLOG
599         __c_id=$(__keycloak_api_get_client_id $1 $2)
600         if [ $? -ne 0 ]; then
601                 echo "<error-no-token>"
602                 return 1
603         fi
604         __c_sec=$(__execute_curl_to_keycloak2 GET "$KEYCLOAK_SERVICE_PATH$KEYCLOAK_REALM_URL_PREFIX/$1/clients/$__c_id/client-secret" "$__KEYCLOAK_ADMIN_TOKEN")
605         if [ $? -ne 0 ]; then
606                 echo "<error-no-token>"
607                 return 1
608         fi
609         __c_sec=$(echo $__c_sec | jq -r .value)
610         __curl_string="-X POST $KEYCLOAK_SERVICE_PATH$KEYCLOAK_TOKEN_URL_PREFIX/$1/protocol/openid-connect/token     -H Content-Type:application/x-www-form-urlencoded     -d client_id="$2" -d client_secret="$__c_sec" -d grant_type=client_credentials"
611         __TMP_TOKEN=$(__execute_curl_to_keycloak "$__curl_string")
612         if [ $? -ne 0 ]; then
613                 echo "<error-no-token>"
614                 return 1
615         fi
616         echo $__TMP_TOKEN| jq -r .access_token
617         return 0
618 }
619
620 # Read secret for client
621 # args: <realm-name> <client-name>
622 keycloak_api_read_client_secret() {
623         TIMESTAMP=$(date "+%Y-%m-%d %H:%M:%S")
624         echo "(${BASH_LINENO[0]}) - ${TIMESTAMP}: ${FUNCNAME[0]}" $@ >> $HTTPLOG
625         __c_id=$(__keycloak_api_get_client_id $1 $2)
626         if [ $? -ne 0 ]; then
627                 echo "<error-no-secret>"
628                 return 1
629         fi
630         __c_sec=$(__execute_curl_to_keycloak2 GET "$KEYCLOAK_SERVICE_PATH$KEYCLOAK_REALM_URL_PREFIX/$1/clients/$__c_id/client-secret" "$__KEYCLOAK_ADMIN_TOKEN")
631         if [ $? -ne 0 ]; then
632                 echo "<error-no-secret>"
633                 return 1
634         fi
635         __c_sec=$(echo $__c_sec | jq -r .value)
636         echo $__c_sec
637         return 0
638 }