diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..9de6f55
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+data
+.DS_Store
\ No newline at end of file
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..bb6e101
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,27 @@
+FROM quay.io/ecosystem-appeng/keycloak-source:latest as keycloak
+
+FROM registry.access.redhat.com/ubi9/openjdk-11-runtime
+WORKDIR /opt/keycloak/bin
+ARG KEYCLOAK_VERSION=21.1.1
+
+USER root
+# COPY ca-bundle.crt /etc/pki/ca-trust/source/anchors
+# RUN update-ca-trust extract
+# RUN trust list --filter=ca-anchors | grep ingress -A3
+
+RUN microdnf install -y jq
+RUN mkdir -p /opt/keycloak/bin/client/lib/
+
+COPY --from=keycloak /opt/keycloak/bin/client/keycloak-admin-cli-${KEYCLOAK_VERSION}.jar client
+COPY --from=keycloak /opt/keycloak/bin/client/lib/ client/lib/
+COPY --from=keycloak /opt/keycloak/bin/kcadm.sh .
+
+COPY scripts/*.sh /opt/keycloak/bin/
+
+RUN chmod +x /opt/keycloak/bin/Entrypoint.sh && \
+ chmod +x /opt/keycloak/bin/kcadm.sh && \
+ chmod +x /opt/keycloak/bin/user-import.sh && \
+ chmod +x /opt/keycloak/bin/user-export.sh
+
+USER 185
+ENTRYPOINT ["/opt/keycloak/bin/Entrypoint.sh"]
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..669bd94
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,33 @@
+WORK_DIRECTORY := $(shell pwd)/data
+CONTAINER_ENGINE ?= $(shell which podman >/dev/null 2>&1 && echo podman || echo docker)
+
+help: ## Prints help for targets with comments
+ @grep -E '^[a-zA-Z0-9.\ _-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
+
+build-docker: ## Build the application image using Docker
+ docker build -t quay.io/ecosystem-appeng/kc-exim .
+
+build-podman: ## Build the application image using Podman
+ podman build -t quay.io/ecosystem-appeng/kc-exim .
+
+build: ## build with available Container Enging
+ @$(CONTAINER_ENGINE) build -t quay.io/ecosystem-appeng/kc-exim .
+
+export: ## run an export job, exports remote server users into local filesystem
+
+ @$(CONTAINER_ENGINE) run -it \
+ -e EXPORT_KEYCLOAK_SERVER=$(EXPORT_KEYCLOAK_SERVER) \
+ -e EXPORT_REALM=$(EXPORT_REALM) \
+ -e EXPORT_TOKEN=$(EXPORT_TOKEN) \
+ -v $(WORK_DIRECTORY):/home/default/kc-exim \
+ quay.io/ecosystem-appeng/kc-exim export
+
+import: ## run an import job, imports local users/groups into a remote server
+ @$(CONTAINER_ENGINE) run -it \
+ -e IMPORT_KEYCLOAK_SERVER=$(IMPORT_KEYCLOAK_SERVER) \
+ -e IMPORT_REALM=$(IMPORT_REALM) \
+ -e IMPORT_TOKEN=$(IMPORT_TOKEN) \
+ -v $(WORK_DIRECTORY):/home/default/kc-exim/ \
+ quay.io/ecosystem-appeng/kc-exim import
+
+generate-token: ## TO-DO maybe support generating token based on username/password
\ No newline at end of file
diff --git a/README.md b/README.md
index c07827e..303f3de 100644
--- a/README.md
+++ b/README.md
@@ -1,69 +1,89 @@
-# kcum
-key cloak user migrationr shell scripts
+# kc-exim
+KeyCloak user Export/Import tool
-## about
-this app contains the kcadm.sh and its dependincies script provided with the latest Keycloak distibution.
-in addition a customized scripts that uses the kcadm.sh to export/import keycloak users from a server/realm into a target server/realm
-it does export relevant user infor including attributes
-it does export group paths
-during the import, the same groups expected to pre-exist in the target server, and the newly migrated users will join the target groups according to the target server group ids, (automatically)
+## Building the Image
-## how to run
+### Build
+```
+make build
+```
-1. clone
-
- ```
- git clone git@github.com:nemerna/kcum.git
+### build with Docker
+```
+make build-docker
+```
+
+
+### build with Podman
+```
+make build-podman
+```
+
+---
+---
+## Variables Used By the Application
+
+| Environment Variables | Description |
+|-------------------------- |:---------------------------------------------------------------------------------------------------------------------: |
+| `EXPORT_KEYCLOAK_SERVER` | The Keycloak Server that you would like to export Users from |
+| `EXPORT_REALM` | The Realm Name under the EXPORT Server you would like to export users from |
+| `EXPORT_TOKEN` | A Temporary Token you need to obtain (using curl or any other method)
used for authenticating to the EXPORT server |
+| `IMPORT_KEYCLOAK_SERVER` | The Keycloak Server that you would like to Import Users into |
+| `IMPORT_REALM` | The Realm Name under the IMPORT Server you would like to IMPORT users into |
+| `IMPORT_TOKEN` | A Temporary Token you need to obtain (using curl or any other method)
used for authenticating to the IMPORT server |
+
+---
+---
+
+## Running The Application
+
+
+### EXPORT
+
+1. prepare variables
+ ```
+ export EXPORT_KEYCLOAK_SERVER=http://localhost:2020
+ export EXPORT_REALM=kcm
+ export EXPORT_TOKEN=xxxxx
```
-2. move to the project dir directory
+2. start the EXPORT job
```
- cd kcum
+ make export
```
-3. add the bin to your PATH
+### IMPORT
+
+1. prepare variables
```
- export PATH=$PATH:$(pwd)/bin
+ # export the following env variables
+ IMPORT_KEYCLOAK_SERVER=http://localhost:1010
+ IMPORT_REALM=kcm
+ IMPORT_TOKEN=xxxxx
```
-4. export relevant env vars
-
+2. start the IMPORT job
+ ```
+ make import
```
- #the work directory to proccess directory (always should be set)
- export WORK_DIRECTORY=./USERMANAGER_EXPORT
-
- # the source server url (copy from)
- export IMPORT_KEYCLOAK_SERVER=https://src-server.com
-
- # the realm of the source server (copy from)
- export IMPORT_REALM=src-realm
-
- # the client-id of the source server (copy from)
- export IMPORT_CLIENT=src-client
+---
+---
- # the client secret of the source server (copy from)
- export IMPORT_SECRET=src-secret
+## Help Commands
+### obtaining an EXPORT_TOKEN token example
- # the target server url (create in)
- export EXPORT_KEYCLOAK_SERVER=https://target-server.com
+```
+ export EXPORT_TOKEN=$(curl -X POST --location "https://$EXPORT_KEYCLOAK_SERVER/realms/$EXPORT_REALM/protocol/openid-connect/token" -H "Content-Type: application/x-www-form-urlencoded" -d "grant_type=password&username=$USER_NAME_PLACE_HOLDER&password=$PASSWORD_PLACE_HOLDER&client_id=$CLIENT_ID_PLACE_HOLDER" | jq -r .access_token)
+```
- # the realm of the target server (create in)
- export EXPORT_REALM=target-realm
+### obtaining an IMPORT_TOKEN token example
- # the client-id of the target server (create in)
- export EXPORT_CLIENT=target-client
+```
+ export IMPORT_TOKEN=$(curl -X POST --location "https://$IMPORT_KEYCLOAK_SERVER/realms/$IMPORT_REALM/protocol/openid-connect/token" -H "Content-Type: application/x-www-form-urlencoded" -d "grant_type=password&username=$USER_NAME_PLACE_HOLDER&password=$PASSWORD_PLACE_HOLDER&client_id=$CLIENT_ID_PLACE_HOLDER" | jq -r .access_token)
+```
- # the client secret of the target server (create in)
- export EXPORT_SECRET=target-secret
- ```
-4. run the user manager
-
- ```
- user-manager.sh [export | import | migrate]
- ```
-**NOTE: when you export, only export parameters needed, when import then only import parameters are needed, when igrate you need to specify both export and import related variables**
diff --git a/bin/client/keycloak-admin-cli-21.1.2.jar b/bin/client/keycloak-admin-cli-21.1.2.jar
deleted file mode 100644
index c8600c9..0000000
Binary files a/bin/client/keycloak-admin-cli-21.1.2.jar and /dev/null differ
diff --git a/bin/client/keycloak-client-registration-cli-21.1.2.jar b/bin/client/keycloak-client-registration-cli-21.1.2.jar
deleted file mode 100644
index a26776d..0000000
Binary files a/bin/client/keycloak-client-registration-cli-21.1.2.jar and /dev/null differ
diff --git a/bin/client/lib/bcprov-jdk15on-1.70.jar b/bin/client/lib/bcprov-jdk15on-1.70.jar
deleted file mode 100644
index 0e4198e..0000000
Binary files a/bin/client/lib/bcprov-jdk15on-1.70.jar and /dev/null differ
diff --git a/bin/client/lib/keycloak-crypto-default-21.1.2.jar b/bin/client/lib/keycloak-crypto-default-21.1.2.jar
deleted file mode 100644
index ba67ed9..0000000
Binary files a/bin/client/lib/keycloak-crypto-default-21.1.2.jar and /dev/null differ
diff --git a/bin/client/lib/keycloak-crypto-fips1402-21.1.2.jar b/bin/client/lib/keycloak-crypto-fips1402-21.1.2.jar
deleted file mode 100644
index 6e4bc99..0000000
Binary files a/bin/client/lib/keycloak-crypto-fips1402-21.1.2.jar and /dev/null differ
diff --git a/bin/groups-ids-wrapper.sh b/bin/groups-ids-wrapper.sh
deleted file mode 100755
index 5bfa94b..0000000
--- a/bin/groups-ids-wrapper.sh
+++ /dev/null
@@ -1,51 +0,0 @@
-#!/bin/bash
-
-# Function to extract the ID of a group by its path
-get_group_id() {
- local group_path=$1
- local id
-
- # Remove double quotes from the path
- group_path="${group_path%\"}"
- group_path="${group_path#\"}"
-
- # Use jq's recursive ".." to traverse the JSON structure
- id=$(jq -r --arg path "$group_path" '.. | select(type=="object" and .path?==$path) | .id' $ALL_GROUPS_FILE)
-
- if [[ $id != "null" ]]; then
- echo $id
- return 0
- fi
-
- return 1
-}
-
-# Iterate over each directory
-for user_dir in "$WORK_DIRECTORY"/*; do
- # Ensure it's a directory
- if [ -d "$user_dir" ]; then
- # Define the group_paths file for this directory
- group_paths_file="$user_dir/group_paths.csv"
- group_ids_file="$user_dir/GROUP_IDS.csv"
-
- # Read each line from the group_paths file
- while IFS= read -r line || [ -n "$line" ]; do
- # Split the line into paths
- IFS=' ' read -ra paths <<< "$line"
- group_ids_line=""
- for path in "${paths[@]}"; do
- # Get the group ID
- group_id=$(get_group_id "$path")
-
- if [[ -n $group_id ]]; then
- # Append group id to group_ids_line
- group_ids_line+="$group_id "
- else
- echo "Group not found for path: $path"
- fi
- done
- # Output the group IDs to the file
- echo "${group_ids_line% }" >> "$group_ids_file"
- done < "$group_paths_file"
- fi
-done
diff --git a/bin/kc.bat b/bin/kc.bat
deleted file mode 100755
index ddf4559..0000000
--- a/bin/kc.bat
+++ /dev/null
@@ -1,175 +0,0 @@
-@echo off
-rem -------------------------------------------------------------------------
-rem Keycloak Startup Script
-rem -------------------------------------------------------------------------
-
-@if not "%ECHO%" == "" echo %ECHO%
-setlocal
-
-rem Get the program name before using shift as the command modify the variable ~nx0
-if "%OS%" == "Windows_NT" (
- set PROGNAME=%~nx0%
-) else (
- set PROGNAME=kc.bat
-)
-
-if "%OS%" == "Windows_NT" (
- set DIRNAME=%~dp0%
-) else (
- set DIRNAME=.\
-)
-
-set SERVER_OPTS=-Djava.util.logging.manager=org.jboss.logmanager.LogManager -Dquarkus-log-max-startup-records=10000
-
-set DEBUG_MODE=false
-set DEBUG_PORT_VAR=8787
-set DEBUG_SUSPEND_VAR=n
-set CONFIG_ARGS=
-
-rem Read command-line args, the ~ removes the quotes from the parameter
-:READ-ARGS
-set KEY=%~1
-if "%KEY%" == "" (
- goto MAIN
-)
-if "%KEY%" == "--debug" (
- set DEBUG_MODE=true
- set DEBUG_PORT_VAR=%2
- if "%DEBUG_PORT_VAR%" == "" (
- set DEBUG_PORT_VAR=8787
- )
- if "%DEBUG_SUSPEND_VAR%" == "" (
- set DEBUG_SUSPEND_VAR=n
- )
- shift
- shift
- goto READ-ARGS
-)
-if "%KEY%" == "start-dev" (
- set CONFIG_ARGS=%CONFIG_ARGS% --profile=dev %KEY%
- shift
- goto READ-ARGS
-)
-if not "%KEY:~0,2%"=="--" if "%KEY:~0,2%"=="-D" (
- set SERVER_OPTS=%SERVER_OPTS% %KEY%=%2
- shift
-)
-if not "%KEY:~0,2%"=="--" if not "%KEY:~0,1%"=="-" (
- set CONFIG_ARGS=%CONFIG_ARGS% %KEY%
-)
-if not "%KEY:~0,2%"=="-D" (
- if "%KEY:~0,1%"=="-" (
- if "%~2"=="" (
- set CONFIG_ARGS=%CONFIG_ARGS% %KEY%
- ) else (
- set CONFIG_ARGS=%CONFIG_ARGS% %KEY% %2%
- )
- shift
- )
-)
-shift
-goto READ-ARGS
-
-:MAIN
-if not "x%JAVA_OPTS%" == "x" (
- echo "JAVA_OPTS already set in environment; overriding default settings with values: %JAVA_OPTS%"
-) else (
- set "JAVA_OPTS=-Xms64m -Xmx512m -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m -Djava.net.preferIPv4Stack=true -Dfile.encoding=UTF-8 -Dsun.stdout.encoding=UTF-8 -Dsun.err.encoding=UTF-8 -Dstdout.encoding=UTF-8 -Dstderr.encoding=UTF-8"
-)
-
-@REM See also https://github.com/wildfly/wildfly-core/blob/7e5624cf92ebe4b64a4793a8c0b2a340c0d6d363/core-feature-pack/common/src/main/resources/content/bin/common.sh#L57-L60
-if not "x%JAVA_ADD_OPENS%" == "x" (
- echo "JAVA_ADD_OPENS already set in environment; overriding default settings with values: %JAVA_ADD_OPENS%"
-) else (
- set "JAVA_ADD_OPENS=--add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.util.concurrent=ALL-UNNAMED --add-opens=java.base/java.security=ALL-UNNAMED"
-)
-set "JAVA_OPTS=%JAVA_OPTS% %JAVA_ADD_OPENS%"
-
-if not "x%JAVA_OPTS_APPEND%" == "x" (
- echo "Appending additional Java properties to JAVA_OPTS: %JAVA_OPTS_APPEND%"
- set JAVA_OPTS=%JAVA_OPTS% %JAVA_OPTS_APPEND%
-)
-
-if NOT "x%DEBUG%" == "x" (
- set DEBUG_MODE=%DEBUG%
-)
-
-if NOT "x%DEBUG_PORT%" == "x" (
- set DEBUG_PORT_VAR=%DEBUG_PORT%
-)
-
-if NOT "x%DEBUG_SUSPEND%" == "x" (
- set DEBUG_SUSPEND_VAR=%DEBUG_SUSPEND%
-)
-
-rem Set debug settings if not already set
-if "%DEBUG_MODE%" == "true" (
- echo "%JAVA_OPTS%" | findstr /I "\-agentlib:jdwp" > nul
- if errorlevel == 1 (
- set JAVA_OPTS=%JAVA_OPTS% -agentlib:jdwp=transport=dt_socket,address=%DEBUG_PORT_VAR%,server=y,suspend=%DEBUG_SUSPEND_VAR%
- ) else (
- echo Debug already enabled in JAVA_OPTS, ignoring --debug argument
- )
-)
-
-rem Setup Keycloak specific properties
-set JAVA_OPTS=-Dprogram.name=%PROGNAME% %JAVA_OPTS%
-
-if "x%JAVA_HOME%" == "x" (
- set JAVA=java
- echo JAVA_HOME is not set. Unexpected results may occur.
- echo Set JAVA_HOME to the directory of your local JDK to avoid this message.
-) else (
- if not exist "%JAVA_HOME%" (
- echo JAVA_HOME "%JAVA_HOME%" path doesn't exist
- goto END
- ) else (
- if not exist "%JAVA_HOME%\bin\java.exe" (
- echo "%JAVA_HOME%\bin\java.exe" does not exist
- goto END
- )
- set "JAVA=%JAVA_HOME%\bin\java"
- )
-)
-
-set "CLASSPATH_OPTS=%DIRNAME%..\lib\quarkus-run.jar"
-
-set JAVA_RUN_OPTS=%JAVA_OPTS% -Dkc.home.dir=%DIRNAME%.. -Djboss.server.config.dir=%DIRNAME%..\conf -Dkeycloak.theme.dir=%DIRNAME%..\themes %SERVER_OPTS% -cp %CLASSPATH_OPTS% io.quarkus.bootstrap.runner.QuarkusEntryPoint %CONFIG_ARGS%
-
-SetLocal EnableDelayedExpansion
-
-set OPTIMIZED_OPTION=--optimized
-set HELP_LONG_OPTION=--help
-set BUILD_OPTION=build
-set IS_HELP_SHORT=false
-
-echo %CONFIG_ARGS% | findstr /r "\<-h\>" > nul
-
-if not errorlevel == 1 (
- set IS_HELP_SHORT=true
-)
-
-if "%PRINT_ENV%" == "true" (
- echo "Using JAVA_OPTS: %JAVA_OPTS%"
- echo "Using JAVA_RUN_OPTS: %JAVA_RUN_OPTS%"
-)
-
-set START_SERVER=true
-
-if "!CONFIG_ARGS:%OPTIMIZED_OPTION%=!"=="!CONFIG_ARGS!" if "!CONFIG_ARGS:%BUILD_OPTION%=!"=="!CONFIG_ARGS!" if "!CONFIG_ARGS:%HELP_LONG_OPTION%=!"=="!CONFIG_ARGS!" if "%IS_HELP_SHORT%" == "false" (
- setlocal enabledelayedexpansion
-
- "%JAVA%" -Dkc.config.build-and-exit=true %JAVA_RUN_OPTS%
-
- if not !errorlevel! == 0 (
- set START_SERVER=false
- )
-
- set JAVA_RUN_OPTS=-Dkc.config.built=true %JAVA_RUN_OPTS%
-)
-
-if "%START_SERVER%" == "true" (
- "%JAVA%" %JAVA_RUN_OPTS%
-)
-
-:END
diff --git a/bin/kc.sh b/bin/kc.sh
deleted file mode 100755
index 6b66014..0000000
--- a/bin/kc.sh
+++ /dev/null
@@ -1,132 +0,0 @@
-#!/bin/bash
-
-case "$(uname)" in
- CYGWIN*)
- IS_CYGWIN="true"
- CFILE="$(cygpath "$0")"
- RESOLVED_NAME="$(readlink -f "$CFILE")"
- ;;
- Darwin*)
- RESOLVED_NAME="$(readlink "$0")"
- ;;
- FreeBSD)
- RESOLVED_NAME="$(readlink -f "$0")"
- ;;
- Linux)
- RESOLVED_NAME="$(readlink -f "$0")"
- ;;
-esac
-
-if [ "x$RESOLVED_NAME" = "x" ]; then
- RESOLVED_NAME="$0"
-fi
-
-GREP="grep"
-DIRNAME="$(dirname "$RESOLVED_NAME")"
-
-abs_path () {
- if [ -z $IS_CYGWIN ] ; then
- echo "$DIRNAME/$1"
- else
- cygpath -w "$DIRNAME/$1"
- fi
-}
-
-SERVER_OPTS="-Dkc.home.dir='$(abs_path '..')'"
-SERVER_OPTS="$SERVER_OPTS -Djboss.server.config.dir='$(abs_path '../conf')'"
-SERVER_OPTS="$SERVER_OPTS -Djava.util.logging.manager=org.jboss.logmanager.LogManager"
-SERVER_OPTS="$SERVER_OPTS -Dquarkus-log-max-startup-records=10000"
-CLASSPATH_OPTS="'$(abs_path "../lib/quarkus-run.jar")'"
-
-DEBUG_MODE="${DEBUG:-false}"
-DEBUG_PORT="${DEBUG_PORT:-8787}"
-DEBUG_SUSPEND="${DEBUG_SUSPEND:-n}"
-
-CONFIG_ARGS=${CONFIG_ARGS:-""}
-
-while [ "$#" -gt 0 ]
-do
- case "$1" in
- --debug)
- DEBUG_MODE=true
- if [ -n "$2" ] && [[ "$2" =~ ^[0-9]+$ ]]; then
- DEBUG_PORT=$2
- shift
- fi
- ;;
- --)
- shift
- break
- ;;
- *)
- if [[ $1 = --* || ! $1 =~ ^-D.* ]]; then
- if [[ "$1" = "start-dev" ]]; then
- CONFIG_ARGS="$CONFIG_ARGS --profile=dev $1"
- else
- CONFIG_ARGS="$CONFIG_ARGS $1"
- fi
- else
- SERVER_OPTS="$SERVER_OPTS $1"
- fi
- ;;
- esac
- shift
-done
-
-if [ "x$JAVA" = "x" ]; then
- if [ "x$JAVA_HOME" != "x" ]; then
- JAVA="$JAVA_HOME/bin/java"
- else
- JAVA="java"
- fi
-fi
-
-#
-# Specify options to pass to the Java VM.
-#
-if [ "x$JAVA_OPTS" = "x" ]; then
- JAVA_OPTS="-Xms64m -Xmx512m -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m -Djava.net.preferIPv4Stack=true -Dfile.encoding=UTF-8 -Dsun.stdout.encoding=UTF-8 -Dsun.err.encoding=UTF-8 -Dstdout.encoding=UTF-8 -Dstderr.encoding=UTF-8"
-else
- echo "JAVA_OPTS already set in environment; overriding default settings with values: $JAVA_OPTS"
-fi
-
-# See also https://github.com/wildfly/wildfly-core/blob/7e5624cf92ebe4b64a4793a8c0b2a340c0d6d363/core-feature-pack/common/src/main/resources/content/bin/common.sh#L57-L60
-if [ "x$JAVA_ADD_OPENS" = "x" ]; then
- JAVA_ADD_OPENS="--add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.util.concurrent=ALL-UNNAMED --add-opens=java.base/java.security=ALL-UNNAMED"
-else
- echo "JAVA_ADD_OPENS already set in environment; overriding default settings with values: $JAVA_ADD_OPENS"
-fi
-JAVA_OPTS="$JAVA_OPTS $JAVA_ADD_OPENS"
-
-if [ "x$JAVA_OPTS_APPEND" != "x" ]; then
- echo "Appending additional Java properties to JAVA_OPTS: $JAVA_OPTS_APPEND"
- JAVA_OPTS="$JAVA_OPTS $JAVA_OPTS_APPEND"
-fi
-
-# Set debug settings if not already set
-if [ "$DEBUG_MODE" = "true" ]; then
- DEBUG_OPT="$(echo "$JAVA_OPTS" | $GREP "\-agentlib:jdwp")"
- if [ "x$DEBUG_OPT" = "x" ]; then
- JAVA_OPTS="$JAVA_OPTS -agentlib:jdwp=transport=dt_socket,address=$DEBUG_PORT,server=y,suspend=$DEBUG_SUSPEND"
- else
- echo "Debug already enabled in JAVA_OPTS, ignoring --debug argument"
- fi
-fi
-
-JAVA_RUN_OPTS="$JAVA_OPTS $SERVER_OPTS -cp $CLASSPATH_OPTS io.quarkus.bootstrap.runner.QuarkusEntryPoint ${CONFIG_ARGS#?}"
-
-if [ "$PRINT_ENV" = "true" ]; then
- echo "Using JAVA_OPTS: $JAVA_OPTS"
- echo "Using JAVA_RUN_OPTS: $JAVA_RUN_OPTS"
-fi
-
-if [[ (! $CONFIG_ARGS = *"--optimized"*) ]] && [[ ! "$CONFIG_ARGS" == " build"* ]] && [[ ! "$CONFIG_ARGS" == *"-h" ]] && [[ ! "$CONFIG_ARGS" == *"--help"* ]]; then
- eval "'$JAVA'" -Dkc.config.build-and-exit=true $JAVA_RUN_OPTS
- EXIT_CODE=$?
- JAVA_RUN_OPTS="-Dkc.config.built=true $JAVA_RUN_OPTS"
- if [ $EXIT_CODE != 0 ]; then
- exit $EXIT_CODE
- fi
-fi
-
-eval exec "'$JAVA'" $JAVA_RUN_OPTS
diff --git a/bin/kcadm.bat b/bin/kcadm.bat
deleted file mode 100644
index 9f69f85..0000000
--- a/bin/kcadm.bat
+++ /dev/null
@@ -1,8 +0,0 @@
-@echo off
-
-if "%OS%" == "Windows_NT" (
- set "DIRNAME=%~dp0%"
-) else (
- set DIRNAME=.\
-)
-java %KC_OPTS% -cp "%DIRNAME%\client\keycloak-admin-cli-21.1.2.jar" --add-opens=java.base/java.security=ALL-UNNAMED -Dkc.lib.dir="%DIRNAME%\client\lib" org.keycloak.client.admin.cli.KcAdmMain %*
diff --git a/bin/kcadm.sh b/bin/kcadm.sh
deleted file mode 100755
index 490c841..0000000
--- a/bin/kcadm.sh
+++ /dev/null
@@ -1,32 +0,0 @@
-#!/bin/sh
-case "`uname`" in
- CYGWIN*)
- CFILE = `cygpath "$0"`
- RESOLVED_NAME=`readlink -f "$CFILE"`
- ;;
- Darwin*)
- RESOLVED_NAME=`readlink "$0"`
- ;;
- FreeBSD)
- RESOLVED_NAME=`readlink -f "$0"`
- ;;
- Linux)
- RESOLVED_NAME=`readlink -f "$0"`
- ;;
-esac
-
-if [ "x$RESOLVED_NAME" = "x" ]; then
- RESOLVED_NAME="$0"
-fi
-
-DIRNAME=`dirname "$RESOLVED_NAME"`
-
-if [ "x$JAVA" = "x" ]; then
- if [ "x$JAVA_HOME" != "x" ]; then
- JAVA="$JAVA_HOME/bin/java"
- else
- JAVA="java"
- fi
-fi
-
-"$JAVA" $KC_OPTS -cp $DIRNAME/client/keycloak-admin-cli-21.1.2.jar --add-opens=java.base/java.security=ALL-UNNAMED -Dkc.lib.dir=$DIRNAME/client/lib org.keycloak.client.admin.cli.KcAdmMain "$@"
diff --git a/bin/kcreg.bat b/bin/kcreg.bat
deleted file mode 100644
index 46fc4e6..0000000
--- a/bin/kcreg.bat
+++ /dev/null
@@ -1,8 +0,0 @@
-@echo off
-
-if "%OS%" == "Windows_NT" (
- set "DIRNAME=%~dp0%"
-) else (
- set DIRNAME=.\
-)
-java %KC_OPTS% -cp "%DIRNAME%\client\keycloak-client-registration-cli-21.1.2.jar" --add-opens=java.base/java.security=ALL-UNNAMED -Dkc.lib.dir="%DIRNAME%\client\lib" org.keycloak.client.registration.cli.KcRegMain %*
diff --git a/bin/kcreg.sh b/bin/kcreg.sh
deleted file mode 100755
index c513eff..0000000
--- a/bin/kcreg.sh
+++ /dev/null
@@ -1,31 +0,0 @@
-#!/bin/sh
-case "`uname`" in
- CYGWIN*)
- CFILE = `cygpath "$0"`
- RESOLVED_NAME=`readlink -f "$CFILE"`
- ;;
- Darwin*)
- RESOLVED_NAME=`readlink "$0"`
- ;;
- FreeBSD)
- RESOLVED_NAME=`readlink -f "$0"`
- ;;
- Linux)
- RESOLVED_NAME=`readlink -f "$0"`
- ;;
-esac
-
-if [ "x$RESOLVED_NAME" = "x" ]; then
- RESOLVED_NAME="$0"
-fi
-
-if [ "x$JAVA" = "x" ]; then
- if [ "x$JAVA_HOME" != "x" ]; then
- JAVA="$JAVA_HOME/bin/java"
- else
- JAVA="java"
- fi
-fi
-
-DIRNAME=`dirname "$RESOLVED_NAME"`
-"$JAVA" $KC_OPTS -cp $DIRNAME/client/keycloak-client-registration-cli-21.1.2.jar --add-opens=java.base/java.security=ALL-UNNAMED -Dkc.lib.dir=$DIRNAME/client/lib org.keycloak.client.registration.cli.KcRegMain "$@"
diff --git a/bin/user-exporter.sh b/bin/user-exporter.sh
deleted file mode 100755
index dc1a0da..0000000
--- a/bin/user-exporter.sh
+++ /dev/null
@@ -1,54 +0,0 @@
-#!/bin/bash
-
-echo "starting exporter"
-
-ERROR_COUNT=0
-# Get users as single json
-kcadm.sh get users -r $EXPORT_REALM -F id,username > $ALL_USERS_FILE
-
-# For each user, get role mappings, group memberships and user attributes and append it to the respective user entry
-users=$(cat $ALL_USERS_FILE | jq -c '.[]')
-
-# For each user id&name get groups paths and full user definition relevant attributes
-for user in $users
-do
- # Get user id
- user_id=$(echo $user | jq -r '.id')
-
- # Get username
- username=$(echo $user | jq -r '.username')
-
- # Display user information for understanding
- echo "Getting user groups for userID=$user_id username=$username"
-
- # Create a directory for each user
- mkdir -p $WORK_DIRECTORY/$username
-
- # Get full user json excluding the id and timestamp
- kcadm.sh get users/$user_id --fields '*(*(*(*(*(*))))),-id,-createdTimestamp' > $WORK_DIRECTORY/$username/user.json
-
- # If failed to get user, skip the current iteration
- if [ $? -ne 0 ]; then
- echo "Failed to get the user with ID=$user_id"
- ((ERROR_COUNT++))
- continue
- fi
-
- # Get the paths of all groups the current user is a member of and save into separate csv file (space separated)
- kcadm.sh get users/$user_id/groups -F path --format CSV > $WORK_DIRECTORY/$username/group_paths.csv
-
- # If failed, skip the rest, (for now there is no rest)
- if [ $? -ne 0 ]; then
- echo "Failed to get the groups of the user with ID=$user_id"
- ((ERROR_COUNT++))
- continue
- fi
-
- echo "Successfully exported user $username"
-done
-
-echo cleaning up temp files
-echo removing $ALL_USERS_FILE
-rm -rf $ALL_USERS_FILE
-
-echo finished the export proccess successfully with $ERROR_COUNT errors
\ No newline at end of file
diff --git a/bin/user-manager.sh b/bin/user-manager.sh
deleted file mode 100755
index 825b450..0000000
--- a/bin/user-manager.sh
+++ /dev/null
@@ -1,124 +0,0 @@
-# #!/bin/bash
-
-action="$1"
-
-case "$action" in
- "export")
-
- export ALL_USERS_FILE=${WORK_DIRECTORY}/EXPORT_SERVER_USERS.json
-
- # check for missing variables
- variables=("EXPORT_KEYCLOAK_SERVER" "EXPORT_REALM"
- "EXPORT_CLIENT" "EXPORT_SECRET"
- "WORK_DIRECTORY" "ALL_USERS_FILE")
-
- for var in "${variables[@]}"; do
- if [ -z "${!var}" ]; then
- echo "Error: $var is not set"
- exit 1
- fi
- done
-
- echo "All variables are set"
-
-
-
- rm -rf $WORK_DIRECTORY
- mkdir $WORK_DIRECTORY
-
-
- # Login to Keycloak EXPORT SERVER
-
- echo $EXPORT_SECRET|kcadm.sh config credentials --server $EXPORT_KEYCLOAK_SERVER --realm $EXPORT_REALM --client $EXPORT_CLIENT
-
-
- # run the exporter
- user-exporter.sh
- ;;
- "import")
-
- export ALL_GROUPS_FILE=${WORK_DIRECTORY}/IMPORT_SERVER_GROUPS.json
-
- # check for missing variables
- variables=("IMPORT_KEYCLOAK_SERVER" "IMPORT_REALM"
- "IMPORT_CLIENT" "IMPORT_SECRET"
- "WORK_DIRECTORY" "ALL_GROUPS_FILE")
-
- for var in "${variables[@]}"; do
- if [ -z "${!var}" ]; then
- echo "Error: $var is not set"
- exit 1
- fi
- done
-
- echo "All variables are set"
-
- # Login to Keycloak IMPORT SERVER
- echo $IMPORT_SECRET|kcadm.sh config credentials --server $IMPORT_KEYCLOAK_SERVER --realm $IMPORT_REALM --client $IMPORT_CLIENT
-
- # get all groups of the target import server
- kcadm.sh get groups > ${ALL_GROUPS_FILE}
-
- # run the groups wrapper
- groups-ids-wrapper.sh
-
- # run the importer
- user_importer.sh
-
- ;;
- "migrate")
-
- export ALL_USERS_FILE=${WORK_DIRECTORY}/EXPORT_SERVER_USERS.json
- export ALL_GROUPS_FILE=${WORK_DIRECTORY}/IMPORT_SERVER_GROUPS.json
-
- # check for missing variables
- variables=("IMPORT_KEYCLOAK_SERVER" "EXPORT_KEYCLOAK_SERVER" "IMPORT_REALM" "EXPORT_REALM"
- "IMPORT_CLIENT" "EXPORT_CLIENT" "IMPORT_SECRET" "EXPORT_SECRET"
- "WORK_DIRECTORY" "WORK_DIRECTORY" "ALL_USERS_FILE" "ALL_GROUPS_FILE")
-
- for var in "${variables[@]}"; do
- if [ -z "${!var}" ]; then
- echo "Error: $var is not set"
- exit 1
- fi
- done
-
- echo "All variables are set"
-
-
-
- rm -rf $WORK_DIRECTORY
- mkdir $WORK_DIRECTORY
- rm -rf $WORK_DIRECTORY
- mkdir $WORK_DIRECTORY
-
-
-
-
- # Login to Keycloak EXPORT SERVER
-
- echo $EXPORT_SECRET|kcadm.sh config credentials --server $EXPORT_KEYCLOAK_SERVER --realm $EXPORT_REALM --client $EXPORT_CLIENT
-
-
- # run the exporter
- user-exporter.sh
-
-
- # Login to Keycloak IMPORT SERVER
- echo $IMPORT_SECRET|kcadm.sh config credentials --server $IMPORT_KEYCLOAK_SERVER --realm $IMPORT_REALM --client $IMPORT_CLIENT
-
- # get all groups of the target import server
- kcadm.sh get groups > ${ALL_GROUPS_FILE}
-
- # run the groups wrapper
- groups-ids-wrapper.sh
-
- # run the importer
- user_importer.sh
- ;;
- *)
- # Invalid action
- echo "Invalid argument. Please provide 'export', 'import', or 'migrate' as the argument."
- exit 1
- ;;
-esac
diff --git a/bin/user_importer.sh b/bin/user_importer.sh
deleted file mode 100755
index 894da23..0000000
--- a/bin/user_importer.sh
+++ /dev/null
@@ -1,34 +0,0 @@
-#!/bin/bash
-
-for USER_DIR in $(find $WORK_DIRECTORY/* -type d)
-do
- USER_JSON_FILE="${USER_DIR}/USER.json"
- GROUP_ID_FILE="${USER_DIR}/GROUP_IDS.csv"
-
- if [[ -f $USER_JSON_FILE ]]
- then
- # Create user from user.json file
- USER_ID=$(kcadm.sh create users -r $IMPORT_REALM -f $USER_JSON_FILE -i)
- if [ $? -ne 0 ]; then
- #TO-DO handle when user exists, only join him to groups?
- echo "skipping the currently user as it exists , we talk about the dir $USER_JSON_FILE"
- continue
- fi
- if [[ -f $GROUP_ID_FILE ]]
- then
- # Add user to each group from the group_ids.csv file
- while read -r GROUP_ID
- do
- if [[ ! -z "$GROUP_ID" ]]
- then
- kcadm.sh update users/$USER_ID/groups/$GROUP_ID -r kcm -s realm=$IMPORT_REALM -s userId=$USER_ID -s groupId=$GROUP_ID -n
- fi
- done < $GROUP_ID_FILE
- else
- echo "user $USER_DIR with new ID $USER_ID has no groups to join to"
- echo the GROUP FIle is $GROUP_ID_FILE
- fi
- else
- echo "cannot find user file under the path $USER_DIR"
- fi
-done
diff --git a/scripts/Entrypoint.sh b/scripts/Entrypoint.sh
new file mode 100644
index 0000000..2372169
--- /dev/null
+++ b/scripts/Entrypoint.sh
@@ -0,0 +1,44 @@
+#!/bin/bash
+
+# define common functions
+log_finish_date() {
+ # Capture the finish time
+ local finish_time=$(date +%s)
+ local finish_date=$(date)
+
+ # Calculate the duration
+ local duration=$((finish_time - start_time))
+ local hours=$((duration / 3600))
+ local minutes=$(( (duration % 3600) / 60 ))
+ local seconds=$((duration % 60))
+
+ # Echo the results
+ echo -e "Script duration: $hours hrs $minutes mins $seconds secs.\n\nStart date: $start_date \n\nFinish date: $finish_date"
+}
+
+# Define comman variables
+export timestamp=$(date "+%Y.%m.%d-%H.%M.%S")
+export PATH=$PATH:/opt/keycloak/bin/
+start_time=$(date +%s)
+start_date=$(date)
+
+if [ -z "$WORK_DIRECTORY" ]; then
+ export WORK_DIRECTORY="/home/default/kc-exim"
+fi
+
+
+
+
+# Start the proccess
+
+if [ "$1" = "import" ]; then
+ user-import.sh 2>&1 | tee "$WORK_DIRECTORY/Logs-import-$IMPORT_REALM-$timestamp"
+ log_finish_date | tee -a "$WORK_DIRECTORY/Logs-import-$IMPORT_REALM-$timestamp"
+elif [ "$1" = "export" ]; then
+ mkdir -p $WORK_DIRECTORY
+ user-export.sh 2>&1 | tee "$WORK_DIRECTORY/Logs-export-$EXPORT_REALM-$timestamp"
+ log_finish_date | tee -a "$WORK_DIRECTORY/Logs-export-$EXPORT_REALM-$timestamp"
+else
+ echo "Invalid argument provided."
+fi
+
diff --git a/scripts/user-export.sh b/scripts/user-export.sh
new file mode 100755
index 0000000..269ad1a
--- /dev/null
+++ b/scripts/user-export.sh
@@ -0,0 +1,63 @@
+#!/bin/bash
+export USERS_FILE=${WORK_DIRECTORY}/EXPORT_SERVER_USERS.json
+
+# Define the temporary file for storing updated users
+temp_file=$(mktemp)
+
+# Check for missing variables
+variables=("EXPORT_KEYCLOAK_SERVER" "EXPORT_REALM" "EXPORT_TOKEN" "WORK_DIRECTORY" "USERS_FILE")
+
+for var in "${variables[@]}"; do
+ if [ -z "${!var}" ]; then
+ echo "Error: $var is not set"
+ exit 1
+ fi
+done
+
+echo "All variables are set"
+
+echo "Starting exporter"
+ERROR_COUNT=0
+EXPORTED_USERS_COUNT=0
+
+# Get users as single JSON
+kcadm.sh get users -r "$EXPORT_REALM" -F '*(*(*(*(*(*))))),-createdTimestamp' --realm "$EXPORT_REALM" --server "$EXPORT_KEYCLOAK_SERVER" --token "$EXPORT_TOKEN" --no-config > "$USERS_FILE"
+
+if [ $? -ne 0 ]; then
+ echo -e "\e[31mError: Failed to Export Users\e[0m"
+ exit 1
+fi
+
+# For each user, get role mappings, group memberships, and user attributes, and append them to the respective user entry
+while IFS= read -r user; do
+ # Get user id and username
+ user_id=$(echo "$user" | jq -r '.id')
+ username=$(echo "$user" | jq -r '.username')
+
+ # Get user group paths
+ REMOTE_GROUPS=$(kcadm.sh get "users/$user_id/groups" -F path --realm "$EXPORT_REALM" --server "$EXPORT_KEYCLOAK_SERVER" --token "$EXPORT_TOKEN" --no-config)
+
+ # If failed to get user groups, skip the current iteration
+ if [ $? -ne 0 ]; then
+ echo "Failed to get groups for user with ID=$user_id, leaving groups empty"
+ ((ERROR_COUNT++))
+ continue
+ fi
+
+ # Turn the user groups into a comma-separated array
+ GROUPS_ARRAY=$(echo "$REMOTE_GROUPS" | jq -r '.[].path' | jq -sR 'split("\n")[:-1]')
+
+ # Update Single User JSON to include the "groups" key and its value
+ UPDATED_USER=$(echo "$user" | jq --argjson groups "$GROUPS_ARRAY" 'if has("groups") then .groups = $groups else . + { "groups": $groups } end')
+
+ # Add the updated user to the temporary file
+ echo "$UPDATED_USER" >> "$temp_file"
+
+ echo "Successfully exported user $username"
+ ((EXPORTED_USERS_COUNT++))
+done < <(jq -c '.[]' "$USERS_FILE")
+
+# Move the temporary file to the final output file
+jq -s '.' "$temp_file" > "$USERS_FILE"
+rm -f $temp_file
+echo -e "Export Process Finished \nSuccessfully made Full Export for: $EXPORTED_USERS_COUNT Users.\nPartially exported: $ERROR_COUNT Users.\n"
diff --git a/scripts/user-import.sh b/scripts/user-import.sh
new file mode 100755
index 0000000..a44c91b
--- /dev/null
+++ b/scripts/user-import.sh
@@ -0,0 +1,34 @@
+#!/bin/bash
+export USERS_FILE=${WORK_DIRECTORY}/EXPORT_SERVER_USERS.json
+
+# check for missing variables
+variables=("IMPORT_KEYCLOAK_SERVER" "IMPORT_TOKEN" "WORK_DIRECTORY")
+
+for var in "${variables[@]}"; do
+ if [ -z "${!var}" ]; then
+ echo "Error: $var is not set"
+ exit 1
+ fi
+done
+
+users=$(cat $USERS_FILE | jq -c '.[]')
+ERROR_COUNT=0
+IMPORTED_USERS_COUNT=0
+# For each user id&name get groups paths and full user definition relevant attributes
+while IFS= read -r user; do
+ echo
+ echo "---------------importing user----------------"
+ echo "${user}" | jq .
+ echo "${user}" | jq . | kcadm.sh create users -r $IMPORT_REALM --realm $IMPORT_REALM --server $IMPORT_KEYCLOAK_SERVER --token $IMPORT_TOKEN --no-config -f -
+ if [ $? -ne 0 ]; then
+ echo "------------Failed To Import------------"
+ ((ERROR_COUNT++))
+ continue
+ fi
+ ((IMPORTED_USERS_COUNT++))
+ echo "------------successfully imported------------"
+ echo
+ echo
+done < <(jq -c '.[]' "$USERS_FILE")
+
+echo -e "\n\nFinished the Import Proccess, Imported:$IMPORTED_USERS_COUNT Users, with $ERROR_COUNT Failed Imports"
\ No newline at end of file