diff --git a/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/EciesEncryptedRequest.java b/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/EciesEncryptedRequest.java
index fadd11dd..827b7b9b 100644
--- a/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/EciesEncryptedRequest.java
+++ b/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/EciesEncryptedRequest.java
@@ -30,6 +30,11 @@
@Data
public class EciesEncryptedRequest {
+ /**
+ * Identifier of the temporary key.
+ */
+ private String temporaryKeyId;
+
/**
* Base64 encoded ephemeral public key.
*/
diff --git a/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/TemporaryKeyRequest.java b/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/TemporaryKeyRequest.java
new file mode 100644
index 00000000..5df0ebd4
--- /dev/null
+++ b/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/TemporaryKeyRequest.java
@@ -0,0 +1,37 @@
+/*
+ * PowerAuth integration libraries for RESTful API applications, examples 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 io.getlime.security.powerauth.rest.api.model.request;
+
+import lombok.Data;
+
+/**
+ * Request class with temporary public key.
+ *
+ * @author Petr Dvorak, petr@wultra.com
+ */
+@Data
+public class TemporaryKeyRequest {
+
+ /**
+ * JWT with encoded temporary key request.
+ */
+ private String jwt;
+
+}
\ No newline at end of file
diff --git a/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/ServerStatusResponse.java b/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/ServerStatusResponse.java
index 16cb7eff..291c4db4 100644
--- a/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/ServerStatusResponse.java
+++ b/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/ServerStatusResponse.java
@@ -25,5 +25,12 @@
* @param serverTime Server time.
* @author Roman Strobl, roman.strobl@wultra.com
*/
-public record ServerStatusResponse(long serverTime) {
+public record ServerStatusResponse(long serverTime, Application application) {
+ /**
+ * Record for information about the application.
+ * @param name Application name, if present in BuildProperties.
+ * @param version Application version, if present in BuildProperties.
+ */
+ public record Application(String name, String version) {
+ }
}
\ No newline at end of file
diff --git a/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/TemporaryKeyResponse.java b/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/TemporaryKeyResponse.java
new file mode 100644
index 00000000..8dd1f85e
--- /dev/null
+++ b/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/TemporaryKeyResponse.java
@@ -0,0 +1,37 @@
+/*
+ * PowerAuth integration libraries for RESTful API applications, examples 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 io.getlime.security.powerauth.rest.api.model.response;
+
+import lombok.Data;
+
+/**
+ * Response class with temporary key.
+ *
+ * @author Petr Dvorak, petr@wultra.com
+ */
+@Data
+public class TemporaryKeyResponse {
+
+ /**
+ * JWT with encoded temporary key response.
+ */
+ private String jwt;
+
+}
diff --git a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/encryption/EncryptionContext.java b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/encryption/EncryptionContext.java
index c919dbea..ce60e171 100644
--- a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/encryption/EncryptionContext.java
+++ b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/encryption/EncryptionContext.java
@@ -44,6 +44,7 @@ public class EncryptionContext {
* Protocol version.
*/
private final String version;
+
/**
* PowerAuth HTTP header used for deriving ECIES encryption context.
*/
diff --git a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/PowerAuthTemporaryKeyException.java b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/PowerAuthTemporaryKeyException.java
new file mode 100644
index 00000000..02db78a3
--- /dev/null
+++ b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/PowerAuthTemporaryKeyException.java
@@ -0,0 +1,55 @@
+/*
+ * PowerAuth integration libraries for RESTful API applications, examples 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 io.getlime.security.powerauth.rest.api.spring.exception;
+
+/**
+ * Exception raised in case PowerAuth fails to return temporary keys.
+ *
+ * @author Petr Dvorak, petr@wultra.com
+ */
+public class PowerAuthTemporaryKeyException extends Exception {
+
+ private static final String DEFAULT_CODE = "ERR_TEMPORARY_KEY";
+ private static final String DEFAULT_ERROR = "POWER_AUTH_TEMPORARY_KEY_FAILURE";
+
+ /**
+ * Default constructor.
+ */
+ public PowerAuthTemporaryKeyException() {
+ super(DEFAULT_ERROR);
+ }
+
+ /**
+ * Get the default error code, used for example in REST response.
+ * @return Default error code.
+ */
+ public String getDefaultCode() {
+ return DEFAULT_CODE;
+ }
+
+ /**
+ * Get default error message, used for example in the REST response.
+ * @return Default error message.
+ */
+ public String getDefaultError() {
+ return DEFAULT_ERROR;
+ }
+
+}
diff --git a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/provider/PowerAuthEncryptionProvider.java b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/provider/PowerAuthEncryptionProvider.java
index 53e05116..c887770e 100644
--- a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/provider/PowerAuthEncryptionProvider.java
+++ b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/provider/PowerAuthEncryptionProvider.java
@@ -58,11 +58,12 @@ public PowerAuthEncryptionProvider(PowerAuthClient powerAuthClient, HttpCustomiz
}
@Override
- public @Nonnull PowerAuthEncryptorParameters getEciesDecryptorParameters(@Nullable String activationId, @Nonnull String applicationKey, @Nonnull String ephemeralPublicKey, @Nonnull String version, String nonce, Long timestamp) throws PowerAuthEncryptionException {
+ public @Nonnull PowerAuthEncryptorParameters getEciesDecryptorParameters(@Nullable String activationId, @Nonnull String applicationKey, @Nonnull String temporaryKeyId, @Nonnull String ephemeralPublicKey, @Nonnull String version, String nonce, Long timestamp) throws PowerAuthEncryptionException {
try {
final GetEciesDecryptorRequest eciesDecryptorRequest = new GetEciesDecryptorRequest();
eciesDecryptorRequest.setActivationId(activationId);
eciesDecryptorRequest.setApplicationKey(applicationKey);
+ eciesDecryptorRequest.setTemporaryKeyId(temporaryKeyId);
eciesDecryptorRequest.setEphemeralPublicKey(ephemeralPublicKey);
eciesDecryptorRequest.setProtocolVersion(version);
eciesDecryptorRequest.setNonce(nonce);
diff --git a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/provider/PowerAuthEncryptionProviderBase.java b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/provider/PowerAuthEncryptionProviderBase.java
index bab6972e..48a3b692 100644
--- a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/provider/PowerAuthEncryptionProviderBase.java
+++ b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/provider/PowerAuthEncryptionProviderBase.java
@@ -80,7 +80,7 @@ public abstract class PowerAuthEncryptionProviderBase {
* @throws PowerAuthEncryptionException In case PowerAuth server call fails.
*/
public abstract @Nonnull
- PowerAuthEncryptorParameters getEciesDecryptorParameters(@Nullable String activationId, @Nonnull String applicationKey, @Nonnull String ephemeralPublicKey, @Nonnull String version, String nonce, Long timestamp) throws PowerAuthEncryptionException;
+ PowerAuthEncryptorParameters getEciesDecryptorParameters(@Nullable String activationId, @Nonnull String applicationKey, @Nonnull String temporaryKeyId, @Nonnull String ephemeralPublicKey, @Nonnull String version, String nonce, Long timestamp) throws PowerAuthEncryptionException;
/**
* Decrypt HTTP request body and construct object with ECIES data. Use the requestType parameter to specify
@@ -136,6 +136,7 @@ public void decryptRequest(@Nonnull HttpServletRequest request, @Nonnull Type re
// Prepare and validate EncryptedRequest object
final EncryptedRequest encryptedRequest = new EncryptedRequest(
+ eciesRequest.getTemporaryKeyId(),
eciesRequest.getEphemeralPublicKey(),
eciesRequest.getEncryptedData(),
eciesRequest.getMac(),
@@ -155,6 +156,7 @@ public void decryptRequest(@Nonnull HttpServletRequest request, @Nonnull Type re
final PowerAuthEncryptorParameters encryptorParameters = getEciesDecryptorParameters(
activationId,
applicationKey,
+ encryptedRequest.getTemporaryKeyId(),
encryptedRequest.getEphemeralPublicKey(),
version,
encryptedRequest.getNonce(),
@@ -165,7 +167,7 @@ public void decryptRequest(@Nonnull HttpServletRequest request, @Nonnull Type re
final byte[] sharedInfo2Base = Base64.getDecoder().decode(encryptorParameters.sharedInfo2());
final ServerEncryptor serverEncryptor = encryptorFactory.getServerEncryptor(
encryptorData.getEncryptorId(),
- new EncryptorParameters(version, applicationKey, activationId),
+ new EncryptorParameters(version, applicationKey, activationId, encryptedRequest.getTemporaryKeyId()),
new ServerEncryptorSecrets(secretKeyBytes, sharedInfo2Base)
);
diff --git a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/ActivationController.java b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/ActivationController.java
index 19613619..78660447 100644
--- a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/ActivationController.java
+++ b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/ActivationController.java
@@ -60,6 +60,9 @@
*
PowerAuth protocol versions:
*
* - 3.0
+ * - 3.1
+ * - 3.2
+ * - 3.3
*
*
* @author Roman Strobl, roman.strobl@wultra.com
diff --git a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/KeyStoreController.java b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/KeyStoreController.java
new file mode 100644
index 00000000..76a706b4
--- /dev/null
+++ b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/KeyStoreController.java
@@ -0,0 +1,85 @@
+/*
+ * PowerAuth integration libraries for RESTful API applications, examples 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 io.getlime.security.powerauth.rest.api.spring.controller;
+
+import io.getlime.core.rest.model.base.request.ObjectRequest;
+import io.getlime.core.rest.model.base.response.ObjectResponse;
+import io.getlime.security.powerauth.rest.api.model.request.TemporaryKeyRequest;
+import io.getlime.security.powerauth.rest.api.model.response.TemporaryKeyResponse;
+import io.getlime.security.powerauth.rest.api.spring.exception.PowerAuthTemporaryKeyException;
+import io.getlime.security.powerauth.rest.api.spring.service.KeyStoreService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * Controller for obtaining temporary encryption keys.
+ *
+ * PowerAuth protocol versions:
+ *
+ *
+ * @author Petr Dvorak, petr@wultra.com
+ */
+@RestController("keyStoreControllerV3")
+@RequestMapping(value = "/pa/v3/keystore")
+public class KeyStoreController {
+
+ private static final Logger logger = LoggerFactory.getLogger(KeyStoreController.class);
+
+ private final KeyStoreService service;
+
+ /**
+ * Default autowiring constructor.
+ * @param service Keystore service.
+ */
+ @Autowired
+ public KeyStoreController(KeyStoreService service) {
+ this.service = service;
+ }
+
+ /**
+ * Create a new temporary key.
+ * @param request Request for temporary key.
+ * @return Response with temporary key.
+ * @throws PowerAuthTemporaryKeyException In case temporary key cannot be returned.
+ */
+ @PostMapping("create")
+ public ObjectResponse fetchTemporaryKey(@RequestBody ObjectRequest request) throws PowerAuthTemporaryKeyException {
+ if (request == null) {
+ logger.warn("Null request while fetching temporary key");
+ throw new PowerAuthTemporaryKeyException();
+ }
+ final TemporaryKeyRequest requestObject = request.getRequestObject();
+ if (requestObject == null) {
+ logger.warn("Null request object while fetching temporary key");
+ throw new PowerAuthTemporaryKeyException();
+ }
+ if (!StringUtils.hasLength(requestObject.getJwt())) {
+ logger.warn("Invalid request object with empty JWT while fetching temporary key");
+ throw new PowerAuthTemporaryKeyException();
+ }
+ return new ObjectResponse<>(service.fetchTemporaryKey(requestObject));
+ }
+
+}
diff --git a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/RecoveryController.java b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/RecoveryController.java
index 0e97c72c..caa99019 100644
--- a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/RecoveryController.java
+++ b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/RecoveryController.java
@@ -44,6 +44,9 @@
* PowerAuth protocol versions:
*
* - 3.0
+ * - 3.1
+ * - 3.2
+ * - 3.3
*
*
* @author Roman Strobl, roman.strobl@wultra.com
@@ -85,8 +88,7 @@ public EciesEncryptedResponse confirmRecoveryCode(@RequestBody EciesEncryptedReq
PowerAuthAuthenticationUtil.checkAuthentication(auth);
PowerAuthVersionUtil.checkUnsupportedVersion(auth.getVersion());
- PowerAuthVersionUtil.checkMissingRequiredNonce(auth.getVersion(), request.getNonce());
- PowerAuthVersionUtil.checkMissingRequiredTimestamp(auth.getVersion(), request.getTimestamp());
+ PowerAuthVersionUtil.checkEciesParameters(auth.getVersion(), request);
return recoveryService.confirmRecoveryCode(request, auth);
}
diff --git a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/SecureVaultController.java b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/SecureVaultController.java
index 875c6cc6..f37845b6 100644
--- a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/SecureVaultController.java
+++ b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/SecureVaultController.java
@@ -44,6 +44,9 @@
* PowerAuth protocol versions:
*
* - 3.0
+ * - 3.1
+ * - 3.2
+ * - 3.3
*
*
* @author Roman Strobl, roman.strobl@wultra.com
@@ -100,9 +103,7 @@ public EciesEncryptedResponse unlockVault(
}
PowerAuthVersionUtil.checkUnsupportedVersion(header.getVersion());
- PowerAuthVersionUtil.checkMissingRequiredNonce(header.getVersion(), request.getNonce());
- PowerAuthVersionUtil.checkMissingRequiredTimestamp(header.getVersion(), request.getTimestamp());
-
+ PowerAuthVersionUtil.checkEciesParameters(header.getVersion(), request);
return secureVaultServiceV3.vaultUnlock(header, request, httpServletRequest);
}
diff --git a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/ServerStatusController.java b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/ServerStatusController.java
index 9e422a91..7bc046f1 100644
--- a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/ServerStatusController.java
+++ b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/ServerStatusController.java
@@ -22,6 +22,8 @@
import io.getlime.core.rest.model.base.response.ObjectResponse;
import io.getlime.security.powerauth.rest.api.model.response.ServerStatusResponse;
import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.info.BuildProperties;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@@ -35,6 +37,7 @@
* 3.0
* 3.1
* 3.2
+ * 3.3
*
*
* @author Petr Dvorak, petr@wultra.com
@@ -44,6 +47,13 @@
@Slf4j
public class ServerStatusController {
+ private BuildProperties buildProperties;
+
+ @Autowired(required = false)
+ public void setBuildProperties(BuildProperties buildProperties) {
+ this.buildProperties = buildProperties;
+ }
+
/**
* Obtain server status.
* @return Server status.
@@ -51,7 +61,17 @@ public class ServerStatusController {
@PostMapping("status")
public ObjectResponse getServerStatus() {
final long serverTime = new Date().getTime();
- final ServerStatusResponse response = new ServerStatusResponse(serverTime);
+ final String version;
+ final String name;
+ if (buildProperties != null) {
+ version = buildProperties.getVersion();
+ name = buildProperties.getName();
+ } else {
+ name = "UNKNOWN";
+ version = "UNKNOWN";
+ }
+ final ServerStatusResponse.Application application = new ServerStatusResponse.Application(name, version);
+ final ServerStatusResponse response = new ServerStatusResponse(serverTime, application);
return new ObjectResponse<>(response);
}
diff --git a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/SignatureController.java b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/SignatureController.java
index c54a8645..6bbbba87 100644
--- a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/SignatureController.java
+++ b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/SignatureController.java
@@ -36,6 +36,9 @@
* PowerAuth protocol versions:
*
* - 3.0
+ * - 3.1
+ * - 3.2
+ * - 3.3
*
*
* @author Roman Strobl, roman.strobl@wultra.com
diff --git a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/TokenController.java b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/TokenController.java
index 8498a691..3d492be8 100644
--- a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/TokenController.java
+++ b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/TokenController.java
@@ -47,6 +47,9 @@
* PowerAuth protocol versions:
*
* - 3.0
+ * - 3.1
+ * - 3.2
+ * - 3.3
*
*
* @author Petr Dvorak, petr@wultra.com
@@ -92,8 +95,7 @@ public EciesEncryptedResponse createToken(@RequestBody EciesEncryptedRequest req
PowerAuthAuthenticationUtil.checkAuthentication(auth);
PowerAuthVersionUtil.checkUnsupportedVersion(auth.getVersion());
- PowerAuthVersionUtil.checkMissingRequiredNonce(auth.getVersion(), request.getNonce());
- PowerAuthVersionUtil.checkMissingRequiredTimestamp(auth.getVersion(), request.getTimestamp());
+ PowerAuthVersionUtil.checkEciesParameters(auth.getVersion(), request);
return tokenServiceV3.createToken(request, auth);
}
diff --git a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/UpgradeController.java b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/UpgradeController.java
index 4fb94ea8..8c3105c8 100644
--- a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/UpgradeController.java
+++ b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/UpgradeController.java
@@ -46,6 +46,10 @@
* PowerAuth protocol versions:
*
* - 3.0
+ * - 3.1
+ * - 3.2
+ * - 3.3
+ *
*
*
* @author Roman Strobl, roman.strobl@wultra
@@ -98,8 +102,7 @@ public EciesEncryptedResponse upgradeStart(@RequestBody EciesEncryptedRequest re
}
PowerAuthVersionUtil.checkUnsupportedVersion(header.getVersion());
- PowerAuthVersionUtil.checkMissingRequiredNonce(header.getVersion(), request.getNonce());
- PowerAuthVersionUtil.checkMissingRequiredTimestamp(header.getVersion(), request.getTimestamp());
+ PowerAuthVersionUtil.checkEciesParameters(header.getVersion(), request);
return upgradeService.upgradeStart(request, header);
diff --git a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/UserInfoController.java b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/UserInfoController.java
index f922524b..965da52a 100644
--- a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/UserInfoController.java
+++ b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/UserInfoController.java
@@ -42,6 +42,7 @@
* 3.0
* 3.1
* 3.2
+ * 3.3
*
*
* @author Petr Dvorak, petr@wultra.com
diff --git a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/PowerAuthExceptionHandler.java b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/PowerAuthExceptionHandler.java
index 20635bd2..cbc99f6f 100644
--- a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/PowerAuthExceptionHandler.java
+++ b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/PowerAuthExceptionHandler.java
@@ -132,4 +132,16 @@ public class PowerAuthExceptionHandler {
return new ErrorResponse(ex.getDefaultCode(), ex.getMessage());
}
+ /**
+ * Handle PowerAuthTemporaryKeyException exceptions.
+ * @param ex Exception instance.
+ * @return Error response.
+ */
+ @ExceptionHandler(value = PowerAuthTemporaryKeyException.class)
+ @ResponseStatus(value = HttpStatus.BAD_REQUEST)
+ public @ResponseBody ErrorResponse handlePowerAuthTemporaryKeyException(PowerAuthTemporaryKeyException ex) {
+ logger.warn(ex.getMessage(), ex);
+ return new ErrorResponse(ex.getDefaultCode(), ex.getDefaultError());
+ }
+
}
diff --git a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/ActivationService.java b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/ActivationService.java
index 9613d9ac..267a558f 100644
--- a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/ActivationService.java
+++ b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/ActivationService.java
@@ -127,6 +127,7 @@ public ActivationLayer1Response createActivation(ActivationLayer1Request request
final String applicationKey = eciesContext.getApplicationKey();
final EciesEncryptedRequest activationData = request.getActivationData();
+ final String temporaryKeyId = activationData.getTemporaryKeyId();
final String ephemeralPublicKey = activationData.getEphemeralPublicKey();
final String encryptedData = activationData.getEncryptedData();
final String mac = activationData.getMac();
@@ -161,6 +162,7 @@ public ActivationLayer1Response createActivation(ActivationLayer1Request request
prepareRequest.setActivationCode(activationCode);
prepareRequest.setApplicationKey(applicationKey);
prepareRequest.setGenerateRecoveryCodes(shouldGenerateRecoveryCodes(identity, customAttributes, context));
+ prepareRequest.setTemporaryKeyId(temporaryKeyId);
prepareRequest.setEphemeralPublicKey(ephemeralPublicKey);
prepareRequest.setEncryptedData(encryptedData);
prepareRequest.setMac(mac);
@@ -285,6 +287,7 @@ public ActivationLayer1Response createActivation(ActivationLayer1Request request
createRequest.setGenerateRecoveryCodes(shouldGenerateRecoveryCodes);
createRequest.setMaxFailureCount(maxFailedCount);
createRequest.setApplicationKey(applicationKey);
+ createRequest.setTemporaryKeyId(temporaryKeyId);
createRequest.setEphemeralPublicKey(ephemeralPublicKey);
createRequest.setEncryptedData(encryptedData);
createRequest.setMac(mac);
@@ -393,6 +396,7 @@ public ActivationLayer1Response createActivation(ActivationLayer1Request request
recoveryRequest.setGenerateRecoveryCodes(shouldGenerateRecoveryCodes);
recoveryRequest.setApplicationKey(applicationKey);
recoveryRequest.setMaxFailureCount(maxFailedCount);
+ recoveryRequest.setTemporaryKeyId(temporaryKeyId);
recoveryRequest.setEphemeralPublicKey(ephemeralPublicKey);
recoveryRequest.setEncryptedData(encryptedData);
recoveryRequest.setMac(mac);
diff --git a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/KeyStoreService.java b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/KeyStoreService.java
new file mode 100644
index 00000000..a0db61a8
--- /dev/null
+++ b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/KeyStoreService.java
@@ -0,0 +1,84 @@
+/*
+ * PowerAuth integration libraries for RESTful API applications, examples 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 io.getlime.security.powerauth.rest.api.spring.service;
+
+import com.wultra.security.powerauth.client.PowerAuthClient;
+import com.wultra.security.powerauth.client.model.error.PowerAuthClientException;
+import com.wultra.security.powerauth.client.model.request.TemporaryPublicKeyRequest;
+import com.wultra.security.powerauth.client.model.response.TemporaryPublicKeyResponse;
+import io.getlime.security.powerauth.rest.api.model.request.TemporaryKeyRequest;
+import io.getlime.security.powerauth.rest.api.model.response.TemporaryKeyResponse;
+import io.getlime.security.powerauth.rest.api.spring.exception.PowerAuthTemporaryKeyException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * Key store service for obtaining temporary encryption keys.
+ *
+ * @author Petr Dvorak, petr@wultra.com
+ */
+@Service
+public class KeyStoreService {
+
+ private static final Logger logger = LoggerFactory.getLogger(KeyStoreService.class);
+
+ private final PowerAuthClient powerAuthClient;
+ private final HttpCustomizationService httpCustomizationService;
+
+ /**
+ * Default autowiring constructor.
+ * @param powerAuthClient PowerAuth Client
+ * @param httpCustomizationService Customization service.
+ */
+ @Autowired
+ public KeyStoreService(PowerAuthClient powerAuthClient, HttpCustomizationService httpCustomizationService) {
+ this.powerAuthClient = powerAuthClient;
+ this.httpCustomizationService = httpCustomizationService;
+ }
+
+ /**
+ * Fetch a temporary public key with provided parameters.
+ * @param request Temporary public key request.
+ * @return Response with temporary public key.
+ * @throws PowerAuthTemporaryKeyException In case internal API call fails.
+ */
+ public TemporaryKeyResponse fetchTemporaryKey(TemporaryKeyRequest request) throws PowerAuthTemporaryKeyException {
+ try {
+ final TemporaryPublicKeyRequest publicKeyRequest = new TemporaryPublicKeyRequest();
+ publicKeyRequest.setJwt(request.getJwt());
+
+ final TemporaryPublicKeyResponse temporaryPublicKeyResponse = powerAuthClient.fetchTemporaryPublicKey(
+ publicKeyRequest,
+ httpCustomizationService.getQueryParams(),
+ httpCustomizationService.getHttpHeaders()
+ );
+
+ final TemporaryKeyResponse response = new TemporaryKeyResponse();
+ response.setJwt(temporaryPublicKeyResponse.getJwt());
+ return response;
+ } catch (PowerAuthClientException ex) {
+ logger.warn("PowerAuth fetching temporary key failed, error: {}", ex.getMessage());
+ logger.debug(ex.getMessage(), ex);
+ throw new PowerAuthTemporaryKeyException();
+ }
+ }
+}
diff --git a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/RecoveryService.java b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/RecoveryService.java
index 0ea79a6f..a8ede082 100644
--- a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/RecoveryService.java
+++ b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/RecoveryService.java
@@ -83,6 +83,7 @@ public EciesEncryptedResponse confirmRecoveryCode(EciesEncryptedRequest request,
final ConfirmRecoveryCodeRequest confirmRequest = new ConfirmRecoveryCodeRequest();
confirmRequest.setActivationId(activationId);
confirmRequest.setApplicationKey(applicationKey);
+ confirmRequest.setTemporaryKeyId(request.getTemporaryKeyId());
confirmRequest.setEphemeralPublicKey(request.getEphemeralPublicKey());
confirmRequest.setEncryptedData(request.getEncryptedData());
confirmRequest.setMac(request.getMac());
diff --git a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/SecureVaultService.java b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/SecureVaultService.java
index f0304ba6..98ed816b 100644
--- a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/SecureVaultService.java
+++ b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/SecureVaultService.java
@@ -112,6 +112,7 @@ public EciesEncryptedResponse vaultUnlock(PowerAuthSignatureHttpHeader header,
unlockRequest.setSignatureType(signatureType);
unlockRequest.setSignatureVersion(signatureVersion);
unlockRequest.setSignedData(data);
+ unlockRequest.setTemporaryKeyId(request.getTemporaryKeyId());
unlockRequest.setEphemeralPublicKey(request.getEphemeralPublicKey());
unlockRequest.setEncryptedData(request.getEncryptedData());
unlockRequest.setMac(request.getMac());
diff --git a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/TokenService.java b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/TokenService.java
index 56312032..cd409ff7 100644
--- a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/TokenService.java
+++ b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/TokenService.java
@@ -101,6 +101,7 @@ public EciesEncryptedResponse createToken(EciesEncryptedRequest request,
final CreateTokenRequest tokenRequest = new CreateTokenRequest();
tokenRequest.setActivationId(activationId);
tokenRequest.setApplicationKey(applicationKey);
+ tokenRequest.setTemporaryKeyId(request.getTemporaryKeyId());
tokenRequest.setEphemeralPublicKey(request.getEphemeralPublicKey());
tokenRequest.setEncryptedData(request.getEncryptedData());
tokenRequest.setMac(request.getMac());
diff --git a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/UpgradeService.java b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/UpgradeService.java
index c8bfa948..2e34f45f 100644
--- a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/UpgradeService.java
+++ b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/UpgradeService.java
@@ -97,6 +97,7 @@ public EciesEncryptedResponse upgradeStart(EciesEncryptedRequest request, PowerA
final StartUpgradeRequest upgradeRequest = new StartUpgradeRequest();
upgradeRequest.setActivationId(activationId);
upgradeRequest.setApplicationKey(applicationKey);
+ upgradeRequest.setTemporaryKeyId(request.getTemporaryKeyId());
upgradeRequest.setEphemeralPublicKey(request.getEphemeralPublicKey());
upgradeRequest.setEncryptedData(request.getEncryptedData());
upgradeRequest.setMac(request.getMac());
diff --git a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/util/PowerAuthVersionUtil.java b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/util/PowerAuthVersionUtil.java
index cad9ecf7..9537df46 100644
--- a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/util/PowerAuthVersionUtil.java
+++ b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/util/PowerAuthVersionUtil.java
@@ -19,6 +19,7 @@
*/
package io.getlime.security.powerauth.rest.api.spring.util;
+import io.getlime.security.powerauth.rest.api.model.request.EciesEncryptedRequest;
import io.getlime.security.powerauth.rest.api.spring.exception.authentication.PowerAuthInvalidRequestException;
import lombok.extern.slf4j.Slf4j;
@@ -47,7 +48,7 @@ private PowerAuthVersionUtil() {
/**
* Set containing all the supported versions of PowerAuth.
*/
- private static final Set SUPPORTED_VERSIONS = Set.of("3.0", "3.1", "3.2");
+ private static final Set SUPPORTED_VERSIONS = Set.of("3.0", "3.1", "3.2", "3.3");
/**
* Check if the provided version string is "3.0".
@@ -69,6 +70,16 @@ private static boolean isVersion3_1(final String version) {
return "3.1".equals(version);
}
+ /**
+ * Check if the provided version string is "3.2".
+ *
+ * @param version Version string to be checked.
+ * @return true if the version is "3.2", false otherwise.
+ */
+ private static boolean isVersion3_2(final String version) {
+ return "3.2".equals(version);
+ }
+
/**
* Checks if the provided PowerAuth protocol version is unsupported.
* Throws an exception if the version is unsupported.
@@ -113,6 +124,35 @@ public static void checkMissingRequiredTimestamp(String version, Long timestamp)
}
}
+ /**
+ * Checks if temporary key ID is missing for the provided PowerAuth protocol version.
+ * Throws an exception if the temporary key ID is required and missing.
+ *
+ * @param version Version string to be checked.
+ * @param temporaryKeyId Temporary key ID value to be verified.
+ * @throws PowerAuthInvalidRequestException If timestamp is required and missing.
+ */
+ public static void checkMissingRequiredTemporaryKeyId(String version, String temporaryKeyId) throws PowerAuthInvalidRequestException {
+ if (isMissingRequiredTemporaryKeyId(version, temporaryKeyId)) {
+ logger.warn("Missing temporary key ID in ECIES request data for version {}", version);
+ throw new PowerAuthInvalidRequestException("Missing temporary kdy ID in ECIES request data for version " + version);
+ }
+ }
+
+ /**
+ * Checks if required ECIES parameters are missing for the provided PowerAuth protocol version.
+ * Throws an exception if the required parameter is missing.
+ *
+ * @param version Version string to be checked.
+ * @param request Request to be verified.
+ * @throws PowerAuthInvalidRequestException If timestamp is required and missing.
+ */
+ public static void checkEciesParameters(String version, EciesEncryptedRequest request) throws PowerAuthInvalidRequestException {
+ checkMissingRequiredNonce(version, request.getNonce());
+ checkMissingRequiredTimestamp(version, request.getTimestamp());
+ checkMissingRequiredTemporaryKeyId(version, request.getTemporaryKeyId());
+ }
+
/**
* Checks if the provided PowerAuth protocol version is unsupported.
*
@@ -146,4 +186,19 @@ private static boolean isMissingRequiredTimestamp(String version, Long timestamp
!isVersion3_0(version) &&
!isVersion3_1(version);
}
+
+ /**
+ * Checks if temporary key ID is missing for the provided PowerAuth protocol version.
+ *
+ * @param version Version string to be checked.
+ * @param temporaryKeyId Temporary key ID
+ * @return true if temporary key ID is required and missing, false otherwise.
+ */
+ private static boolean isMissingRequiredTemporaryKeyId(String version, String temporaryKeyId) {
+ return temporaryKeyId == null &&
+ !isVersion3_0(version) &&
+ !isVersion3_1(version) &&
+ !isVersion3_2(version);
+ }
+
}
diff --git a/powerauth-restful-security-spring/src/test/java/io/getlime/security/powerauth/rest/api/spring/PowerAuthVersionUtilTest.java b/powerauth-restful-security-spring/src/test/java/io/getlime/security/powerauth/rest/api/spring/PowerAuthVersionUtilTest.java
index 6d15f81a..73b67fb3 100644
--- a/powerauth-restful-security-spring/src/test/java/io/getlime/security/powerauth/rest/api/spring/PowerAuthVersionUtilTest.java
+++ b/powerauth-restful-security-spring/src/test/java/io/getlime/security/powerauth/rest/api/spring/PowerAuthVersionUtilTest.java
@@ -23,6 +23,8 @@
import io.getlime.security.powerauth.rest.api.spring.util.PowerAuthVersionUtil;
import org.junit.jupiter.api.Test;
+import java.util.UUID;
+
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertThrows;
@@ -62,4 +64,12 @@ void testMissingRequiredTimestamp() {
assertDoesNotThrow(() -> PowerAuthVersionUtil.checkMissingRequiredTimestamp("3.1", null));
assertDoesNotThrow(() -> PowerAuthVersionUtil.checkMissingRequiredTimestamp("3.2", 1630234567890L));
}
+
+ @Test
+ void testMissingRequiredTemporaryKeyId() {
+ assertThrows(PowerAuthInvalidRequestException.class, () -> PowerAuthVersionUtil.checkMissingRequiredTemporaryKeyId("3.3", null));
+ assertDoesNotThrow(() -> PowerAuthVersionUtil.checkMissingRequiredTemporaryKeyId("3.1", null));
+ assertDoesNotThrow(() -> PowerAuthVersionUtil.checkMissingRequiredTemporaryKeyId("3.2", null));
+ assertDoesNotThrow(() -> PowerAuthVersionUtil.checkMissingRequiredTemporaryKeyId("3.3", UUID.randomUUID().toString()));
+ }
}
\ No newline at end of file