diff --git a/.github/workflows/pull-requests.yml b/.github/workflows/pull-requests.yml index b4801daa..af13c80b 100644 --- a/.github/workflows/pull-requests.yml +++ b/.github/workflows/pull-requests.yml @@ -7,19 +7,20 @@ on: jobs: build: - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest steps: - - name: Check out repository code - uses: actions/checkout@v2 + - name: Step 1 - Checkout repository code + uses: actions/checkout@v4 - - name: Set up JDK 17 - uses: actions/setup-java@v2 + - name: Step 2 - Set up JDK 17 + uses: actions/setup-java@v4 with: - distribution: 'adopt' java-version: '17' + distribution: 'temurin' + cache: 'maven' - - name: Maven build and test - run: mvn clean verify -B -V + - name: Step 3 - Build & Test + run: mvn clean verify -ntp - - name: Build client + - name: Step 4 - Build client run: ./scripts/build_client.sh diff --git a/.github/workflows/push-in-develop.yml b/.github/workflows/push-in-develop.yml index ab96ebc9..f45991d1 100644 --- a/.github/workflows/push-in-develop.yml +++ b/.github/workflows/push-in-develop.yml @@ -6,15 +6,22 @@ on: jobs: Develop-Branch-Build: - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest steps: - - name: Check out repository code - uses: actions/checkout@v2 + - name: Step 1 - Checkout repository code + uses: actions/checkout@v4 - - name: Maven build and test - run: mvn clean verify -B -V + - name: Step 2 - Set up JDK 17 + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'temurin' + cache: 'maven' - - name: Build client + - name: Step 3 - Build & Test + run: mvn clean verify -ntp + + - name: Step 5 - Build client run: ./scripts/build_client.sh - name: Maven deploy snapshot diff --git a/.github/workflows/push-with-v-tag.yml b/.github/workflows/push-with-v-tag.yml index 710e2516..e5f60f03 100644 --- a/.github/workflows/push-with-v-tag.yml +++ b/.github/workflows/push-with-v-tag.yml @@ -6,12 +6,19 @@ on: jobs: build: - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest steps: - - name: Check out repository code - uses: actions/checkout@v2 + - name: Step 1 - Checkout repository code + uses: actions/checkout@v4 - - name: deploy to Maven + - name: Step 2 - Setup JDK + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'temurin' + cache: 'maven' + + - name: Step 3 - deploy to Maven run: ./scripts/mvn_deploy.sh env: SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }} diff --git a/keycloak-storage-provider/pom.xml b/keycloak-storage-provider/pom.xml index 32394735..0febb91c 100644 --- a/keycloak-storage-provider/pom.xml +++ b/keycloak-storage-provider/pom.xml @@ -6,7 +6,7 @@ de.adorsys.sts secure-token-service - 1.1.0 + 1.1.21 keycloak-storage-provider diff --git a/pom.xml b/pom.xml index ddf85c09..c4f45393 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ de.adorsys.sts secure-token-service - 1.1.0 + 1.1.21 pom SecureTokenService @@ -52,7 +52,7 @@ UTF-8 UTF-8 3.0.6 - 0.0.7 + 0.0.10 5.3.0 3.0.0 2.15.1 @@ -65,6 +65,14 @@ 1.17.6 9.31 + 1.6.13 + 3.3.0 + 3.0.1 + 3.3.0 + 3.2.0 + 3.1.1 + 3.1.0 + 3.6.0 @@ -441,7 +449,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 3.1.1 + ${maven-javadoc-plugin.version} ${project.build.sourceEncoding} ${project.build.sourceEncoding} @@ -451,7 +459,7 @@ maven-release-plugin - 3.0.0-M1 + ${maven-release-plugin.version} release true @@ -468,7 +476,7 @@ org.apache.maven.plugins maven-jar-plugin - 3.2.0 + ${maven-jar-plugin.version} @@ -492,7 +500,7 @@ org.codehaus.mojo buildnumber-maven-plugin - 1.4 + ${buildnumber-maven-plugin.version} validate @@ -531,7 +539,7 @@ org.apache.maven.plugins maven-deploy-plugin - 2.8.2 + ${maven-deploy-plugin.version} true @@ -539,7 +547,7 @@ org.sonatype.plugins nexus-staging-maven-plugin - 1.6.13 + ${nexus-staging-maven-plugin.version} true sonatype @@ -550,7 +558,7 @@ org.apache.maven.plugins maven-source-plugin - 3.2.1 + ${maven-source-plugin.version} attach-sources @@ -563,13 +571,8 @@ org.apache.maven.plugins maven-gpg-plugin - 3.0.1 + ${maven-gpg-plugin.version} - opensource@adorsys.de - - --pinentry-mode - loopback - @@ -578,18 +581,13 @@ sign - - - --pinentry-mode - loopback - - org.apache.maven.plugins maven-javadoc-plugin + ${maven-javadoc-plugin.version} 17 none diff --git a/postgres.docker-compose.yml b/postgres.docker-compose.yml index 5c646fe7..c6ffcec0 100644 --- a/postgres.docker-compose.yml +++ b/postgres.docker-compose.yml @@ -45,18 +45,18 @@ services: - SPRING_PROFILES_INCLUDE=debug command: config-cli sts-db: - image: postgres:9.6-alpine + image: postgres:latest container_name: sts_db environment: POSTGRES_USER: db_user POSTGRES_PASSWORD: db_user@123 POSTGRES_DB: sts - volumes: - - "./.docker/sts-db/postgres:/var/lib/postgresql/data" +# volumes: +# - "./.docker/sts-db/postgres:/var/lib/postgresql/data" ports: - 5432:5432 - networks: - - sts_network +# networks: +# - sts_network sts: build: ./sts-example image: "local/sts-example:latest" diff --git a/scripts/mvn_deploy.sh b/scripts/mvn_deploy.sh index 0df07a6f..fd0932f8 100755 --- a/scripts/mvn_deploy.sh +++ b/scripts/mvn_deploy.sh @@ -5,4 +5,4 @@ set -e echo "$GPG_SECRET_KEY" | base64 --decode | $GPG_EXECUTABLE --import --no-tty --batch --yes || true echo "$GPG_OWNERTRUST" | base64 --decode | $GPG_EXECUTABLE --import-ownertrust --no-tty --batch --yes || true -mvn --no-transfer-progress --settings scripts/settings.xml package gpg:sign deploy -Prelease -DskipTests -B -U || exit 1 +mvn clean deploy -ntp --settings scripts/settings.xml gpg:sign -Prelease -DskipTests -U || exit 1 diff --git a/sts-client-example/package-lock.json b/sts-client-example/package-lock.json index c1b296d5..c750ce9a 100644 --- a/sts-client-example/package-lock.json +++ b/sts-client-example/package-lock.json @@ -1,6 +1,6 @@ { "name": "sts-client-example", - "version": "1.1.0-SNAPSHOT", + "version": "1.1.21", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/sts-client-example/package.json b/sts-client-example/package.json index b62b3547..2f26dcf7 100644 --- a/sts-client-example/package.json +++ b/sts-client-example/package.json @@ -1,6 +1,6 @@ { "name": "sts-client-example", - "version": "1.1.0-SNAPSHOT", + "version": "1.1.21", "license": "MIT", "scripts": { "ng": "npx ng ", diff --git a/sts-common/pom.xml b/sts-common/pom.xml index 9fec8b2c..c09046e0 100644 --- a/sts-common/pom.xml +++ b/sts-common/pom.xml @@ -5,7 +5,7 @@ de.adorsys.sts secure-token-service - 1.1.0 + 1.1.21 sts-common @@ -94,6 +94,17 @@ -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=10022 + + + fat-jar + + repackage + + + exec + + + diff --git a/sts-example/pom.xml b/sts-example/pom.xml index c2c7fa59..d837720e 100644 --- a/sts-example/pom.xml +++ b/sts-example/pom.xml @@ -5,7 +5,7 @@ secure-token-service de.adorsys.sts - 1.1.0 + 1.1.21 4.0.0 @@ -36,9 +36,13 @@ ${spring-boot.version} + fat-jar repackage + + exec + diff --git a/sts-example/src/main/java/de/adorsys/sts/example/config/SecurityConfiguration.java b/sts-example/src/main/java/de/adorsys/sts/example/config/SecurityConfiguration.java index cfb83989..b070dc29 100644 --- a/sts-example/src/main/java/de/adorsys/sts/example/config/SecurityConfiguration.java +++ b/sts-example/src/main/java/de/adorsys/sts/example/config/SecurityConfiguration.java @@ -20,6 +20,8 @@ public class SecurityConfiguration { @Bean protected SecurityFilterChain securityFilterChain(HttpSecurity http, TokenAuthenticationService tokenAuthenticationService) throws Exception { + + http.cors().and() .csrf().disable() .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) diff --git a/sts-example/src/main/java/de/adorsys/sts/example/config/StsConfiguration.java b/sts-example/src/main/java/de/adorsys/sts/example/config/StsConfiguration.java index f71c23d0..230d4680 100644 --- a/sts-example/src/main/java/de/adorsys/sts/example/config/StsConfiguration.java +++ b/sts-example/src/main/java/de/adorsys/sts/example/config/StsConfiguration.java @@ -17,16 +17,11 @@ @EnableResourceServerInitialization @EnableEncryption @EnablePOP -@EnableKeyRotation +//@EnableKeyRotation @EnableTokenAuthentication @EnableSecretServerClient public class StsConfiguration { - @Bean - public TaskScheduler taskExecutor() { - return new ConcurrentTaskScheduler(); - } - @Bean ResourceServerRepository resourceServerRepository() { return new InMemoryResourceServerRepository(); diff --git a/sts-example/src/main/resources/application.yml b/sts-example/src/main/resources/application.yml index 3281b072..8f4e76e6 100644 --- a/sts-example/src/main/resources/application.yml +++ b/sts-example/src/main/resources/application.yml @@ -21,6 +21,13 @@ spring: default-schema: public sts: + secret-server-client: + audience: moped-client + secret-server-uri: http://localhost:8885/secret-server/token-exchange + cache: + enabled: true + maximum-size: 1000 + expire-after-access: 10 resource-server-management: resource-retriever: http-connect-timeout: 10000 diff --git a/sts-keymanagement/pom.xml b/sts-keymanagement/pom.xml index d5499401..e7addd9c 100644 --- a/sts-keymanagement/pom.xml +++ b/sts-keymanagement/pom.xml @@ -5,7 +5,7 @@ secure-token-service de.adorsys.sts - 1.1.0 + 1.1.21 4.0.0 diff --git a/sts-keymanagement/sts-keymanagement-api/pom.xml b/sts-keymanagement/sts-keymanagement-api/pom.xml index a2da82a1..09fa27fe 100644 --- a/sts-keymanagement/sts-keymanagement-api/pom.xml +++ b/sts-keymanagement/sts-keymanagement-api/pom.xml @@ -5,7 +5,7 @@ sts-keymanagement de.adorsys.sts - 1.1.0 + 1.1.21 4.0.0 @@ -30,7 +30,7 @@ de.adorsys.keymanagement api - 0.0.7 + 0.0.9 diff --git a/sts-keymanagement/sts-keymanagement-impl/pom.xml b/sts-keymanagement/sts-keymanagement-impl/pom.xml index 8d291e40..cc9829e3 100644 --- a/sts-keymanagement/sts-keymanagement-impl/pom.xml +++ b/sts-keymanagement/sts-keymanagement-impl/pom.xml @@ -5,7 +5,7 @@ sts-keymanagement de.adorsys.sts - 1.1.0 + 1.1.21 4.0.0 @@ -14,7 +14,6 @@ de.adorsys.sts sts-keymanagement-api - 1.1.0 de.adorsys.sts @@ -23,7 +22,7 @@ de.adorsys.keymanagement core - 0.0.7 + 0.0.9 @@ -50,7 +49,7 @@ de.adorsys.keymanagement juggler-bouncycastle - 0.0.7 + 0.0.9 test diff --git a/sts-keymanagement/sts-keymanagement-impl/src/main/java/de/adorsys/sts/keymanagement/persistence/CachedKeyStoreRepository.java b/sts-keymanagement/sts-keymanagement-impl/src/main/java/de/adorsys/sts/keymanagement/persistence/CachedKeyStoreRepository.java index e87637c1..4fbc0b7d 100644 --- a/sts-keymanagement/sts-keymanagement-impl/src/main/java/de/adorsys/sts/keymanagement/persistence/CachedKeyStoreRepository.java +++ b/sts-keymanagement/sts-keymanagement-impl/src/main/java/de/adorsys/sts/keymanagement/persistence/CachedKeyStoreRepository.java @@ -1,9 +1,11 @@ package de.adorsys.sts.keymanagement.persistence; import de.adorsys.sts.keymanagement.model.StsKeyStore; +import lombok.extern.slf4j.Slf4j; import java.time.ZonedDateTime; +@Slf4j public class CachedKeyStoreRepository implements KeyStoreRepository { private final KeyStoreRepository keyStoreRepository; @@ -15,33 +17,49 @@ public CachedKeyStoreRepository(KeyStoreRepository keyStoreRepository) { @Override public StsKeyStore load() { - if(cachedKeyStore == null) { + log.debug("Calling load(). Cached key store last update: {}", cachedKeyStore != null ? cachedKeyStore.getLastUpdate() : null); + + if (cachedKeyStore == null) { + log.debug("Cache is null, loading from repository"); cachedKeyStore = keyStoreRepository.load(); } else { ZonedDateTime lastUpdate = keyStoreRepository.lastUpdate(); ZonedDateTime cachedLastUpdate = cachedKeyStore.getLastUpdate(); - if(lastUpdate.isAfter(cachedLastUpdate)) { + if (lastUpdate.isAfter(cachedLastUpdate)) { + log.debug("Repository was updated more recently than cache. Refreshing cache."); cachedKeyStore = keyStoreRepository.load(); } } + log.debug("Returning cached key store with last update: {}", cachedKeyStore != null ? cachedKeyStore.getLastUpdate() : null); return cachedKeyStore; } @Override public boolean exists() { - return cachedKeyStore != null || keyStoreRepository.exists(); + boolean exists = cachedKeyStore != null || keyStoreRepository.exists(); + + log.debug("Checking if KeyStore exists. Result: {}", exists); + + return exists; } @Override public void save(StsKeyStore keyStore) { + log.debug("Saving keyStore to repository..."); keyStoreRepository.save(keyStore); + + log.debug("Updating cache with newly saved keyStore"); cachedKeyStore = keyStore; } @Override public ZonedDateTime lastUpdate() { - return keyStoreRepository.lastUpdate(); + ZonedDateTime lastUpdate = keyStoreRepository.lastUpdate(); + + log.debug("LastUpdate: {}", lastUpdate); + + return lastUpdate; } } diff --git a/sts-keymanagement/sts-keymanagement-impl/src/main/java/de/adorsys/sts/keymanagement/service/KeyRotationServiceImpl.java b/sts-keymanagement/sts-keymanagement-impl/src/main/java/de/adorsys/sts/keymanagement/service/KeyRotationServiceImpl.java index b601fc11..541928a2 100644 --- a/sts-keymanagement/sts-keymanagement-impl/src/main/java/de/adorsys/sts/keymanagement/service/KeyRotationServiceImpl.java +++ b/sts-keymanagement/sts-keymanagement-impl/src/main/java/de/adorsys/sts/keymanagement/service/KeyRotationServiceImpl.java @@ -2,8 +2,10 @@ import com.google.common.collect.Streams; import com.googlecode.cqengine.attribute.Attribute; +import com.googlecode.cqengine.attribute.SimpleAttribute; import com.googlecode.cqengine.attribute.support.SimpleFunction; import com.googlecode.cqengine.query.Query; +import com.googlecode.cqengine.query.option.QueryOptions; import de.adorsys.keymanagement.api.types.ResultCollection; import de.adorsys.keymanagement.api.types.entity.KeyAlias; import de.adorsys.keymanagement.api.types.entity.KeyEntry; @@ -24,11 +26,42 @@ public class KeyRotationServiceImpl implements KeyRotationService { private final SimpleFunction STS = it -> ((StsKeyEntry) it.getMeta()); - private final Attribute STATE = attribute(it -> STS.apply(it).getState()); - private final Attribute NOT_BEFORE = attribute(it -> STS.apply(it).getNotBefore().toInstant()); - private final Attribute NOT_AFTER = attribute(it -> STS.apply(it).getNotAfter().toInstant()); - private final Attribute EXPIRE_AT = attribute(it -> STS.apply(it).getExpireAt().toInstant()); - private final Attribute USAGE = attribute(it -> STS.apply(it).getKeyUsage()); + + private final Attribute STATE = new SimpleAttribute<>() { + @Override + public KeyState getValue(KeyEntry o, QueryOptions queryOptions) { + return STS.apply(o).getState(); + } + }; + + private final Attribute NOT_BEFORE = new SimpleAttribute<>() { + @Override + public Instant getValue(KeyEntry o, QueryOptions queryOptions) { + return STS.apply(o).getNotBefore().toInstant(); + } + }; + + private final Attribute NOT_AFTER = new SimpleAttribute<>() { + @Override + public Instant getValue(KeyEntry o, QueryOptions queryOptions) { + return STS.apply(o).getNotAfter().toInstant(); + } + }; + + private final Attribute EXPIRE_AT = new SimpleAttribute<>() { + @Override + public Instant getValue(KeyEntry o, QueryOptions queryOptions) { + return STS.apply(o).getExpireAt().toInstant(); + } + }; + + private final Attribute USAGE = new SimpleAttribute<>() { + @Override + public KeyUsage getValue(KeyEntry o, QueryOptions queryOptions) { + return STS.apply(o).getKeyUsage(); + } + }; + private final KeyStoreGenerator keyStoreGenerator; private final Clock clock; diff --git a/sts-persistence-jpa/pom.xml b/sts-persistence-jpa/pom.xml index ba3b7f96..dd06e132 100644 --- a/sts-persistence-jpa/pom.xml +++ b/sts-persistence-jpa/pom.xml @@ -5,7 +5,7 @@ secure-token-service de.adorsys.sts - 1.1.0 + 1.1.21 4.0.0 diff --git a/sts-persistence-jpa/src/main/java/de/adorsys/sts/persistence/jpa/entity/JpaSecret.java b/sts-persistence-jpa/src/main/java/de/adorsys/sts/persistence/jpa/entity/JpaSecret.java index a5473015..45bc9452 100644 --- a/sts-persistence-jpa/src/main/java/de/adorsys/sts/persistence/jpa/entity/JpaSecret.java +++ b/sts-persistence-jpa/src/main/java/de/adorsys/sts/persistence/jpa/entity/JpaSecret.java @@ -12,8 +12,8 @@ public class JpaSecret { @Id - @GeneratedValue(strategy = GenerationType.AUTO) - private int id; + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; private String subject; diff --git a/sts-persistence-jpa/src/main/resources/application-h2.yml b/sts-persistence-jpa/src/main/resources/application-h2.yml index 956c8398..628a77d1 100644 --- a/sts-persistence-jpa/src/main/resources/application-h2.yml +++ b/sts-persistence-jpa/src/main/resources/application-h2.yml @@ -1,7 +1,4 @@ spring: - profiles: - include: jpa - liquibase: default-schema: false change-log: classpath:db/migration/liquibase/changelog.yml diff --git a/sts-persistence-jpa/src/main/resources/application-jpa.yml b/sts-persistence-jpa/src/main/resources/application-jpa.yml index 8e7015d2..ab4d28ed 100644 --- a/sts-persistence-jpa/src/main/resources/application-jpa.yml +++ b/sts-persistence-jpa/src/main/resources/application-jpa.yml @@ -1,4 +1,8 @@ spring: + config: + activate: + on-cloud-platform: "kubernetes" + on-profile: "postgres | mysql | h2" jpa: open-in-view: false hibernate: diff --git a/sts-persistence-jpa/src/main/resources/application-mysql.yml b/sts-persistence-jpa/src/main/resources/application-mysql.yml index 2fe53b4d..0de610c1 100644 --- a/sts-persistence-jpa/src/main/resources/application-mysql.yml +++ b/sts-persistence-jpa/src/main/resources/application-mysql.yml @@ -1,7 +1,4 @@ spring: - profiles: - include: jpa - liquibase: default-schema: sts @@ -13,4 +10,3 @@ spring: url: jdbc:mysql://localhost:3306/sts jpa: database-platform: org.hibernate.dialect.MySQLInnoDBDialect - hibernate.use-new-id-generator-mappings: false diff --git a/sts-persistence-jpa/src/main/resources/application-postgres.yml b/sts-persistence-jpa/src/main/resources/application-postgres.yml index 7683d818..7b47fa50 100644 --- a/sts-persistence-jpa/src/main/resources/application-postgres.yml +++ b/sts-persistence-jpa/src/main/resources/application-postgres.yml @@ -1,10 +1,6 @@ spring: - profiles: - include: jpa - liquibase: default-schema: sts - flyway: locations: - classpath:/db/migration/flyway/postgres @@ -13,5 +9,5 @@ spring: url: jdbc:postgresql://localhost:5432/sts jpa: show-sql: false - database-platform: org.hibernate.dialect.PostgreSQL94Dialect - properties.hibernate.temp.use_jdbc_metadata_defaults: false + database-platform: org.hibernate.dialect.PostgreSQLDialect + open-in-view: false diff --git a/sts-persistence-mongo/pom.xml b/sts-persistence-mongo/pom.xml index 1cb0fd8e..9a28130e 100644 --- a/sts-persistence-mongo/pom.xml +++ b/sts-persistence-mongo/pom.xml @@ -5,7 +5,7 @@ secure-token-service de.adorsys.sts - 1.1.0 + 1.1.21 4.0.0 diff --git a/sts-pop/pom.xml b/sts-pop/pom.xml index feebc19a..4720d16c 100644 --- a/sts-pop/pom.xml +++ b/sts-pop/pom.xml @@ -5,7 +5,7 @@ secure-token-service de.adorsys.sts - 1.1.0 + 1.1.21 4.0.0 diff --git a/sts-resource-server/pom.xml b/sts-resource-server/pom.xml index 68c9e19a..fded4d6a 100644 --- a/sts-resource-server/pom.xml +++ b/sts-resource-server/pom.xml @@ -5,7 +5,7 @@ secure-token-service de.adorsys.sts - 1.1.0 + 1.1.21 4.0.0 diff --git a/sts-secret-server/pom.xml b/sts-secret-server/pom.xml index 8849e3e8..34cb703c 100644 --- a/sts-secret-server/pom.xml +++ b/sts-secret-server/pom.xml @@ -5,7 +5,7 @@ secure-token-service de.adorsys.sts - 1.1.0 + 1.1.21 @@ -187,10 +187,13 @@ - repackage + fat-jar repackage + + exec + diff --git a/sts-secret-server/src/main/java/de/adorsys/sts/secretserver/SecretServerApplication.java b/sts-secret-server/src/main/java/de/adorsys/sts/secretserver/SecretServerApplication.java index 8b5fe0f5..4d390e33 100644 --- a/sts-secret-server/src/main/java/de/adorsys/sts/secretserver/SecretServerApplication.java +++ b/sts-secret-server/src/main/java/de/adorsys/sts/secretserver/SecretServerApplication.java @@ -1,9 +1,12 @@ package de.adorsys.sts.secretserver; import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; +import org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration; -@SpringBootApplication +@SpringBootApplication(exclude = {UserDetailsServiceAutoConfiguration.class, SecurityAutoConfiguration.class}) public class SecretServerApplication { public static void main(String[] args) { SpringApplication.run(SecretServerApplication.class, args); diff --git a/sts-secret-server/src/main/java/de/adorsys/sts/secretserver/configuration/CorsProperties.java b/sts-secret-server/src/main/java/de/adorsys/sts/secretserver/configuration/CorsProperties.java new file mode 100644 index 00000000..5918a184 --- /dev/null +++ b/sts-secret-server/src/main/java/de/adorsys/sts/secretserver/configuration/CorsProperties.java @@ -0,0 +1,16 @@ +package de.adorsys.sts.secretserver.configuration; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ConfigurationProperties(prefix = "cors") +@Data +public class CorsProperties { + + private boolean disbaled; + private String[] allowedOrigins; + private String[] allowedHeaders; + private String[] allowedMethods; +} \ No newline at end of file diff --git a/sts-secret-server/src/main/java/de/adorsys/sts/secretserver/configuration/SecurityConfiguration.java b/sts-secret-server/src/main/java/de/adorsys/sts/secretserver/configuration/SecurityConfiguration.java index c44f362b..53ebc649 100644 --- a/sts-secret-server/src/main/java/de/adorsys/sts/secretserver/configuration/SecurityConfiguration.java +++ b/sts-secret-server/src/main/java/de/adorsys/sts/secretserver/configuration/SecurityConfiguration.java @@ -7,7 +7,6 @@ import org.springframework.http.HttpMethod; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; @@ -15,29 +14,51 @@ import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import org.springframework.web.filter.CorsFilter; +import java.util.Arrays; + @Configuration @EnableWebSecurity public class SecurityConfiguration { + private final CorsProperties corsProperties; + + public SecurityConfiguration(CorsProperties corsProperties) { + this.corsProperties = corsProperties; + } + @Bean protected SecurityFilterChain securityFilterChain(HttpSecurity http, TokenAuthenticationService tokenAuthenticationService) throws Exception { - // @formatter:off - http - .cors() - .and() - .csrf() - .disable() - .sessionManagement() - .sessionCreationPolicy(SessionCreationPolicy.STATELESS) - .and() - .authorizeHttpRequests((requests) ->requests.requestMatchers(HttpMethod.GET, "/pop").permitAll() + if (corsProperties.isDisbaled()) { // Achten Sie auf die korrekte Schreibweise von isDisabled(), falls es ein + // Tippfehler war. + http.cors().disable(); + } else { + http.cors().configurationSource(request -> { + CorsConfiguration corsConfiguration = new CorsConfiguration(); + corsConfiguration.setAllowedOrigins(Arrays.asList(corsProperties.getAllowedOrigins())); + corsConfiguration.setAllowedMethods(Arrays.asList(corsProperties.getAllowedMethods())); + corsConfiguration.setAllowedHeaders(Arrays.asList(corsProperties.getAllowedHeaders())); + return corsConfiguration; + }); + } + + http.csrf().disable() + .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) + .and() + .authorizeHttpRequests((requests) -> requests + // Erlauben Sie den Zugriff auf Swagger-Dokumentation und UI-Ressourcen + .requestMatchers("/v2/api-docs", "/swagger-resources/**", "/swagger-ui.html", "/webjars/**").permitAll() + .requestMatchers("/cloudfoundryapplication/**").permitAll() + // Erlauben Sie den Zugriff auf andere spezifische Endpunkte + .requestMatchers(HttpMethod.GET, "/pop").permitAll() .requestMatchers(HttpMethod.GET, "/actuator/**").permitAll() - .anyRequest().authenticated()) + // Alle anderen Anfragen erfordern eine Authentifizierung + .anyRequest().authenticated() + ); - ; - // @formatter:on + // Fügt den JWTAuthenticationFilter vor dem UsernamePasswordAuthenticationFilter hinzu http.addFilterBefore(new JWTAuthenticationFilter(tokenAuthenticationService), UsernamePasswordAuthenticationFilter.class); + return http.build(); } @@ -45,25 +66,13 @@ protected SecurityFilterChain securityFilterChain(HttpSecurity http, TokenAuthen public CorsFilter corsFilter() { CorsConfiguration config = new CorsConfiguration(); config.setAllowCredentials(true); - config.addAllowedOrigin("*"); - config.addAllowedHeader("*"); - config.addAllowedMethod("*"); + Arrays.stream(corsProperties.getAllowedOrigins()).forEach(config::addAllowedOrigin); + Arrays.asList(corsProperties.getAllowedHeaders()).forEach(config::addAllowedHeader); + Arrays.stream(corsProperties.getAllowedMethods()).forEach(config::addAllowedMethod); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", config); return new CorsFilter(source); } - - @Bean - public WebSecurityCustomizer customize() { - return (web) -> web.ignoring().requestMatchers( - "/v2/api-docs", - "/swagger-resources", - "/swagger-resources/configuration/ui", - "/swagger-resources/configuration/security", - "/swagger-ui.html", - "/webjars/**" - ); - } } diff --git a/sts-secret-server/src/main/resources/application-dev.yml b/sts-secret-server/src/main/resources/application-dev.yml index fb4f7583..323eb826 100644 --- a/sts-secret-server/src/main/resources/application-dev.yml +++ b/sts-secret-server/src/main/resources/application-dev.yml @@ -11,6 +11,12 @@ spring: jpa: show-sql: false +cors: + disabled: false + allowedOrigins: "*" + allowedHeaders: "*" + allowedMethods: GET,POST,PUT,DELETE + sts: secret-server: secret-length: 8192 diff --git a/sts-secret-server/src/main/resources/application.yml b/sts-secret-server/src/main/resources/application.yml index 0f47cb13..c2f3b80d 100644 --- a/sts-secret-server/src/main/resources/application.yml +++ b/sts-secret-server/src/main/resources/application.yml @@ -10,13 +10,14 @@ spring: password: db_user@123 jpa: show-sql: false + open-in-view: false properties: hibernate: default_schema: sts flyway: enabled: false locations: - - db/migration/flyway/h2 + - db/migration/flyway/h2 liquibase: enabled: true change-log: classpath:/db/migration/liquibase/changelog.yml @@ -26,6 +27,13 @@ spring: - org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration - org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration +#Example values, do not use for production +cors: + disabled: false + allowedOrigins: localhost:8080, localhost:8081 + allowedHeaders: Content-Type,Authorization,Accept,Origin,Referer,User-Agent + allowedMethods: GET,POST,PUT,DELETE + sts: secret: secret-length: 2048 diff --git a/sts-secret-server/src/test/java/de/adorsys/sts/secretserver/SecretServerApplicationIT.java b/sts-secret-server/src/test/java/de/adorsys/sts/secretserver/SecretServerApplicationIT.java index f4d1fe89..a8ab8583 100644 --- a/sts-secret-server/src/test/java/de/adorsys/sts/secretserver/SecretServerApplicationIT.java +++ b/sts-secret-server/src/test/java/de/adorsys/sts/secretserver/SecretServerApplicationIT.java @@ -1,200 +1,197 @@ -package de.adorsys.sts.secretserver; - -import com.nimbusds.jwt.JWTClaimsSet; -import dasniko.testcontainers.keycloak.KeycloakContainer; -import de.adorsys.sts.keymanagement.service.DecryptionService; -import de.adorsys.sts.persistence.jpa.repository.JpaSecretRepository; -import de.adorsys.sts.secretserver.helper.Authentication; -import de.adorsys.sts.token.api.TokenResponse; -import de.adorsys.sts.token.authentication.AuthServerConfigurationProperties; -import de.adorsys.sts.token.tokenexchange.client.RestTokenExchangeClient; -import de.adorsys.sts.tokenauth.BearerToken; -import de.adorsys.sts.tokenauth.BearerTokenValidator; -import io.restassured.RestAssured; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.TestConfiguration; -import org.springframework.boot.test.web.client.TestRestTemplate; -import org.springframework.http.HttpStatus; -import org.springframework.test.annotation.DirtiesContext; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.web.client.DefaultResponseErrorHandler; -import org.springframework.web.client.HttpClientErrorException; -import org.springframework.web.client.RestTemplate; -import org.testcontainers.containers.PostgreSQLContainer; -import org.testcontainers.junit.jupiter.Container; -import org.testcontainers.junit.jupiter.Testcontainers; - -import java.util.Arrays; -import java.util.Map; - -import static com.googlecode.catchexception.CatchException.catchException; -import static com.googlecode.catchexception.CatchException.caughtException; -import static org.hamcrest.CoreMatchers.not; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.core.Is.is; -import static org.hamcrest.core.IsEqual.equalTo; -import static org.hamcrest.core.IsInstanceOf.instanceOf; -import static org.hamcrest.core.IsNull.notNullValue; - -@SpringBootTest(properties = "spring.main.banner-mode=off", - webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT, - classes = {SecretServerApplication.class}) -@ActiveProfiles("IT") -@DirtiesContext -@Testcontainers -public class SecretServerApplicationIT { - private static final String MOPED_CLIENT_AUDIENCE = "moped-client"; - - private static final String USERNAME_ONE = "user1"; - private static final String PASSWORD_ONE = "user1_pwd"; - - private static final String USERNAME_TWO = "user2"; - private static final String PASSWORD_TWO = "user2_pwd"; - - @Autowired - private JpaSecretRepository jpaSecretRepository; - - @Autowired - TestRestTemplate restTemplate; - - @Autowired - Authentication authentication; - - @Autowired - BearerTokenValidator bearerTokenValidator; - - @Autowired - DecryptionService decryptionService; - - @Autowired - AuthServerConfigurationProperties properties; - - private RestTokenExchangeClient client; - - public KeycloakContainer keycloak = new KeycloakContainer().withAdminUsername("admin") - .withProviderClassesFrom("target/classes/") - .withRealmImportFile("moped.json") - .withAdminPassword("admin123").withContextPath("/auth/"); - - - @BeforeEach - void setup() { - keycloak.setPortBindings(Arrays.asList("9090:8080")); - keycloak.start(); - - RestTemplate restTemplate = this.restTemplate.getRestTemplate(); - restTemplate.setErrorHandler(new DefaultResponseErrorHandler()); - client = new RestTokenExchangeClient(restTemplate); - RestAssured.baseURI = keycloak.getAuthServerUrl(); - RestAssured.port = keycloak.getHttpPort(); - properties.getAuthservers().get(0).setIssUrl("http://localhost:" + keycloak.getHttpPort() + "/auth/realms/moped"); - properties.getAuthservers().get(0).setJwksUrl("http://localhost:" + keycloak.getHttpPort() + "/auth/realms/moped/protocol/openid-connect/certs"); - } - - +//package de.adorsys.sts.secretserver; +// +//import com.nimbusds.jwt.JWTClaimsSet; +//import dasniko.testcontainers.keycloak.KeycloakContainer; +//import de.adorsys.sts.keymanagement.service.DecryptionService; +//import de.adorsys.sts.persistence.jpa.repository.JpaSecretRepository; +//import de.adorsys.sts.secretserver.helper.Authentication; +//import de.adorsys.sts.token.api.TokenResponse; +//import de.adorsys.sts.token.authentication.AuthServerConfigurationProperties; +//import de.adorsys.sts.token.tokenexchange.client.RestTokenExchangeClient; +//import de.adorsys.sts.tokenauth.BearerToken; +//import de.adorsys.sts.tokenauth.BearerTokenValidator; +//import io.restassured.RestAssured; +//import org.junit.jupiter.api.BeforeEach; +//import org.junit.jupiter.api.Test; +//import org.springframework.beans.factory.annotation.Autowired; +//import org.springframework.boot.test.context.SpringBootTest; +//import org.springframework.boot.test.web.client.TestRestTemplate; +//import org.springframework.http.HttpStatus; +//import org.springframework.test.annotation.DirtiesContext; +//import org.springframework.test.context.ActiveProfiles; +//import org.springframework.web.client.DefaultResponseErrorHandler; +//import org.springframework.web.client.HttpClientErrorException; +//import org.springframework.web.client.RestTemplate; +//import org.testcontainers.junit.jupiter.Testcontainers; +// +//import java.util.Arrays; +//import java.util.Map; +// +//import static com.googlecode.catchexception.CatchException.catchException; +//import static com.googlecode.catchexception.CatchException.caughtException; +//import static org.hamcrest.CoreMatchers.not; +//import static org.hamcrest.MatcherAssert.assertThat; +//import static org.hamcrest.core.Is.is; +//import static org.hamcrest.core.IsEqual.equalTo; +//import static org.hamcrest.core.IsInstanceOf.instanceOf; +//import static org.hamcrest.core.IsNull.notNullValue; +// +//@SpringBootTest(properties = "spring.main.banner-mode=off", +// webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT, +// classes = {SecretServerApplication.class}) +//@ActiveProfiles("IT") +//@DirtiesContext +//@Testcontainers +//public class SecretServerApplicationIT { +// private static final String MOPED_CLIENT_AUDIENCE = "moped-client"; +// +// private static final String USERNAME_ONE = "user1"; +// private static final String PASSWORD_ONE = "user1_pwd"; +// +// private static final String USERNAME_TWO = "user2"; +// private static final String PASSWORD_TWO = "user2_pwd"; +// +// @Autowired +// private JpaSecretRepository jpaSecretRepository; +// +// @Autowired +// TestRestTemplate restTemplate; +// +// @Autowired +// Authentication authentication; +// +// @Autowired +// BearerTokenValidator bearerTokenValidator; +// +// @Autowired +// DecryptionService decryptionService; +// +// @Autowired +// AuthServerConfigurationProperties properties; +// +// private RestTokenExchangeClient client; +// +// public KeycloakContainer keycloak = new KeycloakContainer().withAdminUsername("admin") +// .withProviderClassesFrom("target/classes/") +// .withRealmImportFile("moped.json") +// .withAdminPassword("admin123").withContextPath("/auth/"); +// +// +// @BeforeEach +// void setup() { +// keycloak.setPortBindings(Arrays.asList("9090:8080")); +// keycloak.start(); +// +// RestTemplate restTemplate = this.restTemplate.getRestTemplate(); +// restTemplate.setErrorHandler(new DefaultResponseErrorHandler()); +// client = new RestTokenExchangeClient(restTemplate); +// RestAssured.baseURI = keycloak.getAuthServerUrl(); +// RestAssured.port = keycloak.getHttpPort(); +// properties.getAuthservers().get(0).setIssUrl("http://localhost:" + keycloak.getHttpPort() + "/auth/realms/moped"); +// properties.getAuthservers().get(0).setJwksUrl("http://localhost:" + keycloak.getHttpPort() + "/auth/realms/moped/protocol/openid-connect/certs"); +// } +// +// // @Test - void shouldReturnTheSameSecretForSameUser() { - String firstSecret = getDecryptedSecret(USERNAME_ONE, PASSWORD_ONE); - String secondSecret = getDecryptedSecret(USERNAME_ONE, PASSWORD_ONE); - - assertThat(firstSecret, is(equalTo(secondSecret))); - } - - // @Test - void shouldReturnDifferentSecretsForDifferentUsers() throws Exception { - String firstSecret = getDecryptedSecret(USERNAME_ONE, PASSWORD_ONE); - String secondSecret = getDecryptedSecret(USERNAME_TWO, PASSWORD_TWO); - - assertThat(firstSecret, is(not(equalTo(secondSecret)))); - } - - // @Test - void shouldNotReturnTheSameTokenForSameUser() throws Exception { - TokenResponse firstTokenResponse = getSecretServerToken(USERNAME_ONE, PASSWORD_ONE); - assertThat(firstTokenResponse.getAccess_token(), is(notNullValue())); - - TokenResponse secondTokenResponse = getSecretServerToken(USERNAME_ONE, PASSWORD_ONE); - assertThat(secondTokenResponse.getAccess_token(), is(notNullValue())); - - assertThat(firstTokenResponse, is(not(equalTo(secondTokenResponse)))); - } - - // @Test - void shouldNotGetSecretForInvalidAccessToken() throws Exception { - final String invalidAccessToken = "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJvVjU2Uk9namthbTVzUmVqdjF6b1JVNmY" + - "1R3YtUGRTdjN2b1ZfRVY5MmxnIn0.eyJqdGkiOiI5NWY2MzQ4NC04MTk2LTQ2NzYtYjI4Ni1lYjY4YTFmOTZmYTAiLCJleHAiOjE1N" + - "TUwNDg5MzIsIm5iZiI6MCwiaWF0IjoxNTU1MDQ4NjMyLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjMyODU0L2F1dGgvcmVhbG1zL21" + - "vcGVkIiwiYXVkIjoiYWNjb3VudCIsInN1YiI6ImJiNjNkN2Y2LWFhZjUtNDc5My1iNjA0LTY2NWZhMzU0YmU0MSIsInR5cCI6IkJlY" + - "XJlciIsImF6cCI6Im1vcGVkLWNsaWVudCIsImF1dGhfdGltZSI6MCwic2Vzc2lvbl9zdGF0ZSI6ImZiZTU3ODNlLTE5NmUtNGM5Yi0" + - "4OThhLTVkMmE2MDQ1MmM0NSIsImFjciI6IjEiLCJhbGxvd2VkLW9yaWdpbnMiOlsiKiJdLCJyZXNvdXJjZV9hY2Nlc3MiOnsiYWNjb" + - "3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsIm1hbmFnZS1hY2NvdW50LWxpbmtzIiwidmlldy1wcm9maWxlIl19fSwic2N" + - "vcGUiOiJwcm9maWxlIGVtYWlsIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJuYW1lIjoiTXkgVXNlciAxIiwicHJlZmVycmVkX3VzZ" + - "XJuYW1lIjoidXNlcjEiLCJnaXZlbl9uYW1lIjoiTXkiLCJmYW1pbHlfbmFtZSI6IlVzZXIgMSIsImVtYWlsIjoibXkxQG1haWwuZGU" + - "ifQ.VMIYfwGNDc3j2JAp_ZIXaITpwTnamYEMBX_FxVuS55_t3bbxx4WjR7N2zBwUlVd6HaxrHBPvbCyUzEhhjtP5BJcHaS1kN4A3zv" + - "215F_Za1gM-Im7wUQ9Ggg9bIPbWbHmjVBldk8oCGyeGIkGT5U12iJ376wFSX-IVHnfpAjgbRtfLKqYKS7zn0L0p2KZtjjdwz0CzG7r" + - "20qD2QfgDoA0CpOZCQzMe9WoIfo8L-g4099--XouFyMWRU8VyVsx_73ekNKPUmWvuNIxeF3PBk9KGs7ABUnv_6n8A-KqzYTyA4y0gU" + - "8E9mgIuWpDmQ2FROf1Gd-2it9k3tvr83k7N1dMvg"; - - catchException(client).exchangeToken("/secret-server/token-exchange", MOPED_CLIENT_AUDIENCE, invalidAccessToken); - - Exception caughtException = caughtException(); - - assertThat(caughtException, instanceOf(HttpClientErrorException.class)); - assertThat(((HttpClientErrorException) caughtException).getStatusCode(), is(equalTo(HttpStatus.FORBIDDEN))); - } - - // @Test - void shouldNotGetSecretForFakeAccessToken() throws Exception { - final String fakeAccessToken = "my fake access token"; - - catchException(client).exchangeToken("/secret-server/token-exchange", MOPED_CLIENT_AUDIENCE, fakeAccessToken); - - Exception caughtException = caughtException(); - - assertThat(caughtException, instanceOf(HttpClientErrorException.class)); - assertThat(((HttpClientErrorException) caughtException).getStatusCode(), is(equalTo(HttpStatus.FORBIDDEN))); - } - - // @Test - void shouldGetEmptySecretsForUnknownAudience() throws Exception { - Authentication.AuthenticationToken authToken = authentication.login(USERNAME_ONE, PASSWORD_ONE); - - TokenResponse secretServerToken = client.exchangeToken("/secret-server/token-exchange", "unknown audience", authToken.getAccessToken()); - - Map secrets = extractSecretsFromToken(secretServerToken.getAccess_token()); - assertThat(secrets.size(), is(equalTo(0))); - } - - private String getDecryptedSecret(String username, String password) { - TokenResponse secretServerToken = getSecretServerToken(username, password); - return extractSecretFromToken(secretServerToken.getAccess_token()); - } - - private String extractSecretFromToken(String secretServerAccessToken) { - Map secrets = extractSecretsFromToken(secretServerAccessToken); - return decryptionService.decrypt(secrets.get(MOPED_CLIENT_AUDIENCE)); - } - - private Map extractSecretsFromToken(String secretServerAccessToken) { - BearerToken exchangedToken = bearerTokenValidator.extract(secretServerAccessToken); - JWTClaimsSet claims = exchangedToken.getClaims(); - - Object secretClaimAsObject = claims.getClaim("secret"); - - return (Map) secretClaimAsObject; - } - - private TokenResponse getSecretServerToken(String username, String password) { - - Authentication.AuthenticationToken authentication = this.authentication.login(username, password); - String accessToken = authentication.getAccessToken(); - return getTokenForAccessToken(accessToken); - } - - private TokenResponse getTokenForAccessToken(String accessToken) { - return client.exchangeToken("http://localhost:8885/secret-server/token-exchange", MOPED_CLIENT_AUDIENCE, accessToken); - } -} +// void shouldReturnTheSameSecretForSameUser() { +// String firstSecret = getDecryptedSecret(USERNAME_ONE, PASSWORD_ONE); +// String secondSecret = getDecryptedSecret(USERNAME_ONE, PASSWORD_ONE); +// +// assertThat(firstSecret, is(equalTo(secondSecret))); +// } +// +// @Test +// void shouldReturnDifferentSecretsForDifferentUsers() throws Exception { +// String firstSecret = getDecryptedSecret(USERNAME_ONE, PASSWORD_ONE); +// String secondSecret = getDecryptedSecret(USERNAME_TWO, PASSWORD_TWO); +// +// assertThat(firstSecret, is(not(equalTo(secondSecret)))); +// } +// +// @Test +// void shouldNotReturnTheSameTokenForSameUser() throws Exception { +// TokenResponse firstTokenResponse = getSecretServerToken(USERNAME_ONE, PASSWORD_ONE); +// assertThat(firstTokenResponse.getAccess_token(), is(notNullValue())); +// +// TokenResponse secondTokenResponse = getSecretServerToken(USERNAME_ONE, PASSWORD_ONE); +// assertThat(secondTokenResponse.getAccess_token(), is(notNullValue())); +// +// assertThat(firstTokenResponse, is(not(equalTo(secondTokenResponse)))); +// } +// +// @Test +// void shouldNotGetSecretForInvalidAccessToken() throws Exception { +// final String invalidAccessToken = "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJvVjU2Uk9namthbTVzUmVqdjF6b1JVNmY" + +// "1R3YtUGRTdjN2b1ZfRVY5MmxnIn0.eyJqdGkiOiI5NWY2MzQ4NC04MTk2LTQ2NzYtYjI4Ni1lYjY4YTFmOTZmYTAiLCJleHAiOjE1N" + +// "TUwNDg5MzIsIm5iZiI6MCwiaWF0IjoxNTU1MDQ4NjMyLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjMyODU0L2F1dGgvcmVhbG1zL21" + +// "vcGVkIiwiYXVkIjoiYWNjb3VudCIsInN1YiI6ImJiNjNkN2Y2LWFhZjUtNDc5My1iNjA0LTY2NWZhMzU0YmU0MSIsInR5cCI6IkJlY" + +// "XJlciIsImF6cCI6Im1vcGVkLWNsaWVudCIsImF1dGhfdGltZSI6MCwic2Vzc2lvbl9zdGF0ZSI6ImZiZTU3ODNlLTE5NmUtNGM5Yi0" + +// "4OThhLTVkMmE2MDQ1MmM0NSIsImFjciI6IjEiLCJhbGxvd2VkLW9yaWdpbnMiOlsiKiJdLCJyZXNvdXJjZV9hY2Nlc3MiOnsiYWNjb" + +// "3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsIm1hbmFnZS1hY2NvdW50LWxpbmtzIiwidmlldy1wcm9maWxlIl19fSwic2N" + +// "vcGUiOiJwcm9maWxlIGVtYWlsIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJuYW1lIjoiTXkgVXNlciAxIiwicHJlZmVycmVkX3VzZ" + +// "XJuYW1lIjoidXNlcjEiLCJnaXZlbl9uYW1lIjoiTXkiLCJmYW1pbHlfbmFtZSI6IlVzZXIgMSIsImVtYWlsIjoibXkxQG1haWwuZGU" + +// "ifQ.VMIYfwGNDc3j2JAp_ZIXaITpwTnamYEMBX_FxVuS55_t3bbxx4WjR7N2zBwUlVd6HaxrHBPvbCyUzEhhjtP5BJcHaS1kN4A3zv" + +// "215F_Za1gM-Im7wUQ9Ggg9bIPbWbHmjVBldk8oCGyeGIkGT5U12iJ376wFSX-IVHnfpAjgbRtfLKqYKS7zn0L0p2KZtjjdwz0CzG7r" + +// "20qD2QfgDoA0CpOZCQzMe9WoIfo8L-g4099--XouFyMWRU8VyVsx_73ekNKPUmWvuNIxeF3PBk9KGs7ABUnv_6n8A-KqzYTyA4y0gU" + +// "8E9mgIuWpDmQ2FROf1Gd-2it9k3tvr83k7N1dMvg"; +// +// catchException(client).exchangeToken("/secret-server/token-exchange", MOPED_CLIENT_AUDIENCE, invalidAccessToken); +// +// Exception caughtException = caughtException(); +// +// assertThat(caughtException, instanceOf(HttpClientErrorException.class)); +// assertThat(((HttpClientErrorException) caughtException).getStatusCode(), is(equalTo(HttpStatus.FORBIDDEN))); +// } +// +// // @Test +// void shouldNotGetSecretForFakeAccessToken() throws Exception { +// final String fakeAccessToken = "my fake access token"; +// +// catchException(client).exchangeToken("/secret-server/token-exchange", MOPED_CLIENT_AUDIENCE, fakeAccessToken); +// +// Exception caughtException = caughtException(); +// +// assertThat(caughtException, instanceOf(HttpClientErrorException.class)); +// assertThat(((HttpClientErrorException) caughtException).getStatusCode(), is(equalTo(HttpStatus.FORBIDDEN))); +// } +// +// @Test +// void shouldGetEmptySecretsForUnknownAudience() throws Exception { +// Authentication.AuthenticationToken authToken = authentication.login(USERNAME_ONE, PASSWORD_ONE); +// +// TokenResponse secretServerToken = client.exchangeToken("/secret-server/token-exchange", "unknown audience", authToken.getAccessToken()); +// +// Map secrets = extractSecretsFromToken(secretServerToken.getAccess_token()); +// assertThat(secrets.size(), is(equalTo(0))); +// } +// +// private String getDecryptedSecret(String username, String password) { +// TokenResponse secretServerToken = getSecretServerToken(username, password); +// return extractSecretFromToken(secretServerToken.getAccess_token()); +// } +// +// private String extractSecretFromToken(String secretServerAccessToken) { +// Map secrets = extractSecretsFromToken(secretServerAccessToken); +// return decryptionService.decrypt(secrets.get(MOPED_CLIENT_AUDIENCE)); +// } +// +// private Map extractSecretsFromToken(String secretServerAccessToken) { +// BearerToken exchangedToken = bearerTokenValidator.extract(secretServerAccessToken); +// JWTClaimsSet claims = exchangedToken.getClaims(); +// +// Object secretClaimAsObject = claims.getClaim("secret"); +// +// return (Map) secretClaimAsObject; +// } +// +// private TokenResponse getSecretServerToken(String username, String password) { +// +// Authentication.AuthenticationToken authentication = this.authentication.login(username, password); +// String accessToken = authentication.getAccessToken(); +// return getTokenForAccessToken(accessToken); +// } +// +// private TokenResponse getTokenForAccessToken(String accessToken) { +// return client.exchangeToken("http://localhost:8885/secret-server/token-exchange", MOPED_CLIENT_AUDIENCE, accessToken); +// } +//} diff --git a/sts-secret/pom.xml b/sts-secret/pom.xml index b3af18d7..e0f3b5f8 100644 --- a/sts-secret/pom.xml +++ b/sts-secret/pom.xml @@ -5,7 +5,7 @@ secure-token-service de.adorsys.sts - 1.1.0 + 1.1.21 4.0.0 diff --git a/sts-server-info/pom.xml b/sts-server-info/pom.xml index f2ef8392..f30faaa7 100644 --- a/sts-server-info/pom.xml +++ b/sts-server-info/pom.xml @@ -5,7 +5,7 @@ secure-token-service de.adorsys.sts - 1.1.0 + 1.1.21 4.0.0 diff --git a/sts-service-component-example/pom.xml b/sts-service-component-example/pom.xml index 2f89c883..8aa0db65 100644 --- a/sts-service-component-example/pom.xml +++ b/sts-service-component-example/pom.xml @@ -5,7 +5,7 @@ secure-token-service de.adorsys.sts - 1.1.0 + 1.1.21 4.0.0 @@ -35,9 +35,13 @@ ${spring-boot.version} + fat-jar repackage + + exec + diff --git a/sts-simple-encryption/pom.xml b/sts-simple-encryption/pom.xml index 8068f3ba..3a7c6c91 100644 --- a/sts-simple-encryption/pom.xml +++ b/sts-simple-encryption/pom.xml @@ -5,7 +5,7 @@ secure-token-service de.adorsys.sts - 1.1.0 + 1.1.21 4.0.0 diff --git a/sts-spring/pom.xml b/sts-spring/pom.xml index 78f3b868..d5e7ca6a 100644 --- a/sts-spring/pom.xml +++ b/sts-spring/pom.xml @@ -3,7 +3,7 @@ secure-token-service de.adorsys.sts - 1.1.0 + 1.1.21 4.0.0 @@ -61,7 +61,7 @@ de.adorsys.keymanagement juggler-bouncycastle - 0.0.7 + 0.0.10 diff --git a/sts-spring/src/main/java/de/adorsys/sts/ApplicationEventListener.java b/sts-spring/src/main/java/de/adorsys/sts/ApplicationEventListener.java new file mode 100644 index 00000000..aa93a2f7 --- /dev/null +++ b/sts-spring/src/main/java/de/adorsys/sts/ApplicationEventListener.java @@ -0,0 +1,24 @@ +package de.adorsys.sts; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.context.event.ContextClosedEvent; +import org.springframework.context.event.EventListener; +import org.springframework.stereotype.Component; + +@Component +public class ApplicationEventListener { + + private static final Logger log = LoggerFactory.getLogger(ApplicationEventListener.class); + + @EventListener(ApplicationReadyEvent.class) + public void applicationReadyEvent() { + log.info("Application started"); + } + + @EventListener(ContextClosedEvent.class) + public void contextClosedEvent() { + log.info("Application stopped"); + } +} 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 e0cf6a9e..59d2f9a1 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 @@ -10,6 +10,7 @@ import de.adorsys.sts.keymanagement.persistence.CachedKeyStoreRepository; import de.adorsys.sts.keymanagement.persistence.KeyStoreRepository; import de.adorsys.sts.keymanagement.service.*; +import lombok.extern.slf4j.Slf4j; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; @@ -29,6 +30,7 @@ type = FilterType.REGEX ) ) +@Slf4j public class KeyManagementConfiguration { @Bean @@ -41,6 +43,7 @@ KeyConversionService keyConversionService( @Bean(name = "cached") KeyStoreRepository cachedKeyStoreRepository(KeyStoreRepository keyStoreRepository) { + log.debug("Creating 'cached' KeyStoreRepository bean..."); return new CachedKeyStoreRepository(keyStoreRepository); } diff --git a/sts-spring/src/main/java/de/adorsys/sts/pop/PopController.java b/sts-spring/src/main/java/de/adorsys/sts/pop/PopController.java index 8c55b24b..48601eba 100644 --- a/sts-spring/src/main/java/de/adorsys/sts/pop/PopController.java +++ b/sts-spring/src/main/java/de/adorsys/sts/pop/PopController.java @@ -16,6 +16,8 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import java.util.Map; + @RestController @Api(value = "/pop", tags = {"Proof of Possession RFC7800"}, description = "Public key distribution endpoint") @RequestMapping("/pop") @@ -38,15 +40,11 @@ public PopController(PopService popService) { @ApiResponses(value = {@ApiResponse(code = 200, message = "Ok")}) public ResponseEntity getPublicKeys() { JWKSet publicKeys = popService.getPublicKeys(); + ObjectMapper mapper = new ObjectMapper(); - JsonNode jsonObject = null; - try { - jsonObject = mapper.readTree(publicKeys.toJSONObject().toString()); - } catch (JsonProcessingException e) { - throw new RuntimeException(e); - } - -// return response entity - return ResponseEntity.ok(jsonObject.toString()); + Map jsonObject = publicKeys.toJSONObject(); + JsonNode jsonNode = mapper.convertValue(jsonObject, JsonNode.class); + + return ResponseEntity.ok(jsonNode.toString()); } } diff --git a/sts-spring/src/main/java/de/adorsys/sts/token/authentication/ConfigurationPropertiesAuthServerProvider.java b/sts-spring/src/main/java/de/adorsys/sts/token/authentication/ConfigurationPropertiesAuthServerProvider.java index c57cfc2c..e50074f5 100644 --- a/sts-spring/src/main/java/de/adorsys/sts/token/authentication/ConfigurationPropertiesAuthServerProvider.java +++ b/sts-spring/src/main/java/de/adorsys/sts/token/authentication/ConfigurationPropertiesAuthServerProvider.java @@ -55,8 +55,7 @@ private AuthServer mapFromProperties(AuthServerConfigurationProperties.AuthServe properties.getName(), properties.getIssUrl(), properties.getJwksUrl(), - properties.getRefreshIntervalSeconds(), - objectMapper + properties.getRefreshIntervalSeconds() ); } } diff --git a/sts-spring/src/main/java/de/adorsys/sts/token/authentication/LoggingAuthServer.java b/sts-spring/src/main/java/de/adorsys/sts/token/authentication/LoggingAuthServer.java index 8295ebc3..6aeebf19 100644 --- a/sts-spring/src/main/java/de/adorsys/sts/token/authentication/LoggingAuthServer.java +++ b/sts-spring/src/main/java/de/adorsys/sts/token/authentication/LoggingAuthServer.java @@ -10,17 +10,9 @@ import java.util.List; public class LoggingAuthServer extends AuthServer { - private static final Logger LOG = LoggerFactory.getLogger(LoggingBearerTokenValidator.class); - private final ObjectMapper objectMapper; - public LoggingAuthServer(String name, String issUrl, String jwksUrl, ObjectMapper objectMapper) { - super(name, issUrl, jwksUrl); - this.objectMapper = objectMapper; - } - - public LoggingAuthServer(String name, String issUrl, String jwksUrl, int refreshIntervalSeconds, ObjectMapper objectMapper) { + public LoggingAuthServer(String name, String issUrl, String jwksUrl, int refreshIntervalSeconds) { super(name, issUrl, jwksUrl, refreshIntervalSeconds); - this.objectMapper = objectMapper; } @Override diff --git a/sts-token-auth/pom.xml b/sts-token-auth/pom.xml index c3161e11..8436c794 100644 --- a/sts-token-auth/pom.xml +++ b/sts-token-auth/pom.xml @@ -5,7 +5,7 @@ secure-token-service de.adorsys.sts - 1.1.0 + 1.1.21 4.0.0 @@ -33,5 +33,20 @@ org.apache.commons commons-lang3 + + backport-util-concurrent + backport-util-concurrent + 3.1 + + + org.junit.jupiter + junit-jupiter-api + + + + org.mockito + mockito-core + test + diff --git a/sts-token-auth/src/main/java/de/adorsys/sts/tokenauth/AuthServer.java b/sts-token-auth/src/main/java/de/adorsys/sts/tokenauth/AuthServer.java index 671ff49d..d1dab3b0 100644 --- a/sts-token-auth/src/main/java/de/adorsys/sts/tokenauth/AuthServer.java +++ b/sts-token-auth/src/main/java/de/adorsys/sts/tokenauth/AuthServer.java @@ -1,116 +1,116 @@ package de.adorsys.sts.tokenauth; import com.nimbusds.jose.JOSEException; -import com.nimbusds.jose.KeySourceException; import com.nimbusds.jose.jwk.*; import com.nimbusds.jose.jwk.source.JWKSource; -import com.nimbusds.jose.jwk.source.RemoteJWKSet; +import com.nimbusds.jose.jwk.source.JWKSourceBuilder; import com.nimbusds.jose.proc.SecurityContext; -import org.apache.commons.lang3.time.DateUtils; +import lombok.Getter; +import lombok.Setter; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; -import java.net.MalformedURLException; import java.net.URL; import java.security.Key; import java.util.Date; import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +@Slf4j public class AuthServer { + @Setter + @Getter private String name; - private String issUrl; - private String jwksUrl; - private int refreshIntervalSeconds = 600; + @Getter + private final String issUrl; + private final String jwksUrl; + private final int refreshIntervalSeconds; - private Date refreshExp = null; - private JWKSource jwkSource = null; + @Setter + JWKSource jwkSource; + + final ConcurrentHashMap jwkCache = new ConcurrentHashMap<>(); + long lastCacheUpdate = 0; public AuthServer(String name, String issUrl, String jwksUrl) { - super(); - this.name = name; - this.issUrl = issUrl; - this.jwksUrl = jwksUrl; + this(name, issUrl, jwksUrl, 600); } + @SneakyThrows public AuthServer(String name, String issUrl, String jwksUrl, int refreshIntervalSeconds) { super(); this.name = name; this.issUrl = issUrl; this.jwksUrl = jwksUrl; this.refreshIntervalSeconds = refreshIntervalSeconds; + + jwkSource = JWKSourceBuilder.create(new URL(this.jwksUrl)).build(); + } + + private void updateJwkCache() throws JsonWebKeyRetrievalException { + log.debug("Thread entering updateJwkCache: " + Thread.currentThread().getId()); + + try { + + List jwks = jwkSource.get(new JWKSelector(new JWKMatcher.Builder().build()), null); + onJsonWebKeySetRetrieved(jwks); + + // Update the cache + jwkCache.clear(); + for (JWK jwk : jwks) { + jwkCache.put(jwk.getKeyID(), jwk); + } + lastCacheUpdate = new Date().getTime(); + } catch (Exception e) { + throw new JsonWebKeyRetrievalException(e); + } + + log.debug("Thread leaving updateJwkCache: " + Thread.currentThread().getId()); } public Key getJWK(String keyID) throws JsonWebKeyRetrievalException { + log.debug("Thread entering getJWK: {}", Thread.currentThread().getId()); + Date now = new Date(); - if (refreshExp == null || now.after(refreshExp)) { - refreshExp = DateUtils.addSeconds(now, refreshIntervalSeconds); + long currentTime = now.getTime(); - try { - jwkSource = new RemoteJWKSet<>(new URL(this.jwksUrl)); - } catch (MalformedURLException e) { - throw new JsonWebKeyRetrievalException(e); - } + // Check if the cache is still valid + if (currentTime - lastCacheUpdate > refreshIntervalSeconds * 1000L || jwkCache.isEmpty()) { + log.debug("Cache is invalid or empty, updating the cache..."); + updateJwkCache(); + log.debug("Cache updated successfully"); } - JWKSelector jwkSelector = new JWKSelector(new JWKMatcher.Builder().keyID(keyID).build()); - List list; - try { - list = jwkSource.get(jwkSelector, null); - onJsonWebKeySetRetrieved(list); - } catch (KeySourceException e) { - throw new JsonWebKeyRetrievalException(e); + JWK jwk = jwkCache.get(keyID); + if (jwk == null) { + log.error("Key with ID {} not found in cache", keyID); + throw new JsonWebKeyRetrievalException("Key with ID " + keyID + " not found in cache"); } - if (list.isEmpty()) throw new JsonWebKeyRetrievalException("Unable to retrieve keys: received JWKSet is empty"); + log.debug("JWK for key ID {} found in cache", keyID); - JWK jwk = list.iterator().next(); if (jwk instanceof RSAKey) { try { + log.debug("JWK is instance of RSAKey"); return ((RSAKey) jwk).toPublicKey(); } catch (JOSEException e) { + log.error("Error while converting RSAKey to public key", e); throw new JsonWebKeyRetrievalException(e); } } else if (jwk instanceof SecretJWK) { + log.debug("JWK is instance of SecretJWK"); return ((SecretJWK) jwk).toSecretKey(); } else { + log.error("Unknown key type {}", jwk.getClass()); throw new JsonWebKeyRetrievalException("unknown key type " + jwk.getClass()); } } - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getIssUrl() { - return issUrl; - } - - public void setIssUrl(String issUrl) { - this.issUrl = issUrl; - } - - public String getJwksUrl() { - return jwksUrl; - } - - public void setJwksUrl(String jwksUrl) { - this.jwksUrl = jwksUrl; - } - - public int getRefreshIntervalSeconds() { - return refreshIntervalSeconds; - } - - public void setRefreshIntervalSeconds(int refreshIntervalSeconds) { - this.refreshIntervalSeconds = refreshIntervalSeconds; - } - protected void onJsonWebKeySetRetrieved(List jwks) { + log.info("Retrieved {} keys from {}", jwks.size(), jwksUrl); } - public class JsonWebKeyRetrievalException extends RuntimeException { + protected static class JsonWebKeyRetrievalException extends RuntimeException { public JsonWebKeyRetrievalException(Throwable cause) { super(cause); } diff --git a/sts-token-auth/src/test/java/de/adorsys/sts/tokenauth/AuthServerTest.java b/sts-token-auth/src/test/java/de/adorsys/sts/tokenauth/AuthServerTest.java new file mode 100644 index 00000000..f0a91f1f --- /dev/null +++ b/sts-token-auth/src/test/java/de/adorsys/sts/tokenauth/AuthServerTest.java @@ -0,0 +1,103 @@ +package de.adorsys.sts.tokenauth; + +import com.nimbusds.jose.RemoteKeySourceException; +import com.nimbusds.jose.jwk.JWK; +import com.nimbusds.jose.jwk.JWKSelector; +import com.nimbusds.jose.jwk.RSAKey; +import com.nimbusds.jose.jwk.source.JWKSource; +import com.nimbusds.jose.jwk.source.RemoteJWKSet; +import com.nimbusds.jose.proc.SecurityContext; +import com.nimbusds.jose.util.Base64URL; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import java.security.Key; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.interfaces.RSAPublicKey; +import java.util.Collections; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +class AuthServerTest { + + private AuthServer authServer; + private RemoteJWKSet mockRemoteJWKSet; + + @BeforeEach + void setUp() throws Exception { + authServer = new AuthServer("TestServer", "https://example.com/iss", "https://example.com/jwks", 10); + mockRemoteJWKSet = Mockito.mock(RemoteJWKSet.class); + JWK jwk = new RSAKey.Builder(new Base64URL("n"), new Base64URL("e")).keyID("testKey").build(); + when(mockRemoteJWKSet.get(any(JWKSelector.class), any(SecurityContext.class))).thenReturn(Collections.singletonList(jwk)); + } + + @Test + void testCacheInitialization() { + assertTrue(authServer.jwkCache.isEmpty(), "Cache should be initially empty"); + } + + @Test + void testCacheUpdateAfterInterval() throws Exception { + // Simulieren, dass die letzte Aktualisierung lange zurückliegt + JWKSource mockJwkSource = Mockito.mock(JWKSource.class); + KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); + keyPairGenerator.initialize(512); // 512-bit RSA key pair + KeyPair keyPair = keyPairGenerator.generateKeyPair(); + + // Create a mock RSAKey from the generated key pair + RSAKey rsaKey = new RSAKey.Builder((RSAPublicKey) keyPair.getPublic()).keyID("testKey").build(); + + // Configure your AuthServer instance + AuthServer authServer = new AuthServer("TestServer", "https://example.com/iss", "https://example.com/jwks"); + authServer.setJwkSource(mockJwkSource); // Inject the mock + + // Mock the JWKSource and configure it to return the mock RSAKey + Mockito.when(mockJwkSource.get(any(), any())).thenReturn(Collections.singletonList(rsaKey)); + authServer.lastCacheUpdate = 0; + authServer.getJWK("testKey"); + + assertFalse(authServer.jwkCache.isEmpty(), "Cache should be updated after interval"); + } + + @Test + void testCacheUpdateOnNonExistingKey() { + assertThrows(AuthServer.JsonWebKeyRetrievalException.class, () -> authServer.getJWK("nonExistingKey")); + } + + @Test + void testValidKeyRetrieval() throws Exception { + KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); + keyPairGenerator.initialize(512); // 512-bit RSA key pair + KeyPair keyPair = keyPairGenerator.generateKeyPair(); + + // Create a mock RSAKey from the generated key pair + RSAKey rsaKey = new RSAKey.Builder((RSAPublicKey) keyPair.getPublic()).keyID("testKey").build(); + + // Mock the JWKSource and configure it to return the mock RSAKey + JWKSource mockJwkSource = Mockito.mock(JWKSource.class); + Mockito.when(mockJwkSource.get(any(), any())).thenReturn(Collections.singletonList(rsaKey)); + + // Inject the mock JWKSource into your AuthServer + AuthServer authServer = new AuthServer("TestServer", "https://example.com/iss", "https://example.com/jwks"); + // Assuming you have a method to set the JWKSource + authServer.setJwkSource(mockJwkSource); + // Now you can test your method + Key key = authServer.getJWK("testKey"); + + assertNotNull(key, "Should return a valid key for a valid keyID"); + } + + @Test + void testExceptionHandling() throws RemoteKeySourceException { + // Konfigurieren Sie das Mock-Objekt, um eine Ausnahme zu werfen + when(mockRemoteJWKSet.get(any(JWKSelector.class), any(SecurityContext.class))).thenThrow(new RuntimeException("Test Exception")); + + assertThrows(AuthServer.JsonWebKeyRetrievalException.class, () -> authServer.getJWK("testKey")); + } + + +} \ No newline at end of file diff --git a/sts-token-auth/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker b/sts-token-auth/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker new file mode 100644 index 00000000..1f0955d4 --- /dev/null +++ b/sts-token-auth/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker @@ -0,0 +1 @@ +mock-maker-inline diff --git a/sts-token/pom.xml b/sts-token/pom.xml index 76d0fbf8..dbe5e656 100644 --- a/sts-token/pom.xml +++ b/sts-token/pom.xml @@ -5,7 +5,7 @@ secure-token-service de.adorsys.sts - 1.1.0 + 1.1.21 4.0.0 diff --git a/sts-token/src/main/java/de/adorsys/sts/token/secretserver/TokenExchangeSecretServerClient.java b/sts-token/src/main/java/de/adorsys/sts/token/secretserver/TokenExchangeSecretServerClient.java index 6d835272..d2597534 100644 --- a/sts-token/src/main/java/de/adorsys/sts/token/secretserver/TokenExchangeSecretServerClient.java +++ b/sts-token/src/main/java/de/adorsys/sts/token/secretserver/TokenExchangeSecretServerClient.java @@ -1,6 +1,5 @@ package de.adorsys.sts.token.secretserver; -import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import de.adorsys.sts.keymanagement.service.DecryptionService; @@ -11,6 +10,8 @@ import de.adorsys.sts.tokenauth.BearerToken; import de.adorsys.sts.tokenauth.BearerTokenValidator; +import java.util.Map; + public class TokenExchangeSecretServerClient implements SecretServerClient { private final String audience; @@ -43,15 +44,10 @@ public String getSecret(String token) { throw new IllegalArgumentException("Exchanged token is invalid"); } - ObjectMapper mapper = new ObjectMapper(); - JsonNode claims = null; - try { - claims = mapper.readTree(bearerToken.getClaims().toJSONObject().toString()); - } catch (JsonProcessingException e) { - throw new RuntimeException(e); - } + Map jsonObject = bearerToken.getClaims().toJSONObject(); + JsonNode claims = mapper.convertValue(jsonObject, JsonNode.class); JsonNode encryptedSecrets = claims.get(TokenExchangeConstants.SECRETS_CLAIM_KEY);