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}
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);