From e64a34f16794d9c1f74b7d68bb434471c3e8f94c Mon Sep 17 00:00:00 2001 From: Quentin BEY Date: Wed, 18 Jun 2025 13:23:24 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB(keycloak)=20c?= =?UTF-8?q?ommand=20to=20add=20new=20client?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This introduce a command to create a new client into the "people" realm. This could be use to create a specific client to test the resource server mode on a local deployment: - run the people stack - add the new client, let say, for docs - configure the people backend for token introspection - make calls from docs backend to people's backend The new client is not mandatory because the same client could be used everywhere but this would not demonstrate the fact the introspection works in a real world configuration. --- Makefile | 10 ++ scripts/keycloak/add-keycloak-client.sh | 149 ++++++++++++++++++++++++ 2 files changed, 159 insertions(+) create mode 100755 scripts/keycloak/add-keycloak-client.sh diff --git a/Makefile b/Makefile index 9059650..63d92c4 100644 --- a/Makefile +++ b/Makefile @@ -427,3 +427,13 @@ install-secret: ## install the kubernetes secrets from Vaultwarden fetch-domain-status: @$(MANAGE) fetch_domain_status .PHONY: fetch-domain-status + +# -- Keycloak related +create-new-client: ## run the add-keycloak-client.sh script for keycloak. + @echo "$(BOLD)Running add-keycloak-client.sh$(RESET)" + @$(COMPOSE_RUN) \ + -v ./scripts/keycloak/add-keycloak-client.sh:/tmp/add-keycloak-client.sh \ + --entrypoint="/tmp/add-keycloak-client.sh" \ + keycloak \ + $(filter-out $@,$(MAKECMDGOALS)) +.PHONY: create-new-client diff --git a/scripts/keycloak/add-keycloak-client.sh b/scripts/keycloak/add-keycloak-client.sh new file mode 100755 index 0000000..5f37f6d --- /dev/null +++ b/scripts/keycloak/add-keycloak-client.sh @@ -0,0 +1,149 @@ +#!/bin/bash + +# Script to add a new client to Keycloak using the kcadm.sh CLI +# Usage: ./add-keycloak-client.sh [client_id] [client_secret] + +# Default values +CLIENT_ID=${1:-"some-client-id"} +CLIENT_SECRET=${2:-"ThisIsAnExampleKeyForDevPurposeOnly"} +KEYCLOAK_URL=${KEYCLOAK_URL:-"http://keycloak:8080"} +KEYCLOAK_ADMIN=${KEYCLOAK_ADMIN:-"admin"} +KEYCLOAK_ADMIN_PASSWORD=${KEYCLOAK_ADMIN_PASSWORD:-"admin"} +REALM=${REALM:-"people"} + +# Check for kcadm.sh in common locations +KCADM_LOCATIONS=( + "/opt/keycloak/bin/kcadm.sh" + "/opt/jboss/keycloak/bin/kcadm.sh" + "/usr/local/bin/kcadm.sh" + "./bin/kcadm.sh" + "$(which kcadm.sh 2>/dev/null)" +) + +KCADM="" +for loc in "${KCADM_LOCATIONS[@]}"; do + if [ -x "$loc" ]; then + KCADM="$loc" + break + fi +done + +if [ -z "$KCADM" ]; then + echo "Error: kcadm.sh not found. Please specify its location manually." + echo "You can set the KCADM environment variable to the path of kcadm.sh" + exit 1 +fi + +echo "Using Keycloak Admin CLI at: $KCADM" +echo "Logging in to Keycloak at $KEYCLOAK_URL..." + +# Login to Keycloak +$KCADM config credentials \ + --server $KEYCLOAK_URL \ + --realm master \ + --user $KEYCLOAK_ADMIN \ + --password $KEYCLOAK_ADMIN_PASSWORD + +if [ $? -ne 0 ]; then + echo "Failed to login to Keycloak. Please check your credentials and try again." + exit 1 +fi + +echo "Successfully logged in to Keycloak." +echo "Creating new client '$CLIENT_ID' in realm '$REALM'..." + +# Create a temporary JSON file with client configuration +CLIENT_JSON=$(mktemp) +cat > "$CLIENT_JSON" << EOF +{ + "clientId": "$CLIENT_ID", + "name": "", + "description": "", + "rootUrl": "", + "adminUrl": "", + "baseUrl": "", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "secret": "$CLIENT_SECRET", + "redirectUris": [ + "http://localhost:8070/*", + "http://localhost:8071/*", + "http://localhost:3200/*", + "http://localhost:8088/*", + "http://localhost:3000/*" + ], + "webOrigins": [ + "http://localhost:3200", + "http://localhost:8088", + "http://localhost:8070", + "http://localhost:3000" + ], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": false, + "frontchannelLogout": true, + "protocol": "openid-connect", + "attributes": { + "access.token.lifespan": "-1", + "client.secret.creation.time": "$(date +%s)", + "user.info.response.signature.alg": "RS256", + "post.logout.redirect.uris": "http://localhost:8070/*##http://localhost:3200/*##http://localhost:3000/*", + "oauth2.device.authorization.grant.enabled": "false", + "use.jwks.url": "false", + "backchannel.logout.revoke.offline.tokens": "false", + "use.refresh.tokens": "true", + "tls-client-certificate-bound-access-tokens": "false", + "oidc.ciba.grant.enabled": "false", + "backchannel.logout.session.required": "true", + "client_credentials.use_refresh_token": "false", + "acr.loa.map": "{}", + "require.pushed.authorization.requests": "false", + "display.on.consent.screen": "false", + "client.session.idle.timeout": "-1", + "token.response.type.bearer.lower-case": "false" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": true, + "nodeReRegistrationTimeout": -1, + "defaultClientScopes": [ + "web-origins", + "acr", + "roles", + "profile", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] +} +EOF + +# Create the client using kcadm.sh +$KCADM create clients -r "$REALM" -f "$CLIENT_JSON" + +if [ $? -ne 0 ]; then + echo "Failed to create client. Check the error message above." + rm "$CLIENT_JSON" + exit 1 +fi + +echo "✅ Client '$CLIENT_ID' created successfully!" +echo " Client ID: $CLIENT_ID" +echo " Client Secret: $CLIENT_SECRET" + +# Clean up temporary file +rm "$CLIENT_JSON" + +# Display the created client +echo "Client details:" +$KCADM get clients -r "$REALM" --query "clientId=$CLIENT_ID"