From fdea0224562ed9f246162757ff976c71b3ab0451 Mon Sep 17 00:00:00 2001 From: Boris Skert Date: Fri, 4 May 2018 15:59:54 +0200 Subject: [PATCH] introduce in-memory-cache for keystore-repository --- README.md | 16 ++- mongo.docker-compose.yml | 117 ++++++++++++++++ mysql5.docker-compose.yml | 116 ++++++++++++++++ mysql8.docker-compose.yml | 130 ++++++++++++++++++ ...compose.yml => postgres.docker-compose.yml | 41 ------ .../example/config/MongoConfiguration.java | 9 +- .../sts/keymanagement/model/StsKeyStore.java | 6 + .../persistence/CachedKeyStoreRepository.java | 47 +++++++ .../InMemoryKeyStoreRepository.java | 11 ++ .../persistence/KeyStoreRepository.java | 3 + .../service/KeyStoreGenerator.java | 1 + .../sts/persistence/FsKeyStoreRepository.java | 69 ++++++++-- .../FsPersistenceKeyStoreRepository.java | 6 + .../jpa/DatabaseKeyStoreRepository.java | 5 + .../persistence/jpa/entity/JpaKeyStore.java | 5 + .../jpa/mapping/KeyStoreEntityMapper.java | 2 + .../jpa/mapping/ZonedDateTimeConverter.java | 8 ++ .../jpa/repository/JpaKeyStoreRepository.java | 10 ++ .../V0.26.0.0__add_lastupdate_to_keystore.sql | 1 + .../V0.26.0.0__add_lastupdate_to_keystore.sql | 1 + .../V0.26.0.0__add_lastupdate_to_keystore.sql | 1 + .../db/migration/liquibase/changelog.yml | 2 + .../04-create-table-lock_persistence.yml | 2 +- .../05-add-lastupdate-to-keystore.yml | 12 ++ .../MongoDatabaseKeyStoreRepository.java | 16 +++ .../mongo/entity/KeyStoreEntity.java | 5 + .../mongo/mapper/KeyStoreEntityMapper.java | 19 +++ .../repository/MongoKeyStoreRepository.java | 6 + .../KeyManagementConfiguration.java | 10 +- .../sts/keyrotation/KeyRotationSchedule.java | 31 +++-- .../SecureTokenServiceConfiguration.java | 43 +++--- .../src/main/resources/application.yml | 4 + 32 files changed, 668 insertions(+), 87 deletions(-) create mode 100644 mongo.docker-compose.yml create mode 100644 mysql5.docker-compose.yml create mode 100644 mysql8.docker-compose.yml rename docker-compose.yml => postgres.docker-compose.yml (78%) create mode 100644 sts-keymanagement/src/main/java/de/adorsys/sts/keymanagement/persistence/CachedKeyStoreRepository.java create mode 100644 sts-persistence-jpa/src/main/resources/db/migration/flyway/h2/V0.26.0.0__add_lastupdate_to_keystore.sql create mode 100644 sts-persistence-jpa/src/main/resources/db/migration/flyway/mysql/V0.26.0.0__add_lastupdate_to_keystore.sql create mode 100644 sts-persistence-jpa/src/main/resources/db/migration/flyway/postgres/V0.26.0.0__add_lastupdate_to_keystore.sql create mode 100644 sts-persistence-jpa/src/main/resources/db/migration/liquibase/changelogs/05-add-lastupdate-to-keystore.yml diff --git a/README.md b/README.md index 333743c9..57446ad8 100644 --- a/README.md +++ b/README.md @@ -206,8 +206,22 @@ docker-compose --file build.docker-compose.yml down --remove-orphans && docker-c ## Run example application +### with postgres database + +``` +docker-compose --file postgres.docker-compose.yml down --remove-orphans && docker-compose --file postgres.docker-compose.yml up --build +``` + +### with mysql 8 database + +``` +docker-compose --file mysql8.docker-compose.yml down --remove-orphans && docker-compose --file mysql8.docker-compose.yml up --build +``` + +### with mongo database + ``` -docker-compose --file docker-compose.yml down --remove-orphans && docker-compose --file docker-compose.yml up --build +docker-compose --file mongo.docker-compose.yml down --remove-orphans && docker-compose --file mongo.docker-compose.yml up --build ``` | Container | URL | diff --git a/mongo.docker-compose.yml b/mongo.docker-compose.yml new file mode 100644 index 00000000..2116d62e --- /dev/null +++ b/mongo.docker-compose.yml @@ -0,0 +1,117 @@ +version: '3.1' +services: + keycloak_db: + image: postgres:9.6-alpine + environment: + POSTGRES_USER: keycloak + POSTGRES_PASSWORD: keycloak + volumes: + - "./.docker/keycloak-db/data:/var/lib/postgresql/data" + keycloak: + image: "adorsys/keycloak-sts-adapter:latest" + environment: + KEYCLOAK_PASSWORD: admin123 + KEYCLOAK_USER: admin + POSTGRES_USER: keycloak + POSTGRES_PASSWORD: keycloak + POSTGRES_PORT_5432_TCP_ADDR: keycloak_db + ports: + - "8080:8080" + - "8787:8787" + volumes: + - "./.docker/keycloak/data:/opt/jboss/keycloak/standalone/data" + links: + - keycloak_db + networks: + - sts_network + command: + - "-b" + - "0.0.0.0" + - "--debug" + post_process: + image: adorsys/keycloak-config-cli:latest + depends_on: + - keycloak + networks: + - sts_network + volumes: + - ./keycloak-config:/opt/keycloak-config-cli/configs + environment: + - KEYCLOAK_URL=http://keycloak:8080/auth + - KEYCLOAK_ADMIN=admin + - KEYCLOAK_ADMIN_PASSWORD=admin123 + sts-mongo: + image: mongo:3.6.5 + container_name: sts_mongo + environment: + MONGO_INITDB_DATABASE: sts + volumes: + - "./.docker/sts-mongo:/data/db" + ports: + - 27017:27017 + command: --smallfiles + networks: + - sts_network + sts: + build: ./sts-example + image: "local/sts-example:latest" + depends_on: + - sts-mongo + networks: + - sts_network + environment: + - SPRING_PROFILES_ACTIVE=mongo + - SPRING_DATA_MONGODB_DATABASE=sts + - SPRING_DATA_MONGODB_URI=mongodb://sts-mongo/sts + - logging_level_de_adorsys_sts_keyrotation_KeyRotationSchedule=debug + - SPRING_APPLICATION_JSON={"sts":{"resource-server-management":{"resource-retriever":{"http-connect-timeout":10000,"http-read-timeout":60000,"http-size-limit":512000},"resource-servers":[{"audience":"sts","jwks-url":"http://localhost:8888/pop"},{"audience":"sts-service-component","jwks-url":"http://sts-service-component:8887/pop"}]}}} + ports: + - "8888:8888" + sts-service-component: + build: ./sts-service-component-example + image: "local/sts-service-component-example:latest" + ports: + - "8887:8887" + environment: + - sts_audience_name=sts-service-component + - SPRING_PROFILES_ACTIVE=mongo + - SPRING_DATA_MONGODB_DATABASE=sts + - SPRING_DATA_MONGODB_URI=mongodb://sts-mongo/sts + - logging_level_de_adorsys_sts_keyrotation_KeyRotationSchedule=debug + - SPRING_APPLICATION_JSON={"sts":{"authservers":[{"name":"local keycloak","iss-url":"http://localhost:8080/auth/realms/moped","jwks-url":"http://keycloak:8080/auth/realms/moped/protocol/openid-connect/certs"}]}} + depends_on: + - sts-mongo + networks: + - sts_network + sts-service-component_2: + build: ./sts-service-component-example + image: "local/sts-service-component-example:latest" + ports: + - "8886:8887" + environment: + - sts_audience_name=sts-service-component + - SPRING_PROFILES_ACTIVE=mongo + - SPRING_DATA_MONGODB_DATABASE=sts + - SPRING_DATA_MONGODB_URI=mongodb://sts-mongo/sts + - logging_level_de_adorsys_sts_keyrotation_KeyRotationSchedule=debug + - SPRING_APPLICATION_JSON={"sts":{"authservers":[{"name":"local keycloak","iss-url":"http://localhost:8080/auth/realms/moped","jwks-url":"http://keycloak:8080/auth/realms/moped/protocol/openid-connect/certs"}]}} + depends_on: + - sts-mongo + networks: + - sts_network + sts-client: + build: ./sts-client-example + image: local/sts-client-example:latest + environment: + - "KEYCLOAK_AUTH_URL=http://localhost:8080/auth" + - KEYCLOAK_REALM=moped + - KEYCLOAK_CLIENT_ID=moped-client + - KEYCLOAK_SCOPE=sts-service-component + - SERVICE_URL=http://localhost:8887/helloworld + networks: + - sts_network + ports: + - 8090:8090 + +networks: + sts_network: diff --git a/mysql5.docker-compose.yml b/mysql5.docker-compose.yml new file mode 100644 index 00000000..8644bace --- /dev/null +++ b/mysql5.docker-compose.yml @@ -0,0 +1,116 @@ +version: '3.1' +services: + keycloak_db: + image: postgres:9.6-alpine + environment: + POSTGRES_USER: keycloak + POSTGRES_PASSWORD: keycloak + volumes: + - "./.docker/keycloak-db/data:/var/lib/postgresql/data" + keycloak: + image: "adorsys/keycloak-sts-adapter:latest" + environment: + KEYCLOAK_PASSWORD: admin123 + KEYCLOAK_USER: admin + POSTGRES_USER: keycloak + POSTGRES_PASSWORD: keycloak + POSTGRES_PORT_5432_TCP_ADDR: keycloak_db + ports: + - "8080:8080" + - "8787:8787" + volumes: + - "./.docker/keycloak/data:/opt/jboss/keycloak/standalone/data" + links: + - keycloak_db + networks: + - sts_network + command: + - "-b" + - "0.0.0.0" + - "--debug" + post_process: + image: adorsys/keycloak-config-cli:latest + depends_on: + - keycloak + networks: + - sts_network + volumes: + - ./keycloak-config:/opt/keycloak-config-cli/configs + environment: + - KEYCLOAK_URL=http://keycloak:8080/auth + - KEYCLOAK_ADMIN=admin + - KEYCLOAK_ADMIN_PASSWORD=admin123 + sts-db: + image: mysql:5.7 + container_name: sts_db + environment: + MYSQL_ROOT_PASSWORD: db_root@123 + MYSQL_USER: db_user + MYSQL_PASSWORD: db_user@123 + MYSQL_DATABASE: sts + volumes: + - "./.docker/sts-db/mysql57:/var/lib/mysql" + ports: + - 3306:3306 + networks: + - sts_network + sts: + build: ./sts-example + image: "local/sts-example:latest" + depends_on: + - sts-db + networks: + - sts_network + environment: + - SPRING_PROFILES_ACTIVE=mysql + - SPRING_DATASOURCE_URL=jdbc:mysql://sts-db:3306/sts + - logging_level_de_adorsys_sts_keyrotation_KeyRotationSchedule=debug + - SPRING_APPLICATION_JSON={"sts":{"resource-server-management":{"resource-retriever":{"http-connect-timeout":10000,"http-read-timeout":60000,"http-size-limit":512000},"resource-servers":[{"audience":"sts","jwks-url":"http://localhost:8888/pop"},{"audience":"sts-service-component","jwks-url":"http://sts-service-component:8887/pop"}]}}} + ports: + - "8888:8888" + sts-service-component: + build: ./sts-service-component-example + image: "local/sts-service-component-example:latest" + ports: + - "8887:8887" + environment: + - sts_audience_name=sts-service-component + - SPRING_PROFILES_ACTIVE=mysql + - SPRING_DATASOURCE_URL=jdbc:mysql://sts-db:3306/sts + - logging_level_de_adorsys_sts_keyrotation_KeyRotationSchedule=debug + - SPRING_APPLICATION_JSON={"sts":{"authservers":[{"name":"local keycloak","iss-url":"http://localhost:8080/auth/realms/moped","jwks-url":"http://keycloak:8080/auth/realms/moped/protocol/openid-connect/certs"}]}} + depends_on: + - sts-db + networks: + - sts_network + sts-service-component_2: + build: ./sts-service-component-example + image: "local/sts-service-component-example:latest" + ports: + - "8886:8887" + environment: + - sts_audience_name=sts-service-component + - SPRING_PROFILES_ACTIVE=mysql + - SPRING_DATASOURCE_URL=jdbc:mysql://sts-db:3306/sts + - logging_level_de_adorsys_sts_keyrotation_KeyRotationSchedule=debug + - SPRING_APPLICATION_JSON={"sts":{"authservers":[{"name":"local keycloak","iss-url":"http://localhost:8080/auth/realms/moped","jwks-url":"http://keycloak:8080/auth/realms/moped/protocol/openid-connect/certs"}]}} + depends_on: + - sts-db + networks: + - sts_network + sts-client: + build: ./sts-client-example + image: local/sts-client-example:latest + environment: + - "KEYCLOAK_AUTH_URL=http://localhost:8080/auth" + - KEYCLOAK_REALM=moped + - KEYCLOAK_CLIENT_ID=moped-client + - KEYCLOAK_SCOPE=sts-service-component + - SERVICE_URL=http://localhost:8887/helloworld + networks: + - sts_network + ports: + - 8090:8090 + +networks: + sts_network: diff --git a/mysql8.docker-compose.yml b/mysql8.docker-compose.yml new file mode 100644 index 00000000..b5e7cc55 --- /dev/null +++ b/mysql8.docker-compose.yml @@ -0,0 +1,130 @@ +version: '3.1' +services: + keycloak_db: + image: postgres:9.6-alpine + environment: + POSTGRES_USER: keycloak + POSTGRES_PASSWORD: keycloak + volumes: + - "./.docker/keycloak-db/data:/var/lib/postgresql/data" + keycloak: + image: "adorsys/keycloak-sts-adapter:latest" + environment: + KEYCLOAK_PASSWORD: admin123 + KEYCLOAK_USER: admin + POSTGRES_USER: keycloak + POSTGRES_PASSWORD: keycloak + POSTGRES_PORT_5432_TCP_ADDR: keycloak_db + ports: + - "8080:8080" + - "8787:8787" + volumes: + - "./.docker/keycloak/data:/opt/jboss/keycloak/standalone/data" + links: + - keycloak_db + networks: + - sts_network + command: + - "-b" + - "0.0.0.0" + - "--debug" + post_process: + image: adorsys/keycloak-config-cli:latest + depends_on: + - keycloak + networks: + - sts_network + volumes: + - ./keycloak-config:/opt/keycloak-config-cli/configs + environment: + - KEYCLOAK_URL=http://keycloak:8080/auth + - KEYCLOAK_ADMIN=admin + - KEYCLOAK_ADMIN_PASSWORD=admin123 + sts-db: + image: mysql:8.0 + container_name: sts_db + environment: + MYSQL_ROOT_PASSWORD: db_root@123 + MYSQL_USER: db_user + MYSQL_PASSWORD: db_user@123 + MYSQL_DATABASE: sts + volumes: + - "./.docker/sts-db/mysql8:/var/lib/mysql" + ports: + - 3306:3306 + networks: + - sts_network +# sts-db: +# image: mysql:5.7 +# container_name: sts_db +# environment: +# MYSQL_ROOT_PASSWORD: db_root@123 +# MYSQL_USER: db_user +# MYSQL_PASSWORD: db_user@123 +# MYSQL_DATABASE: sts +# volumes: +# - "./.docker/sts-db/mysql57:/var/lib/mysql" +# ports: +# - 3306:3306 +# networks: +# - sts_network + sts: + build: ./sts-example + image: "local/sts-example:latest" + depends_on: + - sts-db + networks: + - sts_network + environment: + - SPRING_PROFILES_ACTIVE=mysql + - SPRING_DATASOURCE_URL=jdbc:mysql://sts-db:3306/sts + - logging_level_de_adorsys_sts_keyrotation_KeyRotationSchedule=debug + - SPRING_APPLICATION_JSON={"sts":{"resource-server-management":{"resource-retriever":{"http-connect-timeout":10000,"http-read-timeout":60000,"http-size-limit":512000},"resource-servers":[{"audience":"sts","jwks-url":"http://localhost:8888/pop"},{"audience":"sts-service-component","jwks-url":"http://sts-service-component:8887/pop"}]}}} + ports: + - "8888:8888" + sts-service-component: + build: ./sts-service-component-example + image: "local/sts-service-component-example:latest" + ports: + - "8887:8887" + environment: + - sts_audience_name=sts-service-component + - SPRING_PROFILES_ACTIVE=mysql + - SPRING_DATASOURCE_URL=jdbc:mysql://sts-db:3306/sts + - logging_level_de_adorsys_sts_keyrotation_KeyRotationSchedule=debug + - SPRING_APPLICATION_JSON={"sts":{"authservers":[{"name":"local keycloak","iss-url":"http://localhost:8080/auth/realms/moped","jwks-url":"http://keycloak:8080/auth/realms/moped/protocol/openid-connect/certs"}]}} + depends_on: + - sts-db + networks: + - sts_network + sts-service-component_2: + build: ./sts-service-component-example + image: "local/sts-service-component-example:latest" + ports: + - "8886:8887" + environment: + - sts_audience_name=sts-service-component + - SPRING_PROFILES_ACTIVE=mysql + - SPRING_DATASOURCE_URL=jdbc:mysql://sts-db:3306/sts + - logging_level_de_adorsys_sts_keyrotation_KeyRotationSchedule=debug + - SPRING_APPLICATION_JSON={"sts":{"authservers":[{"name":"local keycloak","iss-url":"http://localhost:8080/auth/realms/moped","jwks-url":"http://keycloak:8080/auth/realms/moped/protocol/openid-connect/certs"}]}} + depends_on: + - sts-db + networks: + - sts_network + sts-client: + build: ./sts-client-example + image: local/sts-client-example:latest + environment: + - "KEYCLOAK_AUTH_URL=http://localhost:8080/auth" + - KEYCLOAK_REALM=moped + - KEYCLOAK_CLIENT_ID=moped-client + - KEYCLOAK_SCOPE=sts-service-component + - SERVICE_URL=http://localhost:8887/helloworld + networks: + - sts_network + ports: + - 8090:8090 + +networks: + sts_network: diff --git a/docker-compose.yml b/postgres.docker-compose.yml similarity index 78% rename from docker-compose.yml rename to postgres.docker-compose.yml index c5a7ecce..f0c72beb 100644 --- a/docker-compose.yml +++ b/postgres.docker-compose.yml @@ -53,44 +53,6 @@ services: - 5432:5432 networks: - sts_network -# sts-db: -# image: mysql:8.0 -# container_name: sts_db -# environment: -# MYSQL_ROOT_PASSWORD: db_root@123 -# MYSQL_USER: db_user -# MYSQL_PASSWORD: db_user@123 -# MYSQL_DATABASE: sts -# volumes: -# - "./.docker/sts-db/mysql8:/var/lib/mysql" -# ports: -# - 3306:3306 -# networks: -# - sts_network -# sts-db: -# image: mysql:5.7 -# container_name: sts_db -# environment: -# MYSQL_ROOT_PASSWORD: db_root@123 -# MYSQL_USER: db_user -# MYSQL_PASSWORD: db_user@123 -# MYSQL_DATABASE: sts -# volumes: -# - "./.docker/sts-db/mysql57:/var/lib/mysql" -# ports: -# - 3306:3306 -# networks: -# - sts_network - sts-mongo: - image: mongo:3.0 - container_name: sts_mongo - volumes: - - "./.docker/sts-mongo:/data/db" - ports: - - 27017:27017 - command: --smallfiles - networks: - - sts_network sts: build: ./sts-example image: "local/sts-example:latest" @@ -101,7 +63,6 @@ services: environment: - SPRING_PROFILES_ACTIVE=postgres - SPRING_DATASOURCE_URL=jdbc:postgresql://sts-db:5432/sts -# - SPRING_DATASOURCE_URL=jdbc:mysql://sts-db:3306/sts - logging_level_de_adorsys_sts_keyrotation_KeyRotationSchedule=debug - SPRING_APPLICATION_JSON={"sts":{"resource-server-management":{"resource-retriever":{"http-connect-timeout":10000,"http-read-timeout":60000,"http-size-limit":512000},"resource-servers":[{"audience":"sts","jwks-url":"http://localhost:8888/pop"},{"audience":"sts-service-component","jwks-url":"http://sts-service-component:8887/pop"}]}}} ports: @@ -115,7 +76,6 @@ services: - sts_audience_name=sts-service-component - SPRING_PROFILES_ACTIVE=postgres - SPRING_DATASOURCE_URL=jdbc:postgresql://sts-db:5432/sts -# - SPRING_DATASOURCE_URL=jdbc:mysql://sts-db:3306/sts - logging_level_de_adorsys_sts_keyrotation_KeyRotationSchedule=debug - SPRING_APPLICATION_JSON={"sts":{"authservers":[{"name":"local keycloak","iss-url":"http://localhost:8080/auth/realms/moped","jwks-url":"http://keycloak:8080/auth/realms/moped/protocol/openid-connect/certs"}]}} depends_on: @@ -131,7 +91,6 @@ services: - sts_audience_name=sts-service-component - SPRING_PROFILES_ACTIVE=postgres - SPRING_DATASOURCE_URL=jdbc:postgresql://sts-db:5432/sts -# - SPRING_DATASOURCE_URL=jdbc:mysql://sts-db:3306/sts - logging_level_de_adorsys_sts_keyrotation_KeyRotationSchedule=debug - SPRING_APPLICATION_JSON={"sts":{"authservers":[{"name":"local keycloak","iss-url":"http://localhost:8080/auth/realms/moped","jwks-url":"http://keycloak:8080/auth/realms/moped/protocol/openid-connect/certs"}]}} depends_on: diff --git a/sts-example/src/main/java/de/adorsys/sts/example/config/MongoConfiguration.java b/sts-example/src/main/java/de/adorsys/sts/example/config/MongoConfiguration.java index 2d84b906..00786380 100644 --- a/sts-example/src/main/java/de/adorsys/sts/example/config/MongoConfiguration.java +++ b/sts-example/src/main/java/de/adorsys/sts/example/config/MongoConfiguration.java @@ -1,11 +1,13 @@ package de.adorsys.sts.example.config; -import com.mongodb.MongoClient; +import com.mongodb.*; import de.adorsys.sts.persistence.mongo.config.EnableMongoPersistence; +import org.apache.logging.log4j.util.Strings; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; import org.springframework.data.mongodb.config.AbstractMongoConfiguration; +import org.springframework.web.util.UriBuilder; @Configuration @EnableMongoPersistence @@ -15,6 +17,9 @@ public class MongoConfiguration extends AbstractMongoConfiguration { @Value("${spring.data.mongodb.database:sts}") private String databaseName; + @Value("${spring.data.mongodb.uri:mongodb://localhost/sts}") + private String uri; + @Override protected String getDatabaseName() { return databaseName; @@ -22,6 +27,6 @@ protected String getDatabaseName() { @Override public MongoClient mongoClient() { - return new MongoClient(); + return new MongoClient(new MongoClientURI(uri)); } } diff --git a/sts-keymanagement/src/main/java/de/adorsys/sts/keymanagement/model/StsKeyStore.java b/sts-keymanagement/src/main/java/de/adorsys/sts/keymanagement/model/StsKeyStore.java index 42feb5ee..a645d754 100644 --- a/sts-keymanagement/src/main/java/de/adorsys/sts/keymanagement/model/StsKeyStore.java +++ b/sts-keymanagement/src/main/java/de/adorsys/sts/keymanagement/model/StsKeyStore.java @@ -2,6 +2,7 @@ import java.security.KeyStore; import java.security.KeyStoreException; +import java.time.ZonedDateTime; import java.util.Map; import org.adorsys.jkeygen.keystore.KeyStoreService; @@ -15,6 +16,7 @@ public class StsKeyStore { private final Map keyEntries; private final KeyStore keyStore; + private ZonedDateTime lastUpdate; public void addKey(StsKeyEntry keyEntry) { KeyStoreService.addToKeyStore(keyStore, keyEntry.getKeyEntry()); @@ -31,4 +33,8 @@ public void removeKey(String keyAlias) { throw new RuntimeException(e); } } + + public void setLastUpdate(ZonedDateTime lastUpdate) { + this.lastUpdate = lastUpdate; + } } diff --git a/sts-keymanagement/src/main/java/de/adorsys/sts/keymanagement/persistence/CachedKeyStoreRepository.java b/sts-keymanagement/src/main/java/de/adorsys/sts/keymanagement/persistence/CachedKeyStoreRepository.java new file mode 100644 index 00000000..e87637c1 --- /dev/null +++ b/sts-keymanagement/src/main/java/de/adorsys/sts/keymanagement/persistence/CachedKeyStoreRepository.java @@ -0,0 +1,47 @@ +package de.adorsys.sts.keymanagement.persistence; + +import de.adorsys.sts.keymanagement.model.StsKeyStore; + +import java.time.ZonedDateTime; + +public class CachedKeyStoreRepository implements KeyStoreRepository { + + private final KeyStoreRepository keyStoreRepository; + private StsKeyStore cachedKeyStore; + + public CachedKeyStoreRepository(KeyStoreRepository keyStoreRepository) { + this.keyStoreRepository = keyStoreRepository; + } + + @Override + public StsKeyStore load() { + if(cachedKeyStore == null) { + cachedKeyStore = keyStoreRepository.load(); + } else { + ZonedDateTime lastUpdate = keyStoreRepository.lastUpdate(); + ZonedDateTime cachedLastUpdate = cachedKeyStore.getLastUpdate(); + + if(lastUpdate.isAfter(cachedLastUpdate)) { + cachedKeyStore = keyStoreRepository.load(); + } + } + + return cachedKeyStore; + } + + @Override + public boolean exists() { + return cachedKeyStore != null || keyStoreRepository.exists(); + } + + @Override + public void save(StsKeyStore keyStore) { + keyStoreRepository.save(keyStore); + cachedKeyStore = keyStore; + } + + @Override + public ZonedDateTime lastUpdate() { + return keyStoreRepository.lastUpdate(); + } +} diff --git a/sts-keymanagement/src/main/java/de/adorsys/sts/keymanagement/persistence/InMemoryKeyStoreRepository.java b/sts-keymanagement/src/main/java/de/adorsys/sts/keymanagement/persistence/InMemoryKeyStoreRepository.java index 097ffe5d..f7ee5146 100644 --- a/sts-keymanagement/src/main/java/de/adorsys/sts/keymanagement/persistence/InMemoryKeyStoreRepository.java +++ b/sts-keymanagement/src/main/java/de/adorsys/sts/keymanagement/persistence/InMemoryKeyStoreRepository.java @@ -2,6 +2,8 @@ import de.adorsys.sts.keymanagement.model.StsKeyStore; +import java.time.ZonedDateTime; + public class InMemoryKeyStoreRepository implements KeyStoreRepository { private StsKeyStore keyStore; @@ -20,4 +22,13 @@ public boolean exists() { public void save(StsKeyStore keyStore) { this.keyStore = keyStore; } + + @Override + public ZonedDateTime lastUpdate() { + if(keyStore != null) { + return keyStore.getLastUpdate(); + } + + throw new RuntimeException("No keystore exiting"); + } } diff --git a/sts-keymanagement/src/main/java/de/adorsys/sts/keymanagement/persistence/KeyStoreRepository.java b/sts-keymanagement/src/main/java/de/adorsys/sts/keymanagement/persistence/KeyStoreRepository.java index e9a90144..f82b17a0 100644 --- a/sts-keymanagement/src/main/java/de/adorsys/sts/keymanagement/persistence/KeyStoreRepository.java +++ b/sts-keymanagement/src/main/java/de/adorsys/sts/keymanagement/persistence/KeyStoreRepository.java @@ -2,9 +2,12 @@ import de.adorsys.sts.keymanagement.model.StsKeyStore; +import java.time.ZonedDateTime; + public interface KeyStoreRepository { StsKeyStore load(); boolean exists(); void save(StsKeyStore keyStore); + ZonedDateTime lastUpdate(); } diff --git a/sts-keymanagement/src/main/java/de/adorsys/sts/keymanagement/service/KeyStoreGenerator.java b/sts-keymanagement/src/main/java/de/adorsys/sts/keymanagement/service/KeyStoreGenerator.java index 5b58e0fa..a53c2e6a 100644 --- a/sts-keymanagement/src/main/java/de/adorsys/sts/keymanagement/service/KeyStoreGenerator.java +++ b/sts-keymanagement/src/main/java/de/adorsys/sts/keymanagement/service/KeyStoreGenerator.java @@ -107,6 +107,7 @@ public StsKeyStore generate() { return StsKeyStore.builder() .keyEntries(keyEntries) .keyStore(keystoreBuilder.build()) + .lastUpdate(now()) .build(); } catch (Exception e) { throw new IllegalStateException(e); diff --git a/sts-persistence-docusafe/src/main/java/de/adorsys/sts/persistence/FsKeyStoreRepository.java b/sts-persistence-docusafe/src/main/java/de/adorsys/sts/persistence/FsKeyStoreRepository.java index 49105e34..7859a75f 100644 --- a/sts-persistence-docusafe/src/main/java/de/adorsys/sts/persistence/FsKeyStoreRepository.java +++ b/sts-persistence-docusafe/src/main/java/de/adorsys/sts/persistence/FsKeyStoreRepository.java @@ -1,13 +1,9 @@ package de.adorsys.sts.persistence; -import java.security.KeyStore; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import javax.security.auth.callback.CallbackHandler; - +import de.adorsys.sts.keymanagement.model.StsKeyEntry; +import de.adorsys.sts.keymanagement.model.StsKeyStore; +import de.adorsys.sts.keymanagement.persistence.KeyStoreRepository; +import de.adorsys.sts.keymanagement.service.KeyManagementProperties; import org.adorsys.docusafe.business.DocumentSafeService; import org.adorsys.docusafe.business.types.complex.DSDocument; import org.adorsys.docusafe.business.types.complex.DSDocumentMetaInfo; @@ -20,13 +16,20 @@ import org.adorsys.jkeygen.keystore.KeyStoreType; import org.adorsys.jkeygen.pwd.PasswordCallbackHandler; -import de.adorsys.sts.keymanagement.model.StsKeyEntry; -import de.adorsys.sts.keymanagement.model.StsKeyStore; -import de.adorsys.sts.keymanagement.persistence.KeyStoreRepository; -import de.adorsys.sts.keymanagement.service.KeyManagementProperties; +import javax.security.auth.callback.CallbackHandler; +import java.security.KeyStore; +import java.time.Instant; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; public class FsKeyStoreRepository implements KeyStoreRepository { private final static String KEYSTORE_TYPE_KEY = "INTERNAL_SERVER_KEYSTORE_PERSISTENCE_TYPE_KEY"; + private final static String KEYSTORE_LAST_UPDATE_KEY = "INTERNAL_SERVER_KEYSTORE_PERSISTENCE_LAST_UPDATE_KEY"; + private static final ZonedDateTime DEFAULT_LAST_UPDATE = ZonedDateTime.ofInstant(Instant.EPOCH, ZoneOffset.UTC); private final DocumentFQN keystoreFileFQN; private final DocumentSafeService documentSafeService; @@ -66,7 +69,33 @@ public StsKeyStore load() { Map loadedKeyEntries = loadKeyEntries(keyStore, attributesMap); - return StsKeyStore.builder().keyStore(keyStore).keyEntries(loadedKeyEntries).build(); + return StsKeyStore.builder() + .lastUpdate(readLastUpdateFromMetaInfo(metaInfo)) + .keyStore(keyStore) + .keyEntries(loadedKeyEntries) + .build(); + } + + private ZonedDateTime readLastUpdateFromMetaInfo(UserMetaData metaInfo) { + String lastUpdateAsText = metaInfo.get(KEYSTORE_LAST_UPDATE_KEY); + + if(lastUpdateAsText == null) { + return DEFAULT_LAST_UPDATE; + } + + return ZonedDateTime.parse(lastUpdateAsText); + } + + private void writeLastUpdateIntoMetaInfo(ZonedDateTime lastUpdate, UserMetaData metaInfo) { + String lastUpdateAsText; + + if (lastUpdate == null) { + lastUpdateAsText = DEFAULT_LAST_UPDATE.toString(); + } else { + lastUpdateAsText = lastUpdate.toString(); + } + + metaInfo.put(KEYSTORE_LAST_UPDATE_KEY, lastUpdateAsText); } private Map loadKeyEntries(KeyStore keyStore, Map attributesMap) { @@ -102,6 +131,18 @@ public void save(StsKeyStore keyStore) { documentSafeService.storeDocument(userIDAuth, dsDocument); } + @Override + public ZonedDateTime lastUpdate() { + if(documentSafeService.documentExists(userIDAuth, keystoreFileFQN)) { + DSDocument dsDocument = documentSafeService.readDocument(userIDAuth, keystoreFileFQN); + DSDocumentMetaInfo metaInfo = dsDocument.getDsDocumentMetaInfo(); + + return readLastUpdateFromMetaInfo(metaInfo); + } else { + return DEFAULT_LAST_UPDATE; + } + } + private UserMetaData buildAttributes(StsKeyStore keyStore) { UserMetaData attributes = new UserMetaData(); for (Map.Entry entry : keyStore.getKeyEntries().entrySet()) { @@ -113,6 +154,8 @@ private UserMetaData buildAttributes(StsKeyStore keyStore) { attributes.put(alias, valuesAsString); } + writeLastUpdateIntoMetaInfo(keyStore.getLastUpdate(), attributes); + return attributes; } diff --git a/sts-persistence-fs/src/main/java/de/adorsys/sts/persistence/FsPersistenceKeyStoreRepository.java b/sts-persistence-fs/src/main/java/de/adorsys/sts/persistence/FsPersistenceKeyStoreRepository.java index ebdeba79..ec3e03fd 100644 --- a/sts-persistence-fs/src/main/java/de/adorsys/sts/persistence/FsPersistenceKeyStoreRepository.java +++ b/sts-persistence-fs/src/main/java/de/adorsys/sts/persistence/FsPersistenceKeyStoreRepository.java @@ -1,6 +1,7 @@ package de.adorsys.sts.persistence; import java.security.KeyStore; +import java.time.ZonedDateTime; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -104,6 +105,11 @@ public void save(StsKeyStore keyStore) { keystorePersistence.saveKeyStoreWithAttributes(keyStore.getKeyStore(), attributes, keyPassHandler, handle); } + @Override + public ZonedDateTime lastUpdate() { + throw new RuntimeException("not yet implemented"); + } + private UserMetaData buildAttributes(StsKeyStore keyStore) { UserMetaData attributes = new UserMetaData(); for (Map.Entry entry : keyStore.getKeyEntries().entrySet()) { diff --git a/sts-persistence-jpa/src/main/java/de/adorsys/sts/persistence/jpa/DatabaseKeyStoreRepository.java b/sts-persistence-jpa/src/main/java/de/adorsys/sts/persistence/jpa/DatabaseKeyStoreRepository.java index 5886db22..03513413 100644 --- a/sts-persistence-jpa/src/main/java/de/adorsys/sts/persistence/jpa/DatabaseKeyStoreRepository.java +++ b/sts-persistence-jpa/src/main/java/de/adorsys/sts/persistence/jpa/DatabaseKeyStoreRepository.java @@ -13,6 +13,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.time.ZonedDateTime; import java.util.List; import java.util.Map; @@ -79,7 +80,11 @@ public void save(StsKeyStore keyStore) { addOrUpdateKeyEntries(foundKeyStore, stsKeyEntries); keyStoreRepository.save(foundKeyStore); } + } + @Override + public ZonedDateTime lastUpdate() { + return keyStoreRepository.getLastUpdate(keyStoreName); } private void addOrUpdateKeyEntries(JpaKeyStore savedKeyStore, Map stsKeyEntries) { diff --git a/sts-persistence-jpa/src/main/java/de/adorsys/sts/persistence/jpa/entity/JpaKeyStore.java b/sts-persistence-jpa/src/main/java/de/adorsys/sts/persistence/jpa/entity/JpaKeyStore.java index 36a4582e..8c6a0802 100644 --- a/sts-persistence-jpa/src/main/java/de/adorsys/sts/persistence/jpa/entity/JpaKeyStore.java +++ b/sts-persistence-jpa/src/main/java/de/adorsys/sts/persistence/jpa/entity/JpaKeyStore.java @@ -1,9 +1,11 @@ package de.adorsys.sts.persistence.jpa.entity; +import de.adorsys.sts.persistence.jpa.mapping.ZonedDateTimeConverter; import lombok.Getter; import lombok.Setter; import javax.persistence.*; +import java.time.ZonedDateTime; @Getter @Setter @@ -21,5 +23,8 @@ public class JpaKeyStore { @Column(length = 1024 * 1024) private byte[] keystore; + + @Convert(converter = ZonedDateTimeConverter.class) + private ZonedDateTime lastUpdate; } diff --git a/sts-persistence-jpa/src/main/java/de/adorsys/sts/persistence/jpa/mapping/KeyStoreEntityMapper.java b/sts-persistence-jpa/src/main/java/de/adorsys/sts/persistence/jpa/mapping/KeyStoreEntityMapper.java index bd6a8d80..082c289b 100644 --- a/sts-persistence-jpa/src/main/java/de/adorsys/sts/persistence/jpa/mapping/KeyStoreEntityMapper.java +++ b/sts-persistence-jpa/src/main/java/de/adorsys/sts/persistence/jpa/mapping/KeyStoreEntityMapper.java @@ -46,6 +46,7 @@ public void mapIntoEntity(StsKeyStore keyStore, JpaKeyStore persistentKeyStore) persistentKeyStore.setName(keystoreName); persistentKeyStore.setKeystore(bytes); persistentKeyStore.setType(keyStore.getKeyStore().getType()); + persistentKeyStore.setLastUpdate(keyStore.getLastUpdate()); } public StsKeyStore mapFromEntity(JpaKeyStore persistentKeyStore, List persistentKeyEntries) { @@ -56,6 +57,7 @@ public StsKeyStore mapFromEntity(JpaKeyStore persistentKeyStore, List { JpaKeyStore findByName(String name); long countByName(String name); + + @Query("select k.lastUpdate from JpaKeyStore k where k.name = :name") + ZonedDateTime getLastUpdate(@Param("name") String name); } diff --git a/sts-persistence-jpa/src/main/resources/db/migration/flyway/h2/V0.26.0.0__add_lastupdate_to_keystore.sql b/sts-persistence-jpa/src/main/resources/db/migration/flyway/h2/V0.26.0.0__add_lastupdate_to_keystore.sql new file mode 100644 index 00000000..68cd9277 --- /dev/null +++ b/sts-persistence-jpa/src/main/resources/db/migration/flyway/h2/V0.26.0.0__add_lastupdate_to_keystore.sql @@ -0,0 +1 @@ +ALTER TABLE sts.key_store ADD COLUMN last_update TIMESTAMP NULL; diff --git a/sts-persistence-jpa/src/main/resources/db/migration/flyway/mysql/V0.26.0.0__add_lastupdate_to_keystore.sql b/sts-persistence-jpa/src/main/resources/db/migration/flyway/mysql/V0.26.0.0__add_lastupdate_to_keystore.sql new file mode 100644 index 00000000..68cd9277 --- /dev/null +++ b/sts-persistence-jpa/src/main/resources/db/migration/flyway/mysql/V0.26.0.0__add_lastupdate_to_keystore.sql @@ -0,0 +1 @@ +ALTER TABLE sts.key_store ADD COLUMN last_update TIMESTAMP NULL; diff --git a/sts-persistence-jpa/src/main/resources/db/migration/flyway/postgres/V0.26.0.0__add_lastupdate_to_keystore.sql b/sts-persistence-jpa/src/main/resources/db/migration/flyway/postgres/V0.26.0.0__add_lastupdate_to_keystore.sql new file mode 100644 index 00000000..68cd9277 --- /dev/null +++ b/sts-persistence-jpa/src/main/resources/db/migration/flyway/postgres/V0.26.0.0__add_lastupdate_to_keystore.sql @@ -0,0 +1 @@ +ALTER TABLE sts.key_store ADD COLUMN last_update TIMESTAMP NULL; diff --git a/sts-persistence-jpa/src/main/resources/db/migration/liquibase/changelog.yml b/sts-persistence-jpa/src/main/resources/db/migration/liquibase/changelog.yml index d9dd782d..ff9a11a0 100644 --- a/sts-persistence-jpa/src/main/resources/db/migration/liquibase/changelog.yml +++ b/sts-persistence-jpa/src/main/resources/db/migration/liquibase/changelog.yml @@ -9,3 +9,5 @@ databaseChangeLog: file: db/migration/liquibase/changelogs/03-create-table-keyentry.yml - include: file: db/migration/liquibase/changelogs/04-create-table-lock_persistence.yml +- include: + file: db/migration/liquibase/changelogs/05-add-lastupdate-to-keystore.yml diff --git a/sts-persistence-jpa/src/main/resources/db/migration/liquibase/changelogs/04-create-table-lock_persistence.yml b/sts-persistence-jpa/src/main/resources/db/migration/liquibase/changelogs/04-create-table-lock_persistence.yml index 8b5b7757..26aaef09 100644 --- a/sts-persistence-jpa/src/main/resources/db/migration/liquibase/changelogs/04-create-table-lock_persistence.yml +++ b/sts-persistence-jpa/src/main/resources/db/migration/liquibase/changelogs/04-create-table-lock_persistence.yml @@ -1,6 +1,6 @@ databaseChangeLog: - changeSet: - id: 6 + id: 5 author: sts changes: - createTable: diff --git a/sts-persistence-jpa/src/main/resources/db/migration/liquibase/changelogs/05-add-lastupdate-to-keystore.yml b/sts-persistence-jpa/src/main/resources/db/migration/liquibase/changelogs/05-add-lastupdate-to-keystore.yml new file mode 100644 index 00000000..a269da88 --- /dev/null +++ b/sts-persistence-jpa/src/main/resources/db/migration/liquibase/changelogs/05-add-lastupdate-to-keystore.yml @@ -0,0 +1,12 @@ +databaseChangeLog: +- changeSet: + id: 6 + author: sts + changes: + - addColumn: + schemaName: sts + tableName: key_store + columns: + - column: + name: last_update + type: datetime diff --git a/sts-persistence-mongo/src/main/java/de/adorsys/sts/persistence/mongo/MongoDatabaseKeyStoreRepository.java b/sts-persistence-mongo/src/main/java/de/adorsys/sts/persistence/mongo/MongoDatabaseKeyStoreRepository.java index f9c65239..1172afeb 100644 --- a/sts-persistence-mongo/src/main/java/de/adorsys/sts/persistence/mongo/MongoDatabaseKeyStoreRepository.java +++ b/sts-persistence-mongo/src/main/java/de/adorsys/sts/persistence/mongo/MongoDatabaseKeyStoreRepository.java @@ -10,6 +10,9 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.time.ZonedDateTime; +import java.util.List; + @Service @Transactional public class MongoDatabaseKeyStoreRepository implements KeyStoreRepository { @@ -53,4 +56,17 @@ public void save(StsKeyStore keyStore) { keyStoreRepository.save(foundKeyStore); } } + + @Override + public ZonedDateTime lastUpdate() { + List foundKeyStoresWithLastUpdate = keyStoreRepository.findLastUpdate(keyStoreName); + + if(foundKeyStoresWithLastUpdate.size() > 0) { + KeyStoreEntity keyStoreWithLastUpdate = foundKeyStoresWithLastUpdate.get(0); + + return keyStoreEntityMapper.mapLastUpdate(keyStoreWithLastUpdate); + } + + throw new RuntimeException("No keystore found"); + } } diff --git a/sts-persistence-mongo/src/main/java/de/adorsys/sts/persistence/mongo/entity/KeyStoreEntity.java b/sts-persistence-mongo/src/main/java/de/adorsys/sts/persistence/mongo/entity/KeyStoreEntity.java index 40a4c137..cbdf3537 100644 --- a/sts-persistence-mongo/src/main/java/de/adorsys/sts/persistence/mongo/entity/KeyStoreEntity.java +++ b/sts-persistence-mongo/src/main/java/de/adorsys/sts/persistence/mongo/entity/KeyStoreEntity.java @@ -3,7 +3,9 @@ import lombok.Getter; import lombok.Setter; import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.index.Indexed; +import java.util.Date; import java.util.Map; @Getter @@ -13,6 +15,7 @@ public class KeyStoreEntity { @Id private String id; + @Indexed private String name; private String type; @@ -20,4 +23,6 @@ public class KeyStoreEntity { private byte[] keystore; private Map entries; + + private Date lastUpdate; } diff --git a/sts-persistence-mongo/src/main/java/de/adorsys/sts/persistence/mongo/mapper/KeyStoreEntityMapper.java b/sts-persistence-mongo/src/main/java/de/adorsys/sts/persistence/mongo/mapper/KeyStoreEntityMapper.java index d8441991..eca8ab95 100644 --- a/sts-persistence-mongo/src/main/java/de/adorsys/sts/persistence/mongo/mapper/KeyStoreEntityMapper.java +++ b/sts-persistence-mongo/src/main/java/de/adorsys/sts/persistence/mongo/mapper/KeyStoreEntityMapper.java @@ -12,6 +12,8 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import java.time.Instant; +import java.time.ZoneId; import java.time.ZoneOffset; import java.time.ZonedDateTime; import java.util.Date; @@ -23,6 +25,7 @@ @Component public class KeyStoreEntityMapper { + private static final ZonedDateTime DEFAULT_LAST_UPDATE = ZonedDateTime.ofInstant(Instant.EPOCH, ZoneOffset.UTC); private final PasswordCallbackHandler keyPassHandler; private final String keystoreName; @@ -49,6 +52,7 @@ public void mapIntoEntity(StsKeyStore keyStore, KeyStoreEntity persistentKeyStor persistentKeyStore.setName(keystoreName); persistentKeyStore.setKeystore(bytes); persistentKeyStore.setType(keyStore.getKeyStore().getType()); + persistentKeyStore.setLastUpdate(convert(keyStore.getLastUpdate())); Map mappedEntryAttributes = mapToEntityMap(keyStore.getKeyEntries()); persistentKeyStore.setEntries(mappedEntryAttributes); @@ -127,10 +131,25 @@ public StsKeyStore mapFromEntity(KeyStoreEntity persistentKeyStore) { java.security.KeyStore keyStore = KeyStoreService.loadKeyStore(persistentKeyStore.getKeystore(), keystoreName, new KeyStoreType(persistentKeyStore.getType()), keyPassHandler); Map mappedKeyEntries = mapFromEntities(keyStore, persistentKeyStore.getEntries()); + Date lastUpdate = persistentKeyStore.getLastUpdate(); return StsKeyStore.builder() .keyStore(keyStore) .keyEntries(mappedKeyEntries) + .lastUpdate(mapLastUpdate(lastUpdate)) .build(); } + + public ZonedDateTime mapLastUpdate(KeyStoreEntity keyStoreEntityWithLastUpdate) { + Date lastUpdate = keyStoreEntityWithLastUpdate.getLastUpdate(); + return mapLastUpdate(lastUpdate); + } + + private ZonedDateTime mapLastUpdate(Date lastUpdateAsDate) { + if(lastUpdateAsDate == null) { + return DEFAULT_LAST_UPDATE; + } + + return convert(lastUpdateAsDate); + } } diff --git a/sts-persistence-mongo/src/main/java/de/adorsys/sts/persistence/mongo/repository/MongoKeyStoreRepository.java b/sts-persistence-mongo/src/main/java/de/adorsys/sts/persistence/mongo/repository/MongoKeyStoreRepository.java index 387719c7..340bf0cd 100644 --- a/sts-persistence-mongo/src/main/java/de/adorsys/sts/persistence/mongo/repository/MongoKeyStoreRepository.java +++ b/sts-persistence-mongo/src/main/java/de/adorsys/sts/persistence/mongo/repository/MongoKeyStoreRepository.java @@ -2,10 +2,16 @@ import de.adorsys.sts.persistence.mongo.entity.KeyStoreEntity; import org.springframework.data.mongodb.repository.MongoRepository; +import org.springframework.data.mongodb.repository.Query; + +import java.util.List; public interface MongoKeyStoreRepository extends MongoRepository { KeyStoreEntity findByName(String name); long countByName(String name); + + @Query(value = "{ 'name' : ?0 }", fields = "{ lastUpdate : 1 }") + List findLastUpdate(String name); } diff --git a/sts-spring/src/main/java/de/adorsys/sts/keymanagement/KeyManagementConfiguration.java b/sts-spring/src/main/java/de/adorsys/sts/keymanagement/KeyManagementConfiguration.java index 8ec2cc1c..91b7eecf 100644 --- a/sts-spring/src/main/java/de/adorsys/sts/keymanagement/KeyManagementConfiguration.java +++ b/sts-spring/src/main/java/de/adorsys/sts/keymanagement/KeyManagementConfiguration.java @@ -1,5 +1,6 @@ package de.adorsys.sts.keymanagement; +import de.adorsys.sts.keymanagement.persistence.CachedKeyStoreRepository; import de.adorsys.sts.keymanagement.persistence.KeyStoreRepository; import de.adorsys.sts.keymanagement.service.*; import org.springframework.beans.factory.annotation.Qualifier; @@ -27,9 +28,14 @@ KeyConversionService keyConversionService( return new KeyConversionService(keyManagementProperties.getKeystore().getPassword()); } + @Bean(name = "cached") + KeyStoreRepository cachedKeyStoreRepository(KeyStoreRepository keyStoreRepository) { + return new CachedKeyStoreRepository(keyStoreRepository); + } + @Bean KeyManagementService keyManagerService( - KeyStoreRepository keyStoreRepository, + @Qualifier("cached") KeyStoreRepository keyStoreRepository, KeyConversionService keyConversionService ) { return new KeyManagementService( @@ -85,7 +91,7 @@ SecretKeyGenerator secretKeyGenerator( @Bean KeyStoreInitializer keyStoreInitializer( - KeyStoreRepository keyStoreRepository, + @Qualifier("cached") KeyStoreRepository keyStoreRepository, KeyStoreGenerator keyStoreGenerator ) { return new KeyStoreInitializer(keyStoreRepository, keyStoreGenerator); diff --git a/sts-spring/src/main/java/de/adorsys/sts/keyrotation/KeyRotationSchedule.java b/sts-spring/src/main/java/de/adorsys/sts/keyrotation/KeyRotationSchedule.java index de0fd7c5..012fbec9 100644 --- a/sts-spring/src/main/java/de/adorsys/sts/keyrotation/KeyRotationSchedule.java +++ b/sts-spring/src/main/java/de/adorsys/sts/keyrotation/KeyRotationSchedule.java @@ -8,9 +8,13 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; +import java.time.Clock; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; import java.util.List; import java.util.stream.Collectors; @@ -25,16 +29,20 @@ public class KeyRotationSchedule { private final String rotationLockName; + private final Clock clock; + @Autowired public KeyRotationSchedule( KeyRotationService keyRotationService, - KeyStoreRepository keyStoreRepository, + @Qualifier("cached") KeyStoreRepository keyStoreRepository, LockClient lockClient, - KeyManagementProperties properties + KeyManagementProperties properties, + Clock clock ) { this.keyRotationService = keyRotationService; this.keyStoreRepository = keyStoreRepository; this.lockClient = lockClient; + this.clock = clock; String keyStoreName = properties.getKeystore().getName(); this.rotationLockName = "key-rotation -- " + keyStoreName; @@ -63,18 +71,23 @@ private void performKeyRotation() { StsKeyStore keyStore = keyStoreRepository.load(); KeyRotationService.KeyRotationResult keyRotationResult = keyRotationService.rotate(keyStore); - if(LOG.isDebugEnabled()) { + List removedKeys = keyRotationResult.getRemovedKeys(); + List futureKeys = keyRotationResult.getFutureKeys(); + List generatedKeys = keyRotationResult.getGeneratedKeys(); - List removedKeys = keyRotationResult.getRemovedKeys(); + if(LOG.isDebugEnabled()) { LOG.debug(removedKeys.size() + " keys removed: [" + removedKeys.stream().collect(Collectors.joining(",")) + "]"); - - List futureKeys = keyRotationResult.getFutureKeys(); LOG.debug(futureKeys.size() + " future keys generated: [" + futureKeys.stream().collect(Collectors.joining(",")) + "]"); - - List generatedKeys = keyRotationResult.getGeneratedKeys(); LOG.debug(generatedKeys.size() + " keys generated: [" + generatedKeys.stream().collect(Collectors.joining(",")) + "]"); } - keyStoreRepository.save(keyStore); + if(removedKeys.size() + futureKeys.size() + generatedKeys.size() > 0) { + keyStore.setLastUpdate(now()); + keyStoreRepository.save(keyStore); + } + } + + private ZonedDateTime now() { + return clock.instant().atZone(ZoneOffset.UTC); } } diff --git a/sts-starter/src/main/java/de/adorsys/sts/starter/config/SecureTokenServiceConfiguration.java b/sts-starter/src/main/java/de/adorsys/sts/starter/config/SecureTokenServiceConfiguration.java index cea291a4..0f35e388 100644 --- a/sts-starter/src/main/java/de/adorsys/sts/starter/config/SecureTokenServiceConfiguration.java +++ b/sts-starter/src/main/java/de/adorsys/sts/starter/config/SecureTokenServiceConfiguration.java @@ -1,34 +1,36 @@ package de.adorsys.sts.starter.config; -import javax.annotation.PostConstruct; - -import org.adorsys.docusafe.business.DocumentSafeService; -import org.adorsys.docusafe.business.types.UserID; -import org.adorsys.docusafe.business.types.complex.UserIDAuth; -import org.adorsys.encobject.domain.ReadKeyPassword; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - import com.fasterxml.jackson.databind.ObjectMapper; - +import de.adorsys.lockpersistence.client.LockClient; +import de.adorsys.lockpersistence.client.NoopLockClient; import de.adorsys.sts.admin.EnableAdmin; import de.adorsys.sts.keymanagement.KeyManagementConfigurationProperties; import de.adorsys.sts.keymanagement.persistence.KeyStoreRepository; import de.adorsys.sts.keyrotation.EnableKeyRotation; import de.adorsys.sts.persistence.FsKeyStoreRepository; import de.adorsys.sts.persistence.FsResourceServerRepository; +import de.adorsys.sts.persistence.FsUserDataRepository; import de.adorsys.sts.persistence.KeyEntryMapper; import de.adorsys.sts.pop.EnablePOP; import de.adorsys.sts.resourceserver.persistence.ResourceServerRepository; import de.adorsys.sts.resourceserver.provider.EnvironmentVariableResourceServersProvider; import de.adorsys.sts.resourceserver.provider.ResourceServersProvider; +import de.adorsys.sts.resourceserver.service.UserDataRepository; import de.adorsys.sts.serverinfo.EnableServerInfo; import de.adorsys.sts.token.passwordgrant.EnablePasswordGrant; import de.adorsys.sts.token.tokenexchange.EnableTokenExchange; import de.adorsys.sts.worksheetloader.DataSheetLoader; import de.adorsys.sts.worksheetloader.LoginLoader; +import org.adorsys.docusafe.business.DocumentSafeService; +import org.adorsys.docusafe.business.types.UserID; +import org.adorsys.docusafe.business.types.complex.UserIDAuth; +import org.adorsys.encobject.domain.ReadKeyPassword; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import javax.annotation.PostConstruct; @Configuration @EnablePOP @@ -67,11 +69,6 @@ public LoginLoader loginLoader() { return new LoginLoader(); } - @Bean - public ResourceServersProvider resourceServersProvider() { - return new EnvironmentVariableResourceServersProvider(); - } - @Bean ResourceServerRepository resourceServerRepository() { return new FsResourceServerRepository(systemIdAuth, documentSafeService, objectMapper); @@ -80,5 +77,15 @@ ResourceServerRepository resourceServerRepository() { @Bean KeyStoreRepository keyStoreRepository(KeyManagementConfigurationProperties keyManagementProperties) { return new FsKeyStoreRepository(systemIdAuth, documentSafeService, keyManagementProperties, new KeyEntryMapper(objectMapper)); - } + } + + @Bean + UserDataRepository userDataRepository() { + return new FsUserDataRepository(documentSafeService, objectMapper); + } + + @Bean + LockClient lockClient() { + return new NoopLockClient(); + } } diff --git a/sts-starter/src/main/resources/application.yml b/sts-starter/src/main/resources/application.yml index 670d78b0..0b41a4b8 100644 --- a/sts-starter/src/main/resources/application.yml +++ b/sts-starter/src/main/resources/application.yml @@ -3,6 +3,10 @@ logging: org.springframework.web: DEBUG de.adorsys.sts.keyrotation.KeyRotationSchedule: DEBUG +docusafe.system.user: + name: my_docusafe_user + password: 1234567890 + sts: resource-server-management: resource-retriever: