diff --git a/.github/workflows/develop_pa-test-internal-testserver-app.yml b/.github/workflows/develop_pa-test-internal-testserver-app.yml
index 427b5c25..19de3f95 100644
--- a/.github/workflows/develop_pa-test-internal-testserver-app.yml
+++ b/.github/workflows/develop_pa-test-internal-testserver-app.yml
@@ -1,30 +1,36 @@
# Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy
# More GitHub Actions for Azure: https://github.com/Azure/actions
-name: Build and deploy container app to Azure Web App - pa-test-internal-testserver-app
+name: Build and deploy container app to Container Registries
on:
push:
branches:
- develop
workflow_dispatch:
-
+ inputs:
+ jfrog_deploy:
+ type: boolean
+ description: Check if build image should be uploaded to JFrog
+ default: false
+ required: false
jobs:
build:
runs-on: 'ubuntu-latest'
environment: test
steps:
- - uses: actions/checkout@v3
- - uses: actions/setup-java@v3
+ - uses: actions/checkout@v4
+ - uses: actions/setup-java@v4
with:
- java-version: '17'
+ java-version: '21'
distribution: 'temurin'
server-id: jfrog-central
server-username: INTERNAL_USERNAME
server-password: INTERNAL_PASSWORD
cache: maven
- - name: Set Timestamp for docker image tag
+ - name: Set Timestamp for docker image for development branch
+ if: github.ref == 'refs/heads/develop'
run: echo "TIMESTAMP=-$(date +%Y.%m.%d)" >> $GITHUB_ENV
- name: Get Powerauth Test Server version
run: |
@@ -42,9 +48,9 @@ jobs:
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- - name: Log in to registry
+ - name: Log in to ACR
if: ${{ github.actor != 'dependabot[bot]' }}
- uses: docker/login-action@v2
+ uses: docker/login-action@v3
with:
registry: https://powerauthextendedtest.azurecr.io/
username: ${{ secrets.AZUREAPPSERVICE_CONTAINERUSERNAME }}
@@ -53,12 +59,32 @@ jobs:
run: |
cd powerauth-test-server
./copy_liquibase.sh
- - name: Build and push container image to registry
- uses: docker/build-push-action@v2
+ - name: Build and push container image to ACR
+ uses: docker/build-push-action@v5
with:
push: ${{ github.actor != 'dependabot[bot]' }}
+ platforms: linux/amd64,linux/arm64
tags: powerauthextendedtest.azurecr.io/powerauth-test-server:${{ env.REVISION }}${{ env.TIMESTAMP }}-${{ github.sha }}
file: ./powerauth-test-server/Dockerfile
context: ./powerauth-test-server/
-
+ cache-from: type=gha
+ cache-to: type=gha,mode=max
+ - name: Log in to JFrog
+ if: ${{ github.event_name == 'workflow_dispatch' && inputs.jfrog_deploy == true }}
+ uses: docker/login-action@v3
+ with:
+ registry: https://wultra.jfrog.io/
+ username: ${{ secrets.JFROG_CONTAINER_REGISTRY_USERNAME }}
+ password: ${{ secrets.JFROG_CONTAINER_REGISTRY_PASSWORD }}
+ - name: Build and push container image to JFrog
+ if: ${{ github.event_name == 'workflow_dispatch' && inputs.jfrog_deploy == true }}
+ uses: docker/build-push-action@v5
+ with:
+ push: ${{ github.event_name == 'workflow_dispatch' && inputs.jfrog_deploy == true }}
+ platforms: linux/amd64,linux/arm64
+ tags: wultra.jfrog.io/wultra-docker/powerauth-test-server:${{ env.REVISION }}${{ env.TIMESTAMP }}
+ file: ./powerauth-test-server/Dockerfile
+ context: ./powerauth-test-server/
+ cache-from: type=gha
+ cache-to: type=gha,mode=max
diff --git a/.github/workflows/maven-deploy.yml b/.github/workflows/maven-deploy.yml
new file mode 100644
index 00000000..f098c09d
--- /dev/null
+++ b/.github/workflows/maven-deploy.yml
@@ -0,0 +1,22 @@
+name: Deploy with Maven
+
+on:
+ workflow_dispatch:
+ branches:
+ - 'develop'
+ - 'master'
+ - 'releases/*'
+
+jobs:
+ maven-deploy-manual:
+ if: ${{ github.event_name == 'workflow_dispatch' }}
+ name: Manual deploy
+ uses: wultra/wultra-infrastructure/.github/workflows/maven-deploy.yml@develop
+ with:
+ environment: internal-publish
+ release_type: snapshot
+ directory_path: ./powerauth-test-server
+ java_version: 21
+ secrets:
+ username: ${{ secrets.MAVEN_CENTRAL_USERNAME }}
+ password: ${{ secrets.MAVEN_CENTRAL_PASSWORD }}
diff --git a/.github/workflows/maven-integration-test.yml b/.github/workflows/maven-integration-test.yml
index cdbefeac..78fb9c0f 100644
--- a/.github/workflows/maven-integration-test.yml
+++ b/.github/workflows/maven-integration-test.yml
@@ -21,11 +21,11 @@ jobs:
runs-on: ubuntu-latest
environment: ${{ inputs.environment || 'dev' }}
steps:
- - uses: actions/checkout@v3
- - name: Set up JDK 17
- uses: actions/setup-java@v3
+ - uses: actions/checkout@v4
+ - name: Set up JDK 21
+ uses: actions/setup-java@v4
with:
- java-version: 17
+ java-version: 21
distribution: 'temurin'
server-id: jfrog-central
server-username: INTERNAL_USERNAME
@@ -46,7 +46,7 @@ jobs:
POWERAUTH_SERVICE_SECURITY_CLIENTSECRET: ${{ secrets.POWERAUTH_SERVICE_SECURITY_CLIENTSECRET }}
POWERAUTH_TEST_INCLUDECUSTOMTESTS: ${{ inputs.includeCustomTests == '' || inputs.includeCustomTests }} # default includeCustomTests=true even for 'schedule' event
- name: Publish Test Report
- uses: mikepenz/action-junit-report@v3
+ uses: mikepenz/action-junit-report@v4
if: always()
with:
detailed_summary: true
diff --git a/.github/workflows/maven-test-compile.yml b/.github/workflows/maven-test-compile.yml
index ceeaeb0a..313c7283 100644
--- a/.github/workflows/maven-test-compile.yml
+++ b/.github/workflows/maven-test-compile.yml
@@ -18,11 +18,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Set up JDK ${{ inputs.java_version }}
- uses: actions/setup-java@v3
+ uses: actions/setup-java@v4
with:
- java-version: '17'
+ java-version: '21'
distribution: 'temurin'
server-id: jfrog-central
server-username: INTERNAL_USERNAME
diff --git a/.run/PowerauthFido2TestApplication.run.xml b/.run/PowerauthFido2TestApplication.run.xml
new file mode 100644
index 00000000..3bd0c80f
--- /dev/null
+++ b/.run/PowerauthFido2TestApplication.run.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs-private/Developer-How-To-Start.md b/docs-private/Developer-How-To-Start.md
index 5c5376d2..6a476e01 100644
--- a/docs-private/Developer-How-To-Start.md
+++ b/docs-private/Developer-How-To-Start.md
@@ -18,3 +18,12 @@ Others (like URL, username, password) depend on your environment.
```shell
liquibase --changelog-file=./docs/db/changelog/changesets/powerauth-test-server/db.changelog-module.xml --url=jdbc:postgresql://localhost:5432/powerauth --username=powerauth status
```
+
+## PowerAuth FIDO2 Tests
+
+### Standalone Run
+
+- Enable maven profile `standalone`
+- Use IntelliJ Idea run configuration at `../.run/PowerAuthFido2TestApplication.run.xml`
+- Open [http://localhost:8083/powerauth-fido2-test/actuator/health](http://localhost:8083/powerauth-fido2-test/actuator/health) and you should get `{"status":"UP"}`
+
diff --git a/lombok.config b/lombok.config
new file mode 100644
index 00000000..1bb49ca0
--- /dev/null
+++ b/lombok.config
@@ -0,0 +1 @@
+lombok.log.fieldName=logger
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 7fbb8242..eeaa197f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -8,13 +8,13 @@
org.springframework.bootspring-boot-starter-parent
- 3.1.6
+ 3.2.4com.wultrapowerauth-backend-tests-parent
- 1.6.0
+ 1.7.0pomParent pom for backend tests
@@ -45,22 +45,25 @@
- 1.6.0
- 1.6.0
- 1.6.0
- 1.6.0
- 1.6.0
- 1.8.0
+ 1.7.0
+ 1.7.0
+ 1.7.0
+ 1.7.0
+ 1.7.0
+ 1.7.0
+ 1.9.01.77
- 2.3.0
+ 2.5.07.4
-
- 1.4.14
+ 0.23.0.RELEASE
+
+ truepowerauth-backend-tests
+ powerauth-fido2-testspowerauth-load-testspowerauth-test-serverpowerauth-webflow-tests
@@ -183,6 +186,18 @@
true
+
+
+ jfrog-central
+ Wultra Artifactory-releases
+ https://wultra.jfrog.io/artifactory/internal-maven-repository
+
+
+ jfrog-central
+ Wultra Artifactory-snapshots
+ https://wultra.jfrog.io/artifactory/internal-maven-repository
+
+ jfrog-central
@@ -218,9 +233,6 @@
!useInternalRepo
-
- true
- ossrh-snapshots
diff --git a/powerauth-backend-tests/README.md b/powerauth-backend-tests/README.md
index b6101ad7..0ec4490a 100644
--- a/powerauth-backend-tests/README.md
+++ b/powerauth-backend-tests/README.md
@@ -60,7 +60,6 @@ File `powerauth-java.server.xml`:
-
```
@@ -71,7 +70,6 @@ File `enrollment-server.xml`:
-
diff --git a/powerauth-backend-tests/pom.xml b/powerauth-backend-tests/pom.xml
index 94ef6826..cd78b524 100644
--- a/powerauth-backend-tests/pom.xml
+++ b/powerauth-backend-tests/pom.xml
@@ -8,7 +8,7 @@
com.wultrapowerauth-backend-tests-parent
- 1.6.0
+ 1.7.0com.wultra
diff --git a/powerauth-backend-tests/src/test/java/com/wultra/security/powerauth/test/shared/PowerAuthApiShared.java b/powerauth-backend-tests/src/test/java/com/wultra/security/powerauth/test/shared/PowerAuthApiShared.java
index 50006570..4d5d5b1c 100644
--- a/powerauth-backend-tests/src/test/java/com/wultra/security/powerauth/test/shared/PowerAuthApiShared.java
+++ b/powerauth-backend-tests/src/test/java/com/wultra/security/powerauth/test/shared/PowerAuthApiShared.java
@@ -19,11 +19,10 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import com.wultra.security.powerauth.client.PowerAuthClient;
-import com.wultra.security.powerauth.client.model.entity.*;
-import com.wultra.security.powerauth.client.model.enumeration.*;
+import com.wultra.security.powerauth.client.model.entity.SignatureAuditItem;
+import com.wultra.security.powerauth.client.model.enumeration.ActivationStatus;
+import com.wultra.security.powerauth.client.model.enumeration.SignatureType;
import com.wultra.security.powerauth.client.model.error.PowerAuthClientException;
-import com.wultra.security.powerauth.client.model.request.GetActivationListForUserRequest;
-import com.wultra.security.powerauth.client.model.request.GetEciesDecryptorRequest;
import com.wultra.security.powerauth.client.model.response.*;
import com.wultra.security.powerauth.configuration.PowerAuthTestConfiguration;
import io.getlime.security.powerauth.crypto.client.activation.PowerAuthClientActivation;
@@ -34,15 +33,12 @@
import io.getlime.security.powerauth.crypto.lib.config.SignatureConfiguration;
import io.getlime.security.powerauth.crypto.lib.encryptor.ClientEncryptor;
import io.getlime.security.powerauth.crypto.lib.encryptor.EncryptorFactory;
-import io.getlime.security.powerauth.crypto.lib.encryptor.ServerEncryptor;
-import io.getlime.security.powerauth.crypto.lib.encryptor.ecies.EciesEnvelopeKey;
import io.getlime.security.powerauth.crypto.lib.encryptor.exception.EncryptorException;
import io.getlime.security.powerauth.crypto.lib.encryptor.model.EncryptedRequest;
import io.getlime.security.powerauth.crypto.lib.encryptor.model.EncryptedResponse;
import io.getlime.security.powerauth.crypto.lib.encryptor.model.EncryptorId;
import io.getlime.security.powerauth.crypto.lib.encryptor.model.EncryptorParameters;
import io.getlime.security.powerauth.crypto.lib.encryptor.model.v3.ClientEncryptorSecrets;
-import io.getlime.security.powerauth.crypto.lib.encryptor.model.v3.ServerEncryptorSecrets;
import io.getlime.security.powerauth.crypto.lib.enums.PowerAuthSignatureTypes;
import io.getlime.security.powerauth.crypto.lib.generator.KeyGenerator;
import io.getlime.security.powerauth.crypto.lib.model.exception.CryptoProviderException;
@@ -74,8 +70,10 @@
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
-import java.time.Duration;
-import java.util.*;
+import java.util.Base64;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
@@ -99,190 +97,6 @@ public class PowerAuthApiShared {
private static final int TIME_SYNCHRONIZATION_WINDOW_SECONDS = 60;
- public static void systemStatusTest(PowerAuthClient powerAuthClient) throws PowerAuthClientException {
- final GetSystemStatusResponse response = powerAuthClient.getSystemStatus();
- assertEquals("OK", response.getStatus());
- }
-
- public static void errorListTest(PowerAuthClient powerAuthClient) throws PowerAuthClientException {
- final GetErrorCodeListResponse response = powerAuthClient.getErrorList(Locale.ENGLISH.getLanguage());
- assertTrue(response.getErrors().size() > 32);
- }
-
- public static void initActivationTest(PowerAuthClient powerAuthClient, PowerAuthTestConfiguration config, String version) throws PowerAuthClientException {
- final InitActivationResponse response = powerAuthClient.initActivation(config.getUser(version), config.getApplicationId());
- assertNotNull(response.getActivationId());
- assertNotNull(response.getActivationCode());
- assertNotNull(response.getActivationSignature());
- assertEquals(config.getUser(version), response.getUserId());
- assertEquals(config.getApplicationId(), response.getApplicationId());
- final GetActivationStatusResponse statusResponse = powerAuthClient.getActivationStatus(response.getActivationId());
- assertEquals(ActivationStatus.CREATED, statusResponse.getActivationStatus());
- }
-
- public static void prepareActivationTest(PowerAuthClient powerAuthClient, PowerAuthTestConfiguration config, String version) throws CryptoProviderException, EncryptorException, IOException, PowerAuthClientException {
- String activationName = "test_prepare";
- InitActivationResponse response = powerAuthClient.initActivation(config.getUser(version), config.getApplicationId());
- String activationId = response.getActivationId();
- String activationCode = response.getActivationCode();
- KeyPair deviceKeyPair = CLIENT_ACTIVATION.generateDeviceKeyPair();
- byte[] devicePublicKeyBytes = KEY_CONVERTOR.convertPublicKeyToBytes(deviceKeyPair.getPublic());
- String devicePublicKeyBase64 = Base64.getEncoder().encodeToString(devicePublicKeyBytes);
- ActivationLayer2Request requestL2 = new ActivationLayer2Request();
- requestL2.setActivationName(activationName);
- requestL2.setDevicePublicKey(devicePublicKeyBase64);
- ClientEncryptor clientEncryptorL2 = ENCRYPTOR_FACTORY.getClientEncryptor(
- EncryptorId.ACTIVATION_LAYER_2,
- new EncryptorParameters(version, config.getApplicationKey(), null),
- new ClientEncryptorSecrets(config.getMasterPublicKey(), config.getApplicationSecret())
- );
- ByteArrayOutputStream baosL2 = new ByteArrayOutputStream();
- OBJECT_MAPPER.writeValue(baosL2, requestL2);
- EncryptedRequest encryptedRequestL2 = clientEncryptorL2.encryptRequest(baosL2.toByteArray());
- PrepareActivationResponse prepareResponse = powerAuthClient.prepareActivation(activationCode, config.getApplicationKey(), true, encryptedRequestL2.getEphemeralPublicKey(), encryptedRequestL2.getEncryptedData(), encryptedRequestL2.getMac(), encryptedRequestL2.getNonce(), version, encryptedRequestL2.getTimestamp());
- assertEquals(ActivationStatus.PENDING_COMMIT, prepareResponse.getActivationStatus());
- CommitActivationResponse commitResponse = powerAuthClient.commitActivation(activationId, config.getUser(version));
- assertTrue(commitResponse.isActivated());
- }
-
- public static void createActivationTest(PowerAuthClient powerAuthClient, PowerAuthTestConfiguration config, String version) throws CryptoProviderException, EncryptorException, IOException, PowerAuthClientException {
- String activationName = "test_create";
- KeyPair deviceKeyPair = CLIENT_ACTIVATION.generateDeviceKeyPair();
- byte[] devicePublicKeyBytes = KEY_CONVERTOR.convertPublicKeyToBytes(deviceKeyPair.getPublic());
- String devicePublicKeyBase64 = Base64.getEncoder().encodeToString(devicePublicKeyBytes);
- ActivationLayer2Request requestL2 = new ActivationLayer2Request();
- requestL2.setActivationName(activationName);
- requestL2.setDevicePublicKey(devicePublicKeyBase64);
- ClientEncryptor clientEncryptorL2 = ENCRYPTOR_FACTORY.getClientEncryptor(
- EncryptorId.ACTIVATION_LAYER_2,
- new EncryptorParameters(version, config.getApplicationKey(), null),
- new ClientEncryptorSecrets(config.getMasterPublicKey(), config.getApplicationSecret())
- );
- ByteArrayOutputStream baosL2 = new ByteArrayOutputStream();
- OBJECT_MAPPER.writeValue(baosL2, requestL2);
- EncryptedRequest encryptedRequestL2 = clientEncryptorL2.encryptRequest(baosL2.toByteArray());
- CreateActivationResponse createResponse = powerAuthClient.createActivation(config.getUser(version), null,
- null, config.getApplicationKey(), encryptedRequestL2.getEphemeralPublicKey(), encryptedRequestL2.getEncryptedData(), encryptedRequestL2.getMac(), encryptedRequestL2.getNonce(), version, encryptedRequestL2.getTimestamp());
- String activationId = createResponse.getActivationId();
- assertNotNull(activationId);
- GetActivationStatusResponse statusResponse = powerAuthClient.getActivationStatus(activationId);
- assertEquals(ActivationStatus.PENDING_COMMIT, statusResponse.getActivationStatus());
- CommitActivationResponse commitResponse = powerAuthClient.commitActivation(activationId, config.getUser(version));
- assertTrue(commitResponse.isActivated());
- }
-
- public static void updateActivationOtpAndCommitTest(PowerAuthClient powerAuthClient, PowerAuthTestConfiguration config, String version) throws CryptoProviderException, EncryptorException, IOException, PowerAuthClientException {
- String activationName = "test_update_otp";
- InitActivationResponse response = powerAuthClient.initActivation(config.getUser(version), config.getApplicationId(), ActivationOtpValidation.NONE, null);
- String activationId = response.getActivationId();
- String activationCode = response.getActivationCode();
- KeyPair deviceKeyPair = CLIENT_ACTIVATION.generateDeviceKeyPair();
- byte[] devicePublicKeyBytes = KEY_CONVERTOR.convertPublicKeyToBytes(deviceKeyPair.getPublic());
- String devicePublicKeyBase64 = Base64.getEncoder().encodeToString(devicePublicKeyBytes);
- ActivationLayer2Request requestL2 = new ActivationLayer2Request();
- requestL2.setActivationName(activationName);
- requestL2.setDevicePublicKey(devicePublicKeyBase64);
- ClientEncryptor clientEncryptorL2 = ENCRYPTOR_FACTORY.getClientEncryptor(
- EncryptorId.ACTIVATION_LAYER_2,
- new EncryptorParameters(version, config.getApplicationKey(), null),
- new ClientEncryptorSecrets(config.getMasterPublicKey(), config.getApplicationSecret())
- );
- ByteArrayOutputStream baosL2 = new ByteArrayOutputStream();
- OBJECT_MAPPER.writeValue(baosL2, requestL2);
- EncryptedRequest encryptedRequestL2 = clientEncryptorL2.encryptRequest(baosL2.toByteArray());
- PrepareActivationResponse prepareResponse = powerAuthClient.prepareActivation(activationCode, config.getApplicationKey(), true, encryptedRequestL2.getEphemeralPublicKey(), encryptedRequestL2.getEncryptedData(), encryptedRequestL2.getMac(), encryptedRequestL2.getNonce(), version, encryptedRequestL2.getTimestamp());
- assertEquals(ActivationStatus.PENDING_COMMIT, prepareResponse.getActivationStatus());
- UpdateActivationOtpResponse otpResponse = powerAuthClient.updateActivationOtp(activationId, config.getUser(version), "12345678");
- assertTrue(otpResponse.isUpdated());
- CommitActivationResponse commitResponse = powerAuthClient.commitActivation(activationId, config.getUser(version), "12345678");
- assertTrue(commitResponse.isActivated());
- }
-
- public static void removeActivationTest(PowerAuthClient powerAuthClient, PowerAuthTestConfiguration config, String version) throws PowerAuthClientException {
- InitActivationResponse response = powerAuthClient.initActivation(config.getUser(version), config.getApplicationId());
- GetActivationStatusResponse statusResponse = powerAuthClient.getActivationStatus(response.getActivationId());
- assertEquals(ActivationStatus.CREATED, statusResponse.getActivationStatus());
- RemoveActivationResponse removeResponse = powerAuthClient.removeActivation(response.getActivationId(), null);
- assertTrue(removeResponse.isRemoved());
- GetActivationStatusResponse statusResponse2 = powerAuthClient.getActivationStatus(response.getActivationId());
- assertEquals(ActivationStatus.REMOVED, statusResponse2.getActivationStatus());
- }
-
- public static void activationListForUserTest(PowerAuthClient powerAuthClient, PowerAuthTestConfiguration config, String version) throws PowerAuthClientException {
- InitActivationResponse response = powerAuthClient.initActivation(config.getUser(version), config.getApplicationId());
- GetActivationStatusResponse statusResponse = powerAuthClient.getActivationStatus(response.getActivationId());
- assertEquals(ActivationStatus.CREATED, statusResponse.getActivationStatus());
- final List listResponse = powerAuthClient.getActivationListForUser(config.getUser(version));
- assertNotEquals(0, listResponse.size());
- }
-
- public static void testGetActivationListForUserPagination(PowerAuthClient powerAuthClient, PowerAuthTestConfiguration config, String version) throws PowerAuthClientException {
- // Prepare the base GetActivationListForUserRequest
- final GetActivationListForUserRequest baseRequest = new GetActivationListForUserRequest();
- baseRequest.setUserId(config.getUser(version));
- baseRequest.setApplicationId(config.getApplicationId());
-
- // Create a list to store the activation IDs
- final List activationIds = new ArrayList<>();
-
- // Create multiple activations for the test user
- for (int i = 0; i < 10; i++) {
- InitActivationResponse initResponse = powerAuthClient.initActivation(baseRequest.getUserId(), baseRequest.getApplicationId());
- activationIds.add(initResponse.getActivationId());
- }
-
- // Prepare the request for the first page of activations
- final GetActivationListForUserRequest requestPage1 = new GetActivationListForUserRequest();
- requestPage1.setUserId(baseRequest.getUserId());
- requestPage1.setApplicationId(baseRequest.getApplicationId());
- requestPage1.setPageNumber(0);
- requestPage1.setPageSize(5);
-
- // Fetch the first page of activations
- final GetActivationListForUserResponse responsePage1 = powerAuthClient.getActivationListForUser(requestPage1);
- assertEquals(5, responsePage1.getActivations().size());
-
- // Prepare the request for the second page of activations
- final GetActivationListForUserRequest requestPage2 = new GetActivationListForUserRequest();
- requestPage2.setUserId(baseRequest.getUserId());
- requestPage2.setApplicationId(baseRequest.getApplicationId());
- requestPage2.setPageNumber(1);
- requestPage2.setPageSize(5);
-
- // Fetch the second page of activations
- final GetActivationListForUserResponse responsePage2 = powerAuthClient.getActivationListForUser(requestPage2);
- assertEquals(5, responsePage2.getActivations().size());
-
- // Check that the activations on the different pages are not the same
- assertNotEquals(responsePage1.getActivations(), responsePage2.getActivations());
-
- // Clean up the created activations at the end
- for (String id : activationIds) {
- RemoveActivationResponse removeActivationResponse = powerAuthClient.removeActivation(id, config.getUser(version));
- assertTrue(removeActivationResponse.isRemoved());
- }
- }
-
- public static void lookupActivationsTest(PowerAuthClient powerAuthClient, PowerAuthTestConfiguration config, String version) throws PowerAuthClientException {
- InitActivationResponse response = powerAuthClient.initActivation(config.getUser(version), config.getApplicationId());
- GetActivationStatusResponse statusResponse = powerAuthClient.getActivationStatus(response.getActivationId());
- final Date timestampCreated = statusResponse.getTimestampCreated();
- assertEquals(ActivationStatus.CREATED, statusResponse.getActivationStatus());
- List activations = powerAuthClient.lookupActivations(Collections.singletonList(config.getUser(version)), Collections.singletonList(config.getApplicationId()),
- null, timestampCreated, ActivationStatus.CREATED, null);
- assertTrue(activations.size() >= 1);
- }
-
- public static void activationStatusUpdateTest(PowerAuthClient powerAuthClient, PowerAuthTestConfiguration config, String version) throws PowerAuthClientException {
- InitActivationResponse response = powerAuthClient.initActivation(config.getUser(version), config.getApplicationId());
- GetActivationStatusResponse statusResponse = powerAuthClient.getActivationStatus(response.getActivationId());
- assertEquals(ActivationStatus.CREATED, statusResponse.getActivationStatus());
- UpdateStatusForActivationsResponse updateResponse = powerAuthClient.updateStatusForActivations(Collections.singletonList(response.getActivationId()), ActivationStatus.REMOVED);
- assertTrue(updateResponse.isUpdated());
- GetActivationStatusResponse statusResponse2 = powerAuthClient.getActivationStatus(response.getActivationId());
- assertEquals(ActivationStatus.REMOVED, statusResponse2.getActivationStatus());
- }
-
public static void verifySignatureTest(PowerAuthClient powerAuthClient, PowerAuthTestConfiguration config, String version) throws GenericCryptoException, CryptoProviderException, InvalidKeyException, PowerAuthClientException {
Calendar before = new GregorianCalendar();
before.add(Calendar.SECOND, -TIME_SYNCHRONIZATION_WINDOW_SECONDS);
@@ -307,7 +121,7 @@ public static void verifySignatureTest(PowerAuthClient powerAuthClient, PowerAut
after.add(Calendar.SECOND, TIME_SYNCHRONIZATION_WINDOW_SECONDS);
List auditItems = powerAuthClient.getSignatureAuditLog(config.getUser(version), config.getApplicationId(), before.getTime(), after.getTime());
boolean signatureFound = false;
- for (SignatureAuditItem item: auditItems) {
+ for (SignatureAuditItem item : auditItems) {
if (signatureValue.equals(item.getSignature())) {
assertEquals(config.getActivationId(version), item.getActivationId());
assertEquals(normalizedDataWithSecret, new String(Base64.getDecoder().decode(item.getDataBase64())));
@@ -323,26 +137,6 @@ public static void verifySignatureTest(PowerAuthClient powerAuthClient, PowerAut
assertTrue(signatureFound);
}
- public static void nonPersonalizedOfflineSignaturePayloadTest(PowerAuthClient powerAuthClient, PowerAuthTestConfiguration config) throws PowerAuthClientException {
- // For more complete tests for createNonPersonalizedOfflineSignaturePayload see PowerAuthSignatureTest
- CreateNonPersonalizedOfflineSignaturePayloadResponse response = powerAuthClient.createNonPersonalizedOfflineSignaturePayload(config.getApplicationId(), "test_data");
- assertNotNull(response.getOfflineData());
- assertNotNull(response.getNonce());
- }
-
- public static void personalizedOfflineSignaturePayloadTest(PowerAuthClient powerAuthClient, PowerAuthTestConfiguration config, String version) throws PowerAuthClientException {
- // For more complete tests for createPersonalizedOfflineSignaturePayload see PowerAuthSignatureTest
- CreatePersonalizedOfflineSignaturePayloadResponse response = powerAuthClient.createPersonalizedOfflineSignaturePayload(config.getActivationId(version), "test_data");
- assertNotNull(response.getOfflineData());
- assertNotNull(response.getNonce());
- }
-
- public static void verifyOfflineSignatureTest(PowerAuthClient powerAuthClient, PowerAuthTestConfiguration config, String version) throws PowerAuthClientException {
- // For more complete tests for verifyOfflineSignature see PowerAuthSignatureTest
- VerifyOfflineSignatureResponse response = powerAuthClient.verifyOfflineSignature(config.getActivationId(version), "test_data", "12345678", false);
- assertFalse(response.isSignatureValid());
- }
-
public static void unlockVaultAndECDSASignatureTest(PowerAuthClient powerAuthClient, PowerAuthTestConfiguration config, String version) throws GenericCryptoException, CryptoProviderException, InvalidKeySpecException, EncryptorException, IOException, InvalidKeyException, PowerAuthClientException {
byte[] transportMasterKeyBytes = Base64.getDecoder().decode(JsonUtil.stringValue(config.getResultStatusObject(version), "transportMasterKey"));
byte[] serverPublicKeyBytes = Base64.getDecoder().decode(JsonUtil.stringValue(config.getResultStatusObject(version), "serverPublicKey"));
@@ -401,106 +195,8 @@ public static void unlockVaultAndECDSASignatureTest(PowerAuthClient powerAuthCli
assertTrue(ecdsaResponse.isSignatureValid());
}
- public static void activationHistoryTest(PowerAuthClient powerAuthClient, PowerAuthTestConfiguration config, String version) throws PowerAuthClientException {
- InitActivationResponse response = powerAuthClient.initActivation(config.getUser(version) + "_history_test", config.getApplicationId());
- GetActivationStatusResponse statusResponse = powerAuthClient.getActivationStatus(response.getActivationId());
- assertEquals(ActivationStatus.CREATED, statusResponse.getActivationStatus());
- final Date before = statusResponse.getTimestampCreated();
- final Date after = Date.from(before.toInstant().plus(Duration.ofSeconds(1)));
- final List activationHistory = powerAuthClient.getActivationHistory(response.getActivationId(), before, after);
- final ActivationHistoryItem item = activationHistory.get(0);
- assertEquals(response.getActivationId(), item.getActivationId());
- assertEquals(ActivationStatus.CREATED, item.getActivationStatus());
- }
-
- public static void blockAndUnblockActivationTest(PowerAuthClient powerAuthClient, PowerAuthTestConfiguration config, String version) throws PowerAuthClientException {
- InitActivationResponse response = powerAuthClient.initActivation(config.getUser(version), config.getApplicationId());
- GetActivationStatusResponse statusResponse = powerAuthClient.getActivationStatus(response.getActivationId());
- assertEquals(ActivationStatus.CREATED, statusResponse.getActivationStatus());
- // Fake status change to ACTIVE for block and unblock test
- UpdateStatusForActivationsResponse updateResponse = powerAuthClient.updateStatusForActivations(Collections.singletonList(response.getActivationId()), ActivationStatus.ACTIVE);
- assertTrue(updateResponse.isUpdated());
- BlockActivationResponse blockResponse = powerAuthClient.blockActivation(response.getActivationId(), "TEST", null);
- assertEquals(ActivationStatus.BLOCKED, blockResponse.getActivationStatus());
- GetActivationStatusResponse statusResponse2 = powerAuthClient.getActivationStatus(response.getActivationId());
- assertEquals(ActivationStatus.BLOCKED, statusResponse2.getActivationStatus());
- UnblockActivationResponse unblockResponse = powerAuthClient.unblockActivation(response.getActivationId(), null);
- assertEquals(ActivationStatus.ACTIVE, unblockResponse.getActivationStatus());
- GetActivationStatusResponse statusResponse3 = powerAuthClient.getActivationStatus(response.getActivationId());
- assertEquals(ActivationStatus.ACTIVE, statusResponse3.getActivationStatus());
- }
-
- public static void applicationListTest(PowerAuthClient powerAuthClient, PowerAuthTestConfiguration config) throws PowerAuthClientException {
- final GetApplicationListResponse applications = powerAuthClient.getApplicationList();
- assertNotEquals(0, applications.getApplications().size());
- boolean testApplicationFound = false;
- for (Application app: applications.getApplications()) {
- if (app.getApplicationId().equals(config.getApplicationId())) {
- testApplicationFound = true;
- }
- }
- assertTrue(testApplicationFound);
- }
-
- public static void applicationDetailTest(PowerAuthClient powerAuthClient, PowerAuthTestConfiguration config) throws PowerAuthClientException {
- GetApplicationDetailResponse response = powerAuthClient.getApplicationDetail(config.getApplicationId());
- assertEquals(config.getApplicationName(), response.getApplicationId());
- boolean testAppVersionFound = false;
- for (ApplicationVersion version: response.getVersions()) {
- if (version.getApplicationVersionId().equals(config.getApplicationVersionId())) {
- testAppVersionFound = true;
- }
- }
- assertTrue(testAppVersionFound);
- }
-
- public static void applicationVersionLookupTest(PowerAuthClient powerAuthClient, PowerAuthTestConfiguration config) throws PowerAuthClientException {
- LookupApplicationByAppKeyResponse response = powerAuthClient.lookupApplicationByAppKey(config.getApplicationKey());
- assertEquals(config.getApplicationId(), response.getApplicationId());
- }
-
// createApplication and createApplication version tests are skipped to avoid creating too many applications
- public static void applicationSupportTest(PowerAuthClient powerAuthClient, PowerAuthTestConfiguration config) throws PowerAuthClientException {
- UnsupportApplicationVersionResponse response = powerAuthClient.unsupportApplicationVersion(config.getApplicationId(), config.getApplicationVersionId());
- assertFalse(response.isSupported());
- SupportApplicationVersionResponse response2 = powerAuthClient.supportApplicationVersion(config.getApplicationId(), config.getApplicationVersionId());
- assertTrue(response2.isSupported());
- }
-
- public static void applicationIntegrationTest(PowerAuthClient powerAuthClient, PowerAuthTestConfiguration config) throws PowerAuthClientException {
- String integrationName = UUID.randomUUID().toString();
- CreateIntegrationResponse response = powerAuthClient.createIntegration(integrationName);
- assertEquals(integrationName, response.getName());
- final GetIntegrationListResponse items = powerAuthClient.getIntegrationList();
- boolean integrationFound = false;
- for (Integration integration: items.getItems()) {
- if (integration.getName().equals(integrationName)) {
- integrationFound = true;
- }
- }
- assertTrue(integrationFound);
- RemoveIntegrationResponse removeResponse = powerAuthClient.removeIntegration(response.getId());
- assertTrue(removeResponse.isRemoved());
- }
-
- public static void callbackTest(PowerAuthClient powerAuthClient, PowerAuthTestConfiguration config) throws PowerAuthClientException {
- String callbackName = UUID.randomUUID().toString();
- String url = "http://test.wultra.com/";
- CreateCallbackUrlResponse response = powerAuthClient.createCallbackUrl(config.getApplicationId(), callbackName, CallbackUrlType.ACTIVATION_STATUS_CHANGE, url, Collections.emptyList(), null);
- assertEquals(callbackName, response.getName());
- final GetCallbackUrlListResponse items = powerAuthClient.getCallbackUrlList(config.getApplicationId());
- boolean callbackFound = false;
- for (CallbackUrl callback: items.getCallbackUrlList()) {
- if (callback.getName().equals(callbackName)) {
- callbackFound = true;
- }
- }
- assertTrue(callbackFound);
- RemoveCallbackUrlResponse removeResponse = powerAuthClient.removeCallbackUrl(response.getId());
- assertTrue(removeResponse.isRemoved());
- }
-
public static void createValidateAndRemoveTokenTestActiveActivation(PowerAuthClient powerAuthClient, PowerAuthTestConfiguration config, String version) throws InvalidKeySpecException, CryptoProviderException, GenericCryptoException, IOException, EncryptorException, PowerAuthClientException {
final TokenInfo tokenInfo = createToken(powerAuthClient, config, version);
@@ -518,72 +214,6 @@ public static void createValidateAndRemoveTokenTestActiveActivation(PowerAuthCli
assertTrue(removeResponse.isRemoved());
}
- public static void createValidateAndRemoveTokenTestBlockedActivation(PowerAuthClient powerAuthClient, PowerAuthTestConfiguration config, String version) throws InvalidKeySpecException, CryptoProviderException, GenericCryptoException, IOException, EncryptorException, PowerAuthClientException {
- final TokenInfo tokenInfo = createToken(powerAuthClient, config, version);
-
- // Block activation
- final BlockActivationResponse blockResponse = powerAuthClient.blockActivation(config.getActivationId(version), "TEST", null);
- assertEquals(ActivationStatus.BLOCKED, blockResponse.getActivationStatus());
-
- // Check that token validation failed and activation status and blocked reason is available
- final ValidateTokenResponse validateResponse = powerAuthClient.validateToken(tokenInfo.getTokenId(),
- Base64.getEncoder().encodeToString(tokenInfo.getTokenNonce()),
- version,
- Long.parseLong(new String(tokenInfo.getTokenTimestamp())),
- Base64.getEncoder().encodeToString(tokenInfo.getTokenDigest()));
- assertFalse(validateResponse.isTokenValid());
- assertEquals(ActivationStatus.BLOCKED, validateResponse.getActivationStatus());
- assertEquals("TEST", validateResponse.getBlockedReason());
-
- // Unblock activation
- final UnblockActivationResponse unblockResponse = powerAuthClient.unblockActivation(config.getActivationId(version), "TEST");
- assertEquals(ActivationStatus.ACTIVE, unblockResponse.getActivationStatus());
-
- final RemoveTokenResponse removeResponse = powerAuthClient.removeToken(tokenInfo.getTokenId(), config.getActivationId(version));
- assertTrue(removeResponse.isRemoved());
- }
-
- public static void getEciesDecryptorTest(PowerAuthClient powerAuthClient, PowerAuthTestConfiguration config, String version) throws EncryptorException, PowerAuthClientException {
- String requestData = "test_data";
- ClientEncryptor clientEncryptor = ENCRYPTOR_FACTORY.getClientEncryptor(
- EncryptorId.APPLICATION_SCOPE_GENERIC,
- new EncryptorParameters(version, config.getApplicationKey(), null),
- new ClientEncryptorSecrets(config.getMasterPublicKey(), config.getApplicationSecret())
- );
- EncryptedRequest encryptedRequest = clientEncryptor.encryptRequest(requestData.getBytes(StandardCharsets.UTF_8));
- final GetEciesDecryptorRequest eciesDecryptorRequest = new GetEciesDecryptorRequest();
- eciesDecryptorRequest.setProtocolVersion(version);
- eciesDecryptorRequest.setActivationId(null);
- eciesDecryptorRequest.setApplicationKey(config.getApplicationKey());
- eciesDecryptorRequest.setEphemeralPublicKey(encryptedRequest.getEphemeralPublicKey());
- eciesDecryptorRequest.setNonce(encryptedRequest.getNonce());
- eciesDecryptorRequest.setTimestamp(encryptedRequest.getTimestamp());
- GetEciesDecryptorResponse decryptorResponse = powerAuthClient.getEciesDecryptor(eciesDecryptorRequest);
-
- final byte[] secretKey = Base64.getDecoder().decode(decryptorResponse.getSecretKey());
- final byte[] sharedInfo2Base = Base64.getDecoder().decode(decryptorResponse.getSharedInfo2());
- final byte[] ephemeralPublicKeyBytes = Base64.getDecoder().decode(encryptedRequest.getEphemeralPublicKey());
- final EciesEnvelopeKey envelopeKey = new EciesEnvelopeKey(secretKey, ephemeralPublicKeyBytes);
- final ServerEncryptor serverEncryptor = ENCRYPTOR_FACTORY.getServerEncryptor(
- EncryptorId.APPLICATION_SCOPE_GENERIC,
- new EncryptorParameters(version, config.getApplicationKey(), null),
- new ServerEncryptorSecrets(secretKey, sharedInfo2Base)
- );
- byte[] decryptedData = serverEncryptor.decryptRequest(encryptedRequest);
- assertArrayEquals(requestData.getBytes(StandardCharsets.UTF_8), decryptedData);
- }
-
- public static void recoveryCodeCreateLookupRevokeTest(PowerAuthClient powerAuthClient, PowerAuthTestConfiguration config, String version) throws PowerAuthClientException {
- CreateRecoveryCodeResponse createResponse = powerAuthClient.createRecoveryCode(config.getApplicationId(), config.getUser(version), 2L);
- assertEquals(config.getUser(version), createResponse.getUserId());
- assertEquals(RecoveryCodeStatus.CREATED, createResponse.getStatus());
- assertEquals(2, createResponse.getPuks().size());
- LookupRecoveryCodesResponse lookupResponse = powerAuthClient.lookupRecoveryCodes(config.getUser(version), null, config.getApplicationId(), RecoveryCodeStatus.CREATED, RecoveryPukStatus.VALID);
- assertNotEquals(0, lookupResponse.getRecoveryCodes().size());
- RevokeRecoveryCodesResponse revokeResponse = powerAuthClient.revokeRecoveryCodes(Collections.singletonList(createResponse.getRecoveryCodeId()));
- assertTrue(revokeResponse.isRevoked());
- }
-
public static void recoveryCodeConfirmAndActivationTest(PowerAuthClient powerAuthClient, PowerAuthTestConfiguration config, String version) throws CryptoProviderException, GenericCryptoException, IOException, EncryptorException, InvalidKeyException, InvalidKeySpecException, PowerAuthClientException {
String activationName = "test_create_recovery";
KeyPair deviceKeyPair = CLIENT_ACTIVATION.generateDeviceKeyPair();
@@ -640,8 +270,8 @@ public static void recoveryCodeConfirmAndActivationTest(PowerAuthClient powerAut
confirmResponse.getNonce(),
confirmResponse.getTimestamp()
));
- ConfirmRecoveryResponsePayload confirmResponsePayload = RestClientConfiguration.defaultMapper().readValue(confirmResponseRaw, ConfirmRecoveryResponsePayload.class);
- assertTrue(confirmResponsePayload.getAlreadyConfirmed());
+ final ConfirmRecoveryResponsePayload confirmResponsePayload = RestClientConfiguration.defaultMapper().readValue(confirmResponseRaw, ConfirmRecoveryResponsePayload.class);
+ assertTrue(confirmResponsePayload.isAlreadyConfirmed());
// Create recovery activation
KeyPair deviceKeyPairR = CLIENT_ACTIVATION.generateDeviceKeyPair();
byte[] devicePublicKeyBytesR = KEY_CONVERTOR.convertPublicKeyToBytes(deviceKeyPairR.getPublic());
@@ -668,23 +298,6 @@ public static void recoveryCodeConfirmAndActivationTest(PowerAuthClient powerAut
assertEquals(ActivationStatus.REMOVED, statusResponseR3.getActivationStatus());
}
- public static void recoveryConfigTest(PowerAuthClient powerAuthClient, PowerAuthTestConfiguration config) throws PowerAuthClientException {
- GetRecoveryConfigResponse response = powerAuthClient.getRecoveryConfig(config.getApplicationId());
- String remotePostcardPublicKey = response.getRemotePostcardPublicKey();
- assertNotNull(response.getPostcardPublicKey());
- assertNotNull(remotePostcardPublicKey);
- UpdateRecoveryConfigResponse configResponse = powerAuthClient.updateRecoveryConfig(config.getApplicationId(), false, false, false, "test_key");
- assertTrue(configResponse.isUpdated());
- GetRecoveryConfigResponse response2 = powerAuthClient.getRecoveryConfig(config.getApplicationId());
- assertNotNull(response2.getPostcardPublicKey());
- assertFalse(response2.isActivationRecoveryEnabled());
- assertFalse(response2.isRecoveryPostcardEnabled());
- assertFalse(response2.isAllowMultipleRecoveryCodes());
- assertEquals("test_key", response2.getRemotePostcardPublicKey());
- UpdateRecoveryConfigResponse configResponse2 = powerAuthClient.updateRecoveryConfig(config.getApplicationId(), true, true, false, remotePostcardPublicKey);
- assertTrue(configResponse2.isUpdated());
- }
-
// Activation flags are tested using PowerAuthActivationFlagsTest
// Application roles are tested using PowerAuthApplicationRolesTest
diff --git a/powerauth-backend-tests/src/test/java/com/wultra/security/powerauth/test/shared/PowerAuthApplicationRolesShared.java b/powerauth-backend-tests/src/test/java/com/wultra/security/powerauth/test/shared/PowerAuthApplicationRolesShared.java
deleted file mode 100644
index 61223d57..00000000
--- a/powerauth-backend-tests/src/test/java/com/wultra/security/powerauth/test/shared/PowerAuthApplicationRolesShared.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * PowerAuth test and related software components
- * Copyright (C) 2023 Wultra s.r.o.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published
- * by the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- */
-package com.wultra.security.powerauth.test.shared;
-
-import com.wultra.security.powerauth.client.PowerAuthClient;
-import com.wultra.security.powerauth.client.model.response.GetApplicationDetailResponse;
-import com.wultra.security.powerauth.client.model.response.ListApplicationRolesResponse;
-import com.wultra.security.powerauth.configuration.PowerAuthTestConfiguration;
-
-import java.util.Arrays;
-import java.util.Collections;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
-/**
- * Application roles test shared logic.
- *
- * @author Roman Strobl, roman.strobl@wultra.com
- */
-public class PowerAuthApplicationRolesShared {
-
- public static void applicationRolesCrudTest(PowerAuthClient powerAuthClient, PowerAuthTestConfiguration config) throws Exception {
- // Test application roles CRUD
- String applicationId = config.getApplicationId();
-
- // Remove all existing roles
- final ListApplicationRolesResponse initResponse = powerAuthClient.listApplicationRoles(applicationId);
- if (!initResponse.getApplicationRoles().isEmpty()) {
- powerAuthClient.removeApplicationRoles(applicationId, initResponse.getApplicationRoles());
- }
-
- powerAuthClient.addApplicationRoles(applicationId, Arrays.asList("ROLE1", "ROLE2"));
-
- final GetApplicationDetailResponse response = powerAuthClient.getApplicationDetail(applicationId);
- assertEquals(Arrays.asList("ROLE1", "ROLE2"), response.getApplicationRoles());
-
- ListApplicationRolesResponse listResponse = powerAuthClient.listApplicationRoles(applicationId);
- assertEquals(Arrays.asList("ROLE1", "ROLE2"), listResponse.getApplicationRoles());
-
- powerAuthClient.updateApplicationRoles(applicationId, Arrays.asList("ROLE3", "ROLE4"));
-
- ListApplicationRolesResponse listResponse2 = powerAuthClient.listApplicationRoles(applicationId);
- assertEquals(Arrays.asList("ROLE3", "ROLE4"), listResponse2.getApplicationRoles());
-
- powerAuthClient.removeApplicationRoles(applicationId, Collections.singletonList("ROLE4"));
-
- ListApplicationRolesResponse listResponse3 = powerAuthClient.listApplicationRoles(applicationId);
- assertEquals(Collections.singletonList("ROLE3"), listResponse3.getApplicationRoles());
-
- powerAuthClient.addApplicationRoles(applicationId, Arrays.asList("ROLE3", "ROLE4"));
-
- ListApplicationRolesResponse listResponse4 = powerAuthClient.listApplicationRoles(applicationId);
- assertEquals(Arrays.asList("ROLE3", "ROLE4"), listResponse4.getApplicationRoles());
- }
-}
diff --git a/powerauth-backend-tests/src/test/java/com/wultra/security/powerauth/test/shared/PowerAuthCallbackShared.java b/powerauth-backend-tests/src/test/java/com/wultra/security/powerauth/test/shared/PowerAuthCallbackShared.java
index 9107781f..38dcded9 100644
--- a/powerauth-backend-tests/src/test/java/com/wultra/security/powerauth/test/shared/PowerAuthCallbackShared.java
+++ b/powerauth-backend-tests/src/test/java/com/wultra/security/powerauth/test/shared/PowerAuthCallbackShared.java
@@ -39,64 +39,6 @@
*/
public class PowerAuthCallbackShared {
- public static void callbackCreateDeleteTest(PowerAuthClient powerAuthClient, PowerAuthTestConfiguration config) throws PowerAuthClientException {
- String callbackName = UUID.randomUUID().toString();
- String callbackUrl = "http://test.test";
- powerAuthClient.createCallbackUrl(config.getApplicationId(), callbackName, CallbackUrlType.ACTIVATION_STATUS_CHANGE, callbackUrl, Collections.singletonList("activationId"), null);
- final GetCallbackUrlListResponse callbacks = powerAuthClient.getCallbackUrlList(config.getApplicationId());
- boolean callbackFound = false;
- for (CallbackUrl callback: callbacks.getCallbackUrlList()) {
- if (callbackName.equals(callback.getName())) {
- callbackFound = true;
- assertEquals(callbackUrl, callback.getCallbackUrl());
- assertEquals(config.getApplicationId(), callback.getApplicationId());
- assertEquals(1, callback.getAttributes().size());
- assertEquals("activationId", callback.getAttributes().get(0));
- int callbackCountOrig = callbacks.getCallbackUrlList().size();
- powerAuthClient.removeCallbackUrl(callback.getId());
- }
- }
- assertTrue(callbackFound);
- }
-
- public static void callbackUpdateTest(PowerAuthClient powerAuthClient, PowerAuthTestConfiguration config) throws PowerAuthClientException {
- String callbackName = UUID.randomUUID().toString();
- String callbackUrl = "http://test.test";
- powerAuthClient.createCallbackUrl(config.getApplicationId(), callbackName, CallbackUrlType.ACTIVATION_STATUS_CHANGE, callbackUrl, Collections.singletonList("activationId"), null);
- final GetCallbackUrlListResponse callbacks = powerAuthClient.getCallbackUrlList(config.getApplicationId());
- boolean callbackFound = false;
- String callbackId = null;
- for (CallbackUrl callback: callbacks.getCallbackUrlList()) {
- if (callbackName.equals(callback.getName())) {
- callbackFound = true;
- callbackId = callback.getId();
- assertEquals(callbackUrl, callback.getCallbackUrl());
- assertEquals(config.getApplicationId(), callback.getApplicationId());
- assertEquals(1, callback.getAttributes().size());
- assertEquals("activationId", callback.getAttributes().get(0));
- }
- }
- assertTrue(callbackFound);
- assertNotNull(callbackId);
- String callbackName2 = UUID.randomUUID().toString();
- String callbackUrl2 = "http://test2.test2";
- powerAuthClient.updateCallbackUrl(callbackId, config.getApplicationId(), callbackName2, callbackUrl2, Arrays.asList("activationId", "userId", "deviceInfo", "platform"), null);
- final GetCallbackUrlListResponse callbacks2 = powerAuthClient.getCallbackUrlList(config.getApplicationId());
- boolean callbackFound2 = false;
- for (CallbackUrl callback: callbacks2.getCallbackUrlList()) {
- if (callbackName2.equals(callback.getName())) {
- callbackFound2 = true;
- callbackId = callback.getId();
- assertEquals(callbackUrl2, callback.getCallbackUrl());
- assertEquals(config.getApplicationId(), callback.getApplicationId());
- assertEquals(4, callback.getAttributes().size());
- assertEquals(Arrays.asList("activationId", "userId", "deviceInfo", "platform"), callback.getAttributes());
- }
- }
- assertTrue(callbackFound2);
- powerAuthClient.removeCallbackUrl(callbackId);
- }
-
public static void callbackExecutionTest(PowerAuthClient powerAuthClient, PowerAuthTestConfiguration config, Integer port, String version) throws PowerAuthClientException, RestClientException {
// Skip test when the tested PA server is not running on localhost
assumeTrue(config.getPowerAuthRestUrl().contains("localhost:8080"));
diff --git a/powerauth-backend-tests/src/test/java/com/wultra/security/powerauth/test/shared/PowerAuthIdentityVerificationShared.java b/powerauth-backend-tests/src/test/java/com/wultra/security/powerauth/test/shared/PowerAuthIdentityVerificationShared.java
index 1bed1235..bbd2add5 100644
--- a/powerauth-backend-tests/src/test/java/com/wultra/security/powerauth/test/shared/PowerAuthIdentityVerificationShared.java
+++ b/powerauth-backend-tests/src/test/java/com/wultra/security/powerauth/test/shared/PowerAuthIdentityVerificationShared.java
@@ -21,7 +21,6 @@
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
-import com.google.common.collect.ImmutableList;
import com.wultra.app.enrollmentserver.api.model.onboarding.request.*;
import com.wultra.app.enrollmentserver.api.model.onboarding.response.*;
import com.wultra.app.enrollmentserver.model.enumeration.*;
@@ -99,7 +98,7 @@ private static void processDocuments(final TestProcessContext processCtx, final
approveConsent(ctx, processId);
initIdentityVerification(ctx, activationId, processId);
- final List idCardSubmits = ImmutableList.of(
+ final List idCardSubmits = List.of(
FileSubmit.createFrom("images/id_card_mock_front.png", DocumentType.ID_CARD, CardSide.FRONT),
FileSubmit.createFrom("images/id_card_mock_back.png", DocumentType.ID_CARD, CardSide.BACK)
);
@@ -113,7 +112,7 @@ private static void processDocuments(final TestProcessContext processCtx, final
assertIdentityVerificationStateWithRetries(ctx,
new IdentityVerificationState(IdentityVerificationPhase.DOCUMENT_UPLOAD, IdentityVerificationStatus.IN_PROGRESS));
- final List drivingLicenseSubmits = ImmutableList.of(
+ final List drivingLicenseSubmits = List.of(
FileSubmit.createFrom("images/driving_license_mock_front.png", DocumentType.DRIVING_LICENSE, CardSide.FRONT)
);
final DocumentSubmitRequest driveLicenseSubmitRequest = createDocumentSubmitRequest(processId, drivingLicenseSubmits);
@@ -176,7 +175,7 @@ public static void testSuccessfulIdentityVerificationWithRestarts(final TestCont
for (int i = 0; i < 3; i++) {
initIdentityVerification(ctx, activationId, processId);
- List idCardSubmits = ImmutableList.of(
+ final List idCardSubmits = List.of(
FileSubmit.createFrom("images/id_card_mock_front.png", DocumentType.ID_CARD, CardSide.FRONT),
FileSubmit.createFrom("images/id_card_mock_back.png", DocumentType.ID_CARD, CardSide.BACK)
);
@@ -190,7 +189,7 @@ public static void testSuccessfulIdentityVerificationWithRestarts(final TestCont
assertIdentityVerificationStateWithRetries(ctx,
new IdentityVerificationState(IdentityVerificationPhase.DOCUMENT_UPLOAD, IdentityVerificationStatus.IN_PROGRESS));
- final List drivingLicenseSubmits = ImmutableList.of(
+ final List drivingLicenseSubmits = List.of(
FileSubmit.createFrom("images/driving_license_mock_front.png", DocumentType.DRIVING_LICENSE, CardSide.FRONT)
);
final DocumentSubmitRequest driveLicenseSubmitRequest = createDocumentSubmitRequest(processId, drivingLicenseSubmits);
@@ -227,14 +226,14 @@ public static void testSuccessfulIdentityVerificationMultipleDocSubmits(final Te
approveConsent(ctx, processId);
initIdentityVerification(ctx, activationId, processId);
- List idCardSubmits = ImmutableList.of(
+ final List idCardSubmits = List.of(
FileSubmit.createFrom("images/id_card_mock_front.png", DocumentType.ID_CARD, CardSide.FRONT),
FileSubmit.createFrom("images/id_card_mock_back.png", DocumentType.ID_CARD, CardSide.BACK)
);
DocumentSubmitRequest idCardSubmitRequest = createDocumentSubmitRequest(processId, idCardSubmits);
submitDocuments(ctx, idCardSubmitRequest);
- List drivingLicenseSubmits = ImmutableList.of(
+ final List drivingLicenseSubmits = List.of(
FileSubmit.createFrom("images/driving_license_mock_front.png", DocumentType.DRIVING_LICENSE, CardSide.FRONT)
);
DocumentSubmitRequest driveLicenseSubmitRequest = createDocumentSubmitRequest(processId, drivingLicenseSubmits);
@@ -268,7 +267,7 @@ public static void testDocSubmitDifferentDocumentType(final TestContext ctx) thr
approveConsent(ctx, processId);
initIdentityVerification(ctx, activationId, processId);
- final List docSubmits = ImmutableList.of(
+ final List docSubmits = List.of(
FileSubmit.createFrom("images/id_card_mock_front.png", DocumentType.DRIVING_LICENSE, CardSide.FRONT)
);
DocumentSubmitRequest idCardSubmitRequest = createDocumentSubmitRequest(processId, docSubmits);
@@ -290,7 +289,7 @@ public static void testDocSubmitDifferentCardSide(final TestContext ctx) throws
approveConsent(ctx, processId);
initIdentityVerification(ctx, activationId, processId);
- List docSubmits = ImmutableList.of(
+ final List docSubmits = List.of(
FileSubmit.createFrom("images/id_card_mock_front.png", DocumentType.ID_CARD, CardSide.BACK)
);
DocumentSubmitRequest idCardSubmitRequest = createDocumentSubmitRequest(processId, docSubmits);
@@ -312,7 +311,7 @@ public static void testDocSubmitMaxAttemptsLimit(final TestContext ctx) throws E
approveConsent(ctx, processId);
initIdentityVerification(ctx, activationId, processId);
- final List docSubmits = ImmutableList.of(
+ final List docSubmits = List.of(
FileSubmit.createFrom("images/id_card_mock_front.png", DocumentType.DRIVING_LICENSE, CardSide.FRONT)
);
@@ -340,7 +339,7 @@ public static void testIdentityVerificationNotDocumentPhotos(final TestContext c
approveConsent(ctx, processId);
initIdentityVerification(ctx, activationId, processId);
- List invalidDocSubmits = ImmutableList.of(
+ final List invalidDocSubmits = List.of(
FileSubmit.createFrom("images/random_photo_1.png", DocumentType.ID_CARD, CardSide.FRONT),
FileSubmit.createFrom("images/random_photo_2.png", DocumentType.ID_CARD, CardSide.BACK)
);
@@ -360,7 +359,7 @@ public static void testIdentityVerificationCleanup(final TestContext ctx) throws
approveConsent(ctx, processId);
initIdentityVerification(ctx, activationId, processId);
- List idDocSubmits = ImmutableList.of(
+ final List idDocSubmits = List.of(
FileSubmit.createFrom("images/id_card_mock_front.png", DocumentType.ID_CARD, CardSide.FRONT),
FileSubmit.createFrom("images/id_card_mock_back.png", DocumentType.ID_CARD, CardSide.BACK)
);
@@ -381,7 +380,7 @@ public static void testIdentityVerificationMaxAttemptLimit(final TestContext ctx
for (int i = 0; i < 5; i++) {
initIdentityVerification(ctx, activationId, processId);
- List idDocSubmits = ImmutableList.of(
+ final List idDocSubmits = List.of(
FileSubmit.createFrom("images/id_card_mock_front.png", DocumentType.ID_CARD, CardSide.FRONT),
FileSubmit.createFrom("images/id_card_mock_back.png", DocumentType.ID_CARD, CardSide.BACK)
);
diff --git a/powerauth-backend-tests/src/test/java/com/wultra/security/powerauth/test/shared/PowerAuthOperationShared.java b/powerauth-backend-tests/src/test/java/com/wultra/security/powerauth/test/shared/PowerAuthOperationShared.java
deleted file mode 100644
index d5310297..00000000
--- a/powerauth-backend-tests/src/test/java/com/wultra/security/powerauth/test/shared/PowerAuthOperationShared.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * PowerAuth test and related software components
- * Copyright (C) 2023 Wultra s.r.o.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published
- * by the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- */
-package com.wultra.security.powerauth.test.shared;
-
-import com.wultra.security.powerauth.client.PowerAuthClient;
-import com.wultra.security.powerauth.client.model.enumeration.SignatureType;
-import com.wultra.security.powerauth.client.model.error.PowerAuthClientException;
-import com.wultra.security.powerauth.client.model.request.OperationApproveRequest;
-import com.wultra.security.powerauth.client.model.request.OperationCreateRequest;
-import com.wultra.security.powerauth.client.model.request.OperationDetailRequest;
-import com.wultra.security.powerauth.client.model.response.OperationDetailResponse;
-import com.wultra.security.powerauth.client.model.response.OperationUserActionResponse;
-import com.wultra.security.powerauth.configuration.PowerAuthTestConfiguration;
-
-import java.util.List;
-
-import static com.wultra.security.powerauth.client.model.enumeration.UserActionResult.APPROVAL_FAILED;
-import static com.wultra.security.powerauth.client.model.enumeration.UserActionResult.APPROVED;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-
-/**
- * PowerAuth operations test shared logic.
- *
- * @author Roman Strobl, roman.strobl@wultra.com
- */
-public class PowerAuthOperationShared {
-
- public static void testOperationApprove(final PowerAuthClient powerAuthClient, final PowerAuthTestConfiguration config, final String version) throws Exception {
- final OperationDetailResponse operation = createOperation(powerAuthClient, config, version);
-
- final OperationApproveRequest approveRequest = createOperationApproveRequest(config, operation.getId(), version);
-
- final OperationUserActionResponse result = powerAuthClient.operationApprove(approveRequest);
-
- assertEquals(APPROVED, result.getResult());
- }
-
- public static void testOperationApproveWithValidProximityOtp(final PowerAuthClient powerAuthClient, final PowerAuthTestConfiguration config, final String version) throws Exception {
- final OperationDetailResponse operation = createOperation(powerAuthClient, config, true, version);
-
- final OperationDetailRequest detailRequest = new OperationDetailRequest();
- detailRequest.setOperationId(operation.getId());
-
- final String totp = powerAuthClient.operationDetail(detailRequest).getProximityOtp();
- assertNotNull(totp);
-
- final OperationApproveRequest approveRequest = createOperationApproveRequest(config, operation.getId(), version);
- approveRequest.getAdditionalData().put("proximity_otp", totp);
-
- final OperationUserActionResponse result = powerAuthClient.operationApprove(approveRequest);
-
- assertEquals(APPROVED, result.getResult());
- }
-
- public static void testOperationApproveWithInvalidProximityOtp(final PowerAuthClient powerAuthClient, final PowerAuthTestConfiguration config, final String version) throws Exception {
- final OperationDetailResponse operation = createOperation(powerAuthClient, config, true, version);
-
- final OperationDetailRequest detailRequest = new OperationDetailRequest();
- detailRequest.setOperationId(operation.getId());
-
- final String totp = powerAuthClient.operationDetail(detailRequest).getProximityOtp();
- assertNotNull(totp);
-
- final OperationApproveRequest approveRequest = createOperationApproveRequest(config, operation.getId(), version);
- approveRequest.getAdditionalData().put("proximity_otp", "1111"); // invalid otp on purpose, it is too short
-
- final OperationUserActionResponse result = powerAuthClient.operationApprove(approveRequest);
-
- assertEquals(APPROVAL_FAILED, result.getResult());
- }
-
- private static OperationApproveRequest createOperationApproveRequest(final PowerAuthTestConfiguration config, final String operationId, final String version) {
- final OperationApproveRequest approveRequest = new OperationApproveRequest();
- approveRequest.setOperationId(operationId);
- approveRequest.setUserId(config.getUser(version));
- approveRequest.setApplicationId(config.getApplicationId());
- approveRequest.setData("A2");
- approveRequest.setSignatureType(SignatureType.POSSESSION_KNOWLEDGE);
- return approveRequest;
- }
-
- private static OperationDetailResponse createOperation(final PowerAuthClient powerAuthClient, final PowerAuthTestConfiguration config, String version) throws PowerAuthClientException {
- return createOperation(powerAuthClient, config, null, version);
- }
-
- private static OperationDetailResponse createOperation(final PowerAuthClient powerAuthClient, final PowerAuthTestConfiguration config, final Boolean proximityCheckEnabled, final String version) throws PowerAuthClientException {
- final OperationCreateRequest createRequest = new OperationCreateRequest();
- createRequest.setApplications(List.of(config.getApplicationName()));
- createRequest.setUserId(config.getUser(version));
- createRequest.setTemplateName(config.getLoginOperationTemplateName());
- createRequest.setProximityCheckEnabled(proximityCheckEnabled);
-
- return powerAuthClient.createOperation(createRequest);
- }
-}
diff --git a/powerauth-backend-tests/src/test/java/com/wultra/security/powerauth/test/shared/PowerAuthSignatureShared.java b/powerauth-backend-tests/src/test/java/com/wultra/security/powerauth/test/shared/PowerAuthSignatureShared.java
index 8b9a8b84..721a9d07 100644
--- a/powerauth-backend-tests/src/test/java/com/wultra/security/powerauth/test/shared/PowerAuthSignatureShared.java
+++ b/powerauth-backend-tests/src/test/java/com/wultra/security/powerauth/test/shared/PowerAuthSignatureShared.java
@@ -749,7 +749,7 @@ private static void testSignatureOfflinePersonalizedProximityCheck(final PowerAu
final CreatePersonalizedOfflineSignaturePayloadRequest request = new CreatePersonalizedOfflineSignaturePayloadRequest();
request.setActivationId(config.getActivationId(version));
request.setData(offlineData);
- request.setProximityCheck(new CreatePersonalizedOfflineSignaturePayloadRequest.ProximityCheck());
+ request.setProximityCheck(new CreatePersonalizedOfflineSignaturePayloadRequest.CreateProximityCheck());
request.getProximityCheck().setSeed(seed);
request.getProximityCheck().setStepLength(30);
@@ -808,7 +808,7 @@ private static void testSignatureOfflinePersonalizedProximityCheck(final PowerAu
verifyRequest.setData(signatureBaseString);
verifyRequest.setSignature(signature);
verifyRequest.setAllowBiometry(true);
- verifyRequest.setProximityCheck(new VerifyOfflineSignatureRequest.ProximityCheck());
+ verifyRequest.setProximityCheck(new VerifyOfflineSignatureRequest.VerifyProximityCheck());
verifyRequest.getProximityCheck().setSeed(expectedResult ? seed : "bGlnaHQgd28=");
verifyRequest.getProximityCheck().setStepLength(30);
verifyRequest.getProximityCheck().setStepCount(2);
diff --git a/powerauth-backend-tests/src/test/java/com/wultra/security/powerauth/test/v3x/PowerAuthApiTest.java b/powerauth-backend-tests/src/test/java/com/wultra/security/powerauth/test/v3x/PowerAuthApiTest.java
index 2ec21ce0..5e718731 100644
--- a/powerauth-backend-tests/src/test/java/com/wultra/security/powerauth/test/v3x/PowerAuthApiTest.java
+++ b/powerauth-backend-tests/src/test/java/com/wultra/security/powerauth/test/v3x/PowerAuthApiTest.java
@@ -60,158 +60,29 @@ public void setPowerAuthTestConfiguration(PowerAuthTestConfiguration config) {
this.config = config;
}
- @Test
- void systemStatusTest() throws PowerAuthClientException {
- PowerAuthApiShared.systemStatusTest(powerAuthClient);
- }
-
- @Test
- void errorListTest() throws PowerAuthClientException {
- PowerAuthApiShared.errorListTest(powerAuthClient);
- }
-
- @Test
- void initActivationTest() throws PowerAuthClientException {
- PowerAuthApiShared.initActivationTest(powerAuthClient, config, VERSION);
- }
-
- @Test
- void prepareActivationTest() throws CryptoProviderException, EncryptorException, IOException, PowerAuthClientException {
- PowerAuthApiShared.prepareActivationTest(powerAuthClient, config, VERSION);
- }
-
- @Test
- void createActivationTest() throws CryptoProviderException, EncryptorException, IOException, PowerAuthClientException {
- PowerAuthApiShared.createActivationTest(powerAuthClient, config, VERSION);
- }
-
- @Test
- void updateActivationOtpAndCommitTest() throws CryptoProviderException, EncryptorException, IOException, PowerAuthClientException {
- PowerAuthApiShared.updateActivationOtpAndCommitTest(powerAuthClient, config, VERSION);
- }
-
- @Test
- void removeActivationTest() throws PowerAuthClientException {
- PowerAuthApiShared.removeActivationTest(powerAuthClient, config, VERSION);
- }
-
- @Test
- void activationListForUserTest() throws PowerAuthClientException {
- PowerAuthApiShared.activationListForUserTest(powerAuthClient, config, VERSION);
- }
-
- @Test
- void testGetActivationListForUserPagination() throws PowerAuthClientException {
- PowerAuthApiShared.testGetActivationListForUserPagination(powerAuthClient, config, VERSION);
- }
-
- @Test
- void lookupActivationsTest() throws PowerAuthClientException {
- PowerAuthApiShared.lookupActivationsTest(powerAuthClient, config, VERSION);
- }
-
- @Test
- void activationStatusUpdateTest() throws PowerAuthClientException {
- PowerAuthApiShared.activationStatusUpdateTest(powerAuthClient, config, VERSION);
- }
-
@Test
void verifySignatureTest() throws GenericCryptoException, CryptoProviderException, InvalidKeyException, PowerAuthClientException {
PowerAuthApiShared.verifySignatureTest(powerAuthClient, config, VERSION);
}
- @Test
- void nonPersonalizedOfflineSignaturePayloadTest() throws PowerAuthClientException {
- PowerAuthApiShared.nonPersonalizedOfflineSignaturePayloadTest(powerAuthClient, config);
- }
-
- @Test
- void personalizedOfflineSignaturePayloadTest() throws PowerAuthClientException {
- PowerAuthApiShared.personalizedOfflineSignaturePayloadTest(powerAuthClient, config, VERSION);
- }
-
- @Test
- void verifyOfflineSignatureTest() throws PowerAuthClientException {
- PowerAuthApiShared.verifyOfflineSignatureTest(powerAuthClient, config, VERSION);
- }
-
@Test
void unlockVaultAndECDSASignatureTest() throws GenericCryptoException, CryptoProviderException, InvalidKeySpecException, EncryptorException, IOException, InvalidKeyException, PowerAuthClientException {
PowerAuthApiShared.unlockVaultAndECDSASignatureTest(powerAuthClient, config, VERSION);
}
- @Test
- void activationHistoryTest() throws PowerAuthClientException {
- PowerAuthApiShared.activationHistoryTest(powerAuthClient, config, VERSION);
- }
-
- @Test
- void blockAndUnblockActivationTest() throws PowerAuthClientException {
- PowerAuthApiShared.blockAndUnblockActivationTest(powerAuthClient, config, VERSION);
- }
-
- @Test
- void applicationListTest() throws PowerAuthClientException {
- PowerAuthApiShared.applicationListTest(powerAuthClient, config);
- }
-
- @Test
- void applicationDetailTest() throws PowerAuthClientException {
- PowerAuthApiShared.applicationDetailTest(powerAuthClient, config);
- }
-
- @Test
- void applicationVersionLookupTest() throws PowerAuthClientException {
- PowerAuthApiShared.applicationVersionLookupTest(powerAuthClient, config);
- }
-
// createApplication and createApplication version tests are skipped to avoid creating too many applications
- @Test
- void applicationSupportTest() throws PowerAuthClientException {
- PowerAuthApiShared.applicationSupportTest(powerAuthClient, config);
- }
-
- @Test
- void applicationIntegrationTest() throws PowerAuthClientException {
- PowerAuthApiShared.applicationIntegrationTest(powerAuthClient, config);
- }
-
- @Test
- void callbackTest() throws PowerAuthClientException {
- PowerAuthApiShared.callbackTest(powerAuthClient, config);
- }
-
@Test
void createValidateAndRemoveTokenTestActiveActivation() throws InvalidKeySpecException, CryptoProviderException, GenericCryptoException, IOException, EncryptorException, PowerAuthClientException {
PowerAuthApiShared.createValidateAndRemoveTokenTestActiveActivation(powerAuthClient, config, VERSION);
}
- @Test
- void createValidateAndRemoveTokenTestBlockedActivation() throws InvalidKeySpecException, CryptoProviderException, GenericCryptoException, IOException, EncryptorException, PowerAuthClientException {
- PowerAuthApiShared.createValidateAndRemoveTokenTestBlockedActivation(powerAuthClient, config, VERSION);
- }
-
- @Test
- void getEciesDecryptorTest() throws EncryptorException, PowerAuthClientException {
- PowerAuthApiShared.getEciesDecryptorTest(powerAuthClient, config, VERSION);
- }
-
- @Test
- void recoveryCodeCreateLookupRevokeTest() throws PowerAuthClientException {
- PowerAuthApiShared.recoveryCodeCreateLookupRevokeTest(powerAuthClient, config, VERSION);
- }
@Test
void recoveryCodeConfirmAndActivationTest() throws CryptoProviderException, GenericCryptoException, IOException, EncryptorException, InvalidKeyException, InvalidKeySpecException, PowerAuthClientException {
PowerAuthApiShared.recoveryCodeConfirmAndActivationTest(powerAuthClient, config, VERSION);
}
- @Test
- void recoveryConfigTest() throws PowerAuthClientException {
- PowerAuthApiShared.recoveryConfigTest(powerAuthClient, config);
- }
-
// Activation flags are tested using PowerAuthActivationFlagsTest
// Application roles are tested using PowerAuthApplicationRolesTest
diff --git a/powerauth-backend-tests/src/test/java/com/wultra/security/powerauth/test/v3x/PowerAuthApplicationRolesTest.java b/powerauth-backend-tests/src/test/java/com/wultra/security/powerauth/test/v3x/PowerAuthApplicationRolesTest.java
deleted file mode 100644
index 8f8ba2ed..00000000
--- a/powerauth-backend-tests/src/test/java/com/wultra/security/powerauth/test/v3x/PowerAuthApplicationRolesTest.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * PowerAuth test and related software components
- * Copyright (C) 2020 Wultra s.r.o.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published
- * by the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- */
-package com.wultra.security.powerauth.test.v3x;
-
-import com.wultra.security.powerauth.client.PowerAuthClient;
-import com.wultra.security.powerauth.configuration.PowerAuthTestConfiguration;
-import com.wultra.security.powerauth.test.shared.PowerAuthApplicationRolesShared;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.context.properties.EnableConfigurationProperties;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.test.context.junit.jupiter.SpringExtension;
-
-/**
- * Application roles tests.
- *
- * @author Roman Strobl, roman.strobl@wultra.com
- */
-@ExtendWith(SpringExtension.class)
-@SpringBootTest(classes = PowerAuthTestConfiguration.class)
-@EnableConfigurationProperties
-class PowerAuthApplicationRolesTest {
-
- private PowerAuthClient powerAuthClient;
- private PowerAuthTestConfiguration config;
-
- @Autowired
- public void setPowerAuthClient(PowerAuthClient powerAuthClient) {
- this.powerAuthClient = powerAuthClient;
- }
-
- @Autowired
- public void setPowerAuthTestConfiguration(PowerAuthTestConfiguration config) {
- this.config = config;
- }
-
- @Test
- void applicationRolesCrudTest() throws Exception {
- PowerAuthApplicationRolesShared.applicationRolesCrudTest(powerAuthClient, config);
- }
-}
diff --git a/powerauth-backend-tests/src/test/java/com/wultra/security/powerauth/test/v3x/PowerAuthCallbackTest.java b/powerauth-backend-tests/src/test/java/com/wultra/security/powerauth/test/v3x/PowerAuthCallbackTest.java
index 6995e77b..444f12cb 100644
--- a/powerauth-backend-tests/src/test/java/com/wultra/security/powerauth/test/v3x/PowerAuthCallbackTest.java
+++ b/powerauth-backend-tests/src/test/java/com/wultra/security/powerauth/test/v3x/PowerAuthCallbackTest.java
@@ -73,16 +73,6 @@ void tearDown() throws PowerAuthClientException {
}
}
- @Test
- void callbackCreateDeleteTest() throws PowerAuthClientException {
- PowerAuthCallbackShared.callbackCreateDeleteTest(powerAuthClient, config);
- }
-
- @Test
- void callbackUpdateTest() throws PowerAuthClientException {
- PowerAuthCallbackShared.callbackUpdateTest(powerAuthClient, config);
- }
-
@Test
void callbackExecutionTest() throws PowerAuthClientException, RestClientException {
PowerAuthCallbackShared.callbackExecutionTest(powerAuthClient, config, port, VERSION);
diff --git a/powerauth-backend-tests/src/test/java/com/wultra/security/powerauth/test/v3x/PowerAuthOperationTest.java b/powerauth-backend-tests/src/test/java/com/wultra/security/powerauth/test/v3x/PowerAuthOperationTest.java
deleted file mode 100644
index 063d64fa..00000000
--- a/powerauth-backend-tests/src/test/java/com/wultra/security/powerauth/test/v3x/PowerAuthOperationTest.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * PowerAuth test and related software components
- * Copyright (C) 2023 Wultra s.r.o.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published
- * by the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- */
-package com.wultra.security.powerauth.test.v3x;
-
-import com.wultra.security.powerauth.client.PowerAuthClient;
-import com.wultra.security.powerauth.configuration.PowerAuthTestConfiguration;
-import com.wultra.security.powerauth.test.shared.PowerAuthOperationShared;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.context.properties.EnableConfigurationProperties;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.test.context.junit.jupiter.SpringExtension;
-
-/**
- * Test of PowerAuth operation endpoints.
- *
- * @author Lubos Racansky, lubos.racansky@wultra.com
- */
-@ExtendWith(SpringExtension.class)
-@SpringBootTest(classes = PowerAuthTestConfiguration.class)
-@EnableConfigurationProperties
-class PowerAuthOperationTest {
-
- // Test only in the latestPowerAuth protocol version
- private static final String VERSION = "3.2";
-
- @Autowired
- private PowerAuthClient powerAuthClient;
-
- @Autowired
- private PowerAuthTestConfiguration config;
-
- @Test
- void testOperationApprove() throws Exception {
- PowerAuthOperationShared.testOperationApprove(powerAuthClient, config, VERSION);
- }
-
- @Test
- void testOperationApproveWithValidProximityOtp() throws Exception {
- PowerAuthOperationShared.testOperationApproveWithValidProximityOtp(powerAuthClient, config, VERSION);
- }
-
- @Test
- void testOperationApproveWithInvalidProximityOtp() throws Exception {
- PowerAuthOperationShared.testOperationApproveWithInvalidProximityOtp(powerAuthClient, config, VERSION);
- }
-
-}
diff --git a/powerauth-fido2-tests/pom.xml b/powerauth-fido2-tests/pom.xml
new file mode 100644
index 00000000..e25e312c
--- /dev/null
+++ b/powerauth-fido2-tests/pom.xml
@@ -0,0 +1,124 @@
+
+
+ 4.0.0
+
+ powerauth-fido2-tests
+ PowerAuth FIDO2 Test Web Application
+ powerauth-fido2-tests
+ war
+
+
+ com.wultra
+ powerauth-backend-tests-parent
+ 1.7.0
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
+
+ org.springframework.boot
+ spring-boot-starter-thymeleaf
+
+
+ org.springframework.boot
+ spring-boot-starter-validation
+
+
+
+
+ io.getlime.security
+ powerauth-rest-client-spring
+ ${powerauth-server.version}
+
+
+
+
+ com.webauthn4j
+ webauthn4j-core
+ ${webauthn4j.version}
+
+
+
+
+ io.netty
+ netty-resolver-dns-native-macos
+ runtime
+ osx-aarch_64
+
+
+
+
+ net.logstash.logback
+ logstash-logback-encoder
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+
+
+
+
+ test-repository
+
+
+ !useInternalRepo
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-deploy-plugin
+
+ true
+
+
+
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+ build-info
+
+ build-info
+
+
+
+
+
+
+ org.projectlombok
+ lombok
+
+
+
+
+
+
+
+
diff --git a/powerauth-fido2-tests/src/main/java/com/wultra/security/powerauth/fido2/PowerauthFido2TestApplication.java b/powerauth-fido2-tests/src/main/java/com/wultra/security/powerauth/fido2/PowerauthFido2TestApplication.java
new file mode 100644
index 00000000..b2db5780
--- /dev/null
+++ b/powerauth-fido2-tests/src/main/java/com/wultra/security/powerauth/fido2/PowerauthFido2TestApplication.java
@@ -0,0 +1,36 @@
+/*
+ * PowerAuth Server and related software components
+ * Copyright (C) 2024 Wultra s.r.o.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package com.wultra.security.powerauth.fido2;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+/**
+ * Spring Boot application main class
+ *
+ * @author Jan Pesek, jan.pesek@wultra.com
+ */
+@SpringBootApplication
+public class PowerauthFido2TestApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(PowerauthFido2TestApplication.class, args);
+ }
+
+}
diff --git a/powerauth-fido2-tests/src/main/java/com/wultra/security/powerauth/fido2/ServletInitializer.java b/powerauth-fido2-tests/src/main/java/com/wultra/security/powerauth/fido2/ServletInitializer.java
new file mode 100644
index 00000000..bab1f101
--- /dev/null
+++ b/powerauth-fido2-tests/src/main/java/com/wultra/security/powerauth/fido2/ServletInitializer.java
@@ -0,0 +1,36 @@
+/*
+ * PowerAuth Server and related software components
+ * Copyright (C) 2024 Wultra s.r.o.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package com.wultra.security.powerauth.fido2;
+
+import org.springframework.boot.builder.SpringApplicationBuilder;
+import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
+
+/**
+ * Spring Boot servlet initializer
+ *
+ * @author Jan Pesek, jan.pesek@wultra.com
+ */
+public class ServletInitializer extends SpringBootServletInitializer {
+
+ @Override
+ protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
+ return application.sources(PowerauthFido2TestApplication.class);
+ }
+
+}
diff --git a/powerauth-fido2-tests/src/main/java/com/wultra/security/powerauth/fido2/configuration/PowerAuthConfigProperties.java b/powerauth-fido2-tests/src/main/java/com/wultra/security/powerauth/fido2/configuration/PowerAuthConfigProperties.java
new file mode 100644
index 00000000..3e4d5e9a
--- /dev/null
+++ b/powerauth-fido2-tests/src/main/java/com/wultra/security/powerauth/fido2/configuration/PowerAuthConfigProperties.java
@@ -0,0 +1,40 @@
+/*
+ * PowerAuth test and related software components
+ * Copyright (C) 2024 Wultra s.r.o.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package com.wultra.security.powerauth.fido2.configuration;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * PowerAuth clients configuration properties.
+ *
+ * @author Jan Pesek, jan.pesek@wultra.com
+ */
+@Configuration
+@ConfigurationProperties(prefix = "powerauth.service")
+@Data
+public class PowerAuthConfigProperties {
+
+ private String baseUrl;
+ private SecurityProperties security;
+
+ public record SecurityProperties(String clientToken, String clientSecret) {}
+
+}
diff --git a/powerauth-fido2-tests/src/main/java/com/wultra/security/powerauth/fido2/configuration/PowerAuthWebServiceConfiguration.java b/powerauth-fido2-tests/src/main/java/com/wultra/security/powerauth/fido2/configuration/PowerAuthWebServiceConfiguration.java
new file mode 100644
index 00000000..0b92e757
--- /dev/null
+++ b/powerauth-fido2-tests/src/main/java/com/wultra/security/powerauth/fido2/configuration/PowerAuthWebServiceConfiguration.java
@@ -0,0 +1,62 @@
+/*
+ * PowerAuth test and related software components
+ * Copyright (C) 2024 Wultra s.r.o.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package com.wultra.security.powerauth.fido2.configuration;
+
+import com.wultra.security.powerauth.client.PowerAuthClient;
+import com.wultra.security.powerauth.client.PowerAuthFido2Client;
+import com.wultra.security.powerauth.client.model.error.PowerAuthClientException;
+import com.wultra.security.powerauth.rest.client.PowerAuthFido2RestClient;
+import com.wultra.security.powerauth.rest.client.PowerAuthRestClient;
+import com.wultra.security.powerauth.rest.client.PowerAuthRestClientConfiguration;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.util.StringUtils;
+
+/**
+ * PowerAuth service configuration class.
+ *
+ * @author Jan Pesek, jan.pesek@wultra.com
+ */
+@Configuration
+public class PowerAuthWebServiceConfiguration {
+
+ @Bean
+ public PowerAuthClient powerAuthClient(final PowerAuthConfigProperties properties) throws PowerAuthClientException {
+ final String powerAuthServiceUrl = properties.getBaseUrl() + "/rest";
+ if (StringUtils.hasText(properties.getSecurity().clientToken())) {
+ final PowerAuthRestClientConfiguration config = new PowerAuthRestClientConfiguration();
+ config.setPowerAuthClientToken(properties.getSecurity().clientToken());
+ config.setPowerAuthClientSecret(properties.getSecurity().clientSecret());
+ return new PowerAuthRestClient(powerAuthServiceUrl, config);
+ }
+ return new PowerAuthRestClient(powerAuthServiceUrl);
+ }
+
+ @Bean
+ public PowerAuthFido2Client powerAuthFido2Client(final PowerAuthConfigProperties properties) throws PowerAuthClientException {
+ if (StringUtils.hasText(properties.getSecurity().clientToken())) {
+ final PowerAuthRestClientConfiguration config = new PowerAuthRestClientConfiguration();
+ config.setPowerAuthClientToken(properties.getSecurity().clientToken());
+ config.setPowerAuthClientSecret(properties.getSecurity().clientSecret());
+ return new PowerAuthFido2RestClient(properties.getBaseUrl(), config);
+ }
+ return new PowerAuthFido2RestClient(properties.getBaseUrl());
+ }
+
+}
diff --git a/powerauth-fido2-tests/src/main/java/com/wultra/security/powerauth/fido2/configuration/WebAuthnConfiguration.java b/powerauth-fido2-tests/src/main/java/com/wultra/security/powerauth/fido2/configuration/WebAuthnConfiguration.java
new file mode 100644
index 00000000..d8bbf579
--- /dev/null
+++ b/powerauth-fido2-tests/src/main/java/com/wultra/security/powerauth/fido2/configuration/WebAuthnConfiguration.java
@@ -0,0 +1,43 @@
+/*
+ * PowerAuth test and related software components
+ * Copyright (C) 2024 Wultra s.r.o.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package com.wultra.security.powerauth.fido2.configuration;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+import java.time.Duration;
+import java.util.List;
+
+/**
+ * WebAuthn configuration properties.
+ *
+ * @author Jan Pesek, jan.pesek@wultra.com
+ */
+@Configuration
+@ConfigurationProperties(prefix = "powerauth.webauthn")
+@Data
+public class WebAuthnConfiguration {
+
+ private String rpId;
+ private String rpName;
+ private Duration timeout;
+ private List allowedOrigins;
+
+}
diff --git a/powerauth-fido2-tests/src/main/java/com/wultra/security/powerauth/fido2/controller/AssertionController.java b/powerauth-fido2-tests/src/main/java/com/wultra/security/powerauth/fido2/controller/AssertionController.java
new file mode 100644
index 00000000..6eece2be
--- /dev/null
+++ b/powerauth-fido2-tests/src/main/java/com/wultra/security/powerauth/fido2/controller/AssertionController.java
@@ -0,0 +1,66 @@
+/*
+ * PowerAuth test and related software components
+ * Copyright (C) 2024 Wultra s.r.o.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package com.wultra.security.powerauth.fido2.controller;
+
+import com.wultra.security.powerauth.client.model.error.PowerAuthClientException;
+import com.wultra.security.powerauth.client.model.response.fido2.AssertionVerificationResponse;
+import com.wultra.security.powerauth.fido2.controller.request.AssertionOptionsRequest;
+import com.wultra.security.powerauth.fido2.controller.request.VerifyAssertionRequest;
+import com.wultra.security.powerauth.fido2.controller.response.AssertionOptionsResponse;
+import com.wultra.security.powerauth.fido2.service.AssertionService;
+import jakarta.servlet.http.HttpSession;
+import jakarta.validation.Valid;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * WebAuthn assertion ceremony controller.
+ *
+ * @author Jan Pesek, jan.pesek@wultra.com
+ */
+@Validated
+@RestController
+@RequestMapping("/assertion")
+@AllArgsConstructor
+@Slf4j
+public class AssertionController {
+
+ final AssertionService assertionService;
+
+ @PostMapping("/options")
+ public AssertionOptionsResponse options(@Valid @RequestBody final AssertionOptionsRequest request) throws PowerAuthClientException {
+ return assertionService.assertionOptions(request);
+ }
+
+ @PostMapping
+ public AssertionVerificationResponse verify(@Valid @RequestBody final VerifyAssertionRequest request, final HttpSession session) throws PowerAuthClientException {
+ final AssertionVerificationResponse response = assertionService.authenticate(request);
+ if (response.isAssertionValid()) {
+ session.setAttribute("username", response.getUserId());
+ session.setAttribute("applicationId", response.getApplicationId());
+ }
+ return response;
+ }
+
+}
diff --git a/powerauth-fido2-tests/src/main/java/com/wultra/security/powerauth/fido2/controller/DefaultExceptionHandler.java b/powerauth-fido2-tests/src/main/java/com/wultra/security/powerauth/fido2/controller/DefaultExceptionHandler.java
new file mode 100644
index 00000000..24c7f795
--- /dev/null
+++ b/powerauth-fido2-tests/src/main/java/com/wultra/security/powerauth/fido2/controller/DefaultExceptionHandler.java
@@ -0,0 +1,51 @@
+/*
+ * PowerAuth test and related software components
+ * Copyright (C) 2024 Wultra s.r.o.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package com.wultra.security.powerauth.fido2.controller;
+
+import com.wultra.security.powerauth.client.model.error.PowerAuthError;
+import io.getlime.core.rest.model.base.response.ObjectResponse;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.ResponseStatus;
+
+/**
+ * Controller to handle exceptions.
+ *
+ * @author Jan Pesek, jan.pesek@wultra.com
+ */
+@ControllerAdvice
+@Slf4j
+public class DefaultExceptionHandler {
+
+ @ExceptionHandler
+ @ResponseStatus(HttpStatus.BAD_REQUEST)
+ public @ResponseBody ObjectResponse handleErrors(Exception ex) {
+ logger.error("Error occurred while processing the request: {}", ex.getMessage());
+ logger.debug("Exception details:", ex);
+ final PowerAuthError error = new PowerAuthError();
+ error.setCode("ERROR");
+ error.setMessage(ex.getMessage());
+ error.setLocalizedMessage(ex.getLocalizedMessage());
+ return new ObjectResponse<>("ERROR", error);
+ }
+
+}
diff --git a/powerauth-fido2-tests/src/main/java/com/wultra/security/powerauth/fido2/controller/HomeController.java b/powerauth-fido2-tests/src/main/java/com/wultra/security/powerauth/fido2/controller/HomeController.java
new file mode 100644
index 00000000..d4274fac
--- /dev/null
+++ b/powerauth-fido2-tests/src/main/java/com/wultra/security/powerauth/fido2/controller/HomeController.java
@@ -0,0 +1,94 @@
+/*
+ * PowerAuth Server and related software components
+ * Copyright (C) 2024 Wultra s.r.o.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package com.wultra.security.powerauth.fido2.controller;
+
+import com.wultra.security.powerauth.client.model.error.PowerAuthClientException;
+import com.wultra.security.powerauth.fido2.service.Fido2SharedService;
+import jakarta.servlet.ServletContext;
+import jakarta.servlet.http.HttpSession;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Controller;
+import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.ModelAttribute;
+
+import java.util.Map;
+
+/**
+ * Controller to display initial web page
+ *
+ * @author Jan Pesek, jan.pesek@wultra.com
+ */
+@Controller
+@AllArgsConstructor
+@Slf4j
+public class HomeController {
+
+ private static final String SESSION_KEY_USERNAME = "username";
+ private static final String SESSION_KEY_APPLICATION_ID = "applicationId";
+ private static final String REDIRECT_LOGIN = "redirect:login";
+ private static final String REDIRECT_PAYMENT = "redirect:payment";
+ private static final String LOGIN_PAGE = "login";
+ private static final String PAYMENT_PAGE = "payment";
+
+ private final Fido2SharedService sharedService;
+ private final ServletContext context;
+
+ @ModelAttribute
+ public void addAttributes(Map model) {
+ model.put("servletContextPath", context.getContextPath());
+ }
+
+ @GetMapping("/")
+ public String homePage(Map model, HttpSession session) {
+ if (StringUtils.hasText((String) session.getAttribute(SESSION_KEY_USERNAME))) {
+ return REDIRECT_PAYMENT;
+ }
+ return REDIRECT_LOGIN;
+ }
+
+ @GetMapping("/login")
+ public String loginPage(Map model) throws PowerAuthClientException {
+ model.put("applications", sharedService.fetchApplicationNameList());
+ model.put("templates", sharedService.fetchTemplateNameList());
+ return LOGIN_PAGE;
+ }
+
+ @GetMapping("/payment")
+ public String profilePage(Map model, HttpSession session) throws PowerAuthClientException {
+ final String username = (String) session.getAttribute(SESSION_KEY_USERNAME);
+ final String applicationId = (String) session.getAttribute(SESSION_KEY_APPLICATION_ID);
+ if (!StringUtils.hasText(username)) {
+ return REDIRECT_LOGIN;
+ }
+
+ model.put(SESSION_KEY_USERNAME, username);
+ model.put(SESSION_KEY_APPLICATION_ID, applicationId);
+ model.put("templates", sharedService.fetchTemplateNameList());
+ return PAYMENT_PAGE;
+ }
+
+ @GetMapping("/logout")
+ public String logoutPage(Map model, HttpSession session) {
+ session.removeAttribute(SESSION_KEY_USERNAME);
+ return REDIRECT_LOGIN;
+ }
+
+}
diff --git a/powerauth-fido2-tests/src/main/java/com/wultra/security/powerauth/fido2/controller/RegistrationController.java b/powerauth-fido2-tests/src/main/java/com/wultra/security/powerauth/fido2/controller/RegistrationController.java
new file mode 100644
index 00000000..ce2e535d
--- /dev/null
+++ b/powerauth-fido2-tests/src/main/java/com/wultra/security/powerauth/fido2/controller/RegistrationController.java
@@ -0,0 +1,58 @@
+/*
+ * PowerAuth test and related software components
+ * Copyright (C) 2024 Wultra s.r.o.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package com.wultra.security.powerauth.fido2.controller;
+
+import com.wultra.security.powerauth.client.model.error.PowerAuthClientException;
+import com.wultra.security.powerauth.client.model.response.fido2.RegistrationResponse;
+import com.wultra.security.powerauth.fido2.controller.request.RegisterCredentialRequest;
+import com.wultra.security.powerauth.fido2.controller.request.RegistrationOptionsRequest;
+import com.wultra.security.powerauth.fido2.controller.response.RegistrationOptionsResponse;
+import com.wultra.security.powerauth.fido2.service.RegistrationService;
+import jakarta.validation.Valid;
+import lombok.AllArgsConstructor;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * WebAuthn registration ceremony controller.
+ *
+ * @author Jan Pesek, jan.pesek@wultra.com
+ */
+@Validated
+@RestController
+@RequestMapping("/registration")
+@AllArgsConstructor
+public class RegistrationController {
+
+ private final RegistrationService registrationService;
+
+ @PostMapping("/options")
+ public RegistrationOptionsResponse options(@Valid @RequestBody final RegistrationOptionsRequest request) throws PowerAuthClientException {
+ return registrationService.registerOptions(request);
+ }
+
+ @PostMapping
+ public RegistrationResponse register(@Valid @RequestBody final RegisterCredentialRequest request) throws PowerAuthClientException {
+ return registrationService.register(request);
+ }
+
+}
diff --git a/powerauth-fido2-tests/src/main/java/com/wultra/security/powerauth/fido2/controller/request/AssertionOptionsRequest.java b/powerauth-fido2-tests/src/main/java/com/wultra/security/powerauth/fido2/controller/request/AssertionOptionsRequest.java
new file mode 100644
index 00000000..ebd79cfc
--- /dev/null
+++ b/powerauth-fido2-tests/src/main/java/com/wultra/security/powerauth/fido2/controller/request/AssertionOptionsRequest.java
@@ -0,0 +1,40 @@
+/*
+ * PowerAuth test and related software components
+ * Copyright (C) 2024 Wultra s.r.o.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package com.wultra.security.powerauth.fido2.controller.request;
+
+import jakarta.validation.constraints.NotBlank;
+
+import java.util.Map;
+
+/**
+ * Request for credential assertion options.
+ *
+ * @author Jan Pesek, jan.pesek@wultra.com
+ */
+public record AssertionOptionsRequest (
+ String username,
+
+ @NotBlank
+ String applicationId,
+
+ @NotBlank
+ String templateName,
+
+ Map operationParameters
+) { }
diff --git a/powerauth-fido2-tests/src/main/java/com/wultra/security/powerauth/fido2/controller/request/RegisterCredentialRequest.java b/powerauth-fido2-tests/src/main/java/com/wultra/security/powerauth/fido2/controller/request/RegisterCredentialRequest.java
new file mode 100644
index 00000000..7a5f195e
--- /dev/null
+++ b/powerauth-fido2-tests/src/main/java/com/wultra/security/powerauth/fido2/controller/request/RegisterCredentialRequest.java
@@ -0,0 +1,51 @@
+/*
+ * PowerAuth test and related software components
+ * Copyright (C) 2024 Wultra s.r.o.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package com.wultra.security.powerauth.fido2.controller.request;
+
+import com.webauthn4j.data.AuthenticatorAttachment;
+import com.webauthn4j.data.PublicKeyCredentialType;
+import com.wultra.security.powerauth.client.model.entity.fido2.AuthenticatorAttestationResponse;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+
+/**
+ * Request for register credentials.
+ *
+ * @author Jan Pesek, jan.pesek@wultra.com
+ */
+public record RegisterCredentialRequest (
+ @NotBlank
+ String applicationId,
+
+ @NotBlank
+ String username,
+
+ boolean userVerificationRequired,
+
+ @NotBlank
+ String id,
+
+ @NotNull
+ PublicKeyCredentialType type,
+
+ AuthenticatorAttachment authenticatorAttachment,
+
+ @NotNull
+ AuthenticatorAttestationResponse response
+) {}
diff --git a/powerauth-fido2-tests/src/main/java/com/wultra/security/powerauth/fido2/controller/request/RegistrationOptionsRequest.java b/powerauth-fido2-tests/src/main/java/com/wultra/security/powerauth/fido2/controller/request/RegistrationOptionsRequest.java
new file mode 100644
index 00000000..dd5726e9
--- /dev/null
+++ b/powerauth-fido2-tests/src/main/java/com/wultra/security/powerauth/fido2/controller/request/RegistrationOptionsRequest.java
@@ -0,0 +1,34 @@
+/*
+ * PowerAuth test and related software components
+ * Copyright (C) 2024 Wultra s.r.o.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package com.wultra.security.powerauth.fido2.controller.request;
+
+import jakarta.validation.constraints.NotBlank;
+
+/**
+ * Request for credential registration options.
+ *
+ * @author Jan Pesek, jan.pesek@wultra.com
+ */
+public record RegistrationOptionsRequest(
+ @NotBlank
+ String username,
+
+ @NotBlank
+ String applicationId
+) {}
diff --git a/powerauth-fido2-tests/src/main/java/com/wultra/security/powerauth/fido2/controller/request/VerifyAssertionRequest.java b/powerauth-fido2-tests/src/main/java/com/wultra/security/powerauth/fido2/controller/request/VerifyAssertionRequest.java
new file mode 100644
index 00000000..4e323d6f
--- /dev/null
+++ b/powerauth-fido2-tests/src/main/java/com/wultra/security/powerauth/fido2/controller/request/VerifyAssertionRequest.java
@@ -0,0 +1,50 @@
+/*
+ * PowerAuth test and related software components
+ * Copyright (C) 2024 Wultra s.r.o.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package com.wultra.security.powerauth.fido2.controller.request;
+
+import com.webauthn4j.data.AuthenticatorAttachment;
+import com.webauthn4j.data.PublicKeyCredentialType;
+import com.wultra.security.powerauth.client.model.entity.fido2.AuthenticatorAssertionResponse;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+
+/**
+ * Request for verify credential.
+ *
+ * @author Jan Pesek, jan.pesek@wultra.com
+ */
+public record VerifyAssertionRequest(
+ @NotBlank
+ String applicationId,
+
+ @NotBlank
+ String id,
+
+ @NotNull
+ PublicKeyCredentialType type,
+
+ AuthenticatorAttachment authenticatorAttachment,
+
+ @NotNull
+ AuthenticatorAssertionResponse response,
+
+ String expectedChallenge,
+
+ boolean userVerificationRequired
+) {}
diff --git a/powerauth-fido2-tests/src/main/java/com/wultra/security/powerauth/fido2/controller/response/AssertionOptionsResponse.java b/powerauth-fido2-tests/src/main/java/com/wultra/security/powerauth/fido2/controller/response/AssertionOptionsResponse.java
new file mode 100644
index 00000000..cb6e4425
--- /dev/null
+++ b/powerauth-fido2-tests/src/main/java/com/wultra/security/powerauth/fido2/controller/response/AssertionOptionsResponse.java
@@ -0,0 +1,38 @@
+/*
+ * PowerAuth test and related software components
+ * Copyright (C) 2024 Wultra s.r.o.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package com.wultra.security.powerauth.fido2.controller.response;
+
+import lombok.Builder;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Public key credential assertion options.
+ *
+ * @author Jan Pesek, jan.pesek@wultra.com
+ */
+@Builder
+public record AssertionOptionsResponse(
+ String rpId,
+ String challenge,
+ Long timeout,
+ List allowCredentials,
+ Map extensions
+) {}
diff --git a/powerauth-fido2-tests/src/main/java/com/wultra/security/powerauth/fido2/controller/response/CredentialDescriptor.java b/powerauth-fido2-tests/src/main/java/com/wultra/security/powerauth/fido2/controller/response/CredentialDescriptor.java
new file mode 100644
index 00000000..97c12798
--- /dev/null
+++ b/powerauth-fido2-tests/src/main/java/com/wultra/security/powerauth/fido2/controller/response/CredentialDescriptor.java
@@ -0,0 +1,35 @@
+/*
+ * PowerAuth test and related software components
+ * Copyright (C) 2024 Wultra s.r.o.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package com.wultra.security.powerauth.fido2.controller.response;
+
+import com.webauthn4j.data.AuthenticatorTransport;
+import com.webauthn4j.data.PublicKeyCredentialType;
+
+import java.util.List;
+
+/**
+ * Structure used in allowCredentials and excludeCredentials.
+ *
+ * @author Jan Pesek, jan.pesek@wultra.com
+ */
+public record CredentialDescriptor(
+ PublicKeyCredentialType type,
+ byte[] id,
+ List transports
+) {}
diff --git a/powerauth-fido2-tests/src/main/java/com/wultra/security/powerauth/fido2/controller/response/RegistrationOptionsResponse.java b/powerauth-fido2-tests/src/main/java/com/wultra/security/powerauth/fido2/controller/response/RegistrationOptionsResponse.java
new file mode 100644
index 00000000..227e0e66
--- /dev/null
+++ b/powerauth-fido2-tests/src/main/java/com/wultra/security/powerauth/fido2/controller/response/RegistrationOptionsResponse.java
@@ -0,0 +1,41 @@
+/*
+ * PowerAuth test and related software components
+ * Copyright (C) 2024 Wultra s.r.o.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package com.wultra.security.powerauth.fido2.controller.response;
+
+import com.webauthn4j.data.PublicKeyCredentialParameters;
+import com.webauthn4j.data.PublicKeyCredentialRpEntity;
+import com.webauthn4j.data.PublicKeyCredentialUserEntity;
+import lombok.Builder;
+
+import java.util.List;
+
+/**
+ * Public key credential creation options.
+ *
+ * @author Jan Pesek, jan.pesek@wultra.com
+ */
+@Builder
+public record RegistrationOptionsResponse(
+ PublicKeyCredentialRpEntity rp,
+ PublicKeyCredentialUserEntity user,
+ String challenge,
+ List pubKeyCredParams,
+ Long timeout,
+ List excludeCredentials
+) {}
diff --git a/powerauth-fido2-tests/src/main/java/com/wultra/security/powerauth/fido2/service/AssertionService.java b/powerauth-fido2-tests/src/main/java/com/wultra/security/powerauth/fido2/service/AssertionService.java
new file mode 100644
index 00000000..984e5f4d
--- /dev/null
+++ b/powerauth-fido2-tests/src/main/java/com/wultra/security/powerauth/fido2/service/AssertionService.java
@@ -0,0 +1,140 @@
+/*
+ * PowerAuth test and related software components
+ * Copyright (C) 2024 Wultra s.r.o.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package com.wultra.security.powerauth.fido2.service;
+
+import com.webauthn4j.data.AuthenticatorTransport;
+import com.webauthn4j.data.PublicKeyCredentialType;
+import com.wultra.security.powerauth.client.PowerAuthFido2Client;
+import com.wultra.security.powerauth.client.model.entity.fido2.AllowCredentials;
+import com.wultra.security.powerauth.client.model.error.PowerAuthClientException;
+import com.wultra.security.powerauth.client.model.request.fido2.AssertionChallengeRequest;
+import com.wultra.security.powerauth.client.model.request.fido2.AssertionVerificationRequest;
+import com.wultra.security.powerauth.client.model.response.fido2.AssertionChallengeResponse;
+import com.wultra.security.powerauth.client.model.response.fido2.AssertionVerificationResponse;
+import com.wultra.security.powerauth.fido2.configuration.WebAuthnConfiguration;
+import com.wultra.security.powerauth.fido2.controller.request.AssertionOptionsRequest;
+import com.wultra.security.powerauth.fido2.controller.request.VerifyAssertionRequest;
+import com.wultra.security.powerauth.fido2.controller.response.AssertionOptionsResponse;
+import com.wultra.security.powerauth.fido2.controller.response.CredentialDescriptor;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.util.StringUtils;
+
+import java.util.*;
+
+/**
+ * Service for WebAuthn authentication tasks.
+ *
+ * @author Jan Pesek, jan.pesek@wultra.com
+ */
+@Service
+@AllArgsConstructor
+@Slf4j
+public class AssertionService {
+
+ private final PowerAuthFido2Client fido2Client;
+ private final WebAuthnConfiguration webAuthNConfig;
+
+ /**
+ * Build public key assertion options.
+ * @param request Request form with user input.
+ * @return Public key assertion options.
+ * @throws PowerAuthClientException in case of PowerAuth server communication error.
+ */
+ public AssertionOptionsResponse assertionOptions(final AssertionOptionsRequest request) throws PowerAuthClientException {
+ final String userId = request.username();
+ final String applicationId = request.applicationId();
+
+ logger.info("Building assertion options for userId={}, applicationId={}", userId, applicationId);
+
+ final AssertionChallengeResponse challengeResponse = fetchChallenge(userId, applicationId, request.templateName(), request.operationParameters());
+ final var credentialList = Optional.ofNullable(challengeResponse.getAllowCredentials());
+ if (credentialList.isEmpty() && StringUtils.hasText(userId)) {
+ logger.info("User {} is not yet registered.", userId);
+ throw new IllegalStateException("Not registered yet.");
+ }
+
+ final List existingCredentials = credentialList
+ .orElse(Collections.emptyList())
+ .stream()
+ .map(AssertionService::toCredentialDescriptor)
+ .toList();
+
+ return AssertionOptionsResponse.builder()
+ .challenge(challengeResponse.getChallenge())
+ .rpId(webAuthNConfig.getRpId())
+ .timeout(webAuthNConfig.getTimeout().toMillis())
+ .allowCredentials(existingCredentials)
+ .extensions(Collections.emptyMap()).build();
+ }
+
+ /**
+ * Verify credential at PowerAuth server.
+ * @param credential Received public key credential.
+ * @return PowerAuth authentication response.
+ * @throws PowerAuthClientException in case of PowerAuth server communication error.
+ */
+ public AssertionVerificationResponse authenticate(final VerifyAssertionRequest credential) throws PowerAuthClientException {
+ final byte[] credentialId = Base64.getUrlDecoder().decode(credential.id());
+
+ final AssertionVerificationRequest request = new AssertionVerificationRequest();
+ request.setCredentialId(Base64.getEncoder().encodeToString(credentialId));
+ request.setType(credential.type().getValue());
+ if (credential.authenticatorAttachment() != null) {
+ request.setAuthenticatorAttachment(credential.authenticatorAttachment().getValue());
+ }
+ request.setResponse(credential.response());
+ request.setApplicationId(credential.applicationId());
+ request.setExpectedChallenge(credential.expectedChallenge());
+ request.setRelyingPartyId(webAuthNConfig.getRpId());
+ request.setAllowedOrigins(webAuthNConfig.getAllowedOrigins());
+ request.setRequiresUserVerification(credential.userVerificationRequired());
+
+ final AssertionVerificationResponse response = fido2Client.authenticate(request);
+ logger.debug("Credential assertion response of userId={}: {}", response.getUserId(), response);
+ logger.info("Activation ID {} of userId={}: valid={}", response.getActivationId(), response.getUserId(), response.isAssertionValid());
+
+ return response;
+ }
+
+ private AssertionChallengeResponse fetchChallenge(final String userId, final String applicationId, final String templateName, final Map operationParameters) throws PowerAuthClientException {
+ logger.info("Getting registration challenge for userId={}, applicationId={}, template={}, parameters={}", userId, applicationId, templateName, operationParameters);
+ final AssertionChallengeRequest request = new AssertionChallengeRequest();
+ if (StringUtils.hasText(userId)) {
+ request.setUserId(userId);
+ }
+ request.setApplicationIds(List.of(applicationId));
+ request.setTemplateName(templateName);
+ if (operationParameters != null) {
+ request.setParameters(operationParameters);
+ }
+ final AssertionChallengeResponse response = fido2Client.requestAssertionChallenge(request);
+ logger.debug("Assertion challenge response for userId={}: {}", userId, response);
+ return response;
+ }
+
+ public static CredentialDescriptor toCredentialDescriptor(final AllowCredentials allowCredentials) {
+ final List transports = allowCredentials.getTransports().stream()
+ .map(AuthenticatorTransport::create)
+ .toList();
+ return new CredentialDescriptor(PublicKeyCredentialType.create(allowCredentials.getType()), allowCredentials.getCredentialId(), transports);
+ }
+
+}
diff --git a/powerauth-fido2-tests/src/main/java/com/wultra/security/powerauth/fido2/service/Fido2SharedService.java b/powerauth-fido2-tests/src/main/java/com/wultra/security/powerauth/fido2/service/Fido2SharedService.java
new file mode 100644
index 00000000..b518408c
--- /dev/null
+++ b/powerauth-fido2-tests/src/main/java/com/wultra/security/powerauth/fido2/service/Fido2SharedService.java
@@ -0,0 +1,105 @@
+/*
+ * PowerAuth test and related software components
+ * Copyright (C) 2024 Wultra s.r.o.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package com.wultra.security.powerauth.fido2.service;
+
+import com.webauthn4j.data.AuthenticatorTransport;
+import com.webauthn4j.data.PublicKeyCredentialType;
+import com.wultra.security.powerauth.client.PowerAuthClient;
+import com.wultra.security.powerauth.client.PowerAuthFido2Client;
+import com.wultra.security.powerauth.client.model.entity.Application;
+import com.wultra.security.powerauth.client.model.entity.fido2.AuthenticatorDetail;
+import com.wultra.security.powerauth.client.model.error.PowerAuthClientException;
+import com.wultra.security.powerauth.client.model.response.OperationTemplateDetailResponse;
+import com.wultra.security.powerauth.fido2.controller.response.CredentialDescriptor;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.util.StringUtils;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Service shared for registration and authentication.
+ *
+ * @author Jan Pesek, jan.pesek@wultra.com
+ */
+@Service
+@AllArgsConstructor
+@Slf4j
+public class Fido2SharedService {
+
+ private static final String EXTRAS_TRANSPORT_KEY = "transports";
+ private static final PublicKeyCredentialType CREDENTIAL_TYPE = PublicKeyCredentialType.PUBLIC_KEY;
+
+ private final PowerAuthFido2Client fido2Client;
+ private final PowerAuthClient powerAuthClient;
+
+ /**
+ * Fetch all registered credentials.
+ * @param userId User to whom the credentials belong.
+ * @param applicationId Of the used application.
+ * @return List of credentials.
+ * @throws PowerAuthClientException if there is an error in PowerAuth communication.
+ */
+ public List fetchExistingCredentials(final String userId, final String applicationId) throws PowerAuthClientException {
+ if (!StringUtils.hasText(userId) || !StringUtils.hasText(applicationId)) {
+ return Collections.emptyList();
+ }
+
+ return listAuthenticators(userId, applicationId).stream()
+ .map(Fido2SharedService::toCredentialDescriptor)
+ .toList();
+ }
+
+ /**
+ * Fetch list of all existing applications.
+ * @return List of application ids.
+ * @throws PowerAuthClientException if there is an error in PowerAuth communication.
+ */
+ public List fetchApplicationNameList() throws PowerAuthClientException {
+ return powerAuthClient.getApplicationList().getApplications()
+ .stream()
+ .map(Application::getApplicationId)
+ .sorted().toList();
+ }
+
+ /**
+ * Fetch all existing operation templates.
+ * @return List of operation template names.
+ * @throws PowerAuthClientException if there is an error in PowerAuth communication.
+ */
+ public List fetchTemplateNameList() throws PowerAuthClientException {
+ return powerAuthClient.operationTemplateList()
+ .stream()
+ .map(OperationTemplateDetailResponse::getTemplateName)
+ .sorted().toList();
+ }
+
+ private List listAuthenticators(final String userId, final String applicationId) throws PowerAuthClientException {
+ return fido2Client.getRegisteredAuthenticatorList(userId, applicationId).getAuthenticators();
+ }
+
+ @SuppressWarnings("unchecked")
+ private static CredentialDescriptor toCredentialDescriptor(final AuthenticatorDetail authenticatorDetail) {
+ final List transports = (List) authenticatorDetail.getExtras().getOrDefault(EXTRAS_TRANSPORT_KEY, Collections.emptyList());
+ return new CredentialDescriptor(CREDENTIAL_TYPE, authenticatorDetail.getCredentialId().getBytes(), transports);
+ }
+
+}
diff --git a/powerauth-fido2-tests/src/main/java/com/wultra/security/powerauth/fido2/service/RegistrationService.java b/powerauth-fido2-tests/src/main/java/com/wultra/security/powerauth/fido2/service/RegistrationService.java
new file mode 100644
index 00000000..0d1b06db
--- /dev/null
+++ b/powerauth-fido2-tests/src/main/java/com/wultra/security/powerauth/fido2/service/RegistrationService.java
@@ -0,0 +1,125 @@
+/*
+ * PowerAuth test and related software components
+ * Copyright (C) 2024 Wultra s.r.o.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package com.wultra.security.powerauth.fido2.service;
+
+import com.webauthn4j.data.PublicKeyCredentialParameters;
+import com.webauthn4j.data.PublicKeyCredentialRpEntity;
+import com.webauthn4j.data.PublicKeyCredentialType;
+import com.webauthn4j.data.PublicKeyCredentialUserEntity;
+import com.webauthn4j.data.attestation.statement.COSEAlgorithmIdentifier;
+import com.wultra.security.powerauth.client.PowerAuthFido2Client;
+import com.wultra.security.powerauth.client.model.entity.fido2.AuthenticatorParameters;
+import com.wultra.security.powerauth.client.model.error.PowerAuthClientException;
+import com.wultra.security.powerauth.client.model.request.fido2.RegistrationRequest;
+import com.wultra.security.powerauth.client.model.response.fido2.RegistrationChallengeResponse;
+import com.wultra.security.powerauth.client.model.response.fido2.RegistrationResponse;
+import com.wultra.security.powerauth.fido2.configuration.WebAuthnConfiguration;
+import com.wultra.security.powerauth.fido2.controller.request.RegisterCredentialRequest;
+import com.wultra.security.powerauth.fido2.controller.request.RegistrationOptionsRequest;
+import com.wultra.security.powerauth.fido2.controller.response.RegistrationOptionsResponse;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import java.util.Base64;
+import java.util.List;
+
+/**
+ * Service for WebAuthn registration tasks.
+ *
+ * @author Jan Pesek, jan.pesek@wultra.com
+ */
+@Service
+@AllArgsConstructor
+@Slf4j
+public class RegistrationService {
+
+ private final PowerAuthFido2Client fido2Client;
+ private final Fido2SharedService fido2SharedService;
+ private final WebAuthnConfiguration webAuthNConfig;
+
+ /**
+ * Build public key registration options.
+ * @param request Request form with user input.
+ * @return Public key registration options.
+ * @throws PowerAuthClientException in case of PowerAuth server communication error.
+ */
+ public RegistrationOptionsResponse registerOptions(final RegistrationOptionsRequest request) throws PowerAuthClientException {
+ final String userId = request.username();
+ final String applicationId = request.applicationId();
+
+ final RegistrationChallengeResponse challengeResponse = fetchChallenge(userId, applicationId);
+
+ logger.info("Building registration options for userId={}, applicationId={}", userId, applicationId);
+ return RegistrationOptionsResponse.builder()
+ .rp(new PublicKeyCredentialRpEntity(webAuthNConfig.getRpId(), webAuthNConfig.getRpName()))
+ .user(new PublicKeyCredentialUserEntity(userId.getBytes(), userId, userId))
+ .challenge(challengeResponse.getChallenge())
+ .pubKeyCredParams(List.of(
+ new PublicKeyCredentialParameters(PublicKeyCredentialType.PUBLIC_KEY, COSEAlgorithmIdentifier.ES256)
+ ))
+ .timeout(webAuthNConfig.getTimeout().toMillis())
+ .excludeCredentials(fido2SharedService.fetchExistingCredentials(userId, applicationId))
+ .build();
+ }
+
+ /**
+ * Register credential at PowerAuth server.
+ * @param credential Newly created public key credential
+ * @return PowerAuth registration response.
+ * @throws PowerAuthClientException in case of PowerAuth server communication error.
+ */
+ public RegistrationResponse register(final RegisterCredentialRequest credential) throws PowerAuthClientException {
+ logger.info("Registering created credential of userId={}, applicationId={}", credential.username(), credential.applicationId());
+
+ final RegistrationRequest request = new RegistrationRequest();
+ request.setActivationName(credential.username());
+ request.setApplicationId(credential.applicationId());
+ request.setAuthenticatorParameters(buildAuthenticatorParameters(credential));
+
+ final RegistrationResponse response = fido2Client.register(request);
+ logger.debug("Credential registration response of userId={}: {}", credential.username(), response);
+ logger.info("Activation ID {} of userId={}: status={}", response.getActivationId(), response.getUserId(), response.getActivationStatus());
+ return response;
+ }
+
+ private RegistrationChallengeResponse fetchChallenge(final String userId, final String applicationId) throws PowerAuthClientException {
+ logger.info("Getting registration challenge for userId={}, applicationId={}", userId, applicationId);
+ final RegistrationChallengeResponse response = fido2Client.requestRegistrationChallenge(userId, applicationId);
+ logger.debug("Registration challenge response for userId={}: {}", userId, response);
+ return response;
+ }
+
+ private AuthenticatorParameters buildAuthenticatorParameters(final RegisterCredentialRequest credential) {
+ final byte[] credentialId = Base64.getUrlDecoder().decode(credential.id());
+
+ final AuthenticatorParameters parameters = new AuthenticatorParameters();
+ parameters.setCredentialId(Base64.getEncoder().encodeToString(credentialId));
+ if (credential.authenticatorAttachment() != null) {
+ parameters.setAuthenticatorAttachment(credential.authenticatorAttachment().getValue());
+ }
+ parameters.setType(credential.type().getValue());
+ parameters.setResponse(credential.response());
+ parameters.setAllowedOrigins(webAuthNConfig.getAllowedOrigins());
+ parameters.setRelyingPartyId(webAuthNConfig.getRpId());
+ parameters.setRequiresUserVerification(credential.userVerificationRequired());
+ return parameters;
+ }
+
+}
diff --git a/powerauth-fido2-tests/src/main/resources/application-dev.properties b/powerauth-fido2-tests/src/main/resources/application-dev.properties
new file mode 100644
index 00000000..c44e0c2b
--- /dev/null
+++ b/powerauth-fido2-tests/src/main/resources/application-dev.properties
@@ -0,0 +1,9 @@
+
+# WebAuthn properties configuration
+powerauth.webauthn.rpId=localhost
+powerauth.webauthn.rpName=Local Development
+powerauth.webauthn.allowedOrigins=http://localhost:8083
+
+logging.level.com.wultra.*=DEBUG
+
+
diff --git a/powerauth-fido2-tests/src/main/resources/application.properties b/powerauth-fido2-tests/src/main/resources/application.properties
new file mode 100644
index 00000000..3d5cd9e1
--- /dev/null
+++ b/powerauth-fido2-tests/src/main/resources/application.properties
@@ -0,0 +1,19 @@
+
+# PowerAuth service configuration
+powerauth.service.baseUrl=http://localhost:8080/powerauth-java-server
+powerauth.service.security.clientToken=
+powerauth.service.security.clientSecret=
+
+# WebAuthn properties configuration
+powerauth.webauthn.rpId=
+powerauth.webauthn.rpName=
+powerauth.webauthn.timeout=60s
+powerauth.webauthn.allowedOrigins=
+
+# Application Service Configuration
+powerauth.fido2.test.service.applicationName=powerauth-fido2-tests
+powerauth.fido2.test.service.applicationDisplayName=PowerAuth FIDO2 Test
+powerauth.fido2.test.service.applicationEnvironment=
+
+banner.application.name=${powerauth.fido2.test.service.applicationName}
+banner.application.version=@project.version@
diff --git a/powerauth-fido2-tests/src/main/resources/banner.txt b/powerauth-fido2-tests/src/main/resources/banner.txt
new file mode 100644
index 00000000..875a0a65
--- /dev/null
+++ b/powerauth-fido2-tests/src/main/resources/banner.txt
@@ -0,0 +1,8 @@
+ ___ _ _ _ ___ ___ ___ ___ ___ _____ _
+ | _ \_____ __ _____ _ _ /_\ _ _| |_| |_ | __|_ _| \ / _ \_ ) |_ _|__ __| |_
+ | _/ _ \ V V / -_) '_/ _ \ || | _| ' \ | _| | || |) | (_) / / | |/ -_|_-< _|
+ |_| \___/\_/\_/\___|_|/_/ \_\_,_|\__|_||_| |_| |___|___/ \___/___| |_|\___/__/\__|
+
+${AnsiColor.GREEN} :: ${banner.application.name} (${banner.application.version}) :: ${AnsiColor.GREEN}
+${AnsiColor.RED} :: Spring Boot${spring-boot.formatted-version} :: ${AnsiColor.RED}
+${AnsiColor.DEFAULT}
diff --git a/powerauth-fido2-tests/src/main/resources/templates/error.html b/powerauth-fido2-tests/src/main/resources/templates/error.html
new file mode 100644
index 00000000..fb9cd680
--- /dev/null
+++ b/powerauth-fido2-tests/src/main/resources/templates/error.html
@@ -0,0 +1,26 @@
+
+
+
+
+ ERROR
+
+
+
+
+
+
+
Error
+
+
+
+
Unexpected error occurred. Is the PowerAuth Server reachable?
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/powerauth-fido2-tests/src/main/resources/templates/login.html b/powerauth-fido2-tests/src/main/resources/templates/login.html
new file mode 100644
index 00000000..570b33fe
--- /dev/null
+++ b/powerauth-fido2-tests/src/main/resources/templates/login.html
@@ -0,0 +1,101 @@
+
+
+
+
+ Login
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/powerauth-fido2-tests/src/main/resources/templates/payment.html b/powerauth-fido2-tests/src/main/resources/templates/payment.html
new file mode 100644
index 00000000..881c096a
--- /dev/null
+++ b/powerauth-fido2-tests/src/main/resources/templates/payment.html
@@ -0,0 +1,85 @@
+
+
+
+
+ Payment
+
+
+
+
+
+
+
+
+
+
+
+
+