From ff64103b4d85c62ae304049353da0f7ce886a43b Mon Sep 17 00:00:00 2001
From: Martin Weise <martin.weise@tuwien.ac.at>
Date: Sun, 2 Apr 2023 17:09:15 +0200
Subject: [PATCH] SSL Support

- Gateway has self-signed SSL certificate for all requests
- Authentication service can be used securely behind Gateway
- User service exposes self-registration endpoint
---
 .env.unix.example                             |   5 +-
 docker-compose.yml                            |   4 +-
 fda-authentication-service/Dockerfile         |   4 +-
 fda-authentication-service/dbrepo-realm.json  |  52 ++++++------
 .../docker-entrypoint.sh                      |   4 +-
 fda-authentication-service/server.keystore    | Bin 0 -> 2220 bytes
 .../service-register.sh                       |   7 +-
 .../java/at/tuwien/config/ReadyConfig.java    |   2 +-
 .../tuwien/service/impl/ImageServiceImpl.java |   1 -
 fda-gateway-service/Dockerfile                |   6 ++
 fda-gateway-service/pom.xml                   |   8 ++
 .../java/at/tuwien/config/ReadyConfig.java    |   4 +-
 .../src/main/resources/application-docker.yml |  14 +++-
 .../src/main/resources/application-local.yml  |  14 +++-
 .../src/main/resources/application.yml        |  16 +++-
 fda-gateway-service/server.keystore           | Bin 0 -> 2220 bytes
 ...JwtResponseDto.java => CreateUserDto.java} |  22 +++--
 .../at/tuwien/api/auth/CredentialDto.java     |  29 +++++++
 .../at/tuwien/api/auth/SignupRequestDto.java  |   5 +-
 .../at/tuwien/api/auth/TokenBriefDto.java     |  43 ----------
 .../java/at/tuwien/api/auth/TokenDto.java     |  51 +++++++-----
 .../java/at/tuwien/entities/auth/Realm.java   |  31 +++++++
 .../java/at/tuwien/entities/user/User.java    |   2 +-
 fda-query-service/pom.xml                     |   3 -
 fda-user-service/Dockerfile                   |   3 +
 fda-user-service/pom.xml                      |  30 +------
 .../java/at/tuwien/endpoint/UserEndpoint.java |   6 +-
 .../src/main/resources/application-docker.yml |   5 ++
 .../src/main/resources/application-local.yml  |   9 +-
 .../src/main/resources/application.yml        |   5 ++
 .../src/test/resources/application.properties |   5 --
 .../java/at/tuwien/config/GatewayConfig.java  |  40 +++++++++
 .../java/at/tuwien/config/ReadyConfig.java    |  13 ++-
 .../exception/RealmNotFoundException.java     |  21 +++++
 .../exception/RemoteUnavailableException.java |  21 +++++
 .../gateway/AuthenticationServiceGateway.java |  11 +++
 .../AuthenticationServiceGatewayImpl.java     |  77 ++++++++++++++++++
 .../java/at/tuwien/mapper/UserMapper.java     |   3 +-
 .../repository/elastic/UserIdxRepository.java |  10 +++
 .../repository/jpa/RealmRepository.java       |  14 ++++
 .../java/at/tuwien/service/RealmService.java  |  10 +++
 .../java/at/tuwien/service/UserService.java   |   4 +-
 .../tuwien/service/impl/RealmServiceImpl.java |  43 ++++++++++
 .../tuwien/service/impl/UserServiceImpl.java  |  33 +++++---
 server.keystore                               | Bin 0 -> 2220 bytes
 45 files changed, 520 insertions(+), 170 deletions(-)
 create mode 100644 fda-authentication-service/server.keystore
 create mode 100644 fda-gateway-service/server.keystore
 rename fda-metadata-db/api/src/main/java/at/tuwien/api/auth/{JwtResponseDto.java => CreateUserDto.java} (53%)
 create mode 100644 fda-metadata-db/api/src/main/java/at/tuwien/api/auth/CredentialDto.java
 delete mode 100644 fda-metadata-db/api/src/main/java/at/tuwien/api/auth/TokenBriefDto.java
 create mode 100644 fda-metadata-db/entities/src/main/java/at/tuwien/entities/auth/Realm.java
 create mode 100644 fda-user-service/services/src/main/java/at/tuwien/config/GatewayConfig.java
 create mode 100644 fda-user-service/services/src/main/java/at/tuwien/exception/RealmNotFoundException.java
 create mode 100644 fda-user-service/services/src/main/java/at/tuwien/exception/RemoteUnavailableException.java
 create mode 100644 fda-user-service/services/src/main/java/at/tuwien/gateway/AuthenticationServiceGateway.java
 create mode 100644 fda-user-service/services/src/main/java/at/tuwien/gateway/impl/AuthenticationServiceGatewayImpl.java
 create mode 100644 fda-user-service/services/src/main/java/at/tuwien/repository/elastic/UserIdxRepository.java
 create mode 100644 fda-user-service/services/src/main/java/at/tuwien/repository/jpa/RealmRepository.java
 create mode 100644 fda-user-service/services/src/main/java/at/tuwien/service/RealmService.java
 create mode 100644 fda-user-service/services/src/main/java/at/tuwien/service/impl/RealmServiceImpl.java
 create mode 100644 server.keystore

diff --git a/.env.unix.example b/.env.unix.example
index bbc4ce743d..2e4923867f 100644
--- a/.env.unix.example
+++ b/.env.unix.example
@@ -14,4 +14,7 @@ BROKER_PASSWORD=fda
 KEYCLOAK_ADMIN=fda
 KEYCLOAK_ADMIN_PASSWORD=fda
 BROKER_CONSUMERS=2
-WEBSITE=http://example.com
\ No newline at end of file
+WEBSITE=http://example.com
+KEY_ALIAS=server
+KEY_STORE_PATH=/server.keystore
+KEY_STORE_PASSWORD=password
\ No newline at end of file
diff --git a/docker-compose.yml b/docker-compose.yml
index 07f8df8fa9..4fffbf9e7e 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -235,8 +235,10 @@ services:
     ports:
       - "9099:9099"
     depends_on:
+      fda-authentication-service:
+        condition: service_healthy
       fda-metadata-db:
-        condition: service_started
+        condition: service_healthy
     logging:
       driver: json-file
 
diff --git a/fda-authentication-service/Dockerfile b/fda-authentication-service/Dockerfile
index 38e737360b..243d968918 100644
--- a/fda-authentication-service/Dockerfile
+++ b/fda-authentication-service/Dockerfile
@@ -13,8 +13,8 @@ ENV KC_DB=mariadb
 
 WORKDIR /opt/keycloak
 
-# for demonstration purposes only, please make sure to use proper certificates in production instead
-RUN keytool -genkeypair -storepass password -storetype PKCS12 -keyalg RSA -keysize 2048 -dname "CN=server" -alias server -ext "SAN:c=DNS:localhost,IP:127.0.0.1" -keystore conf/server.keystore
+COPY ./server.keystore ./conf/server.keystore
+
 RUN /opt/keycloak/bin/kc.sh build
 
 ###### SECOND STAGE ######
diff --git a/fda-authentication-service/dbrepo-realm.json b/fda-authentication-service/dbrepo-realm.json
index 0e26cf80c9..2007120dde 100644
--- a/fda-authentication-service/dbrepo-realm.json
+++ b/fda-authentication-service/dbrepo-realm.json
@@ -26,7 +26,7 @@
   "oauth2DeviceCodeLifespan" : 600,
   "oauth2DevicePollingInterval" : 5,
   "enabled" : true,
-  "sslRequired" : "none",
+  "sslRequired" : "external",
   "registrationAllowed" : false,
   "registrationEmailAsUsername" : false,
   "rememberMe" : false,
@@ -843,7 +843,7 @@
   "otpPolicyLookAheadWindow" : 1,
   "otpPolicyPeriod" : 30,
   "otpPolicyCodeReusable" : false,
-  "otpSupportedApplications" : [ "totpAppGoogleName", "totpAppFreeOTPName", "totpAppMicrosoftAuthenticatorName" ],
+  "otpSupportedApplications" : [ "totpAppMicrosoftAuthenticatorName", "totpAppGoogleName", "totpAppFreeOTPName" ],
   "webAuthnPolicyRpEntityName" : "keycloak",
   "webAuthnPolicySignatureAlgorithms" : [ "ES256" ],
   "webAuthnPolicyRpId" : "",
@@ -1761,7 +1761,7 @@
       "subType" : "anonymous",
       "subComponents" : { },
       "config" : {
-        "allowed-protocol-mapper-types" : [ "oidc-usermodel-property-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-address-mapper", "oidc-usermodel-attribute-mapper", "saml-user-attribute-mapper", "oidc-full-name-mapper", "saml-role-list-mapper", "saml-user-property-mapper" ]
+        "allowed-protocol-mapper-types" : [ "saml-user-attribute-mapper", "saml-user-property-mapper", "oidc-address-mapper", "oidc-usermodel-attribute-mapper", "oidc-usermodel-property-mapper", "saml-role-list-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-full-name-mapper" ]
       }
     }, {
       "id" : "1849e52a-b8c9-44a8-af3d-ee19376a1ed1",
@@ -1787,7 +1787,7 @@
       "subType" : "authenticated",
       "subComponents" : { },
       "config" : {
-        "allowed-protocol-mapper-types" : [ "saml-user-property-mapper", "oidc-full-name-mapper", "oidc-usermodel-property-mapper", "saml-role-list-mapper", "oidc-usermodel-attribute-mapper", "saml-user-attribute-mapper", "oidc-address-mapper", "oidc-sha256-pairwise-sub-mapper" ]
+        "allowed-protocol-mapper-types" : [ "saml-user-property-mapper", "saml-role-list-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-usermodel-property-mapper", "saml-user-attribute-mapper", "oidc-usermodel-attribute-mapper", "oidc-address-mapper", "oidc-full-name-mapper" ]
       }
     } ],
     "org.keycloak.userprofile.UserProfileProvider" : [ {
@@ -1845,7 +1845,7 @@
   "internationalizationEnabled" : false,
   "supportedLocales" : [ ],
   "authenticationFlows" : [ {
-    "id" : "5eb1d49c-38cd-41a8-9557-13bcffb1a642",
+    "id" : "6fa20b3b-44fc-40ba-b310-bb2e729d53b9",
     "alias" : "Account verification options",
     "description" : "Method with which to verity the existing account",
     "providerId" : "basic-flow",
@@ -1867,7 +1867,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "29e68803-3d8d-4fe5-af03-0814e35a6ed3",
+    "id" : "c4f55400-b209-4eea-b996-70a19bea428e",
     "alias" : "Authentication Options",
     "description" : "Authentication options.",
     "providerId" : "basic-flow",
@@ -1896,7 +1896,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "aeadaa3b-f3d2-47ef-9e0a-ea4b737fe684",
+    "id" : "e43378cd-51b1-4978-8083-c01b8ab9e4c7",
     "alias" : "Browser - Conditional OTP",
     "description" : "Flow to determine if the OTP is required for the authentication",
     "providerId" : "basic-flow",
@@ -1918,7 +1918,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "4c958b93-579e-45da-8471-a6aebc439641",
+    "id" : "db5f2382-dabd-4a38-901b-95eff1d60c14",
     "alias" : "Direct Grant - Conditional OTP",
     "description" : "Flow to determine if the OTP is required for the authentication",
     "providerId" : "basic-flow",
@@ -1940,7 +1940,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "6878c43f-0aa7-40c6-bf28-f984029e893b",
+    "id" : "29a20ae2-7a1a-44fd-888a-fac7954cfe01",
     "alias" : "First broker login - Conditional OTP",
     "description" : "Flow to determine if the OTP is required for the authentication",
     "providerId" : "basic-flow",
@@ -1962,7 +1962,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "aae75803-fb3c-4c74-9ee7-73fc897aad05",
+    "id" : "3aa766d9-06ec-4073-9143-d810e12a2233",
     "alias" : "Handle Existing Account",
     "description" : "Handle what to do if there is existing account with same email/username like authenticated identity provider",
     "providerId" : "basic-flow",
@@ -1984,7 +1984,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "0987a7fe-5e31-40b1-be1f-6cd4a5a76e43",
+    "id" : "6a72a53f-bf1e-4c06-a366-71a4d963d5d0",
     "alias" : "Reset - Conditional OTP",
     "description" : "Flow to determine if the OTP should be reset or not. Set to REQUIRED to force.",
     "providerId" : "basic-flow",
@@ -2006,7 +2006,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "68078236-033e-4f17-b02f-fb5f401be3fe",
+    "id" : "5cb272da-a960-4429-b090-e676b358bb80",
     "alias" : "User creation or linking",
     "description" : "Flow for the existing/non-existing user alternatives",
     "providerId" : "basic-flow",
@@ -2029,7 +2029,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "28c746e7-fc22-4c61-872a-26670fffb8ed",
+    "id" : "58c9a9c9-3a95-45bf-9c40-d2926246158a",
     "alias" : "Verify Existing Account by Re-authentication",
     "description" : "Reauthentication of existing account",
     "providerId" : "basic-flow",
@@ -2051,7 +2051,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "502957db-db9d-4138-a5e3-90fce22bff15",
+    "id" : "976a2b1b-0a72-4c7b-9ebb-356595ad08b4",
     "alias" : "browser",
     "description" : "browser based authentication",
     "providerId" : "basic-flow",
@@ -2087,7 +2087,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "9312b6c7-f999-4285-ae9f-e365666066e7",
+    "id" : "63b290b2-4828-457b-9ed4-c68aa477cd2b",
     "alias" : "clients",
     "description" : "Base authentication for clients",
     "providerId" : "client-flow",
@@ -2123,7 +2123,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "31c2af88-b37c-4fdb-8dec-23a5ba145114",
+    "id" : "9c557280-9319-45c7-8656-198765ab5f23",
     "alias" : "direct grant",
     "description" : "OpenID Connect Resource Owner Grant",
     "providerId" : "basic-flow",
@@ -2152,7 +2152,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "c11ae35d-772a-4a1f-9934-a1945b45d617",
+    "id" : "6b0351e2-9b6b-475a-b59b-045096c2bbfa",
     "alias" : "docker auth",
     "description" : "Used by Docker clients to authenticate against the IDP",
     "providerId" : "basic-flow",
@@ -2167,7 +2167,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "0485179d-460c-4ad0-b0b2-02bbf57eb012",
+    "id" : "39d51855-eabd-4b38-b2da-04046c3d156c",
     "alias" : "first broker login",
     "description" : "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account",
     "providerId" : "basic-flow",
@@ -2190,7 +2190,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "aa1b06b4-1c12-4f7c-9d5a-6422ab5bb89a",
+    "id" : "ee67da7f-0738-4ef6-a07f-cb814a171dc6",
     "alias" : "forms",
     "description" : "Username, password, otp and other auth forms.",
     "providerId" : "basic-flow",
@@ -2212,7 +2212,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "fc52dc5f-16ee-499e-ad0a-ba04093efc33",
+    "id" : "011fb692-45ac-487f-8124-56836be0fbfe",
     "alias" : "http challenge",
     "description" : "An authentication flow based on challenge-response HTTP Authentication Schemes",
     "providerId" : "basic-flow",
@@ -2234,7 +2234,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "576fb8d9-96b4-464a-a2b5-655c61755ec0",
+    "id" : "7fe214c5-6462-4965-8a37-6c5753f27a97",
     "alias" : "registration",
     "description" : "registration flow",
     "providerId" : "basic-flow",
@@ -2250,7 +2250,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "a026a910-1a04-4eb0-9fe2-6eb72139a39b",
+    "id" : "e140eca6-cb4e-4db9-811a-f2c8a012d873",
     "alias" : "registration form",
     "description" : "registration form",
     "providerId" : "form-flow",
@@ -2286,7 +2286,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "0d0e32f3-7030-42fa-be83-528281d9eca0",
+    "id" : "715bab3d-905a-4f91-8c62-b141cfd89002",
     "alias" : "reset credentials",
     "description" : "Reset credentials for a user if they forgot their password or something",
     "providerId" : "basic-flow",
@@ -2322,7 +2322,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "ec850fcc-5b8c-4109-9cf4-a16f84cd7804",
+    "id" : "83dd0a05-4fc5-47d3-84d8-f6f2641e4de3",
     "alias" : "saml ecp",
     "description" : "SAML ECP Profile Authentication Flow",
     "providerId" : "basic-flow",
@@ -2338,13 +2338,13 @@
     } ]
   } ],
   "authenticatorConfig" : [ {
-    "id" : "d42b19d3-2efe-4879-9ce0-7c055a3d949e",
+    "id" : "c07fe13c-bb0d-451b-955e-078376f851db",
     "alias" : "create unique user config",
     "config" : {
       "require.password.update.after.registration" : "false"
     }
   }, {
-    "id" : "f1c71d63-f83f-432d-b9b4-e1a97095b5e1",
+    "id" : "5b25a33e-a4dc-4827-a4e8-62fc1f383cef",
     "alias" : "review profile config",
     "config" : {
       "update.profile.on.first.login" : "missing"
diff --git a/fda-authentication-service/docker-entrypoint.sh b/fda-authentication-service/docker-entrypoint.sh
index ca82a7bada..d8e0fdcd85 100644
--- a/fda-authentication-service/docker-entrypoint.sh
+++ b/fda-authentication-service/docker-entrypoint.sh
@@ -1,6 +1,6 @@
 #!/bin/bash
 
-/app/service-register.sh authentication-service 8080
-(while sleep 60; do bash /app/service-register.sh authentication-service 8080; done) &
+/app/service-register.sh authentication-service 8443 8080
+(while sleep 60; do bash /app/service-register.sh authentication-service 8443 8080; done) &
 
 /opt/keycloak/bin/kc.sh start-dev --import-realm
diff --git a/fda-authentication-service/server.keystore b/fda-authentication-service/server.keystore
new file mode 100644
index 0000000000000000000000000000000000000000..93e5c28b23293910dac23a3e974cb485524a3a17
GIT binary patch
literal 2220
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
C1<soQ

literal 0
HcmV?d00001

diff --git a/fda-authentication-service/service-register.sh b/fda-authentication-service/service-register.sh
index 72734426bb..2d7f64be97 100755
--- a/fda-authentication-service/service-register.sh
+++ b/fda-authentication-service/service-register.sh
@@ -9,7 +9,8 @@ EUREKA_URI="http://$EUREKA_HOST:$EUREKA_PORT"
 SERVICE_NAME="$1"
 SERVICE_PROTOCOL="http"
 SERVICE_HOST="$1"
-SERVICE_PORT="${2:-9000}"
+SECURE_PORT="${2:-9000}"
+SERVICE_PORT="${3:-9000}"
 
 SERVICE_URI="$SERVICE_PROTOCOL://$SERVICE_HOST:$SERVICE_PORT"
 HOME_URI="$SERVICE_URI/realms/dbrepo"
@@ -72,8 +73,8 @@ cat <<EOF > /tmp/json.json
       "@enabled": "true"
     },
     "securePort": {
-      "\$": "$SERVICE_PORT",
-      "@enabled": "false"
+      "\$": "$SECURE_PORT",
+      "@enabled": "true"
     },
     "vipAddress": "$SERVICE_HOST",
     "secureVipAddress": "$SERVICE_HOST",
diff --git a/fda-container-service/services/src/main/java/at/tuwien/config/ReadyConfig.java b/fda-container-service/services/src/main/java/at/tuwien/config/ReadyConfig.java
index 00c5a1f3dc..37617f6ccf 100644
--- a/fda-container-service/services/src/main/java/at/tuwien/config/ReadyConfig.java
+++ b/fda-container-service/services/src/main/java/at/tuwien/config/ReadyConfig.java
@@ -37,7 +37,7 @@ public class ReadyConfig {
             imageService.pull(imageRepository, imageTag);
         } else {
             log.debug("image {}:{} is present on the host", imageRepository, imageTag);
-            log.debug("skip pulling image {}:{}", imageRepository, imageTag);
+            log.trace("skip pulling image {}:{}", imageRepository, imageTag);
         }
         Files.touch(new File(readyPath));
         log.info("Service is ready");
diff --git a/fda-container-service/services/src/main/java/at/tuwien/service/impl/ImageServiceImpl.java b/fda-container-service/services/src/main/java/at/tuwien/service/impl/ImageServiceImpl.java
index 682ced6609..ccb3dbae79 100644
--- a/fda-container-service/services/src/main/java/at/tuwien/service/impl/ImageServiceImpl.java
+++ b/fda-container-service/services/src/main/java/at/tuwien/service/impl/ImageServiceImpl.java
@@ -162,7 +162,6 @@ public class ImageServiceImpl implements ImageService {
     public boolean exists(String repository, String tag) {
         final List<Image> images = dockerClient.listImagesCmd()
                 .exec();
-        log.trace("found images {}", images);
         return images.stream()
                 .filter(i -> Objects.nonNull(i.getRepoTags()))
                 .filter(i -> i.getRepoTags().length > 0)
diff --git a/fda-gateway-service/Dockerfile b/fda-gateway-service/Dockerfile
index f8aea4c73b..a270239d58 100644
--- a/fda-gateway-service/Dockerfile
+++ b/fda-gateway-service/Dockerfile
@@ -21,6 +21,12 @@ ENV METADATA_USERNAME=postgres
 ENV METADATA_PASSWORD=postgres
 ENV GATEWAY_ENDPOINT=http://gateway-service:9095
 ENV LOG_LEVEL=debug
+ENV KEY_ALIAS=server
+ENV KEY_PASS=password
+ENV KEY_STORE=/server.keystore
+ENV KEY_STORE_PASS=password
+
+COPY ./server.keystore /server.keystore
 
 COPY ./service_ready /usr/bin
 RUN chmod +x /usr/bin/service_ready
diff --git a/fda-gateway-service/pom.xml b/fda-gateway-service/pom.xml
index 210f10156c..5110b896d8 100644
--- a/fda-gateway-service/pom.xml
+++ b/fda-gateway-service/pom.xml
@@ -12,6 +12,14 @@
     <version>1.1.0-alpha</version>
     <name>fda-gateway-service</name>
     <description>Demo project for Spring Boot</description>
+    <url>https://dbrepo-docs.ossdip.at</url>
+    <developers>
+        <developer>
+            <name>Martin Weise</name>
+            <email>martin.weise@tuwien.ac.at</email>
+            <organization>TU Wien</organization>
+        </developer>
+    </developers>
 
     <packaging>pom</packaging>
     <modules>
diff --git a/fda-gateway-service/rest-service/src/main/java/at/tuwien/config/ReadyConfig.java b/fda-gateway-service/rest-service/src/main/java/at/tuwien/config/ReadyConfig.java
index f4eae349a4..2250fa5088 100644
--- a/fda-gateway-service/rest-service/src/main/java/at/tuwien/config/ReadyConfig.java
+++ b/fda-gateway-service/rest-service/src/main/java/at/tuwien/config/ReadyConfig.java
@@ -18,9 +18,7 @@ public class ReadyConfig {
     private String readyPath;
 
     @EventListener(ApplicationReadyEvent.class)
-    public void init() throws IOException, InterruptedException {
-        log.info("Wait more for gateway start");
-        Thread.sleep(20 * 1000L);
+    public void init() throws IOException {
         Files.touch(new File(readyPath));
     }
 
diff --git a/fda-gateway-service/rest-service/src/main/resources/application-docker.yml b/fda-gateway-service/rest-service/src/main/resources/application-docker.yml
index 7c42301ea6..b1eda86566 100644
--- a/fda-gateway-service/rest-service/src/main/resources/application-docker.yml
+++ b/fda-gateway-service/rest-service/src/main/resources/application-docker.yml
@@ -22,8 +22,20 @@ spring:
     name: gateway-service
   cloud:
     loadbalancer.ribbon.enabled: false
+    gateway:
+      httpclient:
+        ssl:
+          useInsecureTrustManager: true
 management.endpoints.web.exposure.include: health,info,prometheus
-server.port: 9095
+server:
+  port: 9095
+  ssl:
+    enabled: true
+    key-alias: "${KEY_ALIAS}"
+    key-store: "${KEY_STORE}"
+    key-store-type: jks
+    key-store-password: "${KEY_STORE_PASS}"
+    key-password: "${KEY_PASS}"
 logging:
   pattern.console: "%d %highlight(%-5level) %msg%n"
   level:
diff --git a/fda-gateway-service/rest-service/src/main/resources/application-local.yml b/fda-gateway-service/rest-service/src/main/resources/application-local.yml
index 6c2aeb22df..ab294c2a57 100644
--- a/fda-gateway-service/rest-service/src/main/resources/application-local.yml
+++ b/fda-gateway-service/rest-service/src/main/resources/application-local.yml
@@ -22,8 +22,20 @@ spring:
     name: gateway-service
   cloud:
     loadbalancer.ribbon.enabled: false
+    gateway:
+      httpclient:
+        ssl:
+          useInsecureTrustManager: true
 management.endpoints.web.exposure.include: health,info,prometheus
-server.port: 9095
+server:
+  port: 9095
+  ssl:
+    enabled: true
+    key-alias: server
+    key-store: "./server.keystore"
+    key-store-type: jks
+    key-store-password: password
+    key-password: password
 logging:
   pattern.console: "%d %highlight(%-5level) %msg%n"
   level:
diff --git a/fda-gateway-service/rest-service/src/main/resources/application.yml b/fda-gateway-service/rest-service/src/main/resources/application.yml
index 21e4e554b3..94983082cb 100644
--- a/fda-gateway-service/rest-service/src/main/resources/application.yml
+++ b/fda-gateway-service/rest-service/src/main/resources/application.yml
@@ -17,9 +17,23 @@ spring:
           time_zone: UTC
   application:
     name: gateway-service
+  cloud:
+    loadbalancer.ribbon.enabled: false
+    gateway:
+      httpclient:
+        ssl:
+          useInsecureTrustManager: true
 springdoc.swagger-ui.enabled: false
 management.endpoints.web.exposure.include: health,info,prometheus
-server.port: 9095
+server:
+  port: 9095
+  ssl:
+    enabled: true
+    key-alias: "${KEY_ALIAS}"
+    key-store: "${KEY_STORE}"
+    key-store-type: jks
+    key-store-password: "${KEY_STORE_PASS}"
+    key-password: "${KEY_PASS}"
 logging:
   pattern.console: "%d %highlight(%-5level) %msg%n"
   level:
diff --git a/fda-gateway-service/server.keystore b/fda-gateway-service/server.keystore
new file mode 100644
index 0000000000000000000000000000000000000000..93e5c28b23293910dac23a3e974cb485524a3a17
GIT binary patch
literal 2220
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
C1<soQ

literal 0
HcmV?d00001

diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/auth/JwtResponseDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/auth/CreateUserDto.java
similarity index 53%
rename from fda-metadata-db/api/src/main/java/at/tuwien/api/auth/JwtResponseDto.java
rename to fda-metadata-db/api/src/main/java/at/tuwien/api/auth/CreateUserDto.java
index c92b4913c8..d300e66967 100644
--- a/fda-metadata-db/api/src/main/java/at/tuwien/api/auth/JwtResponseDto.java
+++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/auth/CreateUserDto.java
@@ -3,6 +3,8 @@ package at.tuwien.api.auth;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.*;
 
+import javax.validation.constraints.Email;
+import javax.validation.constraints.NotBlank;
 import javax.validation.constraints.NotNull;
 import java.util.List;
 
@@ -12,22 +14,26 @@ import java.util.List;
 @Builder
 @AllArgsConstructor
 @NoArgsConstructor
-public class JwtResponseDto {
+public class CreateUserDto {
 
     @NotNull
-    @ToString.Exclude
-    private String token;
-
-    private String type;
-
-    private Long id;
+    @Schema(example = "true")
+    private Boolean enabled;
 
+    @NotBlank
     @Schema(example = "user")
     private String username;
 
+    @NotBlank
+    @Email
     @Schema(example = "user@example.com")
     private String email;
 
-    private List<String> roles;
+    private String firstName;
+
+    private String lastName;
+
+    @NotNull
+    private List<CredentialDto> credentials;
 
 }
diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/auth/CredentialDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/auth/CredentialDto.java
new file mode 100644
index 0000000000..fe1400d3ab
--- /dev/null
+++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/auth/CredentialDto.java
@@ -0,0 +1,29 @@
+package at.tuwien.api.auth;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+@Getter
+@Setter
+@ToString
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class CredentialDto {
+
+    @NotBlank
+    @Schema(example = "password")
+    private String type;
+
+    @NotBlank
+    @Schema(example = "abc123")
+    private String value;
+
+    @NotNull
+    @Schema(example = "false")
+    private Boolean temporary;
+
+}
diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/auth/SignupRequestDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/auth/SignupRequestDto.java
index 7f6f3937bc..3f6784bdd0 100644
--- a/fda-metadata-db/api/src/main/java/at/tuwien/api/auth/SignupRequestDto.java
+++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/auth/SignupRequestDto.java
@@ -4,6 +4,7 @@ import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.*;
 
 import javax.validation.constraints.Email;
+import javax.validation.constraints.NotBlank;
 import javax.validation.constraints.NotNull;
 import javax.validation.constraints.Pattern;
 
@@ -15,12 +16,12 @@ import javax.validation.constraints.Pattern;
 @NoArgsConstructor
 public class SignupRequestDto {
 
-    @NotNull
+    @NotBlank
     @Pattern(regexp = "^[a-z0-9]{3,}$")
     @Schema(example = "user")
     private String username;
 
-    @NotNull
+    @NotBlank
     @Email
     @Schema(example = "user@example.com")
     private String email;
diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/auth/TokenBriefDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/auth/TokenBriefDto.java
deleted file mode 100644
index cbb5060540..0000000000
--- a/fda-metadata-db/api/src/main/java/at/tuwien/api/auth/TokenBriefDto.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package at.tuwien.api.auth;
-
-import com.fasterxml.jackson.annotation.JsonFormat;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.*;
-
-import javax.validation.constraints.NotBlank;
-import javax.validation.constraints.NotNull;
-import java.time.Instant;
-
-@Getter
-@Setter
-@ToString
-@Builder
-@AllArgsConstructor
-@NoArgsConstructor
-public class TokenBriefDto {
-
-    @NotNull
-    private Long id;
-
-    @NotBlank
-    @JsonProperty("token_hash")
-    @Schema(example = "5891b5b522d5df086d0ff0b110fbd9d21bb4fc7163af34d08286a2e846f6be03")
-    private String tokenHash;
-
-    @NotNull
-    @Schema(example = "2020-08-04 11:12:00")
-    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX", timezone = "UTC")
-    private Instant created;
-
-    @JsonProperty("last_used")
-    @Schema(example = "2020-08-04 11:12:00")
-    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX", timezone = "UTC")
-    private Instant lastUsed;
-
-    @NotNull
-    @Schema(example = "2020-08-04 11:12:00")
-    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX", timezone = "UTC")
-    private Instant expires;
-
-}
diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/auth/TokenDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/auth/TokenDto.java
index 1cf442509c..cf3399dbe9 100644
--- a/fda-metadata-db/api/src/main/java/at/tuwien/api/auth/TokenDto.java
+++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/auth/TokenDto.java
@@ -1,13 +1,11 @@
 package at.tuwien.api.auth;
 
-import com.fasterxml.jackson.annotation.JsonFormat;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.*;
 
 import javax.validation.constraints.NotBlank;
 import javax.validation.constraints.NotNull;
-import java.time.Instant;
 
 @Getter
 @Setter
@@ -17,31 +15,44 @@ import java.time.Instant;
 @NoArgsConstructor
 public class TokenDto {
 
-    @NotNull
-    private Long id;
+    @NotBlank
+    @JsonProperty("access_token")
+    @Schema(example = "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJBbFdvalRsa1dBSVVoYTJLWjFvOEluWEtNbVAzUTg0STZiMFFHYkR6aEpvIn0.eyJleHAiOjE2ODAyNjgyNjgsImlhdCI6MTY4MDI2ODIwOCwianRpIjoiNjkwNjRlNTQtODNhNS00NGYxLWE3OTItNWFjOWU4OTA5YTlkIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL3JlYWxtcy9tYXN0ZXIiLCJzdWIiOiI4MjQ2OWMyMS0yYjNjLTRmMDctODg1Yi1hMzViMGQ5YTJhNjYiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJhZG1pbi1jbGkiLCJzZXNzaW9uX3N0YXRlIjoiNDQ1ODA3ZWUtMjg3Ni00NjFkLWE4ZjMtNGQyN2IzMGMyMWZhIiwiYWNyIjoiMSIsInNjb3BlIjoicHJvZmlsZSBlbWFpbCIsInNpZCI6IjQ0NTgwN2VlLTI4NzYtNDYxZC1hOGYzLTRkMjdiMzBjMjFmYSIsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwicHJlZmVycmVkX3VzZXJuYW1lIjoiZmRhIn0.IOQxqWvlPDV9WuFOeLVG-ayexbK8OqylPABghEMSbMpmNlQhSAjbjaMY31uU-uADZRHB-mC8bmRS5PoWNtanuhz0lORDCeissFsbv0UL9Q42CaxG75vFAAD5WsdIHIr-dtEjEiXYtu-qwdg83griAUeO119TTdgldyPxo4jWzNw0ui6W7r4LqP4fSk31iJfxR5urgs5k6Ctzg-fXCORT31-nKz_YJQwLoPO9j4afX_1mnCXY5qFGMSrmPKzB0CArZfUpa_4nqt4Y768yOC3gigAyCjXtvXKkgCmARPSRjERGDdTb6SGbAwRDiVHVy9wy7XZwOcCFMEra9H7mV0Mx2A")
+    private String accessToken;
 
     @NotBlank
-    @JsonProperty("token_hash")
-    @Schema(example = "5891b5b522d5df086d0ff0b110fbd9d21bb4fc7163af34d08286a2e846f6be03")
-    private String tokenHash;
+    @JsonProperty("refresh_token")
+    @Schema(example = "eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICI4YTczZGYwZS03NzMwLTRiZDEtOGVhOC1mZTdjZWViNmMxYWMifQ.eyJleHAiOjE2ODAyNzAwMDgsImlhdCI6MTY4MDI2ODIwOCwianRpIjoiNWYyNDIwNDItNmJmZi00ZTQ2LTg2NTAtNDBhY2E3YjVkZjMyIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL3JlYWxtcy9tYXN0ZXIiLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjgwODAvcmVhbG1zL21hc3RlciIsInN1YiI6IjgyNDY5YzIxLTJiM2MtNGYwNy04ODViLWEzNWIwZDlhMmE2NiIsInR5cCI6IlJlZnJlc2giLCJhenAiOiJhZG1pbi1jbGkiLCJzZXNzaW9uX3N0YXRlIjoiNDQ1ODA3ZWUtMjg3Ni00NjFkLWE4ZjMtNGQyN2IzMGMyMWZhIiwic2NvcGUiOiJwcm9maWxlIGVtYWlsIiwic2lkIjoiNDQ1ODA3ZWUtMjg3Ni00NjFkLWE4ZjMtNGQyN2IzMGMyMWZhIn0.-GltWGkIaKUJ4AqRYnGHblTr0ygZm2CsRQB6zz5ePm4")
+    private String refreshToken;
+
+    @NotBlank
+    @JsonProperty("token_type")
+    @Schema(example = "Bearer")
+    private String tokenType;
 
     @NotNull
-    @Schema(example = "2020-08-04 11:12:00")
-    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX", timezone = "UTC")
-    private Instant created;
+    @JsonProperty("expires_in")
+    @Schema(example = "60")
+    private Long expiresIn;
 
-    @JsonProperty("last_used")
-    @Schema(example = "2020-08-04 11:12:00")
-    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX", timezone = "UTC")
-    private Instant lastUsed;
+    @NotNull
+    @JsonProperty("session_state")
+    @Schema(example = "445807ee-2876-461d-a8f3-4d27b30c21fa")
+    private String sessionState;
 
     @NotNull
-    @Schema(example = "2020-08-04 11:12:00")
-    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX", timezone = "UTC")
-    private Instant expires;
+    @JsonProperty("scope")
+    @Schema(example = "profile email")
+    private String scope;
 
-    @NotBlank
-    @Schema(example = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c")
-    private String token;
+    @NotNull
+    @JsonProperty("refresh_expires_in")
+    @Schema(example = "1800")
+    private Long refreshExpiresIn;
+
+    @NotNull
+    @JsonProperty("not-before-policy")
+    @Schema(example = "0")
+    private Long notBeforePolicy;
 
 }
diff --git a/fda-metadata-db/entities/src/main/java/at/tuwien/entities/auth/Realm.java b/fda-metadata-db/entities/src/main/java/at/tuwien/entities/auth/Realm.java
new file mode 100644
index 0000000000..fb7010325f
--- /dev/null
+++ b/fda-metadata-db/entities/src/main/java/at/tuwien/entities/auth/Realm.java
@@ -0,0 +1,31 @@
+package at.tuwien.entities.auth;
+
+import lombok.*;
+
+import javax.persistence.*;
+
+@Data
+@Entity
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+@ToString
+@EqualsAndHashCode(onlyExplicitlyIncluded = true)
+@Table(name = "realm")
+public class Realm {
+
+    @Id
+    @EqualsAndHashCode.Include
+    @Column(nullable = false)
+    private String id;
+
+    @Column(nullable = false)
+    private Boolean enabled;
+
+    @Column(nullable = false)
+    private String name;
+
+    @Column(nullable = false)
+    private String sslRequired;
+
+}
diff --git a/fda-metadata-db/entities/src/main/java/at/tuwien/entities/user/User.java b/fda-metadata-db/entities/src/main/java/at/tuwien/entities/user/User.java
index abd946bdb9..29f7222a71 100644
--- a/fda-metadata-db/entities/src/main/java/at/tuwien/entities/user/User.java
+++ b/fda-metadata-db/entities/src/main/java/at/tuwien/entities/user/User.java
@@ -36,7 +36,7 @@ public class User {
     @Column(name = "last_name")
     private String lastname;
 
-    @Column(name = "realm id")
+    @Column(name = "realm_id")
     private String realmId;
 
     @Column(unique = true, nullable = false)
diff --git a/fda-query-service/pom.xml b/fda-query-service/pom.xml
index 67fb838c96..35ec3a2928 100644
--- a/fda-query-service/pom.xml
+++ b/fda-query-service/pom.xml
@@ -297,9 +297,6 @@
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-project-info-reports-plugin</artifactId>
                 <version>3.0.0</version>
-<!--                <configuration>-->
-<!--                    <outputDirectory>docs</outputDirectory>-->
-<!--                </configuration>-->
             </plugin>
             <plugin>
                 <groupId>com.soebes.maven.plugins</groupId>
diff --git a/fda-user-service/Dockerfile b/fda-user-service/Dockerfile
index dd9fe0250e..a772cacf6f 100644
--- a/fda-user-service/Dockerfile
+++ b/fda-user-service/Dockerfile
@@ -24,6 +24,9 @@ FROM openjdk:11-jre-slim as runtime
 ENV METADATA_DB=fda
 ENV METADATA_USERNAME=root
 ENV METADATA_PASSWORD=dbrepo
+ENV GATEWAY_ENDPOINT=http://gateway-service:9095
+ENV KEYCLOAK_ADMIN=fda
+ENV KEYCLOAK_ADMIN_PASSWORD=fda
 ENV LOG_LEVEL=debug
 ENV DBREPO_CLIENT_SECRET=client-secret
 ENV CLIENT_ID=dbrepo-client
diff --git a/fda-user-service/pom.xml b/fda-user-service/pom.xml
index f06580d159..989dafab4c 100644
--- a/fda-user-service/pom.xml
+++ b/fda-user-service/pom.xml
@@ -118,29 +118,6 @@
             <groupId>org.springframework.data</groupId>
             <artifactId>spring-data-elasticsearch</artifactId>
         </dependency>
-        <!-- AMPQ -->
-        <dependency>
-            <groupId>com.rabbitmq</groupId>
-            <artifactId>amqp-client</artifactId>
-            <version>${rabbit-amqp-client.version}</version>
-        </dependency>
-        <!-- Docker -->
-        <dependency>
-            <groupId>com.github.docker-java</groupId>
-            <artifactId>docker-java</artifactId>
-            <version>${docker.version}</version>
-            <exclusions>
-                <exclusion>
-                    <groupId>javax.ws.rs</groupId>
-                    <artifactId>jsr311-api</artifactId>
-                </exclusion>
-            </exclusions>
-        </dependency>
-        <dependency>
-            <groupId>com.github.docker-java</groupId>
-            <artifactId>docker-java-transport-httpclient5</artifactId>
-            <version>${docker.version}</version>
-        </dependency>
         <!-- IDE -->
         <dependency>
             <groupId>org.projectlombok</groupId>
@@ -237,9 +214,7 @@
                         <exclude>at/tuwien/handlers/**/*</exclude>
                         <exclude>at/tuwien/exception/**/*</exclude>
                         <exclude>at/tuwien/config/**/*</exclude>
-                        <exclude>**/RabbitMqServiceImpl.class</exclude>
-                        <exclude>**/ServiceSeeder.class</exclude>
-                        <exclude>**/FdaQueryServiceApplication.class</exclude>
+                        <exclude>**/FdaUserServiceApplication.class</exclude>
                     </excludes>
                 </configuration>
                 <executions>
@@ -267,9 +242,6 @@
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-project-info-reports-plugin</artifactId>
                 <version>3.0.0</version>
-<!--                <configuration>-->
-<!--                    <outputDirectory>docs</outputDirectory>-->
-<!--                </configuration>-->
             </plugin>
             <plugin>
                 <groupId>com.soebes.maven.plugins</groupId>
diff --git a/fda-user-service/rest-service/src/main/java/at/tuwien/endpoint/UserEndpoint.java b/fda-user-service/rest-service/src/main/java/at/tuwien/endpoint/UserEndpoint.java
index 7bb8dc3149..20c4119928 100644
--- a/fda-user-service/rest-service/src/main/java/at/tuwien/endpoint/UserEndpoint.java
+++ b/fda-user-service/rest-service/src/main/java/at/tuwien/endpoint/UserEndpoint.java
@@ -2,6 +2,9 @@ package at.tuwien.endpoint;
 
 import at.tuwien.api.auth.SignupRequestDto;
 import at.tuwien.api.user.UserBriefDto;
+import at.tuwien.exception.RealmNotFoundException;
+import at.tuwien.exception.RemoteUnavailableException;
+import at.tuwien.exception.UserNotFoundException;
 import at.tuwien.mapper.UserMapper;
 import at.tuwien.service.UserService;
 import io.micrometer.core.annotation.Timed;
@@ -48,7 +51,8 @@ public class UserEndpoint {
     @Transactional
     @Timed(value = "user.create", description = "Time needed to create a user in the metadata database")
     @Operation(summary = "Create a user")
-    public ResponseEntity<UserBriefDto> create(SignupRequestDto data) {
+    public ResponseEntity<?> create(SignupRequestDto data) throws RealmNotFoundException, UserNotFoundException,
+            RemoteUnavailableException {
         log.debug("endpoint create a user, data={}", data);
         final UserBriefDto dto = userMapper.userToUserBriefDto(userService.create(data));
         log.trace("create user resulted in dto {}", dto);
diff --git a/fda-user-service/rest-service/src/main/resources/application-docker.yml b/fda-user-service/rest-service/src/main/resources/application-docker.yml
index 084cc82986..486101dd8e 100644
--- a/fda-user-service/rest-service/src/main/resources/application-docker.yml
+++ b/fda-user-service/rest-service/src/main/resources/application-docker.yml
@@ -35,6 +35,11 @@ eureka:
   client.serviceUrl.defaultZone: http://discovery-service:9090/eureka/
 fda:
   ready.path: /ready
+  gateway.endpoint: "${GATEWAY_ENDPOINT}"
+  keycloak:
+    endpoint: https://authentication-service:8443/
+    username: "${KEYCLOAK_ADMIN}"
+    password: "${KEYCLOAK_ADMIN_PASSWORD}"
   jwt:
     issuer: "${JWT_ISSUER}"
     public_key: "${JWT_PUBKEY}"
\ No newline at end of file
diff --git a/fda-user-service/rest-service/src/main/resources/application-local.yml b/fda-user-service/rest-service/src/main/resources/application-local.yml
index 4b86aa03a8..c6ac95610e 100644
--- a/fda-user-service/rest-service/src/main/resources/application-local.yml
+++ b/fda-user-service/rest-service/src/main/resources/application-local.yml
@@ -32,9 +32,14 @@ logging:
     org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver: debug
 eureka:
   instance.hostname: user-service
-  client.serviceUrl.defaultZone: http://discovery-service:9090/eureka/
+  client.serviceUrl.defaultZone: http://localhost:9090/eureka/
 fda:
-  ready.path: /ready
+  ready.path: ./ready
+  gateway.endpoint: http://localhost:9095
+  keycloak:
+    endpoint: https://localhost:8443/
+    username: fda
+    password: fda
   jwt:
     issuer: http://localhost:8080/realms/dbrepo
     public_key: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqqnHQ2BWWW9vDNLRCcxD++xZg/16oqMo/c1l+lcFEjjAIJjJp/HqrPYU/U9GvquGE6PbVFtTzW1KcKawOW+FJNOA3CGo8Q1TFEfz43B8rZpKsFbJKvQGVv1Z4HaKPvLUm7iMm8Hv91cLduuoWx6Q3DPe2vg13GKKEZe7UFghF+0T9u8EKzA/XqQ0OiICmsmYPbwvf9N3bCKsB/Y10EYmZRb8IhCoV9mmO5TxgWgiuNeCTtNCv2ePYqL/U0WvyGFW0reasIK8eg3KrAUj8DpyOgPOVBn3lBGf+3KFSYi+0bwZbJZWqbC/Xlk20Go1YfeJPRIt7ImxD27R/lNjgDO/MwIDAQAB
\ No newline at end of file
diff --git a/fda-user-service/rest-service/src/main/resources/application.yml b/fda-user-service/rest-service/src/main/resources/application.yml
index 9ba4e1547a..5f93e7a618 100644
--- a/fda-user-service/rest-service/src/main/resources/application.yml
+++ b/fda-user-service/rest-service/src/main/resources/application.yml
@@ -35,6 +35,11 @@ eureka:
   client.serviceUrl.defaultZone: http://discovery-service:9090/eureka/
 fda:
   ready.path: /ready
+  gateway.endpoint: "${GATEWAY_ENDPOINT}"
+  keycloak:
+    endpoint: https://authentication-service:8443/
+    username: "${KEYCLOAK_ADMIN}"
+    password: "${KEYCLOAK_ADMIN_PASSWORD}"
   jwt:
     issuer: "${JWT_ISSUER}"
     public_key: "${JWT_PUBKEY}"
diff --git a/fda-user-service/rest-service/src/test/resources/application.properties b/fda-user-service/rest-service/src/test/resources/application.properties
index 4eea490a91..ddba279a3b 100644
--- a/fda-user-service/rest-service/src/test/resources/application.properties
+++ b/fda-user-service/rest-service/src/test/resources/application.properties
@@ -21,11 +21,6 @@ spring.jpa.show-sql=false
 logging.level.root=error
 logging.level.at.tuwien.=trace
 
-# broker service
-spring.rabbitmq.host=dbrepo-broker-service
-spring.rabbitmq.username=guest
-spring.rabbitmq.password=guest
-
 # search service
 fda.consumers=2
 fda.gateway.endpoint: http://localhost:15672
diff --git a/fda-user-service/services/src/main/java/at/tuwien/config/GatewayConfig.java b/fda-user-service/services/src/main/java/at/tuwien/config/GatewayConfig.java
new file mode 100644
index 0000000000..540b5d96f4
--- /dev/null
+++ b/fda-user-service/services/src/main/java/at/tuwien/config/GatewayConfig.java
@@ -0,0 +1,40 @@
+package at.tuwien.config;
+
+import lombok.Getter;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.client.RestTemplate;
+import org.springframework.web.util.DefaultUriBuilderFactory;
+
+@Getter
+@Configuration
+public class GatewayConfig {
+
+    @Value("${fda.gateway.endpoint}")
+    private String gatewayEndpoint;
+
+    @Value("${fda.keycloak.endpoint}")
+    private String keycloakEndpoint;
+
+    @Value("${fda.keycloak.username}")
+    private String keycloakUsername;
+
+    @Value("${fda.keycloak.password}")
+    private String keycloakPassword;
+
+    @Bean
+    public RestTemplate gatewayRestTemplate() {
+        final RestTemplate restTemplate =  new RestTemplate();
+        restTemplate.setUriTemplateHandler(new DefaultUriBuilderFactory(gatewayEndpoint));
+        return restTemplate;
+    }
+
+    @Bean
+    public RestTemplate keycloakRestTemplate() {
+        final RestTemplate restTemplate =  new RestTemplate();
+        restTemplate.setUriTemplateHandler(new DefaultUriBuilderFactory(keycloakEndpoint));
+        return restTemplate;
+    }
+
+}
diff --git a/fda-user-service/services/src/main/java/at/tuwien/config/ReadyConfig.java b/fda-user-service/services/src/main/java/at/tuwien/config/ReadyConfig.java
index 2250fa5088..388480c9be 100644
--- a/fda-user-service/services/src/main/java/at/tuwien/config/ReadyConfig.java
+++ b/fda-user-service/services/src/main/java/at/tuwien/config/ReadyConfig.java
@@ -1,7 +1,10 @@
 package at.tuwien.config;
 
+import at.tuwien.exception.RealmNotFoundException;
+import at.tuwien.service.RealmService;
 import com.google.common.io.Files;
 import lombok.extern.log4j.Log4j2;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.boot.context.event.ApplicationReadyEvent;
 import org.springframework.context.annotation.Configuration;
@@ -17,8 +20,16 @@ public class ReadyConfig {
     @Value("${fda.ready.path}")
     private String readyPath;
 
+    private final RealmService realmService;
+
+    @Autowired
+    public ReadyConfig(RealmService realmService) {
+        this.realmService = realmService;
+    }
+
     @EventListener(ApplicationReadyEvent.class)
-    public void init() throws IOException {
+    public void init() throws IOException, RealmNotFoundException {
+        realmService.update("master");
         Files.touch(new File(readyPath));
     }
 
diff --git a/fda-user-service/services/src/main/java/at/tuwien/exception/RealmNotFoundException.java b/fda-user-service/services/src/main/java/at/tuwien/exception/RealmNotFoundException.java
new file mode 100644
index 0000000000..1750cfb525
--- /dev/null
+++ b/fda-user-service/services/src/main/java/at/tuwien/exception/RealmNotFoundException.java
@@ -0,0 +1,21 @@
+package at.tuwien.exception;
+
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.ResponseStatus;
+
+@ResponseStatus(code = HttpStatus.NOT_FOUND)
+public class RealmNotFoundException extends Exception {
+
+    public RealmNotFoundException(String msg) {
+        super(msg);
+    }
+
+    public RealmNotFoundException(String msg, Throwable thr) {
+        super(msg, thr);
+    }
+
+    public RealmNotFoundException(Throwable thr) {
+        super(thr);
+    }
+
+}
diff --git a/fda-user-service/services/src/main/java/at/tuwien/exception/RemoteUnavailableException.java b/fda-user-service/services/src/main/java/at/tuwien/exception/RemoteUnavailableException.java
new file mode 100644
index 0000000000..3f6700d06b
--- /dev/null
+++ b/fda-user-service/services/src/main/java/at/tuwien/exception/RemoteUnavailableException.java
@@ -0,0 +1,21 @@
+package at.tuwien.exception;
+
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.ResponseStatus;
+
+@ResponseStatus(code = HttpStatus.NO_CONTENT)
+public class RemoteUnavailableException extends Exception {
+
+    public RemoteUnavailableException(String msg) {
+        super(msg);
+    }
+
+    public RemoteUnavailableException(String msg, Throwable thr) {
+        super(msg, thr);
+    }
+
+    public RemoteUnavailableException(Throwable thr) {
+        super(thr);
+    }
+
+}
diff --git a/fda-user-service/services/src/main/java/at/tuwien/gateway/AuthenticationServiceGateway.java b/fda-user-service/services/src/main/java/at/tuwien/gateway/AuthenticationServiceGateway.java
new file mode 100644
index 0000000000..3d41955d06
--- /dev/null
+++ b/fda-user-service/services/src/main/java/at/tuwien/gateway/AuthenticationServiceGateway.java
@@ -0,0 +1,11 @@
+package at.tuwien.gateway;
+
+import at.tuwien.api.auth.CreateUserDto;
+import at.tuwien.api.auth.TokenDto;
+import at.tuwien.exception.RemoteUnavailableException;
+
+public interface AuthenticationServiceGateway {
+    TokenDto getToken() throws RemoteUnavailableException;
+
+    void createUser(String token, CreateUserDto data) throws RemoteUnavailableException;
+}
diff --git a/fda-user-service/services/src/main/java/at/tuwien/gateway/impl/AuthenticationServiceGatewayImpl.java b/fda-user-service/services/src/main/java/at/tuwien/gateway/impl/AuthenticationServiceGatewayImpl.java
new file mode 100644
index 0000000000..19e2544e29
--- /dev/null
+++ b/fda-user-service/services/src/main/java/at/tuwien/gateway/impl/AuthenticationServiceGatewayImpl.java
@@ -0,0 +1,77 @@
+package at.tuwien.gateway.impl;
+
+import at.tuwien.api.auth.CreateUserDto;
+import at.tuwien.api.auth.TokenDto;
+import at.tuwien.config.GatewayConfig;
+import at.tuwien.exception.RemoteUnavailableException;
+import at.tuwien.gateway.AuthenticationServiceGateway;
+import lombok.extern.log4j.Log4j2;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.http.*;
+import org.springframework.stereotype.Service;
+import org.springframework.util.LinkedMultiValueMap;
+import org.springframework.util.MultiValueMap;
+import org.springframework.web.client.HttpServerErrorException;
+import org.springframework.web.client.ResourceAccessException;
+import org.springframework.web.client.RestTemplate;
+
+@Log4j2
+@Service
+public class AuthenticationServiceGatewayImpl implements AuthenticationServiceGateway {
+
+    private final RestTemplate restTemplate;
+    private final GatewayConfig gatewayConfig;
+
+    @Autowired
+    public AuthenticationServiceGatewayImpl(@Qualifier("keycloakRestTemplate") RestTemplate restTemplate,
+                                            GatewayConfig gatewayConfig) {
+        this.restTemplate = restTemplate;
+        this.gatewayConfig = gatewayConfig;
+    }
+
+    @Override
+    public TokenDto getToken() throws RemoteUnavailableException {
+        final HttpHeaders headers = new HttpHeaders();
+        headers.add("Content-Type", MediaType.APPLICATION_FORM_URLENCODED.toString());
+        final MultiValueMap<String, String> payload = new LinkedMultiValueMap<>();
+        payload.add("username", gatewayConfig.getKeycloakUsername());
+        payload.add("password", gatewayConfig.getKeycloakPassword());
+        payload.add("grant_type", "password");
+        payload.add("client_id", "admin-cli");
+        final String url = "/realms/master/protocol/openid-connect/token";
+        log.debug("call authentication service {}", url);
+        final ResponseEntity<TokenDto> response;
+        try {
+            response = restTemplate.exchange(url, HttpMethod.POST, new HttpEntity<>(payload, headers), TokenDto.class);
+        } catch (ResourceAccessException | HttpServerErrorException.ServiceUnavailable e) {
+            log.error("Failed to obtain admin token: {}", e.getMessage());
+            throw new RemoteUnavailableException("Failed to obtain admin token", e);
+        }
+        if (response.getStatusCode().equals(HttpStatus.UNAUTHORIZED)) {
+            log.error("Failed to obtain admin token: credentials are invalid");
+            throw new RemoteUnavailableException("Failed to obtain admin token: credentials are invalid");
+        }
+        return response.getBody();
+    }
+
+    @Override
+    public void createUser(String token, CreateUserDto data) throws RemoteUnavailableException {
+        final HttpHeaders headers = new HttpHeaders();
+        headers.add("Content-Type", MediaType.APPLICATION_JSON.toString());
+        headers.add("Accept", MediaType.APPLICATION_JSON.toString());
+        headers.add("Authorization", "Bearer: " + token);
+        final ResponseEntity<Void> response;
+        try {
+            response = restTemplate.exchange("/admin/realms/dbrepo/users", HttpMethod.POST, new HttpEntity<>(data, headers), Void.class);
+        } catch (ResourceAccessException | HttpServerErrorException.ServiceUnavailable e) {
+            log.error("Failed to create user: {}", e.getMessage());
+            throw new RemoteUnavailableException("Failed to create user", e);
+        }
+        if (response.getStatusCode().equals(HttpStatus.UNAUTHORIZED)) {
+            log.error("Failed to create user: credentials are invalid");
+            throw new RemoteUnavailableException("Failed to create user: credentials are invalid");
+        }
+    }
+
+}
diff --git a/fda-user-service/services/src/main/java/at/tuwien/mapper/UserMapper.java b/fda-user-service/services/src/main/java/at/tuwien/mapper/UserMapper.java
index cba134ae89..3a60fc1c3d 100644
--- a/fda-user-service/services/src/main/java/at/tuwien/mapper/UserMapper.java
+++ b/fda-user-service/services/src/main/java/at/tuwien/mapper/UserMapper.java
@@ -1,5 +1,6 @@
 package at.tuwien.mapper;
 
+import at.tuwien.api.auth.CreateUserDto;
 import at.tuwien.api.auth.SignupRequestDto;
 import at.tuwien.api.user.GrantedAuthorityDto;
 import at.tuwien.api.user.UserBriefDto;
@@ -21,7 +22,7 @@ public interface UserMapper {
 
     UserBriefDto userToUserBriefDto(User data);
 
-    User signupRequestDtoToUser(SignupRequestDto data);
+    CreateUserDto signupRequestDtoToCreateUserDto(SignupRequestDto data);
 
     default GrantedAuthority grantedAuthorityDtoToGrantedAuthority(GrantedAuthorityDto data) {
         final GrantedAuthority authority = new SimpleGrantedAuthority(data.getAuthority());
diff --git a/fda-user-service/services/src/main/java/at/tuwien/repository/elastic/UserIdxRepository.java b/fda-user-service/services/src/main/java/at/tuwien/repository/elastic/UserIdxRepository.java
new file mode 100644
index 0000000000..812cb439f6
--- /dev/null
+++ b/fda-user-service/services/src/main/java/at/tuwien/repository/elastic/UserIdxRepository.java
@@ -0,0 +1,10 @@
+package at.tuwien.repository.elastic;
+
+import at.tuwien.api.identifier.IdentifierDto;
+import at.tuwien.api.user.UserDto;
+import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface UserIdxRepository extends ElasticsearchRepository<UserDto, Long> {
+}
\ No newline at end of file
diff --git a/fda-user-service/services/src/main/java/at/tuwien/repository/jpa/RealmRepository.java b/fda-user-service/services/src/main/java/at/tuwien/repository/jpa/RealmRepository.java
new file mode 100644
index 0000000000..db0443c0a7
--- /dev/null
+++ b/fda-user-service/services/src/main/java/at/tuwien/repository/jpa/RealmRepository.java
@@ -0,0 +1,14 @@
+package at.tuwien.repository.jpa;
+
+import at.tuwien.entities.auth.Realm;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+import java.util.Optional;
+
+@Repository
+public interface RealmRepository extends JpaRepository<Realm, String> {
+
+    Optional<Realm> findByName(String name);
+
+}
diff --git a/fda-user-service/services/src/main/java/at/tuwien/service/RealmService.java b/fda-user-service/services/src/main/java/at/tuwien/service/RealmService.java
new file mode 100644
index 0000000000..fc3f15f288
--- /dev/null
+++ b/fda-user-service/services/src/main/java/at/tuwien/service/RealmService.java
@@ -0,0 +1,10 @@
+package at.tuwien.service;
+
+import at.tuwien.entities.auth.Realm;
+import at.tuwien.exception.RealmNotFoundException;
+
+public interface RealmService {
+    Realm find(String name) throws RealmNotFoundException;
+
+    Realm update(String name) throws RealmNotFoundException;
+}
diff --git a/fda-user-service/services/src/main/java/at/tuwien/service/UserService.java b/fda-user-service/services/src/main/java/at/tuwien/service/UserService.java
index d9371a4695..abf06036cb 100644
--- a/fda-user-service/services/src/main/java/at/tuwien/service/UserService.java
+++ b/fda-user-service/services/src/main/java/at/tuwien/service/UserService.java
@@ -3,6 +3,8 @@ package at.tuwien.service;
 import at.tuwien.api.auth.SignupRequestDto;
 import at.tuwien.entities.container.Container;
 import at.tuwien.entities.user.User;
+import at.tuwien.exception.RealmNotFoundException;
+import at.tuwien.exception.RemoteUnavailableException;
 import at.tuwien.exception.UserNotFoundException;
 
 import java.security.Principal;
@@ -26,7 +28,7 @@ public interface UserService {
      */
     User findByUsername(String username) throws UserNotFoundException;
 
-    User create(SignupRequestDto data);
+    User create(SignupRequestDto data) throws RealmNotFoundException, RemoteUnavailableException, UserNotFoundException;
 
     /**
      * Finds a user by id.
diff --git a/fda-user-service/services/src/main/java/at/tuwien/service/impl/RealmServiceImpl.java b/fda-user-service/services/src/main/java/at/tuwien/service/impl/RealmServiceImpl.java
new file mode 100644
index 0000000000..249876f68d
--- /dev/null
+++ b/fda-user-service/services/src/main/java/at/tuwien/service/impl/RealmServiceImpl.java
@@ -0,0 +1,43 @@
+package at.tuwien.service.impl;
+
+import at.tuwien.entities.auth.Realm;
+import at.tuwien.exception.RealmNotFoundException;
+import at.tuwien.repository.jpa.RealmRepository;
+import at.tuwien.service.RealmService;
+import lombok.extern.log4j.Log4j2;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.Optional;
+
+@Log4j2
+@Service
+public class RealmServiceImpl implements RealmService {
+
+    final RealmRepository realmRepository;
+
+    @Autowired
+    public RealmServiceImpl(RealmRepository realmRepository) {
+        this.realmRepository = realmRepository;
+    }
+
+    @Override
+    public Realm find(String name) throws RealmNotFoundException {
+        final Optional<Realm> optional = realmRepository.findByName(name);
+        if (optional.isEmpty()) {
+            log.error("Failed to find realm with name '{}'", name);
+            throw new RealmNotFoundException("Failed to find realm");
+        }
+        return optional.get();
+    }
+
+    @Override
+    public Realm update(String name) throws RealmNotFoundException {
+        final Realm realm = find("master");
+        realm.setSslRequired("NONE");
+        final Realm entity = realmRepository.save(realm);
+        log.info("Disabled SSL for realm with name '{}'", name);
+        return entity;
+    }
+
+}
diff --git a/fda-user-service/services/src/main/java/at/tuwien/service/impl/UserServiceImpl.java b/fda-user-service/services/src/main/java/at/tuwien/service/impl/UserServiceImpl.java
index 5578d9186b..50bbea2634 100644
--- a/fda-user-service/services/src/main/java/at/tuwien/service/impl/UserServiceImpl.java
+++ b/fda-user-service/services/src/main/java/at/tuwien/service/impl/UserServiceImpl.java
@@ -1,8 +1,13 @@
 package at.tuwien.service.impl;
 
+import at.tuwien.api.auth.CreateUserDto;
 import at.tuwien.api.auth.SignupRequestDto;
+import at.tuwien.api.auth.TokenDto;
 import at.tuwien.entities.user.User;
+import at.tuwien.exception.RealmNotFoundException;
+import at.tuwien.exception.RemoteUnavailableException;
 import at.tuwien.exception.UserNotFoundException;
+import at.tuwien.gateway.AuthenticationServiceGateway;
 import at.tuwien.mapper.UserMapper;
 import at.tuwien.repository.jpa.UserRepository;
 import at.tuwien.service.UserService;
@@ -12,7 +17,6 @@ import org.springframework.stereotype.Service;
 
 import java.util.List;
 import java.util.Optional;
-import java.util.UUID;
 
 @Log4j2
 @Service
@@ -20,11 +24,14 @@ public class UserServiceImpl implements UserService {
 
     private final UserMapper userMapper;
     private final UserRepository userRepository;
+    private final AuthenticationServiceGateway authenticationServiceGateway;
 
     @Autowired
-    public UserServiceImpl(UserMapper userMapper, UserRepository userRepository) {
+    public UserServiceImpl(UserMapper userMapper, UserRepository userRepository,
+                           AuthenticationServiceGateway authenticationServiceGateway) {
         this.userMapper = userMapper;
         this.userRepository = userRepository;
+        this.authenticationServiceGateway = authenticationServiceGateway;
     }
 
     @Override
@@ -43,14 +50,20 @@ public class UserServiceImpl implements UserService {
     }
 
     @Override
-    public User create(SignupRequestDto data) {
-        final User user = userMapper.signupRequestDtoToUser(data);
-        user.setRealmId("82c39861-d877-4667-a0f3-4daa2ee230e0");
-        user.setEmailVerified(false);
-        user.setId(UUID.randomUUID().toString());
-        final User entity = userRepository.save(user);
-        log.info("Created user with id {}", entity.getId());
-        return entity;
+    public User create(SignupRequestDto data) throws RealmNotFoundException, RemoteUnavailableException,
+            UserNotFoundException {
+        final TokenDto dto = authenticationServiceGateway.getToken();
+        log.debug("obtained authentication token");
+        final CreateUserDto userDto = userMapper.signupRequestDtoToCreateUserDto(data);
+        authenticationServiceGateway.createUser(dto.getAccessToken(), userDto);
+        final Optional<User> optional = userRepository.findByUsername(data.getUsername());
+        if (optional.isEmpty()) {
+            /* should never occur */
+            throw new UserNotFoundException("User not found with username '" + data.getUsername() + "'");
+        }
+        final User user = optional.get();
+        log.info("Created user with id {}", user.getId());
+        return user;
     }
 
     @Override
diff --git a/server.keystore b/server.keystore
new file mode 100644
index 0000000000000000000000000000000000000000..93e5c28b23293910dac23a3e974cb485524a3a17
GIT binary patch
literal 2220
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
C1<soQ

literal 0
HcmV?d00001

-- 
GitLab