Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhance configuration of Keycloak valid redirects list in the canned deployment #3503

Merged
merged 5 commits into from
Aug 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion server/pbenchinacan/etc/pbench-server/pbench-server.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ uri = postgresql://pbenchcontainer:pbench@localhost:5432/pbenchcontainer
secret-key = "pbench-in-a-can secret shhh"

[openid]
server_url = https://localhost:8090
server_url = ##KEYCLOAK_SERVER_URL##
realm = ##KEYCLOAK_REALM##
client = ##KEYCLOAK_CLIENT##

# Provide a CA cert for the pbenchinacan Keycloak server connection.
tls_ca_file = /etc/pki/tls/certs/pbench_CA.crt
Expand Down
34 changes: 23 additions & 11 deletions server/pbenchinacan/load_keycloak.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,14 @@

# The script defaults to using master realm username/password as admin/admin
# unless specified otherwise by 'ADMIN_USERNAME' and 'ADMIN_PASSWORD' env
# variables. The script also defaults the keycloak redirect URI as
# "https://localhost:8443/*" unless specified otherwise by 'KEYCLOAK_REDIRECT_URI'
# env variable.
# variables. The script constructs the Keycloak redirect URI list as
# "https://<node>:8443/*" from the space-separated list of nodes in
# the 'KEYCLOAK_REDIRECT_HOSTS' env variable, defaulting to 'localhost' plus
# whatever we can glean from the 'hostname' command. It adds to that list the
# value of 'KEYCLOAK_DEV_REDIRECT' which defaults to "http://localhost:3000/*".

KEYCLOAK_HOST_PORT=${KEYCLOAK_HOST_PORT:-"https://localhost:8090"}
KEYCLOAK_REDIRECT_URI=${KEYCLOAK_REDIRECT_URI:-"https://localhost:8443/*"}
KEYCLOAK_REDIRECT_HOSTS=${KEYCLOAK_REDIRECT_HOSTS:-"localhost $(hostname -A) $(hostname -f) 127.0.0.1 ::1 $(hostname -I)"}
KEYCLOAK_DEV_REDIRECT=${KEYCLOAK_DEV_REDIRECT:-"http://localhost:3000/*"}
ADMIN_USERNAME=${ADMIN_USERNAME:-"admin"}
ADMIN_PASSWORD=${ADMIN_PASSWORD:-"admin"}
Expand All @@ -34,6 +36,16 @@ export CURL_CA_BUNDLE=${CURL_CA_BUNDLE:-"${PWD}/server/pbenchinacan/etc/pki/tls/

end_in_epoch_secs=$(date --date "2 minutes" +%s)

keycloak_redirect_uris="\"${KEYCLOAK_DEV_REDIRECT}\""
for n in ${KEYCLOAK_REDIRECT_HOSTS}; do
if [[ $n =~ ^[0-9a-f]{0,4}(:[0-9a-f]{0,4}){1,8}$ ]]; then
n="[$n]" # IPv6 addresses must be wrapped in square-brackets
fi
keycloak_redirect_uris="${keycloak_redirect_uris}, \"https://${n}:8443/*\""
done

echo "Keycloak redirect URI list is <${keycloak_redirect_uris}>."

# Run the custom configuration

ADMIN_TOKEN=""
Expand Down Expand Up @@ -64,7 +76,7 @@ status_code=$(curl -f -s -o /dev/null -w "%{http_code}" -X POST \
"${KEYCLOAK_HOST_PORT}/admin/realms" \
-H "Authorization: Bearer ${ADMIN_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"realm": "'${REALM}'", "enabled": true}')
-d '{"realm": "'"${REALM}"'", "enabled": true}')

if [[ "${status_code}" != "201" ]]; then
echo "Realm creation failed with ${status_code}"
Expand Down Expand Up @@ -99,7 +111,7 @@ curl -si -f -X POST \
"protocolMapper": "oidc-audience-mapper",
"consentRequired": false,
"config": {
"included.client.audience": "'${CLIENT}'",
"included.client.audience": "'"${CLIENT}"'",
"id.token.claim": "false",
"access.token.claim": "true"
}
Expand All @@ -111,16 +123,16 @@ CLIENT_CONF=$(curl -si -f -X POST \
"${KEYCLOAK_HOST_PORT}/admin/realms/${REALM}/clients" \
-H "Authorization: Bearer ${ADMIN_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"clientId": "'${CLIENT}'",
-d '{"clientId": "'"${CLIENT}"'",
"publicClient": true,
"defaultClientScopes": ["pbench", "openid", "profile", "email"],
"directAccessGrantsEnabled": true,
"serviceAccountsEnabled": true,
"enabled": true,
"attributes": {"post.logout.redirect.uris": "+"},
"redirectUris": ["'${KEYCLOAK_REDIRECT_URI}'", "'${KEYCLOAK_DEV_REDIRECT}'"]}')
"redirectUris": ['"${keycloak_redirect_uris}"']}')

CLIENT_ID=$(grep -o -e 'https://[^[:space:]]*' <<< ${CLIENT_CONF} | sed -e 's|.*/||')
CLIENT_ID=$(grep -o -e 'https://[^[:space:]]*' <<< "${CLIENT_CONF}" | sed -e 's|.*/||')
if [[ -z "${CLIENT_ID}" ]]; then
echo "${CLIENT} id is empty"
exit 1
Expand Down Expand Up @@ -155,7 +167,7 @@ USER=$(curl -si -f -X POST \
-H "Content-Type: application/json" \
-d '{"username": "admin", "enabled": true, "credentials": [{"type": "password", "value": "123", "temporary": false}]}')

USER_ID=$(grep -o -e 'https://[^[:space:]]*' <<< ${USER} | sed -e 's|.*/||')
USER_ID=$(grep -o -e 'https://[^[:space:]]*' <<< "${USER}" | sed -e 's|.*/||')

if [[ -z "${USER_ID}" ]]; then
echo "User id is empty"
Expand All @@ -168,7 +180,7 @@ status_code=$(curl -s -o /dev/null -w "%{http_code}" -X POST \
"${KEYCLOAK_HOST_PORT}/admin/realms/${REALM}/users/${USER_ID}/role-mappings/clients/${CLIENT_ID}" \
-H "Authorization: Bearer ${ADMIN_TOKEN}" \
-H "Content-Type: application/json" \
-d '[{"id":"'${ROLE_ID}'","name":"ADMIN"}]')
-d '[{"id":"'"${ROLE_ID}"'","name":"ADMIN"}]')

if [[ "${status_code}" != "204" ]]; then
echo "Assigning 'ADMIN' client role to the user 'admin' failed with ${status_code}"
Expand Down
47 changes: 35 additions & 12 deletions server/pbenchinacan/run-pbench-in-a-can
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,41 @@ export PB_SERVER_IMAGE_PULL_POLICY="${PB_SERVER_IMAGE_PULL_POLICY:-${PB_COMMON_I
# Directory to use for the fully built dashboard code.
export PB_DASHBOARD_DIR="${PB_DASHBOARD_DIR:-${PWD}/dashboard/build/}"

# Keycloak realm and client IDs to be used by the load_keycloak.sh script and
# the pbench-server.cfg file.
export KEYCLOAK_REALM=${KEYCLOAK_REALM:-"pbench-server"}
export KEYCLOAK_CLIENT=${KEYCLOAK_CLIENT:-"pbench-client"}

# Note: the value of PB_HOST_IP will be used to generate the TLS certificate
# and so it (not `localhost`) must also be used to access the Pbench Server;
# otherwise, the TLS validation will fail due to a host mismatch.
if [[ -z "${PB_HOST_IP}" ]]; then
host_ip_list=$(hostname -I)
PB_HOST_IP=${host_ip_list%% *}
export PB_HOST_IP
fi
# Name or IP address to be used by the client to access the Pbench Server, to
# load the Dashboard, and to interface with the canned Keycloak server
host_name=${PB_HOST:-localhost}

host_name=${PB_HOST_NAME:-$(hostname --fqdn)}
# Set a value for the -addext "subjectAltName=..." option to the cert creation.
# Set the initial value "manually" and skip the "dummy" value to make the
# comma-separated concatenations work nicely.
#
# Notes about the use of `readarray`: in order for the output array to be
# visible to the rest of the commands, the `readarray` command must not be
# executed in a subprocess, and therefore it cannot be on the receiving end
# of a pipe. Instead we execute the `hostname` command in a "command
# expansion" inside a "here string". Unfortunately, this causes a newline
# to be appended to the output, so that if we divide the result on spaces
# we end up with an extra array entry containing just a newline. So, instead
# we translate the spaces into newlines ("squeezing" out any repeated
# delimiters) and use the `readarray` default delimiter which is the newline.
subj_alt_name="DNS.1:localhost"
readarray -t cert_hostnames <<< "$(echo "dummy $(hostname -A)" | tr -s ' ' '\n')"
for ((i=1; i < ${#cert_hostnames[*]}; i++)); do
subj_alt_name+=", DNS.$((i+1)):${cert_hostnames[i]}"
done
dbutenhof marked this conversation as resolved.
Show resolved Hide resolved
readarray -t cert_ipaddrs <<< "$(echo "127.0.0.1 ::1 $(hostname -I)" | tr -s ' ' '\n')"
for ((i=0; i < ${#cert_ipaddrs[*]}; i++)); do
subj_alt_name+=", IP.$((i+1)):${cert_ipaddrs[i]}"
done
echo "subjectAltName is <${subj_alt_name}>."

grep -q ${host_name} <<< ${subj_alt_name} \
|| echo "Warning: requested host name/addr (${host_name}) is not covered by the TLS cert." >&2

# Set up TMP_DIR, if it's not already defined, to point to WORKSPACE_TMP, if it
# is defined (e.g., by the CI), or to `/var/tmp/pbench` as a fallback.
Expand Down Expand Up @@ -65,8 +87,9 @@ cp ${pbiac_etc}/pbench-server/pbench-server.cfg ${PB_DEPLOY_FILES}/
# Customize the Pbench Server config file for canned operation
sed -Ei \
-e "/^ *realhost/ s/=.*/= $(hostname -f)/" \
-e "s/<keycloak_realm>/${KEYCLOAK_REALM}/" \
-e "s/<keycloak_client>/${KEYCLOAK_CLIENT}/" \
-e "s|##KEYCLOAK_SERVER_URL##|https://${host_name}:8090|" \
-e "s/##KEYCLOAK_REALM##/${KEYCLOAK_REALM}/" \
-e "s/##KEYCLOAK_CLIENT##/${KEYCLOAK_CLIENT}/" \
-e "s/##ADMIN_NAMES##/${PB_ADMIN_NAMES}/" \
${PB_DEPLOY_FILES}/pbench-server.cfg

Expand Down Expand Up @@ -132,7 +155,7 @@ podman run \
-addext "authorityKeyIdentifier = keyid,issuer" \
-addext "basicConstraints=CA:FALSE" \
-addext "keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment" \
-addext "subjectAltName = IP.2:${PB_HOST_IP}, DNS:localhost" \
-addext "subjectAltName = ${subj_alt_name}" \
2>&1 | sed -E -e '/^[.+*-]*$/ d'

chmod 0640 ${PB_DEPLOY_FILES}/pbench-server.key
Expand Down