diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..81dcf707 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,11 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates + +version: 2 +updates: + - package-ecosystem: "maven" + directory: "/" + schedule: + interval: "weekly" diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index dee72c9e..d750a715 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -1,67 +1,22 @@ -# For most projects, this workflow file will not need changing; you simply need -# to commit it to your repository. -# -# You may wish to alter this file to override the set of languages analyzed, -# or to provide custom queries or build logic. -# -# ******** NOTE ******** -# We have attempted to detect the languages in your repository. Please check -# the `language` matrix defined below to confirm you have the correct set of -# supported CodeQL languages. -# name: "CodeQL" on: + workflow_dispatch: push: - branches: [ develop, master ] + branches: [ 'develop', 'master', 'releases/**' ] pull_request: # The branches below must be a subset of the branches above - branches: [ develop ] + branches: [ 'develop', 'master', 'releases/**' ] schedule: - - cron: '27 4 * * 2' + - cron: '0 2 * * 4' jobs: - analyze: - name: Analyze - runs-on: ubuntu-latest - - strategy: - fail-fast: false - matrix: - language: [ 'java' ] - # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] - # Learn more: - # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed - - steps: - - name: Checkout repository - uses: actions/checkout@v2 - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v1 - with: - languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - # queries: ./path/to/local/query, your-org/your-repo/queries@main - - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - uses: github/codeql-action/autobuild@v1 - - # ℹī¸ Command-line programs to run using the OS shell. - # 📚 https://git.io/JvXDl - - # ✏ī¸ If the Autobuild fails above, remove it and uncomment the following three lines - # and modify them (or add more) to build your code if your project - # uses a compiled language - - #- run: | - # make bootstrap - # make release - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 + codeql-analysis: + uses: wultra/wultra-infrastructure/.github/workflows/codeql-analysis.yml@develop + secrets: inherit + with: + languages: "['java']" + # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] + # Use only 'java' to analyze code written in Java, Kotlin or both + # Use only 'javascript' to analyze code written in JavaScript, TypeScript or both + # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support \ No newline at end of file diff --git a/.github/workflows/owas-dependecy-check.yml b/.github/workflows/owas-dependecy-check.yml deleted file mode 100644 index c79178b2..00000000 --- a/.github/workflows/owas-dependecy-check.yml +++ /dev/null @@ -1,12 +0,0 @@ -name: Run OWASP Dependency Check -on: - workflow_dispatch: - - push: - branches: - - 'develop' - -jobs: - owasp-check: - uses: wultra/wultra-infrastructure/.github/workflows/owasp-dependency-check.yml@develop - secrets: inherit \ No newline at end of file diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index cfa25b4b..00000000 --- a/.travis.yml +++ /dev/null @@ -1,23 +0,0 @@ -language: java -jdk: - - openjdk11 -branches: - only: - - master - - coverity_scan -env: - global: - - secure: "fS5NtYWaRbacaor5Nc8W+/5mFdyirXRVmkTZ0RO6zgmtZCBKnXfOFKCLXMZ2oHCTkyicJASPdPBxfKkxMVMUR+Dr0HjqicAY1/tERS8JYYMgreDP2Na6OvAmKNB1kulBPC2z5kJihaKL69gbqbLJi2qv/Juv/LDQJgOqEVmEdhMHuQ6X9HG51DGAQBDDTVS3j5diVaYW31pa4b7FNgU58pClnSfdaeUYMdKQjQHdSOgvMCP49TnDKBc4ZmtVmrrusM4yPpbLQeNJK0m79kVY1kN8camHKyDn85CsV1S4qMj6ylHgQ90UaATq/yH97gkrV0Vm/XbQEAYN/RpkEsW/Gm5bvPY5CtlXG2lUkbzPYgutxtVUKrRqd4MDc6B/Yxs/ADrmNtKCu2rnTbxlKKpe/wtfxRecP4+QmPx3bbgeHEUt8aDqZvSwNtgaUeY3jTb/vYwkm13VNq8jE7HvOX2Aaq1awbz0xC9aeEihc4xfmMOFaS5pK9ANDqND9EWHamICEonlYU7gNSYgKXfTgPJvUaZDMVrhlACl1c62sucvZaE7bn17mF/5OOj6RHYllM5WjbCmBgLO5sUbWaBJwWLnYSU/MKtoISPToTEsW1wWAYXeQvjY80nAML4dgb4lTqqYy96T3/QrGSXwZ4scVInjxtdpf4bHkElqPA/KLEzEqZ0=" - -before_install: - - echo -n | openssl s_client -connect https://scan.coverity.com:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' | sudo tee -a /etc/ssl/certs/ca- - -addons: - coverity_scan: - project: - name: "wultra/powerauth-restful-integration" - description: "Build submitted via Travis CI" - notification_email: roman.strobl@wultra.com - build_command_prepend: "mvn clean" - build_command: "mvn -DskipTests=true compile" - branch_pattern: coverity_scan \ No newline at end of file diff --git a/docs/RESTful-API-for-Spring.md b/docs/RESTful-API-for-Spring.md index 02f42ce5..81ff89e9 100644 --- a/docs/RESTful-API-for-Spring.md +++ b/docs/RESTful-API-for-Spring.md @@ -394,16 +394,16 @@ You can encrypt data in `application` scope (non-personalized) using following p public class EncryptedDataExchangeController { @RequestMapping(value = "application", method = RequestMethod.POST) - @PowerAuthEncryption(scope = EciesScope.APPLICATION_SCOPE) + @PowerAuthEncryption(scope = EncryptionScope.APPLICATION_SCOPE) public DataExchangeResponse exchangeInApplicationScope(@EncryptedRequestBody DataExchangeRequest request, - EciesEncryptionContext eciesContext) throws PowerAuthEncryptionException { + EncryptionContext encryptionContext) throws PowerAuthEncryptionException { - if (eciesContext == null) { + if (encryptionContext == null) { throw new PowerAuthEncryptionException(); } // Return a slightly different String containing original data in response - return new DataExchangeResponse("Server successfully decrypted signed data: " + (request == null ? "''" : request.getData()) + ", scope: " + eciesContext.getEciesScope()); + return new DataExchangeResponse("Server successfully decrypted signed data: " + (request == null ? "''" : request.getData()) + ", scope: " + encryptionContext.getEncryptionScope()); } } ``` @@ -422,16 +422,16 @@ You can encrypt data in `activation` scope (personalized) using following patter public class EncryptedDataExchangeController { @RequestMapping(value = "activation", method = RequestMethod.POST) - @PowerAuthEncryption(scope = EciesScope.ACTIVATION_SCOPE) + @PowerAuthEncryption(scope = EncryptionScope.ACTIVATION_SCOPE) public DataExchangeResponse exchangeInActivationScope(@EncryptedRequestBody DataExchangeRequest request, - EciesEncryptionContext eciesContext) throws PowerAuthEncryptionException { + EncryptionContext encryptionContext) throws PowerAuthEncryptionException { - if (eciesContext == null) { + if (encryptionContext == null) { throw new PowerAuthEncryptionException(); } // Return a slightly different String containing original data in response - return new DataExchangeResponse("Server successfully decrypted signed data: " + (request == null ? "''" : request.getData()) + ", scope: " + eciesContext.getEciesScope()); + return new DataExchangeResponse("Server successfully decrypted signed data: " + (request == null ? "''" : request.getData()) + ", scope: " + encryptionContext.getEncryptionScope()); } } ``` @@ -451,16 +451,16 @@ public class EncryptedDataExchangeController { @RequestMapping(value = "signed", method = RequestMethod.POST) @PowerAuth(resourceId = "/exchange/signed") - @PowerAuthEncryption(scope = EciesScope.ACTIVATION_SCOPE) + @PowerAuthEncryption(scope = EncryptionScope.ACTIVATION_SCOPE) public DataExchangeResponse exchangeSignedAndEncryptedData(@EncryptedRequestBody DataExchangeRequest request, - EciesEncryptionContext eciesContext, + EncryptionContext encryptionContext, PowerAuthApiAuthentication auth) throws PowerAuthAuthenticationException, PowerAuthEncryptionException { if (auth == null || auth.getUserId() == null) { throw new PowerAuthSignatureInvalidException(); } - if (eciesContext == null) { + if (encryptionContext == null) { throw new PowerAuthEncryptionException(); } diff --git a/docs/Readme.md b/docs/Readme.md index 2d1b8b95..07fb8041 100644 --- a/docs/Readme.md +++ b/docs/Readme.md @@ -1,12 +1,12 @@ # PowerAuth RESTful Integration Libraries -In order to easily secure your RESTful APIs with PowerAuth, you can use our easy to use integration libraries for Java technology. Integration libraries are responsible for connecting to PowerAuth Server and for publishing required endpoints toward mobile apps. +In order to easily secure your RESTful APIs with PowerAuth, you can use our integration libraries for Spring technology. Integration libraries are responsible for connecting to PowerAuth Server and for publishing required endpoints toward mobile apps. -**Integration Tutorials** +## Integration Tutorials - [Introduction](./Introduction.md) - [Build Secure RESTful API (Spring)](./RESTful-API-for-Spring.md) -**Deployment Tutorials** +## Deployment Tutorials - [Deploy PowerAuth REST API Standalone Application](./Deploying-PowerAuth-Standard-RESTful-API.md) diff --git a/lombok.config b/lombok.config new file mode 100644 index 00000000..2bb794fd --- /dev/null +++ b/lombok.config @@ -0,0 +1 @@ +lombok.log.fieldName=logger diff --git a/pom.xml b/pom.xml index d8d0aa6b..c2303f8b 100644 --- a/pom.xml +++ b/pom.xml @@ -28,7 +28,7 @@ io.getlime.security powerauth-restful-integration-parent - 1.4.0 + 1.5.0 pom 2017 @@ -75,21 +75,20 @@ UTF-8 - 1.8 - 1.8 + 17 + ${java.version} + ${java.version} 3.3.0 - 3.0.0 - 3.4.1 - 3.2.1 - 3.3.2 - 4.0.1 - 2.6.14 + 3.1.1 + 3.6.0 + 3.3.0 + 3.4.0 + 3.1.3 1.10.0 - 1.72 - 1.6.0 - 1.4.0 - 1.4.0 - 1.4.0 + 1.76 + 1.7.0 + 1.5.0 + 1.5.1 @@ -115,6 +114,18 @@ ${project.version} + + io.getlime.core + annotations + ${wultra-core.version} + + + + io.getlime.core + rest-model-base + ${wultra-core.version} + + org.bouncycastle @@ -124,6 +135,14 @@ + + + org.projectlombok + lombok + provided + + + diff --git a/powerauth-restful-model/pom.xml b/powerauth-restful-model/pom.xml index 353620ce..3ee6c82c 100644 --- a/powerauth-restful-model/pom.xml +++ b/powerauth-restful-model/pom.xml @@ -30,14 +30,13 @@ io.getlime.security powerauth-restful-integration-parent - 1.4.0 + 1.5.0 io.getlime.core rest-model-base - ${rest-model-base.version} diff --git a/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/v3/TokenRemoveResponse.java b/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/entity/UserInfoStage.java similarity index 54% rename from powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/v3/TokenRemoveResponse.java rename to powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/entity/UserInfoStage.java index 5d30fb68..aaf5072a 100644 --- a/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/v3/TokenRemoveResponse.java +++ b/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/entity/UserInfoStage.java @@ -2,7 +2,7 @@ * PowerAuth integration libraries for RESTful API applications, examples and * related software components * - * Copyright (C) 2018 Wultra s.r.o. + * 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 @@ -17,34 +17,34 @@ * 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.v3; +package io.getlime.security.powerauth.rest.api.model.entity; /** - * Class representing response transport object for token removal. + * Information about where the user info is requested from, i.e., during the activation, or via a separate user info + * endpoint. * * @author Petr Dvorak, petr@wultra.com */ -public class TokenRemoveResponse { +public enum UserInfoStage { /** - * Token ID of the token to be removed. + * The user info was requested from the activation process carried out via activation code. */ - private String tokenId; + ACTIVATION_PROCESS_ACTIVATION_CODE, /** - * Get token ID. - * @return Token ID. + * The user info was requested from the activation process carried out via custom attributes. */ - public String getTokenId() { - return tokenId; - } + ACTIVATION_PROCESS_CUSTOM, /** - * Set token ID. - * @param tokenId Token ID. + * The user info was requested from the activation process carried out via recovery codes. */ - public void setTokenId(String tokenId) { - this.tokenId = tokenId; - } + ACTIVATION_PROCESS_RECOVERY, + + /** + * The user info was requested from the user info endpoint. + */ + USER_INFO_ENDPOINT } diff --git a/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/v3/ActivationLayer1Request.java b/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/ActivationLayer1Request.java similarity index 97% rename from powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/v3/ActivationLayer1Request.java rename to powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/ActivationLayer1Request.java index 892e74ec..057822b3 100644 --- a/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/v3/ActivationLayer1Request.java +++ b/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/ActivationLayer1Request.java @@ -17,7 +17,7 @@ * 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.v3; +package io.getlime.security.powerauth.rest.api.model.request; import io.getlime.security.powerauth.rest.api.model.entity.ActivationType; diff --git a/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/v3/ActivationLayer2Request.java b/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/ActivationLayer2Request.java similarity index 98% rename from powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/v3/ActivationLayer2Request.java rename to powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/ActivationLayer2Request.java index 431626cd..efafe64b 100644 --- a/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/v3/ActivationLayer2Request.java +++ b/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/ActivationLayer2Request.java @@ -17,7 +17,7 @@ * 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.v3; +package io.getlime.security.powerauth.rest.api.model.request; /** * Request object for activation layer 2 request. diff --git a/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/v3/ActivationStatusRequest.java b/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/ActivationStatusRequest.java similarity index 96% rename from powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/v3/ActivationStatusRequest.java rename to powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/ActivationStatusRequest.java index 98875fcb..2004cfb6 100644 --- a/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/v3/ActivationStatusRequest.java +++ b/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/ActivationStatusRequest.java @@ -17,7 +17,7 @@ * 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.v3; +package io.getlime.security.powerauth.rest.api.model.request; /** * Request object for /pa/v3/activation/status end-point. diff --git a/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/v3/ConfirmRecoveryRequestPayload.java b/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/ConfirmRecoveryRequestPayload.java similarity index 95% rename from powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/v3/ConfirmRecoveryRequestPayload.java rename to powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/ConfirmRecoveryRequestPayload.java index 9bf9b8b9..1258d514 100644 --- a/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/v3/ConfirmRecoveryRequestPayload.java +++ b/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/ConfirmRecoveryRequestPayload.java @@ -17,7 +17,7 @@ * 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.v3; +package io.getlime.security.powerauth.rest.api.model.request; /** * Request object for confirm recovery code ECIES payload. diff --git a/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/v3/EciesEncryptedRequest.java b/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/EciesEncryptedRequest.java similarity index 84% rename from powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/v3/EciesEncryptedRequest.java rename to powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/EciesEncryptedRequest.java index 001876d6..bc53a5d4 100644 --- a/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/v3/EciesEncryptedRequest.java +++ b/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/EciesEncryptedRequest.java @@ -17,7 +17,7 @@ * 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.v3; +package io.getlime.security.powerauth.rest.api.model.request; /** * Request object with data encrypted by ECIES encryption. @@ -30,6 +30,7 @@ public class EciesEncryptedRequest { private String encryptedData; private String mac; private String nonce; + private Long timestamp; /** * Get Base64 encoded ephemeral public key. @@ -94,4 +95,20 @@ public String getNonce() { public void setNonce(String nonce) { this.nonce = nonce; } + + /** + * Get request timestamp as unix timestamp in milliseconds. + * @return Request timestamp. + */ + public Long getTimestamp() { + return timestamp; + } + + /** + * Set request timestamp as unix timestamp in milliseconds. + * @param timestamp Request timestamp. + */ + public void setTimestamp(Long timestamp) { + this.timestamp = timestamp; + } } diff --git a/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/v2/TokenRemoveRequest.java b/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/TokenRemoveRequest.java similarity index 95% rename from powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/v2/TokenRemoveRequest.java rename to powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/TokenRemoveRequest.java index 5e6fbb61..231e828b 100644 --- a/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/v2/TokenRemoveRequest.java +++ b/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/TokenRemoveRequest.java @@ -17,7 +17,7 @@ * 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.v2; +package io.getlime.security.powerauth.rest.api.model.request; /** * Class representing request transport object for token removal. diff --git a/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/v2/ActivationRemoveResponse.java b/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/UserInfoRequest.java similarity index 59% rename from powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/v2/ActivationRemoveResponse.java rename to powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/UserInfoRequest.java index 18535673..f9fa9b3f 100644 --- a/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/v2/ActivationRemoveResponse.java +++ b/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/UserInfoRequest.java @@ -2,7 +2,7 @@ * PowerAuth integration libraries for RESTful API applications, examples and * related software components * - * Copyright (C) 2018 Wultra s.r.o. + * 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 @@ -17,32 +17,12 @@ * 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.v2; +package io.getlime.security.powerauth.rest.api.model.request; /** - * Response object for /pa/activation/remove end-point + * Request object for user info endpoint. * * @author Petr Dvorak, petr@wultra.com - * */ -public class ActivationRemoveResponse { - - private String activationId; - - /** - * Get activation ID - * @return Activation ID - */ - public String getActivationId() { - return activationId; - } - - /** - * Set activation ID - * @param activationId Activation ID - */ - public void setActivationId(String activationId) { - this.activationId = activationId; - } - +public class UserInfoRequest { } diff --git a/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/v3/VaultUnlockRequestPayload.java b/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/VaultUnlockRequestPayload.java similarity index 95% rename from powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/v3/VaultUnlockRequestPayload.java rename to powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/VaultUnlockRequestPayload.java index 3f12a1f8..294f3dbb 100644 --- a/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/v3/VaultUnlockRequestPayload.java +++ b/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/VaultUnlockRequestPayload.java @@ -17,7 +17,7 @@ * 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.v3; +package io.getlime.security.powerauth.rest.api.model.request; /** * Request object for vault unlock ECIES payload. diff --git a/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/v2/ActivationCreateCustomRequest.java b/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/v2/ActivationCreateCustomRequest.java deleted file mode 100644 index 2d6c278a..00000000 --- a/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/v2/ActivationCreateCustomRequest.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * PowerAuth integration libraries for RESTful API applications, examples and - * related software components - * - * Copyright (C) 2018 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.v2; - -import java.util.Map; - -/** - * Request object for /pa/activation/direct/create end-point. - * - * Object representing an activation performed with given identity, custom (non-identity related) attributes, and - * PowerAuth activation object. - * - * @author Petr Dvorak, petr@wultra.com - */ -public class ActivationCreateCustomRequest { - - private Map identity; - private Map customAttributes; - private ActivationCreateRequest powerauth; - - /** - * Get identity attributes. - * @return Identity attributes. - */ - public Map getIdentity() { - return identity; - } - - /** - * Set identity attributes. - * @param identity Identity attributes. - */ - public void setIdentity(Map identity) { - this.identity = identity; - } - - /** - * Get custom attributes. - * @return Custom attributes. - */ - public Map getCustomAttributes() { - return customAttributes; - } - - /** - * Set custom attributes. - * @param customAttributes Custom attributes. - */ - public void setCustomAttributes(Map customAttributes) { - this.customAttributes = customAttributes; - } - - /** - * Get PowerAuth activation data. - * @return PowerAuth activation data. - */ - public ActivationCreateRequest getPowerauth() { - return powerauth; - } - - /** - * Set PowerAuth activation data. - * @param powerauth PowerAuth activation data. - */ - public void setPowerauth(ActivationCreateRequest powerauth) { - this.powerauth = powerauth; - } -} diff --git a/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/v2/ActivationCreateRequest.java b/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/v2/ActivationCreateRequest.java deleted file mode 100644 index 71b0027c..00000000 --- a/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/v2/ActivationCreateRequest.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * PowerAuth integration libraries for RESTful API applications, examples and - * related software components - * - * Copyright (C) 2018 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.v2; - -/** - * Request object for /pa/activation/create end-point. - * - * @author Petr Dvorak, petr@wultra.com - * - */ -public class ActivationCreateRequest { - - private String activationIdShort; - private String activationNonce; - private String ephemeralPublicKey; - private String encryptedDevicePublicKey; - private String activationName; - private String extras; - private String applicationKey; - private String applicationSignature; - - /** - * Get activation ID short. - * @return Activation ID short. - */ - public String getActivationIdShort() { - return activationIdShort; - } - - /** - * Set activation ID short. - * @param activationIdShort Activation ID short. - */ - public void setActivationIdShort(String activationIdShort) { - this.activationIdShort = activationIdShort; - } - - /** - * Get activation nonce. - * @return Activation nonce. - */ - public String getActivationNonce() { - return activationNonce; - } - - /** - * Set activation nonce. - * @param activationNonce Activation nonce. - */ - public void setActivationNonce(String activationNonce) { - this.activationNonce = activationNonce; - } - - /** - * Get the ephemeral public key. - * @return Ephemeral public key. - */ - public String getEphemeralPublicKey() { - return ephemeralPublicKey; - } - - /** - * Set the ephemeral public key. - * @param ephemeralPublicKey Ephemeral public key. - */ - public void setEphemeralPublicKey(String ephemeralPublicKey) { - this.ephemeralPublicKey = ephemeralPublicKey; - } - - /** - * Get encrypted device public key. - * @return cDevicePublicKey - */ - public String getEncryptedDevicePublicKey() { - return encryptedDevicePublicKey; - } - - /** - * Set encrypted device public key. - * @param encryptedDevicePublicKey Encrypted device public key. - */ - public void setEncryptedDevicePublicKey(String encryptedDevicePublicKey) { - this.encryptedDevicePublicKey = encryptedDevicePublicKey; - } - - /** - * Get activation name. - * @return Activation name. - */ - public String getActivationName() { - return activationName; - } - - /** - * Set activation name. - * @param activationName Activation name. - */ - public void setActivationName(String activationName) { - this.activationName = activationName; - } - - /** - * Get extra parameter. - * @return Extra parameter. - */ - public String getExtras() { - return extras; - } - - /** - * Set extra parameter. - * @param extras Extra parameter. - */ - public void setExtras(String extras) { - this.extras = extras; - } - - /** - * Get application key. - * @return Application key. - */ - public String getApplicationKey() { - return applicationKey; - } - - /** - * Set application key. - * @param applicationKey Application key. - */ - public void setApplicationKey(String applicationKey) { - this.applicationKey = applicationKey; - } - - /** - * Get application signature. - * @return Application signature. - */ - public String getApplicationSignature() { - return applicationSignature; - } - - /** - * Set application signature. - * @param applicationSignature Application signature. - */ - public void setApplicationSignature(String applicationSignature) { - this.applicationSignature = applicationSignature; - } - -} diff --git a/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/v2/TokenCreateRequest.java b/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/v2/TokenCreateRequest.java deleted file mode 100644 index 48ec75ad..00000000 --- a/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/v2/TokenCreateRequest.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * PowerAuth integration libraries for RESTful API applications, examples and - * related software components - * - * Copyright (C) 2018 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.v2; - -/** - * Request object for the /pa/token endpoint, that enables fetching token for simple authentication. - * - * @author Petr Dvorak, petr@wultra.com - */ -public class TokenCreateRequest { - - private String ephemeralPublicKey; - - /** - * Get ephemeral public key (Base64 encoded data). - * @return Ephemeral public key. - */ - public String getEphemeralPublicKey() { - return ephemeralPublicKey; - } - - /** - * Set ephemeral public key (Base64 encoded data). - * @param ephemeralPublicKey Ephemeral public key. - */ - public void setEphemeralPublicKey(String ephemeralPublicKey) { - this.ephemeralPublicKey = ephemeralPublicKey; - } -} diff --git a/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/v3/TokenRemoveRequest.java b/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/v3/TokenRemoveRequest.java deleted file mode 100644 index c88dde3a..00000000 --- a/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/v3/TokenRemoveRequest.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * PowerAuth integration libraries for RESTful API applications, examples and - * related software components - * - * Copyright (C) 2018 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.v3; - -/** - * Class representing request transport object for token removal. - * - * @author Petr Dvorak, petr@wultra.com - */ -public class TokenRemoveRequest { - - /** - * Token ID of the token to be removed. - */ - private String tokenId; - - /** - * Get token ID. - * @return Token ID. - */ - public String getTokenId() { - return tokenId; - } - - /** - * Set token ID. - * @param tokenId Token ID. - */ - public void setTokenId(String tokenId) { - this.tokenId = tokenId; - } -} diff --git a/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/v3/ActivationLayer1Response.java b/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/ActivationLayer1Response.java similarity index 80% rename from powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/v3/ActivationLayer1Response.java rename to powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/ActivationLayer1Response.java index a39707d6..5d9b764a 100644 --- a/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/v3/ActivationLayer1Response.java +++ b/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/ActivationLayer1Response.java @@ -17,7 +17,7 @@ * 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.v3; +package io.getlime.security.powerauth.rest.api.model.response; import java.util.Map; @@ -31,6 +31,7 @@ public class ActivationLayer1Response { private EciesEncryptedResponse activationData; private Map customAttributes; + private Map userInfo; /** * Get encrypted activation data. @@ -63,4 +64,20 @@ public Map getCustomAttributes() { public void setCustomAttributes(Map customAttributes) { this.customAttributes = customAttributes; } + + /** + * Get user info as a map of claims. + * @return User info. + */ + public Map getUserInfo() { + return userInfo; + } + + /** + * Set user info via a map of claims. + * @param userInfo User info. + */ + public void setUserInfo(Map userInfo) { + this.userInfo = userInfo; + } } diff --git a/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/v3/ActivationLayer2Response.java b/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/ActivationLayer2Response.java similarity index 97% rename from powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/v3/ActivationLayer2Response.java rename to powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/ActivationLayer2Response.java index 9254d071..43e54ffe 100644 --- a/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/v3/ActivationLayer2Response.java +++ b/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/ActivationLayer2Response.java @@ -17,7 +17,7 @@ * 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.v3; +package io.getlime.security.powerauth.rest.api.model.response; import io.getlime.security.powerauth.rest.api.model.entity.ActivationRecovery; diff --git a/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/v3/ActivationRemoveResponse.java b/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/ActivationRemoveResponse.java similarity index 95% rename from powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/v3/ActivationRemoveResponse.java rename to powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/ActivationRemoveResponse.java index af772b7c..0be0bd33 100644 --- a/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/v3/ActivationRemoveResponse.java +++ b/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/ActivationRemoveResponse.java @@ -17,7 +17,7 @@ * 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.v3; +package io.getlime.security.powerauth.rest.api.model.response; /** * Response object for /pa/v3/activation/remove end-point. diff --git a/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/v3/ActivationStatusResponse.java b/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/ActivationStatusResponse.java similarity index 97% rename from powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/v3/ActivationStatusResponse.java rename to powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/ActivationStatusResponse.java index b419ef10..2bfee56d 100644 --- a/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/v3/ActivationStatusResponse.java +++ b/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/ActivationStatusResponse.java @@ -17,7 +17,7 @@ * 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.v3; +package io.getlime.security.powerauth.rest.api.model.response; import java.util.Map; diff --git a/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/v3/ConfirmRecoveryResponsePayload.java b/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/ConfirmRecoveryResponsePayload.java similarity index 95% rename from powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/v3/ConfirmRecoveryResponsePayload.java rename to powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/ConfirmRecoveryResponsePayload.java index d885a5cc..41f1e8ed 100644 --- a/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/v3/ConfirmRecoveryResponsePayload.java +++ b/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/ConfirmRecoveryResponsePayload.java @@ -17,7 +17,7 @@ * 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.v3; +package io.getlime.security.powerauth.rest.api.model.response; /** * Response object for confirm recovery code ECIES payload. diff --git a/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/v3/EciesEncryptedResponse.java b/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/EciesEncryptedResponse.java similarity index 69% rename from powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/v3/EciesEncryptedResponse.java rename to powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/EciesEncryptedResponse.java index 8692c29e..fc1ca2df 100644 --- a/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/v3/EciesEncryptedResponse.java +++ b/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/EciesEncryptedResponse.java @@ -17,7 +17,7 @@ * 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.v3; +package io.getlime.security.powerauth.rest.api.model.response; /** * Response object for endpoints returning data encrypted by ECIES. @@ -28,6 +28,8 @@ public class EciesEncryptedResponse { private String encryptedData; private String mac; + private String nonce; + private Long timestamp; /** * Default constructor. @@ -39,10 +41,14 @@ public EciesEncryptedResponse() { * Constructor with Base64 encoded encrypted data and MAC of key and data. * @param encryptedData Encrypted data. * @param mac MAC of key and data. + * @param nonce ECIES nonce. + * @param timestamp Unix timestamp in milliseconds. */ - public EciesEncryptedResponse(String encryptedData, String mac) { + public EciesEncryptedResponse(String encryptedData, String mac, String nonce, Long timestamp) { this.encryptedData = encryptedData; this.mac = mac; + this.nonce = nonce; + this.timestamp = timestamp; } /** @@ -77,4 +83,35 @@ public void setMac(String mac) { this.mac = mac; } + /** + * Get nonce. + * @return Nonce. + */ + public String getNonce() { + return nonce; + } + + /** + * Set nonce. + * @param nonce Nonce. + */ + public void setNonce(String nonce) { + this.nonce = nonce; + } + + /** + * Get response timestamp as unix timestamp in milliseconds. + * @return Response timestamp. + */ + public Long getTimestamp() { + return timestamp; + } + + /** + * Set response timestamp as unix timestamp in milliseconds. + * @param timestamp Response timestamp. + */ + public void setTimestamp(Long timestamp) { + this.timestamp = timestamp; + } } 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 new file mode 100644 index 00000000..16cb7eff --- /dev/null +++ b/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/ServerStatusResponse.java @@ -0,0 +1,29 @@ +/* + * PowerAuth integration libraries for RESTful API applications, examples 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 io.getlime.security.powerauth.rest.api.model.response; + +/** + * Response object for /pa/v3/status end-point. + * + * @param serverTime Server time. + * @author Roman Strobl, roman.strobl@wultra.com + */ +public record ServerStatusResponse(long serverTime) { +} \ No newline at end of file diff --git a/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/v3/ServiceStatusResponse.java b/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/ServiceStatusResponse.java similarity index 98% rename from powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/v3/ServiceStatusResponse.java rename to powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/ServiceStatusResponse.java index 985cba68..ece1596e 100644 --- a/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/v3/ServiceStatusResponse.java +++ b/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/ServiceStatusResponse.java @@ -17,7 +17,7 @@ * 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.v3; +package io.getlime.security.powerauth.rest.api.model.response; import java.util.Date; diff --git a/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/v2/TokenRemoveResponse.java b/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/TokenRemoveResponse.java similarity index 95% rename from powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/v2/TokenRemoveResponse.java rename to powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/TokenRemoveResponse.java index db97b78b..a2faa8e0 100644 --- a/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/v2/TokenRemoveResponse.java +++ b/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/TokenRemoveResponse.java @@ -17,7 +17,7 @@ * 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.v2; +package io.getlime.security.powerauth.rest.api.model.response; /** * Class representing response transport object for token removal. diff --git a/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/v3/UpgradeResponsePayload.java b/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/UpgradeResponsePayload.java similarity index 95% rename from powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/v3/UpgradeResponsePayload.java rename to powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/UpgradeResponsePayload.java index 94424f3a..bd367b5d 100644 --- a/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/v3/UpgradeResponsePayload.java +++ b/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/UpgradeResponsePayload.java @@ -17,7 +17,7 @@ * 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.v3; +package io.getlime.security.powerauth.rest.api.model.response; /** * Response object for upgrade payload. diff --git a/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/v3/VaultUnlockResponsePayload.java b/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/VaultUnlockResponsePayload.java similarity index 96% rename from powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/v3/VaultUnlockResponsePayload.java rename to powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/VaultUnlockResponsePayload.java index c7705dbc..a222f4bb 100644 --- a/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/v3/VaultUnlockResponsePayload.java +++ b/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/VaultUnlockResponsePayload.java @@ -17,7 +17,7 @@ * 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.v3; +package io.getlime.security.powerauth.rest.api.model.response; /** * Response object for vault unlock payload. diff --git a/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/v2/ActivationCreateResponse.java b/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/v2/ActivationCreateResponse.java deleted file mode 100644 index 6930649e..00000000 --- a/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/v2/ActivationCreateResponse.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * PowerAuth integration libraries for RESTful API applications, examples and - * related software components - * - * Copyright (C) 2018 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.v2; - -import java.util.Map; - -/** - * Response object for /pa/activation/create end-point. - * - * @author Petr Dvorak, petr@wultra.com - * - */ -public class ActivationCreateResponse { - - private String activationId; - private String activationNonce; - private String ephemeralPublicKey; - private String encryptedServerPublicKey; - private String encryptedServerPublicKeySignature; - private Map customAttributes; - - /** - * Get activation ID - * @return Activation ID - */ - public String getActivationId() { - return activationId; - } - - /** - * Set activation ID - * @param activationId Activation ID - */ - public void setActivationId(String activationId) { - this.activationId = activationId; - } - - /** - * Get activation nonce. - * @return Activation nonce. - */ - public String getActivationNonce() { - return activationNonce; - } - - /** - * Set activation nonce. - * @param activationNonce Activation nonce. - */ - public void setActivationNonce(String activationNonce) { - this.activationNonce = activationNonce; - } - - /** - * Get ephemeral public key. - * @return Ephemeral public key. - */ - public String getEphemeralPublicKey() { - return ephemeralPublicKey; - } - - /** - * Set ephemeral public key. - * @param ephemeralPublicKey Ephemeral public key. - */ - public void setEphemeralPublicKey(String ephemeralPublicKey) { - this.ephemeralPublicKey = ephemeralPublicKey; - } - - /** - * Get encrypted server public key. - * @return Encrypted server public key. - */ - public String getEncryptedServerPublicKey() { - return encryptedServerPublicKey; - } - - /** - * Set encrypted server public key. - * @param encryptedServerPublicKey Encrypted server public key. - */ - public void setEncryptedServerPublicKey(String encryptedServerPublicKey) { - this.encryptedServerPublicKey = encryptedServerPublicKey; - } - - /** - * Get server data signature. - * @return Server data signature. - */ - public String getEncryptedServerPublicKeySignature() { - return encryptedServerPublicKeySignature; - } - - /** - * Set server data signature. - * @param encryptedServerPublicKeySignature Server data signature. - */ - public void setEncryptedServerPublicKeySignature(String encryptedServerPublicKeySignature) { - this.encryptedServerPublicKeySignature = encryptedServerPublicKeySignature; - } - - /** - * Custom attributes for the response. - * @return Custom response attributes. - */ - public Map getCustomAttributes() { - return customAttributes; - } - - /** - * Custom attributes for the response. - * @param customAttributes Custom response attributes. - */ - public void setCustomAttributes(Map customAttributes) { - this.customAttributes = customAttributes; - } - -} diff --git a/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/v2/ActivationStatusResponse.java b/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/v2/ActivationStatusResponse.java deleted file mode 100644 index d165efeb..00000000 --- a/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/v2/ActivationStatusResponse.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * PowerAuth integration libraries for RESTful API applications, examples and - * related software components - * - * Copyright (C) 2018 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.v2; - -import java.util.Map; - -/** - * Response object for /pa/activation/status end-point - * - * @author Petr Dvorak, petr@wultra.com - * - */ -public class ActivationStatusResponse { - - private String activationId; - private String encryptedStatusBlob; - private Map customObject; - - /** - * Get activation ID - * @return Activation ID - */ - public String getActivationId() { - return activationId; - } - - /** - * Set activation ID - * @param activationId Activation ID - */ - public void setActivationId(String activationId) { - this.activationId = activationId; - } - - /** - * Get encrypted activation status blob - * @return Encrypted activation status blob - */ - public String getEncryptedStatusBlob() { - return encryptedStatusBlob; - } - - /** - * Set encrypted activation status blob - * @param cStatusBlob encrypted activation status blob - */ - public void setEncryptedStatusBlob(String cStatusBlob) { - this.encryptedStatusBlob = cStatusBlob; - } - - /** - * Get custom associated object. - * @return Custom associated object - */ - public Map getCustomObject() { - return customObject; - } - - /** - * Set custom associated object - * @param customObject Custom associated object - */ - public void setCustomObject(Map customObject) { - this.customObject = customObject; - } - -} diff --git a/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/v2/TokenCreateResponse.java b/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/v2/TokenCreateResponse.java deleted file mode 100644 index af8002ad..00000000 --- a/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/v2/TokenCreateResponse.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * PowerAuth integration libraries for RESTful API applications, examples and - * related software components - * - * Copyright (C) 2018 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.v2; - -/** - * Response object for the /pa/token endpoint, that enables fetching token for simple authentication. - * - * @author Petr Dvorak, petr@wultra.com - */ -public class TokenCreateResponse { - - private String mac; - private String encryptedData; - - /** - * Get MAC signature of the request. - * @return MAC of the request. - */ - public String getMac() { - return mac; - } - - /** - * Set MAC signature of the request. - * @param mac MAC of the request. - */ - public void setMac(String mac) { - this.mac = mac; - } - - /** - * Get encrypted data payload. - * @return Encrypted data. - */ - public String getEncryptedData() { - return encryptedData; - } - - /** - * Set encrypted data payload. - * @param encryptedData Encrypted data. - */ - public void setEncryptedData(String encryptedData) { - this.encryptedData = encryptedData; - } -} diff --git a/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/v2/VaultUnlockResponse.java b/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/v2/VaultUnlockResponse.java deleted file mode 100644 index 55c53a95..00000000 --- a/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/response/v2/VaultUnlockResponse.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * PowerAuth integration libraries for RESTful API applications, examples and - * related software components - * - * Copyright (C) 2018 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.v2; - -/** - * Response object for /pa/vault/unlock end-point. - * - * @author Petr Dvorak, petr@wultra.com - * - */ -public class VaultUnlockResponse { - - private String activationId; - private String encryptedVaultEncryptionKey; - - /** - * Get activation ID - * @return Activation ID - */ - public String getActivationId() { - return activationId; - } - - /** - * Set activation ID - * @param activationId Activation ID - */ - public void setActivationId(String activationId) { - this.activationId = activationId; - } - - /** - * Get encrypted vault encryption key (using a key derived from the master transport key). - * @return Encrypted vault encryption key. - */ - public String getEncryptedVaultEncryptionKey() { - return encryptedVaultEncryptionKey; - } - - /** - * Set encrypted vault encryption key (using a key derived from the master transport key). - * @param encryptedVaultEncryptionKey Encrypted vault encryption key. - */ - public void setEncryptedVaultEncryptionKey(String encryptedVaultEncryptionKey) { - this.encryptedVaultEncryptionKey = encryptedVaultEncryptionKey; - } - -} diff --git a/powerauth-restful-security-spring-annotation/pom.xml b/powerauth-restful-security-spring-annotation/pom.xml index 91d185a4..e9f4a62f 100644 --- a/powerauth-restful-security-spring-annotation/pom.xml +++ b/powerauth-restful-security-spring-annotation/pom.xml @@ -30,7 +30,7 @@ io.getlime.security powerauth-restful-integration-parent - 1.4.0 + 1.5.0 @@ -61,17 +61,22 @@ io.getlime.security powerauth-java-crypto - ${powerauth-java-crypto.version} + ${powerauth-crypto.version} io.getlime.security powerauth-java-http - ${powerauth-java-http.version} + ${powerauth-crypto.version} io.getlime.security powerauth-rest-client-spring - ${powerauth-rest-client-spring.version} + ${powerauth.version} + + + + io.getlime.core + annotations diff --git a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/annotation/PowerAuthEncryption.java b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/annotation/PowerAuthEncryption.java index f186fda5..814c59fd 100644 --- a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/annotation/PowerAuthEncryption.java +++ b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/annotation/PowerAuthEncryption.java @@ -19,7 +19,8 @@ */ package io.getlime.security.powerauth.rest.api.spring.annotation; -import io.getlime.security.powerauth.crypto.lib.encryptor.ecies.model.EciesScope; +import io.getlime.security.powerauth.crypto.lib.encryptor.model.EncryptorScope; +import io.getlime.security.powerauth.rest.api.spring.encryption.EncryptionScope; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; @@ -27,7 +28,7 @@ import java.lang.annotation.Target; /** - * Annotation that simplifies end to end encryption. + * Annotation that simplifies end-to-end encryption. * * @author Roman Strobl, roman.strobl@wultra.com */ @@ -36,10 +37,9 @@ public @interface PowerAuthEncryption { /** - * Encryption scope, either EciesScope.ACTIVATION_SCOPE or EciesScope.APPLICATION_SCOPE. - * @see EciesScope + * Encryption scope, either {@link EncryptionScope#ACTIVATION_SCOPE} or {@link EncryptionScope#APPLICATION_SCOPE}. + * @see EncryptorScope * @return Encryption scope. */ - EciesScope scope() default EciesScope.ACTIVATION_SCOPE; - + EncryptionScope scope() default EncryptionScope.ACTIVATION_SCOPE; } diff --git a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/annotation/support/PowerAuthAnnotationInterceptor.java b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/annotation/support/PowerAuthAnnotationInterceptor.java index f005ed3f..3be2e428 100644 --- a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/annotation/support/PowerAuthAnnotationInterceptor.java +++ b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/annotation/support/PowerAuthAnnotationInterceptor.java @@ -46,8 +46,8 @@ import org.springframework.web.servlet.AsyncHandlerInterceptor; import org.springframework.web.servlet.HandlerMapping; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import java.lang.reflect.Type; import java.util.Arrays; import java.util.List; @@ -92,9 +92,7 @@ public boolean preHandle(@NonNull HttpServletRequest request, @NonNull HttpServl // This is to avoid issues with possible CORS requests )in case of // incorrect filter mapping) where there are special "pre-flight" // requests before the actual requests. - if (handler instanceof HandlerMethod) { - - final HandlerMethod handlerMethod = (HandlerMethod) handler; + if (handler instanceof final HandlerMethod handlerMethod) { // Obtain annotations PowerAuth powerAuthSignatureAnnotation = handlerMethod.getMethodAnnotation(PowerAuth.class); diff --git a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/annotation/support/PowerAuthEncryptionArgumentResolver.java b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/annotation/support/PowerAuthEncryptionArgumentResolver.java index 4774c998..3abcffe3 100644 --- a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/annotation/support/PowerAuthEncryptionArgumentResolver.java +++ b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/annotation/support/PowerAuthEncryptionArgumentResolver.java @@ -24,9 +24,10 @@ import com.fasterxml.jackson.databind.type.TypeFactory; import io.getlime.security.powerauth.rest.api.spring.annotation.EncryptedRequestBody; import io.getlime.security.powerauth.rest.api.spring.annotation.PowerAuthEncryption; -import io.getlime.security.powerauth.rest.api.spring.encryption.EciesEncryptionContext; -import io.getlime.security.powerauth.rest.api.spring.encryption.PowerAuthEciesEncryption; +import io.getlime.security.powerauth.rest.api.spring.encryption.EncryptionContext; +import io.getlime.security.powerauth.rest.api.spring.encryption.PowerAuthEncryptorData; import io.getlime.security.powerauth.rest.api.spring.model.PowerAuthRequestObjects; +import jakarta.servlet.http.HttpServletRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.MethodParameter; @@ -36,13 +37,12 @@ import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.method.support.ModelAndViewContainer; -import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.lang.reflect.Type; /** - * Argument resolver for {@link PowerAuthEciesEncryption} objects. It enables automatic - * parameter resolution for methods that are annotated via {@link PowerAuthEciesEncryption} annotation. + * Argument resolver for {@link PowerAuthEncryptorData} objects. It enables automatic + * parameter resolution for methods that are annotated via {@link PowerAuthEncryptorData} annotation. * * @author Roman Strobl, roman.strobl@wultra.com */ @@ -55,13 +55,13 @@ public class PowerAuthEncryptionArgumentResolver implements HandlerMethodArgumen @Override public boolean supportsParameter(@NonNull MethodParameter parameter) { return parameter.hasMethodAnnotation(PowerAuthEncryption.class) - && (parameter.hasParameterAnnotation(EncryptedRequestBody.class) || EciesEncryptionContext.class.isAssignableFrom(parameter.getParameterType())); + && (parameter.hasParameterAnnotation(EncryptedRequestBody.class) || EncryptionContext.class.isAssignableFrom(parameter.getParameterType())); } @Override public Object resolveArgument(@NonNull MethodParameter parameter, ModelAndViewContainer mavContainer, @NonNull NativeWebRequest webRequest, WebDataBinderFactory binderFactory) { final HttpServletRequest request = (HttpServletRequest) webRequest.getNativeRequest(); - final PowerAuthEciesEncryption eciesObject = (PowerAuthEciesEncryption) request.getAttribute(PowerAuthRequestObjects.ENCRYPTION_OBJECT); + final PowerAuthEncryptorData eciesObject = (PowerAuthEncryptorData) request.getAttribute(PowerAuthRequestObjects.ENCRYPTION_OBJECT); // Decrypted object is inserted into parameter annotated by @EncryptedRequestBody annotation if (parameter.hasParameterAnnotation(EncryptedRequestBody.class) && eciesObject != null && eciesObject.getDecryptedRequest() != null) { final Type requestType = parameter.getGenericParameterType(); @@ -81,11 +81,11 @@ public Object resolveArgument(@NonNull MethodParameter parameter, ModelAndViewCo } } // Ecies encryption object is inserted into parameter which is of type PowerAuthEciesEncryption - if (eciesObject != null && EciesEncryptionContext.class.isAssignableFrom(parameter.getParameterType())) { + if (eciesObject != null && EncryptionContext.class.isAssignableFrom(parameter.getParameterType())) { // Set ECIES scope in case it is specified by the @PowerAuthEncryption annotation - PowerAuthEncryption powerAuthEncryption = parameter.getMethodAnnotation(PowerAuthEncryption.class); + final PowerAuthEncryption powerAuthEncryption = parameter.getMethodAnnotation(PowerAuthEncryption.class); if (powerAuthEncryption != null) { - EciesEncryptionContext eciesContext = eciesObject.getContext(); + EncryptionContext eciesContext = eciesObject.getContext(); boolean validScope = validateEciesScope(eciesContext); if (validScope) { return eciesContext; @@ -99,9 +99,9 @@ public Object resolveArgument(@NonNull MethodParameter parameter, ModelAndViewCo * Validate that encryption HTTP header contains correct values for given ECIES scope. * @param eciesContext ECIES context. */ - private boolean validateEciesScope(EciesEncryptionContext eciesContext) { - switch (eciesContext.getEciesScope()) { - case ACTIVATION_SCOPE: + private boolean validateEciesScope(EncryptionContext eciesContext) { + switch (eciesContext.getEncryptionScope()) { + case ACTIVATION_SCOPE -> { if (eciesContext.getApplicationKey() == null || eciesContext.getApplicationKey().isEmpty()) { logger.warn("ECIES activation scope is invalid because of missing application key"); return false; @@ -110,18 +110,17 @@ private boolean validateEciesScope(EciesEncryptionContext eciesContext) { logger.warn("ECIES activation scope is invalid because of missing activation ID"); return false; } - break; - - case APPLICATION_SCOPE: + } + case APPLICATION_SCOPE -> { if (eciesContext.getApplicationKey() == null || eciesContext.getApplicationKey().isEmpty()) { logger.warn("ECIES application scope is invalid because of missing application key"); return false; } - break; - - default: - logger.warn("Unsupported ECIES scope: {}", eciesContext.getEciesScope()); + } + default -> { + logger.warn("Unsupported ECIES scope: {}", eciesContext.getEncryptionScope()); return false; + } } return true; } diff --git a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/annotation/support/PowerAuthWebArgumentResolver.java b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/annotation/support/PowerAuthWebArgumentResolver.java index e3b9260c..d3629c67 100644 --- a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/annotation/support/PowerAuthWebArgumentResolver.java +++ b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/annotation/support/PowerAuthWebArgumentResolver.java @@ -30,7 +30,7 @@ import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.method.support.ModelAndViewContainer; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; /** * Argument resolver for {@link PowerAuthApiAuthentication} objects. It enables automatic diff --git a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/authentication/impl/PowerAuthActivationImpl.java b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/authentication/impl/PowerAuthActivationImpl.java index 52becd95..9d5e60b8 100644 --- a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/authentication/impl/PowerAuthActivationImpl.java +++ b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/authentication/impl/PowerAuthActivationImpl.java @@ -23,6 +23,7 @@ import io.getlime.security.powerauth.rest.api.spring.model.ActivationStatus; import io.getlime.security.powerauth.rest.api.spring.model.AuthenticationContext; +import java.io.Serial; import java.io.Serializable; import java.util.ArrayList; import java.util.List; @@ -35,6 +36,7 @@ */ public class PowerAuthActivationImpl implements PowerAuthActivation, Serializable { + @Serial private static final long serialVersionUID = -2171754572617130041L; /** diff --git a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/authentication/impl/PowerAuthApiAuthenticationImpl.java b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/authentication/impl/PowerAuthApiAuthenticationImpl.java index 81a9aecc..b77bcce1 100644 --- a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/authentication/impl/PowerAuthApiAuthenticationImpl.java +++ b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/authentication/impl/PowerAuthApiAuthenticationImpl.java @@ -28,6 +28,7 @@ import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; +import java.io.Serial; import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; @@ -43,6 +44,7 @@ */ public class PowerAuthApiAuthenticationImpl extends AbstractAuthenticationToken implements PowerAuthApiAuthentication, Serializable { + @Serial private static final long serialVersionUID = -3790516505615465445L; /** @@ -145,9 +147,7 @@ public String getName() { @Override public Collection getAuthorities() { - ArrayList authorities = new ArrayList<>(1); - authorities.add(new SimpleGrantedAuthority("USER")); - return Collections.unmodifiableList(authorities); + return List.of(new SimpleGrantedAuthority("USER")); } @Override diff --git a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/authentication/impl/PowerAuthSignatureAuthenticationImpl.java b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/authentication/impl/PowerAuthSignatureAuthenticationImpl.java index 70cc1c50..b8b5624c 100644 --- a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/authentication/impl/PowerAuthSignatureAuthenticationImpl.java +++ b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/authentication/impl/PowerAuthSignatureAuthenticationImpl.java @@ -23,6 +23,8 @@ import io.getlime.security.powerauth.rest.api.spring.authentication.PowerAuthSignatureAuthentication; import org.springframework.security.authentication.AbstractAuthenticationToken; +import java.io.Serial; + /** * PowerAuth authentication object used between PowerAuth Client and intermediate server * application (such as mobile banking API). @@ -32,6 +34,7 @@ */ public class PowerAuthSignatureAuthenticationImpl extends AbstractAuthenticationToken implements PowerAuthSignatureAuthentication { + @Serial private static final long serialVersionUID = 6495166873663643144L; /** diff --git a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/converter/v3/ActivationContextConverter.java b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/converter/ActivationContextConverter.java similarity index 82% rename from powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/converter/v3/ActivationContextConverter.java rename to powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/converter/ActivationContextConverter.java index c140f9eb..bc6a6f5f 100644 --- a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/converter/v3/ActivationContextConverter.java +++ b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/converter/ActivationContextConverter.java @@ -17,13 +17,13 @@ * 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.converter.v3; +package io.getlime.security.powerauth.rest.api.spring.converter; -import com.wultra.security.powerauth.client.v3.GetActivationStatusResponse; +import com.wultra.security.powerauth.client.model.response.GetActivationStatusResponse; import io.getlime.security.powerauth.rest.api.spring.model.ActivationContext; import org.springframework.stereotype.Component; -import javax.xml.datatype.XMLGregorianCalendar; +import java.util.Date; import java.util.List; /** @@ -66,17 +66,17 @@ public ActivationContext fromActivationDetailResponse(GetActivationStatusRespons if (activationFlags != null) { destination.getActivationFlags().addAll(activationFlags); } - final XMLGregorianCalendar timestampCreated = source.getTimestampCreated(); + final Date timestampCreated = source.getTimestampCreated(); if (timestampCreated != null) { - destination.setTimestampCreated(timestampCreated.toGregorianCalendar().toInstant()); + destination.setTimestampCreated(timestampCreated.toInstant()); } - final XMLGregorianCalendar timestampLastUsed = source.getTimestampLastUsed(); + final Date timestampLastUsed = source.getTimestampLastUsed(); if (timestampLastUsed != null) { - destination.setTimestampLastUsed(timestampLastUsed.toGregorianCalendar().toInstant()); + destination.setTimestampLastUsed(timestampLastUsed.toInstant()); } - final XMLGregorianCalendar timestampLastChange = source.getTimestampLastChange(); + final Date timestampLastChange = source.getTimestampLastChange(); if (timestampLastChange != null) { - destination.setTimestampLastChange(timestampLastChange.toGregorianCalendar().toInstant()); + destination.setTimestampLastChange(timestampLastChange.toInstant()); } return destination; } diff --git a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/converter/v3/ActivationStatusConverter.java b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/converter/ActivationStatusConverter.java similarity index 65% rename from powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/converter/v3/ActivationStatusConverter.java rename to powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/converter/ActivationStatusConverter.java index dd974ff0..ac2d8bdd 100644 --- a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/converter/v3/ActivationStatusConverter.java +++ b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/converter/ActivationStatusConverter.java @@ -17,11 +17,9 @@ * 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.converter.v3; +package io.getlime.security.powerauth.rest.api.spring.converter; import io.getlime.security.powerauth.rest.api.spring.model.ActivationStatus; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; /** @@ -32,36 +30,23 @@ @Component public class ActivationStatusConverter { - private static final Logger logger = LoggerFactory.getLogger(ActivationStatusConverter.class); - /** - * Convert {@link ActivationStatus} from a {@link com.wultra.security.powerauth.client.v3.ActivationStatus} value. + * Convert {@link ActivationStatus} from a {@link com.wultra.security.powerauth.client.model.enumeration.ActivationStatus} value. * @param activationStatus Activation status from PowerAuth client model. * @return Activation status from Restful integration model. */ - public ActivationStatus convertFrom(com.wultra.security.powerauth.client.v3.ActivationStatus activationStatus) { + public ActivationStatus convertFrom(com.wultra.security.powerauth.client.model.enumeration.ActivationStatus activationStatus) { if (activationStatus == null) { return null; } - switch (activationStatus) { - case CREATED: - return ActivationStatus.CREATED; - - case PENDING_COMMIT: - return ActivationStatus.PENDING_COMMIT; - - case ACTIVE: - return ActivationStatus.ACTIVE; - - case BLOCKED: - return ActivationStatus.BLOCKED; - - case REMOVED: - return ActivationStatus.REMOVED; - } - - return null; + return switch (activationStatus) { + case CREATED -> ActivationStatus.CREATED; + case PENDING_COMMIT -> ActivationStatus.PENDING_COMMIT; + case ACTIVE -> ActivationStatus.ACTIVE; + case BLOCKED -> ActivationStatus.BLOCKED; + case REMOVED -> ActivationStatus.REMOVED; + }; } } diff --git a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/converter/v2/SignatureTypeConverter.java b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/converter/SignatureTypeConverter.java similarity index 71% rename from powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/converter/v2/SignatureTypeConverter.java rename to powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/converter/SignatureTypeConverter.java index 93149a46..3033573c 100644 --- a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/converter/v2/SignatureTypeConverter.java +++ b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/converter/SignatureTypeConverter.java @@ -17,16 +17,16 @@ * 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.converter.v2; +package io.getlime.security.powerauth.rest.api.spring.converter; -import com.wultra.security.powerauth.client.v2.SignatureType; +import com.wultra.security.powerauth.client.model.enumeration.SignatureType; import io.getlime.security.powerauth.crypto.lib.enums.PowerAuthSignatureTypes; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Helper class to convert from and to - * {@link com.wultra.security.powerauth.client.v2.SignatureType} class. + * {@link SignatureType} class. * * @author Petr Dvorak, petr@wultra.com */ @@ -35,7 +35,7 @@ public class SignatureTypeConverter { private static final Logger logger = LoggerFactory.getLogger(SignatureTypeConverter.class); /** - * Convert {@link com.wultra.security.powerauth.client.v2.SignatureType} + * Convert {@link SignatureType} * from a {@link String} value. * @param signatureTypeString String value representing signature type. * @return Signature type. @@ -49,7 +49,7 @@ public SignatureType convertFrom(String signatureTypeString) { // Try to convert signature type try { signatureTypeString = signatureTypeString.toUpperCase(); - return SignatureType.fromValue(signatureTypeString); + return SignatureType.enumFromString(signatureTypeString); } catch (IllegalArgumentException ex) { logger.warn("Invalid signature type, error: {}", ex.getMessage()); logger.debug("Error details", ex); @@ -65,20 +65,14 @@ public SignatureType convertFrom(String signatureTypeString) { * @return Signature type. */ public SignatureType convertFrom(PowerAuthSignatureTypes powerAuthSignatureTypes) { - switch (powerAuthSignatureTypes) { - case POSSESSION: - return SignatureType.POSSESSION; - case KNOWLEDGE: - return SignatureType.KNOWLEDGE; - case BIOMETRY: - return SignatureType.BIOMETRY; - case POSSESSION_KNOWLEDGE: - return SignatureType.POSSESSION_KNOWLEDGE; - case POSSESSION_BIOMETRY: - return SignatureType.POSSESSION_BIOMETRY; - default: - return null; - } + return switch (powerAuthSignatureTypes) { + case POSSESSION -> SignatureType.POSSESSION; + case KNOWLEDGE -> SignatureType.KNOWLEDGE; + case BIOMETRY -> SignatureType.BIOMETRY; + case POSSESSION_KNOWLEDGE -> SignatureType.POSSESSION_KNOWLEDGE; + case POSSESSION_BIOMETRY -> SignatureType.POSSESSION_BIOMETRY; + default -> null; + }; } } diff --git a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/converter/v3/SignatureTypeConverter.java b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/converter/v3/SignatureTypeConverter.java deleted file mode 100644 index 6f6fde32..00000000 --- a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/converter/v3/SignatureTypeConverter.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * PowerAuth integration libraries for RESTful API applications, examples and - * related software components - * - * Copyright (C) 2018 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.converter.v3; - -import com.wultra.security.powerauth.client.v3.SignatureType; -import io.getlime.security.powerauth.crypto.lib.enums.PowerAuthSignatureTypes; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Helper class to convert from and to - * {@link com.wultra.security.powerauth.client.v3.SignatureType} class. - * - * @author Petr Dvorak, petr@wultra.com - */ -public class SignatureTypeConverter { - - private static final Logger logger = LoggerFactory.getLogger(SignatureTypeConverter.class); - - /** - * Convert {@link com.wultra.security.powerauth.client.v3.SignatureType} - * from a {@link String} value. - * @param signatureTypeString String value representing signature type. - * @return Signature type. - */ - public SignatureType convertFrom(String signatureTypeString) { - - if (signatureTypeString == null) { - return null; - } - - // Try to convert signature type - try { - signatureTypeString = signatureTypeString.toUpperCase(); - return SignatureType.fromValue(signatureTypeString); - } catch (IllegalArgumentException ex) { - logger.warn("Invalid signature type, error: {}", ex.getMessage()); - logger.debug("Error details", ex); - // Return null value which represents an unknown signature type - return null; - } - - } - - /** - * Convert {@link com.wultra.security.powerauth.client.v3.SignatureType} from {@link PowerAuthSignatureTypes}. - * @param powerAuthSignatureTypes Signature type from crypto representation. - * @return Signature type. - */ - public SignatureType convertFrom(PowerAuthSignatureTypes powerAuthSignatureTypes) { - switch (powerAuthSignatureTypes) { - case POSSESSION: - return SignatureType.POSSESSION; - case KNOWLEDGE: - return SignatureType.KNOWLEDGE; - case BIOMETRY: - return SignatureType.BIOMETRY; - case POSSESSION_KNOWLEDGE: - return SignatureType.POSSESSION_KNOWLEDGE; - case POSSESSION_BIOMETRY: - return SignatureType.POSSESSION_BIOMETRY; - default: - return null; - } - } - -} diff --git a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/encryption/EciesEncryptionContext.java b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/encryption/EciesEncryptionContext.java deleted file mode 100644 index a02c9382..00000000 --- a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/encryption/EciesEncryptionContext.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * PowerAuth integration libraries for RESTful API applications, examples and - * related software components - * - * Copyright (C) 2018 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.encryption; - -import io.getlime.security.powerauth.crypto.lib.encryptor.ecies.model.EciesScope; -import io.getlime.security.powerauth.http.PowerAuthHttpHeader; - -/** - * Class for storing ECIES encryption context derived from HTTP headers. - * - * @author Roman Strobl, roman.strobl@wultra.com - * - */ -public class EciesEncryptionContext { - - private String applicationKey; - private String activationId; - private String version; - private EciesScope eciesScope; - private PowerAuthHttpHeader httpHeader; - - /** - * Default constructor. - */ - public EciesEncryptionContext() { - } - - /** - * Constructor with all context parameters. - * - * @param applicationKey Application key. - * @param activationId Activation ID. - * @param version PowerAuth protocol version. - * @param httpHeader HTTP header used to derive ECIES encryption context. - */ - public EciesEncryptionContext(String applicationKey, String activationId, String version, PowerAuthHttpHeader httpHeader) { - this.applicationKey = applicationKey; - this.activationId = activationId; - this.version = version; - this.httpHeader = httpHeader; - } - - /** - * Get application key. - * - * @return Application key. - */ - public String getApplicationKey() { - return applicationKey; - } - - /** - * Set application key. - * - * @param applicationKey Application key. - */ - public void setApplicationKey(String applicationKey) { - this.applicationKey = applicationKey; - } - - /** - * Get activation ID. - * - * @return Activation ID. - */ - public String getActivationId() { - return activationId; - } - - /** - * Set activation ID. - * - * @param activationId Activation ID. - */ - public void setActivationId(String activationId) { - this.activationId = activationId; - } - - /** - * Get PowerAuth protocol version. - * - * @return PowerAuth protocol version. - */ - public String getVersion() { - return version; - } - - /** - * Set PowerAuth protocol version. - * - * @param version PowerAuth protocol version. - */ - public void setVersion(String version) { - this.version = version; - } - - /** - * Get ECIES scope (application or activation). - * @return ECIES scope. - */ - public EciesScope getEciesScope() { - return eciesScope; - } - - /** - * Set ECIES scope (application or activation). - * @param eciesScope ECIES scope. - */ - public void setEciesScope(EciesScope eciesScope) { - this.eciesScope = eciesScope; - } - - /** - * Get PowerAuth HTTP header used for deriving ECIES encryption context. - * - * @return PowerAuth HTTP header used for deriving ECIES encryption context. - */ - public PowerAuthHttpHeader getHttpHeader() { - return httpHeader; - } - - /** - * Set PowerAuth HTTP header used for deriving ECIES encryption context. - * - * @param httpHeader PowerAuth HTTP header used for deriving ECIES encryption context. - */ - public void setHttpHeader(PowerAuthHttpHeader httpHeader) { - this.httpHeader = httpHeader; - } -} \ No newline at end of file diff --git a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/encryption/PowerAuthEciesDecryptorParameters.java b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/encryption/EncryptionContext.java similarity index 55% rename from powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/encryption/PowerAuthEciesDecryptorParameters.java rename to powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/encryption/EncryptionContext.java index acdc2aa6..c919dbea 100644 --- a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/encryption/PowerAuthEciesDecryptorParameters.java +++ b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/encryption/EncryptionContext.java @@ -17,44 +17,39 @@ * 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.encryption; +import io.getlime.security.powerauth.http.PowerAuthHttpHeader; +import lombok.AllArgsConstructor; +import lombok.Getter; + /** - * Class used for storing ECIES decryptor parameters. + * Class for storing PowerAuth End-To-End encryption context derived from HTTP headers. * * @author Roman Strobl, roman.strobl@wultra.com */ -public class PowerAuthEciesDecryptorParameters { - - private final String secretKey; - private final String sharedInfo2; - +@Getter +@AllArgsConstructor +public class EncryptionContext { /** - * Constructor with secretKey and sharedInfo2. - * - * @param secretKey ECIES secret key. - * @param sharedInfo2 Parameter sharedInfo2 for ECIES. + * Application key. */ - public PowerAuthEciesDecryptorParameters(String secretKey, String sharedInfo2) { - this.secretKey = secretKey; - this.sharedInfo2 = sharedInfo2; - } - + private final String applicationKey; /** - * Get ECIES secret key. - * - * @return ECIES secret key. + * Activation ID. */ - public String getSecretKey() { - return secretKey; - } - + private final String activationId; /** - * Get parameter sharedInfo2 for ECIES. - * @return Parameter sharedInfo2 for ECIES. + * Protocol version. */ - public String getSharedInfo2() { - return sharedInfo2; - } - -} + private final String version; + /** + * PowerAuth HTTP header used for deriving ECIES encryption context. + */ + private final PowerAuthHttpHeader httpHeader; + /** + * Scope of the encryption. + */ + private final EncryptionScope encryptionScope; +} \ No newline at end of file diff --git a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/encryption/EncryptionScope.java b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/encryption/EncryptionScope.java new file mode 100644 index 00000000..36e945e4 --- /dev/null +++ b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/encryption/EncryptionScope.java @@ -0,0 +1,57 @@ +/* + * PowerAuth integration libraries for RESTful API applications, examples 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 io.getlime.security.powerauth.rest.api.spring.encryption; + +import io.getlime.security.powerauth.crypto.lib.encryptor.model.EncryptorScope; + +/** + * Enumeration of application scopes for encryptor. + */ +public enum EncryptionScope { + + /** + * Application scope (non-personalized). + */ + APPLICATION_SCOPE, + + /** + * Activation scope (personalized). + */ + ACTIVATION_SCOPE; + + /** + * Translate this scope object into {@link EncryptorScope} used by low level PowerAuth Crypto library. + * @return Translated {@link EncryptorScope}. + */ + public EncryptorScope toEncryptorScope() { + switch (this) { + case APPLICATION_SCOPE -> { + return EncryptorScope.APPLICATION_SCOPE; + } + case ACTIVATION_SCOPE -> { + return EncryptorScope.ACTIVATION_SCOPE; + } + default -> { + throw new IllegalArgumentException("Unsupported scope " + this); + } + } + } +} diff --git a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/encryption/EncryptorFactory.java b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/encryption/EncryptorFactory.java deleted file mode 100644 index 30c0386d..00000000 --- a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/encryption/EncryptorFactory.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * PowerAuth integration libraries for RESTful API applications, examples and - * related software components - * - * Copyright (C) 2018 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.encryption; - -import com.wultra.security.powerauth.client.PowerAuthClient; -import com.wultra.security.powerauth.client.model.error.PowerAuthClientException; -import com.wultra.security.powerauth.client.v2.GetNonPersonalizedEncryptionKeyRequest; -import com.wultra.security.powerauth.client.v2.GetNonPersonalizedEncryptionKeyResponse; -import io.getlime.core.rest.model.base.request.ObjectRequest; -import io.getlime.security.powerauth.rest.api.model.entity.NonPersonalizedEncryptedPayloadModel; -import io.getlime.security.powerauth.rest.api.spring.exception.PowerAuthEncryptionException; -import io.getlime.security.powerauth.rest.api.spring.service.HttpCustomizationService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -/** - * Class responsible for building encryptors. - * - * @author Petr Dvorak, petr@wultra.com - */ -@Component -public class EncryptorFactory { - - private static final Logger logger = LoggerFactory.getLogger(EncryptorFactory.class); - - private final PowerAuthClient powerAuthClient; - private final HttpCustomizationService httpCustomizationService; - - /** - * Factory constructor. - * @param powerAuthClient PowerAuth client. - * @param httpCustomizationService HTTP customization service. - */ - @Autowired - public EncryptorFactory(PowerAuthClient powerAuthClient, HttpCustomizationService httpCustomizationService) { - this.powerAuthClient = powerAuthClient; - this.httpCustomizationService = httpCustomizationService; - } - - /** - * Return a new instance of a non-personalized encryptor. - * @param object Request object to be used to initialize a new encryptor. - * @return New instance of a non-personalized encryptor. - * @throws PowerAuthEncryptionException Thrown in case encryptor could not be built. - */ - public PowerAuthNonPersonalizedEncryptor buildNonPersonalizedEncryptor(ObjectRequest object) throws PowerAuthEncryptionException { - return this.buildNonPersonalizedEncryptor( - object.getRequestObject().getApplicationKey(), - object.getRequestObject().getSessionIndex(), - object.getRequestObject().getEphemeralPublicKey() - ); - } - - /** - * Return a new instance of a non-personalized encryptor. - * @param applicationKeyBase64 Application key associated with an application master key used for encryption. - * @param sessionIndexBase64 Session index. - * @param ephemeralPublicKeyBase64 Ephemeral public key. - * @return New instance of a non-personalized encryptor. - * @throws PowerAuthEncryptionException Thrown in case encryptor could not be built. - */ - public PowerAuthNonPersonalizedEncryptor buildNonPersonalizedEncryptor(String applicationKeyBase64, String sessionIndexBase64, String ephemeralPublicKeyBase64) throws PowerAuthEncryptionException { - try { - final GetNonPersonalizedEncryptionKeyRequest encryptRequest = new GetNonPersonalizedEncryptionKeyRequest(); - encryptRequest.setApplicationKey(applicationKeyBase64); - encryptRequest.setEphemeralPublicKey(ephemeralPublicKeyBase64); - encryptRequest.setSessionIndex(sessionIndexBase64); - final GetNonPersonalizedEncryptionKeyResponse encryptionKeyResponse = powerAuthClient.v2().generateNonPersonalizedE2EEncryptionKey( - encryptRequest, - httpCustomizationService.getQueryParams(), - httpCustomizationService.getHttpHeaders() - ); - - return new PowerAuthNonPersonalizedEncryptor( - encryptionKeyResponse.getApplicationKey(), - encryptionKeyResponse.getEncryptionKey(), encryptionKeyResponse.getEncryptionKeyIndex(), - encryptionKeyResponse.getEphemeralPublicKey() - ); - } catch (PowerAuthClientException ex) { - logger.warn("Encryption failed, error: {}", ex.getMessage()); - logger.debug(ex.getMessage(), ex); - throw new PowerAuthEncryptionException(); - } - } - -} diff --git a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/encryption/PowerAuthEciesEncryption.java b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/encryption/PowerAuthEciesEncryption.java deleted file mode 100644 index 9a23808e..00000000 --- a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/encryption/PowerAuthEciesEncryption.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * PowerAuth integration libraries for RESTful API applications, examples and - * related software components - * - * Copyright (C) 2018 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.encryption; - -import io.getlime.security.powerauth.crypto.lib.encryptor.ecies.EciesDecryptor; - -/** - * Class used for storing data used during ECIES decryption and encryption. A reference to an initialized ECIES decryptor - * is also stored so that response can be encrypted using same decryptor as used for request decryption. - * - * Use the T parameter to specify the type of request object to be decrypted. - * - * @author Roman Strobl, roman.strobl@wultra.com - */ -public class PowerAuthEciesEncryption { - - private final EciesEncryptionContext context; - private EciesDecryptor eciesDecryptor; - private byte[] encryptedRequest; - private byte[] decryptedRequest; - private Object requestObject; - - /** - * Initialize ECIES encryption object from either encryption or signature HTTP header. - * - * @param context PowerAuth encryption context derived from either encryption or signature HTTP header. - */ - public PowerAuthEciesEncryption(EciesEncryptionContext context) { - this.context = context; - } - - /** - * Get ECIES encryption context. - * @return ECIES encryption context. - */ - public EciesEncryptionContext getContext() { - return context; - } - - /** - * Get ECIES decryptor. - * @return ECIES decryptor. - */ - public EciesDecryptor getEciesDecryptor() { - return eciesDecryptor; - } - - /** - * Set ECIES decryptor. - * @param eciesDecryptor ECIES decryptor. - */ - public void setEciesDecryptor(EciesDecryptor eciesDecryptor) { - this.eciesDecryptor = eciesDecryptor; - } - - /** - * Get encrypted request data. - * @return Encrypted request data. - */ - public byte[] getEncryptedRequest() { - return encryptedRequest; - } - - /** - * Set encrypted request data. - * @param encryptedRequest Encrypted request data. - */ - public void setEncryptedRequest(byte[] encryptedRequest) { - this.encryptedRequest = encryptedRequest; - } - - /** - * Get decrypted request data. - * @return Decrypted request data. - */ - public byte[] getDecryptedRequest() { - return decryptedRequest; - } - - /** - * Set decrypted request data. - * @param decryptedRequest Decrypted request data. - */ - public void setDecryptedRequest(byte[] decryptedRequest) { - this.decryptedRequest = decryptedRequest; - } - - /** - * Get decrypted request object. - * @return Decrypted request object. - */ - public Object getRequestObject() { - return requestObject; - } - - /** - * Set decrypted request object. - * @param requestObject Decrypted request object. - */ - public void setRequestObject(Object requestObject) { - this.requestObject = requestObject; - } - -} diff --git a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/encryption/PowerAuthEncryptorData.java b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/encryption/PowerAuthEncryptorData.java new file mode 100644 index 00000000..11caa171 --- /dev/null +++ b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/encryption/PowerAuthEncryptorData.java @@ -0,0 +1,83 @@ +/* + * PowerAuth integration libraries for RESTful API applications, examples 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 io.getlime.security.powerauth.rest.api.spring.encryption; + +import io.getlime.security.powerauth.crypto.lib.encryptor.ServerEncryptor; +import io.getlime.security.powerauth.crypto.lib.encryptor.model.EncryptedRequest; +import io.getlime.security.powerauth.crypto.lib.encryptor.model.EncryptorId; +import lombok.Getter; +import lombok.Setter; + +/** + * Class used for storing data used during PowerAuth decryption and encryption. A reference to an initialized ServerEncryptor + * is also stored so that the response can be encrypted using the same object as used for request decryption. + */ +@Getter +@Setter +public class PowerAuthEncryptorData { + /** + * ECIES encryption context. + */ + private final EncryptionContext context; + /** + * {@link ServerEncryptor} implementation. + */ + private ServerEncryptor serverEncryptor; + /** + * Encrypted request data. + */ + private EncryptedRequest encryptedRequest; + /** + * Decrypted request data. + */ + private byte[] decryptedRequest; + /** + * Request object + */ + private Object requestObject; + + /** + * Initialize encryption object from either encryption or signature HTTP header. + * + * @param context PowerAuth encryption context derived from either encryption or signature HTTP header. + */ + public PowerAuthEncryptorData(EncryptionContext context) { + this.context = context; + } + + /** + * Get EncryptorId depending on scope of encryption. + * @return EncryptorId depending on scope of encryption. + */ + public EncryptorId getEncryptorId() { + switch (context.getEncryptionScope()) { + case ACTIVATION_SCOPE -> { + return EncryptorId.ACTIVATION_SCOPE_GENERIC; + } + case APPLICATION_SCOPE -> { + return EncryptorId.APPLICATION_SCOPE_GENERIC; + } + default -> { + throw new IllegalStateException("Unsupported scope " + this); + } + } + } +} diff --git a/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/v2/VaultUnlockRequest.java b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/encryption/PowerAuthEncryptorParameters.java similarity index 60% rename from powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/v2/VaultUnlockRequest.java rename to powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/encryption/PowerAuthEncryptorParameters.java index 395c71e1..2bb54b80 100644 --- a/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/v2/VaultUnlockRequest.java +++ b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/encryption/PowerAuthEncryptorParameters.java @@ -17,30 +17,14 @@ * 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.v2; +package io.getlime.security.powerauth.rest.api.spring.encryption; /** - * Request object for /pa/vault/unlock end-point used for unlocking the vault. + * Class used for storing encryptor parameters. * + * @param secretKey Secret key. + * @param sharedInfo2 Parameter sharedInfo2 for ECIES (V3.x protocols). * @author Roman Strobl, roman.strobl@wultra.com */ -public class VaultUnlockRequest { - - private String reason; - - /** - * Get reason why vault is being unlocked. - * @return Reason why vault is being unlocked. - */ - public String getReason() { - return reason; - } - - /** - * Set reason why vault is being unlocked. - * @param reason Reason why vault is being unlocked. - */ - public void setReason(String reason) { - this.reason = reason; - } +public record PowerAuthEncryptorParameters(String secretKey, String sharedInfo2) { } diff --git a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/encryption/PowerAuthNonPersonalizedEncryptor.java b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/encryption/PowerAuthNonPersonalizedEncryptor.java deleted file mode 100644 index c36e8cd2..00000000 --- a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/encryption/PowerAuthNonPersonalizedEncryptor.java +++ /dev/null @@ -1,169 +0,0 @@ -/* - * PowerAuth integration libraries for RESTful API applications, examples and - * related software components - * - * Copyright (C) 2018 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.encryption; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.google.common.io.BaseEncoding; -import io.getlime.core.rest.model.base.request.ObjectRequest; -import io.getlime.core.rest.model.base.response.ObjectResponse; -import io.getlime.security.powerauth.crypto.lib.encryptor.NonPersonalizedEncryptor; -import io.getlime.security.powerauth.crypto.lib.encryptor.model.NonPersonalizedEncryptedMessage; -import io.getlime.security.powerauth.crypto.lib.model.exception.CryptoProviderException; -import io.getlime.security.powerauth.crypto.lib.model.exception.GenericCryptoException; -import io.getlime.security.powerauth.rest.api.model.entity.NonPersonalizedEncryptedPayloadModel; - -import java.io.IOException; -import java.security.InvalidKeyException; - -/** - * Non-personalized encryptor class. - * - * @author Petr Dvorak, petr@wultra.com - */ -public class PowerAuthNonPersonalizedEncryptor { - - private final NonPersonalizedEncryptor encryptor; - - private final ObjectMapper mapper = new ObjectMapper(); - - /** - * Constructor with all mandatory parameters. - * - * @param applicationKeyBase64 Application key. - * @param sessionKeyBytesBase64 Session key. - * @param sessionIndexBase64 Session index. - * @param ephemeralPublicKeyBase64 Ephemeral public key. - */ - public PowerAuthNonPersonalizedEncryptor(String applicationKeyBase64, String sessionKeyBytesBase64, String sessionIndexBase64, String ephemeralPublicKeyBase64) { - final byte[] applicationKey = BaseEncoding.base64().decode(applicationKeyBase64); - final byte[] sessionIndex = BaseEncoding.base64().decode(sessionIndexBase64); - final byte[] sessionKeyBytes = BaseEncoding.base64().decode(sessionKeyBytesBase64); - final byte[] ephemeralKeyBytes = BaseEncoding.base64().decode(ephemeralPublicKeyBase64); - this.encryptor = new NonPersonalizedEncryptor(applicationKey, sessionKeyBytes, sessionIndex, ephemeralKeyBytes); - } - - /** - * Encrypt object. - * - * @param object Object to be encrypted. - * @return Encrypted object. - * @throws JsonProcessingException In case the resulting object cannot be encoded as JSON. - * @throws GenericCryptoException In case of a cryptography error. - * @throws CryptoProviderException In case of a cryptographic provider error. - * @throws InvalidKeyException In case the key provided for encryption is invalid. - */ - public ObjectResponse encrypt(Object object) throws JsonProcessingException, GenericCryptoException, CryptoProviderException, InvalidKeyException { - if (object == null) { - return null; - } - final byte[] originalData = mapper.writeValueAsBytes(object); - return this.encrypt(originalData); - } - - /** - * Encrypt data. - * - * @param originalData Bytes to be encrypted. - * @return Encrypted object. - * @throws GenericCryptoException In case of a cryptography error. - * @throws CryptoProviderException In case of a cryptographic provider error. - * @throws InvalidKeyException In case the key provided for encryption is invalid. - */ - public ObjectResponse encrypt(byte[] originalData) throws GenericCryptoException, CryptoProviderException, InvalidKeyException { - - if (originalData == null) { - return null; - } - - final NonPersonalizedEncryptedMessage message = encryptor.encrypt(originalData); - - if (message == null) { // this will happen only in case of an unlikely randomness error, or if keys are corrupted - return null; - } - - final NonPersonalizedEncryptedPayloadModel responseObject = new NonPersonalizedEncryptedPayloadModel(); - responseObject.setApplicationKey(BaseEncoding.base64().encode(message.getApplicationKey())); - responseObject.setEphemeralPublicKey(BaseEncoding.base64().encode(message.getEphemeralPublicKey())); - responseObject.setSessionIndex(BaseEncoding.base64().encode(message.getSessionIndex())); - responseObject.setAdHocIndex(BaseEncoding.base64().encode(message.getAdHocIndex())); - responseObject.setMacIndex(BaseEncoding.base64().encode(message.getMacIndex())); - responseObject.setNonce(BaseEncoding.base64().encode(message.getNonce())); - responseObject.setMac(BaseEncoding.base64().encode(message.getMac())); - responseObject.setEncryptedData(BaseEncoding.base64().encode(message.getEncryptedData())); - - return new ObjectResponse<>(responseObject); - } - - /** - * Decrypt an object. - * - * @param request Object with encrypted payload. - * @return Decrypted bytes. - * @throws GenericCryptoException In case of a cryptography error. - * @throws CryptoProviderException In case of a cryptographic provider error. - * @throws InvalidKeyException In case the key provided for encryption is invalid. - */ - public byte[] decrypt(ObjectRequest request) throws GenericCryptoException, CryptoProviderException, InvalidKeyException { - - if (request == null) { - return null; - } - - final NonPersonalizedEncryptedPayloadModel requestObject = request.getRequestObject(); - - if (requestObject == null) { - return null; - } - - final NonPersonalizedEncryptedMessage message = new NonPersonalizedEncryptedMessage(); - message.setApplicationKey(BaseEncoding.base64().decode(requestObject.getApplicationKey())); - message.setEphemeralPublicKey(BaseEncoding.base64().decode(requestObject.getEphemeralPublicKey())); - message.setSessionIndex(BaseEncoding.base64().decode(requestObject.getSessionIndex())); - message.setAdHocIndex(BaseEncoding.base64().decode(requestObject.getAdHocIndex())); - message.setMacIndex(BaseEncoding.base64().decode(requestObject.getMacIndex())); - message.setNonce(BaseEncoding.base64().decode(requestObject.getNonce())); - message.setMac(BaseEncoding.base64().decode(requestObject.getMac())); - message.setEncryptedData(BaseEncoding.base64().decode(requestObject.getEncryptedData())); - - return encryptor.decrypt(message); - } - - /** - * Decrypt data and serialize object. - * - * @param request Request with encrypted data. - * @param resultClass Result deserialized class. - * @param Specific type of the result class. - * @return Decrypted object of a provided type T. - * @throws IOException In case the JSON deserialization fails. - * @throws GenericCryptoException In case of a cryptography error. - * @throws CryptoProviderException In case of a cryptographic provider error. - * @throws InvalidKeyException In case the key provided for encryption is invalid. - */ - public T decrypt(ObjectRequest request, Class resultClass) throws IOException, GenericCryptoException, CryptoProviderException, InvalidKeyException { - final byte[] result = this.decrypt(request); - if (result == null) { - return null; - } - return mapper.readValue(result, resultClass); - } - -} diff --git a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/entrypoint/PowerAuthApiAuthenticationEntryPoint.java b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/entrypoint/PowerAuthApiAuthenticationEntryPoint.java index 55889a17..4fe3fc97 100644 --- a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/entrypoint/PowerAuthApiAuthenticationEntryPoint.java +++ b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/entrypoint/PowerAuthApiAuthenticationEntryPoint.java @@ -26,8 +26,8 @@ import org.springframework.security.web.AuthenticationEntryPoint; import org.springframework.stereotype.Service; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; /** diff --git a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/PowerAuthActivationException.java b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/PowerAuthActivationException.java index fa201ca5..13dbf5ea 100644 --- a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/PowerAuthActivationException.java +++ b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/PowerAuthActivationException.java @@ -19,6 +19,8 @@ */ package io.getlime.security.powerauth.rest.api.spring.exception; +import java.io.Serial; + /** * Exception related to processes during a new activation process. * @@ -26,6 +28,7 @@ */ public class PowerAuthActivationException extends Exception { + @Serial private static final long serialVersionUID = -7975115359211508795L; private static final String DEFAULT_CODE = "ERR_ACTIVATION"; diff --git a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/PowerAuthAuthenticationException.java b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/PowerAuthAuthenticationException.java index cbd8b8a8..1157e90c 100644 --- a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/PowerAuthAuthenticationException.java +++ b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/PowerAuthAuthenticationException.java @@ -19,6 +19,8 @@ */ package io.getlime.security.powerauth.rest.api.spring.exception; +import java.io.Serial; + /** * Exception raised in case PowerAuth authentication fails. * @@ -27,6 +29,7 @@ */ public class PowerAuthAuthenticationException extends Exception { + @Serial private static final long serialVersionUID = 4280095091435126237L; private static final String DEFAULT_CODE = "ERR_AUTHENTICATION"; diff --git a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/PowerAuthEncryptionException.java b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/PowerAuthEncryptionException.java index 64ae1c04..0151dfc6 100644 --- a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/PowerAuthEncryptionException.java +++ b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/PowerAuthEncryptionException.java @@ -19,6 +19,8 @@ */ package io.getlime.security.powerauth.rest.api.spring.exception; +import java.io.Serial; + /** * Exception raised in case encryption or decryption fails. * @@ -27,6 +29,7 @@ */ public class PowerAuthEncryptionException extends Exception { + @Serial private static final long serialVersionUID = -4247463135868495185L; private static final String DEFAULT_CODE = "ERR_ENCRYPTION"; diff --git a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/PowerAuthRecoveryException.java b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/PowerAuthRecoveryException.java index 80721ccc..07e85ebe 100644 --- a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/PowerAuthRecoveryException.java +++ b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/PowerAuthRecoveryException.java @@ -19,6 +19,8 @@ */ package io.getlime.security.powerauth.rest.api.spring.exception; +import java.io.Serial; + /** * Exception thrown in case PowerAuth recovery fails, with optional current PUK index. * @@ -26,6 +28,7 @@ */ public class PowerAuthRecoveryException extends Exception { + @Serial private static final long serialVersionUID = 6497199187989286105L; private static final String DEFAULT_CODE = "ERR_RECOVERY"; diff --git a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/PowerAuthSecureVaultException.java b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/PowerAuthSecureVaultException.java index e676947c..eeecd0c5 100644 --- a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/PowerAuthSecureVaultException.java +++ b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/PowerAuthSecureVaultException.java @@ -19,6 +19,8 @@ */ package io.getlime.security.powerauth.rest.api.spring.exception; +import java.io.Serial; + /** * Exception related to processes during a new secure vault unlocking. * @@ -26,6 +28,7 @@ */ public class PowerAuthSecureVaultException extends Exception { + @Serial private static final long serialVersionUID = -6996857964853505534L; private static final String DEFAULT_CODE = "ERR_SECURE_VAULT"; diff --git a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/PowerAuthUpgradeException.java b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/PowerAuthUpgradeException.java index d5af05f7..d3f00c82 100644 --- a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/PowerAuthUpgradeException.java +++ b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/PowerAuthUpgradeException.java @@ -19,6 +19,8 @@ */ package io.getlime.security.powerauth.rest.api.spring.exception; +import java.io.Serial; + /** * Exception raised in case PowerAuth upgrade fails. * @@ -27,6 +29,7 @@ */ public class PowerAuthUpgradeException extends Exception { + @Serial private static final long serialVersionUID = -5750221213611810117L; private static final String DEFAULT_CODE = "ERR_UPGRADE"; diff --git a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/PowerAuthUserInfoException.java b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/PowerAuthUserInfoException.java new file mode 100644 index 00000000..6a79d21f --- /dev/null +++ b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/PowerAuthUserInfoException.java @@ -0,0 +1,86 @@ +/* + * PowerAuth integration libraries for RESTful API applications, examples 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 io.getlime.security.powerauth.rest.api.spring.exception; + +import java.io.Serial; + +/** + * Exception for endpoints related to the user info endpoint. + * + * @author Petr Dvorak, petr@wultra.com + */ +public class PowerAuthUserInfoException extends Exception { + + @Serial + private static final long serialVersionUID = 5046389522294059168L; + + private static final String DEFAULT_CODE = "ERR_USER_INFO"; + private static final String DEFAULT_ERROR = "POWER_AUTH_USER_INFO_ERROR"; + + /** + * Default constructor. + */ + public PowerAuthUserInfoException() { + super(DEFAULT_ERROR); + } + + /** + * Constructor with a custom error message. + * @param message Error message. + */ + public PowerAuthUserInfoException(String message) { + super(message); + } + + /** + * Constructor with a cause. + * @param cause Error cause. + */ + public PowerAuthUserInfoException(Throwable cause) { + super(cause); + } + + /** + * Constructor with a message and cause. + * @param message Error message. + * @param cause Error cause. + */ + public PowerAuthUserInfoException(String message, Throwable cause) { + super(message, cause); + } + + + /** + * Get default error code, used for example in the 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/exception/authentication/PowerAuthHeaderMissingException.java b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/authentication/PowerAuthHeaderMissingException.java index cc2a8652..c5dcea7b 100644 --- a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/authentication/PowerAuthHeaderMissingException.java +++ b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/authentication/PowerAuthHeaderMissingException.java @@ -21,6 +21,8 @@ import io.getlime.security.powerauth.rest.api.spring.exception.PowerAuthAuthenticationException; +import java.io.Serial; + /** * Exception raised in case PowerAuth HTTP header is missing. * @@ -29,6 +31,7 @@ */ public class PowerAuthHeaderMissingException extends PowerAuthAuthenticationException { + @Serial private static final long serialVersionUID = -2359879611684674690L; private static final String DEFAULT_CODE = "ERR_AUTHENTICATION"; diff --git a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/authentication/PowerAuthInvalidRequestException.java b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/authentication/PowerAuthInvalidRequestException.java index 42ab5a21..0a84741f 100644 --- a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/authentication/PowerAuthInvalidRequestException.java +++ b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/authentication/PowerAuthInvalidRequestException.java @@ -21,6 +21,8 @@ import io.getlime.security.powerauth.rest.api.spring.exception.PowerAuthAuthenticationException; +import java.io.Serial; + /** * Exception raised in case PowerAuth authentication request is invalid. * @@ -29,6 +31,7 @@ */ public class PowerAuthInvalidRequestException extends PowerAuthAuthenticationException { + @Serial private static final long serialVersionUID = -6068516562428771519L; private static final String DEFAULT_CODE = "ERR_AUTHENTICATION"; @@ -61,6 +64,7 @@ public PowerAuthInvalidRequestException(Throwable cause) { * Get the default error code, used for example in REST response. * @return Default error code. */ + @Override public String getDefaultCode() { return DEFAULT_CODE; } diff --git a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/authentication/PowerAuthRecoveryConfirmationException.java b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/authentication/PowerAuthRecoveryConfirmationException.java index 5fd70d88..b0abc2ab 100644 --- a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/authentication/PowerAuthRecoveryConfirmationException.java +++ b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/authentication/PowerAuthRecoveryConfirmationException.java @@ -21,6 +21,8 @@ import io.getlime.security.powerauth.rest.api.spring.exception.PowerAuthAuthenticationException; +import java.io.Serial; + /** * Exception raised in case PowerAuth recovery confirmation fails with an error. * @@ -29,6 +31,7 @@ */ public class PowerAuthRecoveryConfirmationException extends PowerAuthAuthenticationException { + @Serial private static final long serialVersionUID = 7840709829931142914L; private static final String DEFAULT_CODE = "ERR_AUTHENTICATION"; diff --git a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/authentication/PowerAuthRequestFilterException.java b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/authentication/PowerAuthRequestFilterException.java index 571368b1..6f9147d8 100644 --- a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/authentication/PowerAuthRequestFilterException.java +++ b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/authentication/PowerAuthRequestFilterException.java @@ -21,6 +21,8 @@ import io.getlime.security.powerauth.rest.api.spring.exception.PowerAuthAuthenticationException; +import java.io.Serial; + /** * Exception raised in case PowerAuth authentication request filter is missing. * @@ -29,6 +31,7 @@ */ public class PowerAuthRequestFilterException extends PowerAuthAuthenticationException { + @Serial private static final long serialVersionUID = -6832983011115467428L; private static final String DEFAULT_CODE = "ERR_AUTHENTICATION"; diff --git a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/authentication/PowerAuthSignatureErrorException.java b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/authentication/PowerAuthSignatureErrorException.java index 0a818b8e..1d72a09f 100644 --- a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/authentication/PowerAuthSignatureErrorException.java +++ b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/authentication/PowerAuthSignatureErrorException.java @@ -21,6 +21,8 @@ import io.getlime.security.powerauth.rest.api.spring.exception.PowerAuthAuthenticationException; +import java.io.Serial; + /** * Exception raised in case PowerAuth signature validation fails with an error. * @@ -29,6 +31,7 @@ */ public class PowerAuthSignatureErrorException extends PowerAuthAuthenticationException { + @Serial private static final long serialVersionUID = 1428981649658439163L; private static final String DEFAULT_CODE = "ERR_AUTHENTICATION"; diff --git a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/authentication/PowerAuthSignatureInvalidException.java b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/authentication/PowerAuthSignatureInvalidException.java index 253ca895..31b150a7 100644 --- a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/authentication/PowerAuthSignatureInvalidException.java +++ b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/authentication/PowerAuthSignatureInvalidException.java @@ -21,6 +21,8 @@ import io.getlime.security.powerauth.rest.api.spring.exception.PowerAuthAuthenticationException; +import java.io.Serial; + /** * Exception raised in case PowerAuth signature validation fails. * @@ -29,6 +31,7 @@ */ public class PowerAuthSignatureInvalidException extends PowerAuthAuthenticationException { + @Serial private static final long serialVersionUID = -8628851623611808408L; private static final String DEFAULT_CODE = "ERR_AUTHENTICATION"; diff --git a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/authentication/PowerAuthSignatureTypeInvalidException.java b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/authentication/PowerAuthSignatureTypeInvalidException.java index 678a7849..70339874 100644 --- a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/authentication/PowerAuthSignatureTypeInvalidException.java +++ b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/authentication/PowerAuthSignatureTypeInvalidException.java @@ -21,6 +21,8 @@ import io.getlime.security.powerauth.rest.api.spring.exception.PowerAuthAuthenticationException; +import java.io.Serial; + /** * Exception raised in case PowerAuth signature type is invalid. * @@ -29,6 +31,7 @@ */ public class PowerAuthSignatureTypeInvalidException extends PowerAuthAuthenticationException { + @Serial private static final long serialVersionUID = 6914310542180702420L; private static final String DEFAULT_CODE = "ERR_AUTHENTICATION"; diff --git a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/authentication/PowerAuthTokenErrorException.java b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/authentication/PowerAuthTokenErrorException.java index 7d386678..a1e81c9a 100644 --- a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/authentication/PowerAuthTokenErrorException.java +++ b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/authentication/PowerAuthTokenErrorException.java @@ -21,6 +21,8 @@ import io.getlime.security.powerauth.rest.api.spring.exception.PowerAuthAuthenticationException; +import java.io.Serial; + /** * Exception raised in case PowerAuth token validation fails with an error. * @@ -29,6 +31,7 @@ */ public class PowerAuthTokenErrorException extends PowerAuthAuthenticationException { + @Serial private static final long serialVersionUID = 3900547437080764802L; private static final String DEFAULT_CODE = "ERR_AUTHENTICATION"; diff --git a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/authentication/PowerAuthTokenInvalidException.java b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/authentication/PowerAuthTokenInvalidException.java index 50596161..044ebe40 100644 --- a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/authentication/PowerAuthTokenInvalidException.java +++ b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/exception/authentication/PowerAuthTokenInvalidException.java @@ -21,6 +21,8 @@ import io.getlime.security.powerauth.rest.api.spring.exception.PowerAuthAuthenticationException; +import java.io.Serial; + /** * Exception raised in case PowerAuth token validation fails. * @@ -29,6 +31,7 @@ */ public class PowerAuthTokenInvalidException extends PowerAuthAuthenticationException { + @Serial private static final long serialVersionUID = 1052831183125328518L; private static final String DEFAULT_CODE = "ERR_AUTHENTICATION"; diff --git a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/filter/EncryptionResponseBodyAdvice.java b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/filter/EncryptionResponseBodyAdvice.java index fe13db0f..5de8617c 100644 --- a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/filter/EncryptionResponseBodyAdvice.java +++ b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/filter/EncryptionResponseBodyAdvice.java @@ -20,13 +20,12 @@ package io.getlime.security.powerauth.rest.api.spring.filter; import com.fasterxml.jackson.databind.ObjectMapper; -import com.google.common.io.BaseEncoding; -import io.getlime.security.powerauth.crypto.lib.encryptor.ecies.EciesDecryptor; -import io.getlime.security.powerauth.crypto.lib.encryptor.ecies.model.EciesCryptogram; -import io.getlime.security.powerauth.rest.api.spring.encryption.PowerAuthEciesEncryption; -import io.getlime.security.powerauth.rest.api.spring.model.PowerAuthRequestObjects; -import io.getlime.security.powerauth.rest.api.model.response.v3.EciesEncryptedResponse; +import io.getlime.security.powerauth.crypto.lib.encryptor.model.EncryptedResponse; +import io.getlime.security.powerauth.rest.api.model.response.EciesEncryptedResponse; import io.getlime.security.powerauth.rest.api.spring.annotation.PowerAuthEncryption; +import io.getlime.security.powerauth.rest.api.spring.encryption.PowerAuthEncryptorData; +import io.getlime.security.powerauth.rest.api.spring.model.PowerAuthRequestObjects; +import jakarta.servlet.http.HttpServletRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -47,7 +46,6 @@ import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter; import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice; -import javax.servlet.http.HttpServletRequest; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; @@ -110,34 +108,33 @@ public Object beforeBodyWrite(Object response, @NonNull MethodParameter methodPa return null; } - // Extract ECIES encryption object from HTTP request + // Extract encryption object from HTTP request final HttpServletRequest httpServletRequest = ((ServletServerHttpRequest) serverHttpRequest).getServletRequest(); - final PowerAuthEciesEncryption eciesEncryption = (PowerAuthEciesEncryption) httpServletRequest.getAttribute(PowerAuthRequestObjects.ENCRYPTION_OBJECT); - if (eciesEncryption == null) { + final PowerAuthEncryptorData encryption = (PowerAuthEncryptorData) httpServletRequest.getAttribute(PowerAuthRequestObjects.ENCRYPTION_OBJECT); + if (encryption == null || encryption.getServerEncryptor() == null) { return null; } // Convert response to JSON try { byte[] responseBytes = serializeResponseObject(response); - - // Encrypt response using decryptor and return ECIES cryptogram - final EciesDecryptor eciesDecryptor = eciesEncryption.getEciesDecryptor(); - final EciesCryptogram cryptogram = eciesDecryptor.encryptResponse(responseBytes); - final String encryptedDataBase64 = BaseEncoding.base64().encode(cryptogram.getEncryptedData()); - final String macBase64 = BaseEncoding.base64().encode(cryptogram.getMac()); - + final EncryptedResponse encryptedResponse = encryption.getServerEncryptor().encryptResponse(responseBytes); // Return encrypted response with type given by converter class - final EciesEncryptedResponse encryptedResponse = new EciesEncryptedResponse(encryptedDataBase64, macBase64); + final EciesEncryptedResponse encryptedResponseObject = new EciesEncryptedResponse( + encryptedResponse.getEncryptedData(), + encryptedResponse.getMac(), + encryptedResponse.getNonce(), + encryptedResponse.getTimestamp() + ); if (converterClass.isAssignableFrom(MappingJackson2HttpMessageConverter.class)) { // Object conversion is done automatically using MappingJackson2HttpMessageConverter - return encryptedResponse; + return encryptedResponseObject; } else if (converterClass.isAssignableFrom(StringHttpMessageConverter.class)) { // Conversion to byte[] is done using first applicable configured HTTP message converter, corresponding String is returned - return new String(convertEncryptedResponse(encryptedResponse, mediaType), StandardCharsets.UTF_8); + return new String(convertEncryptedResponse(encryptedResponseObject, mediaType), StandardCharsets.UTF_8); } else { // Conversion to byte[] is done using first applicable configured HTTP message converter - return convertEncryptedResponse(encryptedResponse, mediaType); + return convertEncryptedResponse(encryptedResponseObject, mediaType); } } catch (Exception ex) { logger.warn("Encryption failed, error: {}", ex.getMessage()); diff --git a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/filter/PowerAuthRequestFilter.java b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/filter/PowerAuthRequestFilter.java index dcb9fb55..1ccea56e 100644 --- a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/filter/PowerAuthRequestFilter.java +++ b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/filter/PowerAuthRequestFilter.java @@ -22,10 +22,10 @@ import org.springframework.lang.NonNull; import org.springframework.web.filter.OncePerRequestFilter; -import javax.servlet.FilterChain; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; /** diff --git a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/filter/PowerAuthRequestFilterBase.java b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/filter/PowerAuthRequestFilterBase.java index 58c68d98..7ccc6e12 100644 --- a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/filter/PowerAuthRequestFilterBase.java +++ b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/filter/PowerAuthRequestFilterBase.java @@ -25,7 +25,7 @@ import io.getlime.security.powerauth.rest.api.spring.model.PowerAuthRequestBody; import io.getlime.security.powerauth.rest.api.spring.model.PowerAuthRequestObjects; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; import java.io.IOException; import java.net.URLDecoder; import java.nio.charset.StandardCharsets; @@ -63,7 +63,7 @@ public static ResettableStreamHttpServletRequest filterRequest(HttpServletReques if (queryString != null && queryString.length() > 0) { // Decode the query string - queryString = URLDecoder.decode(queryString, "UTF-8"); + queryString = URLDecoder.decode(queryString, StandardCharsets.UTF_8); // Get the canonized form final String signatureBaseStringData = PowerAuthRequestCanonizationUtils.canonizeGetParameters(queryString); diff --git a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/filter/ResettableStreamHttpServletRequest.java b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/filter/ResettableStreamHttpServletRequest.java index fadc265a..ee6d03d1 100644 --- a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/filter/ResettableStreamHttpServletRequest.java +++ b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/filter/ResettableStreamHttpServletRequest.java @@ -22,10 +22,10 @@ import com.google.common.io.ByteStreams; import javax.annotation.Nonnull; -import javax.servlet.ReadListener; -import javax.servlet.ServletInputStream; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletRequestWrapper; +import jakarta.servlet.ReadListener; +import jakarta.servlet.ServletInputStream; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequestWrapper; import java.io.*; import java.util.Arrays; diff --git a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/model/ActivationContext.java b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/model/ActivationContext.java index aa617838..967c227d 100644 --- a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/model/ActivationContext.java +++ b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/model/ActivationContext.java @@ -46,6 +46,9 @@ public class ActivationContext { private String deviceInfo; private String extras; + /** + * Activation context constructor. + */ public ActivationContext() { this.activationFlags = new ArrayList<>(); } diff --git a/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/v2/ActivationStatusRequest.java b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/model/UserInfoContext.java similarity index 61% rename from powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/v2/ActivationStatusRequest.java rename to powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/model/UserInfoContext.java index eb3d10e0..99b6993a 100644 --- a/powerauth-restful-model/src/main/java/io/getlime/security/powerauth/rest/api/model/request/v2/ActivationStatusRequest.java +++ b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/model/UserInfoContext.java @@ -2,7 +2,7 @@ * PowerAuth integration libraries for RESTful API applications, examples and * related software components * - * Copyright (C) 2018 Wultra s.r.o. + * 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 @@ -17,32 +17,39 @@ * 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.v2; +package io.getlime.security.powerauth.rest.api.spring.model; + +import io.getlime.security.powerauth.rest.api.model.entity.UserInfoStage; +import lombok.Builder; +import lombok.Data; /** - * Request object for /pa/activation/status end-point + * Class for passing the context attributes to user info provider. * * @author Petr Dvorak, petr@wultra.com - * */ -public class ActivationStatusRequest { +@Data +@Builder +public class UserInfoContext { - private String activationId; + /** + * Information about where the user info is requested from. + */ + private UserInfoStage stage; /** - * Get activation ID - * @return Activation ID + * User ID. */ - public String getActivationId() { - return activationId; - } + private String userId; + + /** + * Activation ID. + */ + private String activationId; /** - * Set activation ID - * @param activationId Activation ID + * Application ID. */ - public void setActivationId(String activationId) { - this.activationId = activationId; - } + private String applicationId; } diff --git a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/provider/CustomActivationProvider.java b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/provider/CustomActivationProvider.java index e52ef4af..66311516 100644 --- a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/provider/CustomActivationProvider.java +++ b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/provider/CustomActivationProvider.java @@ -19,6 +19,7 @@ */ package io.getlime.security.powerauth.rest.api.spring.provider; +import com.wultra.core.annotations.PublicSpi; import io.getlime.security.powerauth.rest.api.spring.exception.PowerAuthActivationException; import io.getlime.security.powerauth.rest.api.model.entity.ActivationType; @@ -34,6 +35,7 @@ * @author Petr Dvorak, petr@wultra.com * @author Roman Strobl, roman.strobl@wultra.com */ +@PublicSpi public interface CustomActivationProvider { /** @@ -108,21 +110,20 @@ default boolean shouldAutoCommitActivation(Map identityAttribute default void activationWasCommitted(Map identityAttributes, Map customAttributes, String activationId, String userId, String appId, ActivationType activationType, Map context) throws PowerAuthActivationException {} /** - * Method that indicates if recovery codes should be generated for a given activation or not. The method may return null, - * in such case, it uses settings of the PowerAuth Server to determine if the recovery codes should be generated or not. Also, - * just specifying true in the call will not result in generating recovery codes in case that recovery codes are + * Method that indicates if recovery codes should be generated for a given activation or not. + * Note that specifying true in the call will not result in generating recovery codes in case that recovery codes are * globally disabled at the PowerAuth Server. * * @param identityAttributes Identity related attributes. * @param customAttributes Custom attributes, not related to identity. * @param activationType Activation type. * @param context Context for passing parameters between activation provider calls. - * @return False to prevent generating recovery codes, "null" to let the PowerAuth Server decide, and true to generate recovery codes + * @return False to prevent generating recovery codes, true to generate recovery codes * in case that the feature is enabled globally on PowerAuth Server. * @throws PowerAuthActivationException In case of error in custom activation business logic that should terminate the rest of the activation. */ - default Boolean shouldCreateRecoveryCodes(Map identityAttributes, Map customAttributes, ActivationType activationType, Map context) throws PowerAuthActivationException { - return null; + default boolean shouldCreateRecoveryCodes(Map identityAttributes, Map customAttributes, ActivationType activationType, Map context) throws PowerAuthActivationException { + return true; } /** diff --git a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/provider/MinimalClaimsUserInfoProvider.java b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/provider/MinimalClaimsUserInfoProvider.java new file mode 100644 index 00000000..6d457291 --- /dev/null +++ b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/provider/MinimalClaimsUserInfoProvider.java @@ -0,0 +1,75 @@ +/* + * PowerAuth integration libraries for RESTful API applications, examples 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 io.getlime.security.powerauth.rest.api.spring.provider; + +import com.wultra.core.annotations.PublicSpi; +import io.getlime.security.powerauth.rest.api.spring.model.UserInfoContext; + +import javax.annotation.Nonnull; +import java.time.Instant; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.UUID; + +/** + * Specialization of {@link UserInfoProvider}. + * Claims {@code sub, jti, iat} are filled. + * UserInfo is always returned, even for activation. + * + * @author Lubos Racansky, lubos.racansky@wultra.com + */ +@PublicSpi +public class MinimalClaimsUserInfoProvider implements UserInfoProvider{ + + /** + * Always true, even for activation. + *

+ * {@inheritDoc} + */ + @Override + public boolean shouldReturnUserInfo(@Nonnull UserInfoContext context) { + return true; + } + + /** + * Fill claims {@code sub, jti, iat}. + *

+ * {@inheritDoc} + */ + @Override + public Map fetchUserClaimsForUserId(@Nonnull UserInfoContext context) { + return minimalClaims(context); + } + + /** + * Prepare a set of minimal claims sub, jti and iat. + * + * @param context User info context object. + * @return Map of claims obtained for a given user ID. + */ + private static Map minimalClaims(@Nonnull UserInfoContext context) { + final Map defaultClaims = new LinkedHashMap<>(); + defaultClaims.put("sub", context.getUserId()); + defaultClaims.put("jti", UUID.randomUUID().toString()); + defaultClaims.put("iat", Instant.now().getEpochSecond()); + return Collections.unmodifiableMap(defaultClaims); + } +} diff --git a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/provider/PowerAuthAuthenticationProvider.java b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/provider/PowerAuthAuthenticationProvider.java index e499b167..e7ce01d4 100644 --- a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/provider/PowerAuthAuthenticationProvider.java +++ b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/provider/PowerAuthAuthenticationProvider.java @@ -19,10 +19,13 @@ */ package io.getlime.security.powerauth.rest.api.spring.provider; -import com.google.common.io.BaseEncoding; 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.v3.*; +import com.wultra.security.powerauth.client.model.request.ValidateTokenRequest; +import com.wultra.security.powerauth.client.model.request.VerifySignatureRequest; +import com.wultra.security.powerauth.client.model.response.ValidateTokenResponse; +import com.wultra.security.powerauth.client.model.response.VerifySignatureResponse; import io.getlime.security.powerauth.crypto.lib.enums.PowerAuthSignatureTypes; import io.getlime.security.powerauth.http.PowerAuthHttpBody; import io.getlime.security.powerauth.http.PowerAuthHttpHeader; @@ -37,8 +40,8 @@ import io.getlime.security.powerauth.rest.api.spring.authentication.impl.PowerAuthApiAuthenticationImpl; import io.getlime.security.powerauth.rest.api.spring.authentication.impl.PowerAuthSignatureAuthenticationImpl; import io.getlime.security.powerauth.rest.api.spring.authentication.impl.PowerAuthTokenAuthenticationImpl; -import io.getlime.security.powerauth.rest.api.spring.converter.v3.ActivationStatusConverter; -import io.getlime.security.powerauth.rest.api.spring.converter.v3.SignatureTypeConverter; +import io.getlime.security.powerauth.rest.api.spring.converter.ActivationStatusConverter; +import io.getlime.security.powerauth.rest.api.spring.converter.SignatureTypeConverter; import io.getlime.security.powerauth.rest.api.spring.exception.PowerAuthAuthenticationException; import io.getlime.security.powerauth.rest.api.spring.exception.authentication.PowerAuthHeaderMissingException; import io.getlime.security.powerauth.rest.api.spring.exception.authentication.PowerAuthSignatureInvalidException; @@ -56,6 +59,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; +import java.util.Base64; import java.util.List; /** @@ -157,7 +161,7 @@ private PowerAuthApiAuthenticationImpl validateSignatureAuthentication(PowerAuth final AuthenticationContext authenticationContext = new AuthenticationContext(); authenticationContext.setValid(response.isSignatureValid()); authenticationContext.setRemainingAttempts(response.getRemainingAttempts() != null ? response.getRemainingAttempts().intValue() : null); - authenticationContext.setSignatureType(response.getSignatureType() != null ? PowerAuthSignatureTypes.getEnumFromString(response.getSignatureType().value()) : null); + authenticationContext.setSignatureType(response.getSignatureType() != null ? PowerAuthSignatureTypes.getEnumFromString(response.getSignatureType().name()) : null); final PowerAuthActivation activationContext = copyActivationAttributes(response.getActivationId(), response.getUserId(), activationStatus, response.getBlockedReason(), response.getActivationFlags(), authenticationContext, authentication.getVersion()); @@ -183,6 +187,7 @@ private PowerAuthApiAuthenticationImpl validateTokenAuthentication(PowerAuthToke validateRequest.setTokenDigest(authentication.getTokenDigest()); validateRequest.setNonce(authentication.getNonce()); validateRequest.setTimestamp(Long.parseLong(authentication.getTimestamp())); + validateRequest.setProtocolVersion(authentication.getVersion()); final ValidateTokenResponse response = powerAuthClient.validateToken( validateRequest, @@ -194,7 +199,7 @@ private PowerAuthApiAuthenticationImpl validateTokenAuthentication(PowerAuthToke final AuthenticationContext authenticationContext = new AuthenticationContext(); authenticationContext.setValid(response.isTokenValid()); authenticationContext.setRemainingAttempts(null); - authenticationContext.setSignatureType(response.getSignatureType() != null ? PowerAuthSignatureTypes.getEnumFromString(response.getSignatureType().value()) : null); + authenticationContext.setSignatureType(response.getSignatureType() != null ? PowerAuthSignatureTypes.getEnumFromString(response.getSignatureType().name()) : null); final PowerAuthActivation activationContext = copyActivationAttributes(response.getActivationId(), response.getUserId(), activationStatus, response.getBlockedReason(), response.getActivationFlags(), authenticationContext, authentication.getVersion()); @@ -326,7 +331,7 @@ public PowerAuthApiAuthentication validateRequestSignature( final PowerAuthSignatureAuthenticationImpl powerAuthAuthentication = new PowerAuthSignatureAuthenticationImpl(); powerAuthAuthentication.setActivationId(header.getActivationId()); powerAuthAuthentication.setApplicationKey(header.getApplicationKey()); - powerAuthAuthentication.setNonce(BaseEncoding.base64().decode(header.getNonce())); + powerAuthAuthentication.setNonce(Base64.getDecoder().decode(header.getNonce())); powerAuthAuthentication.setSignatureType(header.getSignatureType()); powerAuthAuthentication.setSignature(header.getSignature()); powerAuthAuthentication.setHttpMethod(httpMethod); diff --git a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/provider/PowerAuthAuthenticationProviderBase.java b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/provider/PowerAuthAuthenticationProviderBase.java index c5798279..ee04280c 100644 --- a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/provider/PowerAuthAuthenticationProviderBase.java +++ b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/provider/PowerAuthAuthenticationProviderBase.java @@ -21,7 +21,7 @@ import io.getlime.security.powerauth.crypto.lib.enums.PowerAuthSignatureTypes; import io.getlime.security.powerauth.rest.api.spring.authentication.PowerAuthApiAuthentication; -import io.getlime.security.powerauth.rest.api.spring.encryption.PowerAuthEciesEncryption; +import io.getlime.security.powerauth.rest.api.spring.encryption.PowerAuthEncryptorData; import io.getlime.security.powerauth.rest.api.spring.exception.PowerAuthAuthenticationException; import io.getlime.security.powerauth.rest.api.spring.exception.authentication.PowerAuthRequestFilterException; import io.getlime.security.powerauth.rest.api.spring.model.PowerAuthRequestBody; @@ -31,7 +31,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; import java.util.ArrayList; import java.util.List; @@ -198,8 +198,8 @@ public abstract class PowerAuthAuthenticationProviderBase { */ public @Nullable byte[] extractRequestBodyBytes(@Nonnull HttpServletRequest servletRequest) throws PowerAuthAuthenticationException { if (servletRequest.getAttribute(PowerAuthRequestObjects.ENCRYPTION_OBJECT) != null) { - // Implementation of sign-then-encrypt - in case the encryption object is present and signature is validate, use decrypted request data - PowerAuthEciesEncryption eciesEncryption = (PowerAuthEciesEncryption) servletRequest.getAttribute(PowerAuthRequestObjects.ENCRYPTION_OBJECT); + // Implementation of sign-then-encrypt - in case the encryption object is present and signature is valid, use decrypted request data + PowerAuthEncryptorData eciesEncryption = (PowerAuthEncryptorData) servletRequest.getAttribute(PowerAuthRequestObjects.ENCRYPTION_OBJECT); return eciesEncryption.getDecryptedRequest(); } else { // Request data was not encrypted - use regular PowerAuth request body for signature validation 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 8451c560..9b04439d 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 @@ -20,9 +20,9 @@ package io.getlime.security.powerauth.rest.api.spring.provider; import com.wultra.security.powerauth.client.PowerAuthClient; -import com.wultra.security.powerauth.client.v3.GetEciesDecryptorRequest; -import com.wultra.security.powerauth.client.v3.GetEciesDecryptorResponse; -import io.getlime.security.powerauth.rest.api.spring.encryption.PowerAuthEciesDecryptorParameters; +import com.wultra.security.powerauth.client.model.request.GetEciesDecryptorRequest; +import com.wultra.security.powerauth.client.model.response.GetEciesDecryptorResponse; +import io.getlime.security.powerauth.rest.api.spring.encryption.PowerAuthEncryptorParameters; import io.getlime.security.powerauth.rest.api.spring.exception.PowerAuthEncryptionException; import io.getlime.security.powerauth.rest.api.spring.service.HttpCustomizationService; import org.slf4j.Logger; @@ -59,19 +59,22 @@ public PowerAuthEncryptionProvider(PowerAuthClient powerAuthClient, HttpCustomiz } @Override - public @Nonnull PowerAuthEciesDecryptorParameters getEciesDecryptorParameters(@Nullable String activationId, @Nonnull String applicationKey, @Nonnull String ephemeralPublicKey) throws PowerAuthEncryptionException { + public @Nonnull PowerAuthEncryptorParameters getEciesDecryptorParameters(@Nullable String activationId, @Nonnull String applicationKey, @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.setEphemeralPublicKey(ephemeralPublicKey); + eciesDecryptorRequest.setProtocolVersion(version); + eciesDecryptorRequest.setNonce(nonce); + eciesDecryptorRequest.setTimestamp(timestamp); final GetEciesDecryptorResponse eciesDecryptorResponse = powerAuthClient.getEciesDecryptor( eciesDecryptorRequest, httpCustomizationService.getQueryParams(), httpCustomizationService.getHttpHeaders() ); - return new PowerAuthEciesDecryptorParameters(eciesDecryptorResponse.getSecretKey(), eciesDecryptorResponse.getSharedInfo2()); + return new PowerAuthEncryptorParameters(eciesDecryptorResponse.getSecretKey(), eciesDecryptorResponse.getSharedInfo2()); } catch (Exception ex) { logger.warn("Get ECIES decryptor call failed, error: {}", ex.getMessage()); logger.debug(ex.getMessage(), ex); 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 04b100b4..5376a3da 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 @@ -23,33 +23,33 @@ import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.type.TypeFactory; -import com.google.common.io.BaseEncoding; -import io.getlime.security.powerauth.crypto.lib.encryptor.ecies.EciesDecryptor; -import io.getlime.security.powerauth.crypto.lib.encryptor.ecies.EciesEnvelopeKey; -import io.getlime.security.powerauth.crypto.lib.encryptor.ecies.EciesFactory; -import io.getlime.security.powerauth.crypto.lib.encryptor.ecies.model.EciesCryptogram; -import io.getlime.security.powerauth.crypto.lib.encryptor.ecies.model.EciesScope; +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.model.*; +import io.getlime.security.powerauth.crypto.lib.encryptor.model.v3.ServerEncryptorSecrets; import io.getlime.security.powerauth.http.PowerAuthEncryptionHttpHeader; import io.getlime.security.powerauth.http.PowerAuthSignatureHttpHeader; import io.getlime.security.powerauth.http.validator.InvalidPowerAuthHttpHeaderException; import io.getlime.security.powerauth.http.validator.PowerAuthEncryptionHttpHeaderValidator; import io.getlime.security.powerauth.http.validator.PowerAuthSignatureHttpHeaderValidator; -import io.getlime.security.powerauth.rest.api.spring.encryption.EciesEncryptionContext; -import io.getlime.security.powerauth.rest.api.spring.encryption.PowerAuthEciesDecryptorParameters; -import io.getlime.security.powerauth.rest.api.spring.encryption.PowerAuthEciesEncryption; +import io.getlime.security.powerauth.rest.api.model.request.EciesEncryptedRequest; +import io.getlime.security.powerauth.rest.api.model.response.EciesEncryptedResponse; +import io.getlime.security.powerauth.rest.api.spring.encryption.EncryptionContext; +import io.getlime.security.powerauth.rest.api.spring.encryption.EncryptionScope; +import io.getlime.security.powerauth.rest.api.spring.encryption.PowerAuthEncryptorParameters; +import io.getlime.security.powerauth.rest.api.spring.encryption.PowerAuthEncryptorData; import io.getlime.security.powerauth.rest.api.spring.exception.PowerAuthEncryptionException; import io.getlime.security.powerauth.rest.api.spring.model.PowerAuthRequestBody; import io.getlime.security.powerauth.rest.api.spring.model.PowerAuthRequestObjects; -import io.getlime.security.powerauth.rest.api.model.request.v3.EciesEncryptedRequest; -import io.getlime.security.powerauth.rest.api.model.response.v3.EciesEncryptedResponse; +import jakarta.servlet.http.HttpServletRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.annotation.Nonnull; import javax.annotation.Nullable; -import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.lang.reflect.Type; +import java.util.Base64; /** * Abstract class for PowerAuth encryption provider with common HTTP header parsing logic. The class is available for @@ -63,30 +63,33 @@ public abstract class PowerAuthEncryptionProviderBase { private static final Logger logger = LoggerFactory.getLogger(PowerAuthEncryptionProviderBase.class); private final ObjectMapper objectMapper = new ObjectMapper(); - private final EciesFactory eciesFactory = new EciesFactory(); + private final EncryptorFactory encryptorFactory = new EncryptorFactory(); /** * Get ECIES decryptor parameters from PowerAuth server. * - * @param activationId Activation ID (only used in activation scope, in application scope use null). - * @param applicationKey Application key. + * @param activationId Activation ID (only used in activation scope, in application scope use null). + * @param applicationKey Application key. * @param ephemeralPublicKey Ephemeral public key for ECIES. + * @param version ECIES protocol version. + * @param nonce ECIES nonce. + * @param timestamp Timestamp for ECIES. * @return ECIES decryptor parameters. * @throws PowerAuthEncryptionException In case PowerAuth server call fails. */ - public abstract @Nonnull PowerAuthEciesDecryptorParameters getEciesDecryptorParameters(@Nullable String activationId, @Nonnull String applicationKey, @Nonnull String ephemeralPublicKey) throws PowerAuthEncryptionException; + public abstract @Nonnull + PowerAuthEncryptorParameters getEciesDecryptorParameters(@Nullable String activationId, @Nonnull String applicationKey, @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 * the type of decrypted object. * - * @param request HTTP request. - * @param requestType Class of request object. - * @param eciesScope ECIES scope. - * @return Object with ECIES data. + * @param request HTTP request. + * @param requestType Class of request object. + * @param encryptionScope Encryption scope. * @throws PowerAuthEncryptionException In case request decryption fails. */ - public @Nonnull PowerAuthEciesEncryption decryptRequest(@Nonnull HttpServletRequest request, @Nonnull Type requestType, @Nonnull EciesScope eciesScope) throws PowerAuthEncryptionException { + public void decryptRequest(@Nonnull HttpServletRequest request, @Nonnull Type requestType, @Nonnull EncryptionScope encryptionScope) throws PowerAuthEncryptionException { // Only POST HTTP method is supported for ECIES if (!"POST".equals(request.getMethod())) { logger.warn("Invalid HTTP method: {}", request.getMethod()); @@ -94,13 +97,10 @@ public abstract class PowerAuthEncryptionProviderBase { } // Resolve either signature or encryption HTTP header for ECIES - final EciesEncryptionContext encryptionContext = extractEciesEncryptionContext(request); + final EncryptionContext encryptionContext = extractEciesEncryptionContext(request, encryptionScope); // Construct ECIES encryption object from HTTP header - final PowerAuthEciesEncryption eciesEncryption = new PowerAuthEciesEncryption(encryptionContext); - - // Save ECIES scope in context - eciesEncryption.getContext().setEciesScope(eciesScope); + final PowerAuthEncryptorData encryptorData = new PowerAuthEncryptorData(encryptionContext); try { // Parse ECIES cryptogram from request body @@ -122,103 +122,108 @@ public abstract class PowerAuthEncryptionProviderBase { logger.debug(ex.getMessage(), ex); throw new PowerAuthEncryptionException(); } - if (eciesRequest == null) { logger.warn("Deserialization of request body bytes resulted in null value."); throw new PowerAuthEncryptionException(); } - // Prepare ephemeral public key - final String ephemeralPublicKey = eciesRequest.getEphemeralPublicKey(); - final String encryptedData = eciesRequest.getEncryptedData(); - final String mac = eciesRequest.getMac(); - final String nonce = eciesRequest.getNonce(); + // Extract useful properties in advance + final String version = encryptionContext.getVersion(); + final String applicationKey = encryptionContext.getApplicationKey(); + final String activationId = encryptionContext.getActivationId(); - // Verify ECIES request data. Nonce is required for protocol 3.1+ - if (ephemeralPublicKey == null || encryptedData == null || mac == null) { - logger.warn("Invalid ECIES request data"); + // Prepare and validate EncryptedRequest object + final EncryptedRequest encryptedRequest = new EncryptedRequest( + eciesRequest.getEphemeralPublicKey(), + eciesRequest.getEncryptedData(), + eciesRequest.getMac(), + eciesRequest.getNonce(), + eciesRequest.getTimestamp() + ); + if (!encryptorFactory.getRequestResponseValidator(version).validateEncryptedRequest(encryptedRequest)) { + logger.warn("Invalid encrypted request data"); throw new PowerAuthEncryptionException(); } - if (nonce == null && !"3.0".equals(encryptionContext.getVersion())) { - logger.warn("Missing nonce in ECIES request data"); + // Validate presence of activation id for activation scope. + if (encryptionScope == EncryptionScope.ACTIVATION_SCOPE && activationId == null) { + logger.warn("Activation ID is required for activation scope"); throw new PowerAuthEncryptionException(); } + // Get encryptor parameters from the PowerAuth Server. + final PowerAuthEncryptorParameters encryptorParameters = getEciesDecryptorParameters( + activationId, + applicationKey, + encryptedRequest.getEphemeralPublicKey(), + version, + encryptedRequest.getNonce(), + encryptedRequest.getTimestamp() + ); + // Build server encryptor with obtained encryptor parameters + final byte[] secretKeyBytes = Base64.getDecoder().decode(encryptorParameters.secretKey()); + final byte[] sharedInfo2Base = Base64.getDecoder().decode(encryptorParameters.sharedInfo2()); + final ServerEncryptor serverEncryptor = encryptorFactory.getServerEncryptor( + encryptorData.getEncryptorId(), + new EncryptorParameters(version, applicationKey, activationId), + new ServerEncryptorSecrets(secretKeyBytes, sharedInfo2Base) + ); - final byte[] ephemeralPublicKeyBytes = BaseEncoding.base64().decode(ephemeralPublicKey); - final byte[] encryptedDataBytes = BaseEncoding.base64().decode(encryptedData); - final byte[] macBytes = BaseEncoding.base64().decode(mac); - final byte[] nonceBytes = nonce != null ? BaseEncoding.base64().decode(nonce) : null; - - final String applicationKey = eciesEncryption.getContext().getApplicationKey(); - final PowerAuthEciesDecryptorParameters decryptorParameters; - // Obtain ECIES decryptor parameters from PowerAuth server - switch (eciesScope) { - case ACTIVATION_SCOPE: - final String activationId = eciesEncryption.getContext().getActivationId(); - if (activationId == null) { - logger.warn("Activation ID is required in ECIES activation scope"); - throw new PowerAuthEncryptionException(); - } - decryptorParameters = getEciesDecryptorParameters(activationId, applicationKey, ephemeralPublicKey); - break; - case APPLICATION_SCOPE: - decryptorParameters = getEciesDecryptorParameters(null, applicationKey, ephemeralPublicKey); - break; - default: - logger.warn("Unsupported ECIES scope: {}", eciesScope); - throw new PowerAuthEncryptionException(); - } - - // Prepare envelope key and sharedInfo2 parameter for decryptor - final byte[] secretKey = BaseEncoding.base64().decode(decryptorParameters.getSecretKey()); - final EciesEnvelopeKey envelopeKey = new EciesEnvelopeKey(secretKey, ephemeralPublicKeyBytes); - final byte[] sharedInfo2 = BaseEncoding.base64().decode(decryptorParameters.getSharedInfo2()); + // Try to decrypt request data + final byte[] decryptedData = serverEncryptor.decryptRequest(encryptedRequest); - // Construct decryptor and set it to the request for later encryption of response - final EciesDecryptor eciesDecryptor = eciesFactory.getEciesDecryptor(envelopeKey, sharedInfo2); - eciesEncryption.setEciesDecryptor(eciesDecryptor); + encryptorData.setEncryptedRequest(encryptedRequest); + encryptorData.setDecryptedRequest(decryptedData); + encryptorData.setServerEncryptor(serverEncryptor); - // Decrypt request data - final EciesCryptogram cryptogram = new EciesCryptogram(ephemeralPublicKeyBytes, macBytes, encryptedDataBytes, nonceBytes); - final byte[] decryptedData = eciesDecryptor.decryptRequest(cryptogram); - eciesEncryption.setEncryptedRequest(encryptedDataBytes); - eciesEncryption.setDecryptedRequest(decryptedData); // Set the request object only in case when request data is sent if (decryptedData.length != 0) { - eciesEncryption.setRequestObject(deserializeRequestData(decryptedData, requestType)); + encryptorData.setRequestObject(deserializeRequestData(decryptedData, requestType)); } // Set encryption object in HTTP servlet request - request.setAttribute(PowerAuthRequestObjects.ENCRYPTION_OBJECT, eciesEncryption); + request.setAttribute(PowerAuthRequestObjects.ENCRYPTION_OBJECT, encryptorData); } catch (Exception ex) { logger.warn("Request decryption failed, error: " + ex.getMessage()); logger.debug(ex.getMessage(), ex); throw new PowerAuthEncryptionException(); } - return eciesEncryption; } /** - * Encrypt response using ECIES. + * Encrypt response using End-To-End Encryptor. * - * @param responseObject Response object which should be encrypted. - * @param eciesEncryption PowerAuth encryption object. + * @param responseObject Response object which should be encrypted. + * @param encryption PowerAuth encryption object. * @return ECIES encrypted response. */ - public @Nullable EciesEncryptedResponse encryptResponse(@Nonnull Object responseObject, @Nonnull PowerAuthEciesEncryption eciesEncryption) { + public @Nullable + EciesEncryptedResponse encryptResponse(@Nonnull Object responseObject, @Nonnull PowerAuthEncryptorData encryption) { try { + final EncryptionContext encryptionContext = encryption.getContext(); + final ServerEncryptor serverEncryptor = encryption.getServerEncryptor(); + if (encryptionContext == null) { + logger.warn("Encryption context is not prepared"); + throw new PowerAuthEncryptionException(); + } + if (serverEncryptor == null || serverEncryptor.canEncryptResponse()) { + logger.warn("Encryptor is not available or not prepared for encryption. Scope: {}", encryptionContext.getEncryptionScope()); + throw new PowerAuthEncryptionException(); + } + // Serialize response data final byte[] responseData = serializeResponseData(responseObject); - // Encrypt response using decryptor and return ECIES cryptogram - final EciesCryptogram cryptogram = eciesEncryption.getEciesDecryptor().encryptResponse(responseData); - final String encryptedDataBase64 = BaseEncoding.base64().encode(cryptogram.getEncryptedData()); - final String macBase64 = BaseEncoding.base64().encode(cryptogram.getMac()); - return new EciesEncryptedResponse(encryptedDataBase64, macBase64); + // Encrypt response + final EncryptedResponse encryptedResponse = serverEncryptor.encryptResponse(responseData); + return new EciesEncryptedResponse( + encryptedResponse.getEncryptedData(), + encryptedResponse.getMac(), + encryptedResponse.getNonce(), + encryptedResponse.getTimestamp() + ); } catch (Exception ex) { logger.debug("Response encryption failed, error: " + ex.getMessage(), ex); return null; } } - + /** * Convert byte[] request data to Object with given type. * @@ -259,10 +264,11 @@ private byte[] serializeResponseData(Object responseObject) throws JsonProcessin * Extract context required for ECIES encryption from either encryption or signature HTTP header. * * @param request HTTP servlet request. + * @param encryptorScope Scope of encryption. * @return Context for ECIES encryption. * @throws PowerAuthEncryptionException Thrown when HTTP header with ECIES data is invalid. */ - private EciesEncryptionContext extractEciesEncryptionContext(HttpServletRequest request) throws PowerAuthEncryptionException { + private EncryptionContext extractEciesEncryptionContext(HttpServletRequest request, EncryptionScope encryptorScope) throws PowerAuthEncryptionException { final String encryptionHttpHeader = request.getHeader(PowerAuthEncryptionHttpHeader.HEADER_NAME); final String signatureHttpHeader = request.getHeader(PowerAuthSignatureHttpHeader.HEADER_NAME); @@ -290,14 +296,14 @@ private EciesEncryptionContext extractEciesEncryptionContext(HttpServletRequest final String applicationKey = header.getApplicationKey(); final String activationId = header.getActivationId(); final String version = header.getVersion(); - return new EciesEncryptionContext(applicationKey, activationId, version, header); + return new EncryptionContext(applicationKey, activationId, version, header, encryptorScope); } else { // Parse encryption HTTP header final PowerAuthEncryptionHttpHeader header = new PowerAuthEncryptionHttpHeader().fromValue(encryptionHttpHeader); // Validate the encryption HTTP header try { - PowerAuthEncryptionHttpHeaderValidator.validate(header); + PowerAuthEncryptionHttpHeaderValidator.validate(header, encryptorScope.toEncryptorScope()); } catch (InvalidPowerAuthHttpHeaderException ex) { logger.warn("Encryption validation failed, error: {}", ex.getMessage()); logger.debug(ex.getMessage(), ex); @@ -308,8 +314,7 @@ private EciesEncryptionContext extractEciesEncryptionContext(HttpServletRequest final String applicationKey = header.getApplicationKey(); final String activationId = header.getActivationId(); final String version = header.getVersion(); - return new EciesEncryptionContext(applicationKey, activationId, version, header); + return new EncryptionContext(applicationKey, activationId, version, header, encryptorScope); } } - } diff --git a/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/provider/UserInfoProvider.java b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/provider/UserInfoProvider.java new file mode 100644 index 00000000..ae7be0f4 --- /dev/null +++ b/powerauth-restful-security-spring-annotation/src/main/java/io/getlime/security/powerauth/rest/api/spring/provider/UserInfoProvider.java @@ -0,0 +1,60 @@ +/* + * PowerAuth integration libraries for RESTful API applications, examples 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 io.getlime.security.powerauth.rest.api.spring.provider; + +import com.wultra.core.annotations.PublicSpi; +import io.getlime.security.powerauth.rest.api.model.entity.UserInfoStage; +import io.getlime.security.powerauth.rest.api.spring.model.UserInfoContext; + +import javax.annotation.Nonnull; +import java.util.Collections; +import java.util.Map; + +/** + * Interface for bean that provides information about a given user. + * + * @author Petr Dvorak, petr@wultra.com + */ +@PublicSpi +public interface UserInfoProvider { + + /** + * Determine if the user info should be returned during the provided stage. By default, the user info is only + * available via a specialized /pa/v3/user/info endpoint. By overriding this method, the user info claims + * might be also returned in the activation response body (inside the outer-encrypted layer). + * + * @param context User info context object. + * @return True if the user info should be returned during the activation, false otherwise (user info is only + * returned in the separate user info endpoint). + */ + default boolean shouldReturnUserInfo(@Nonnull UserInfoContext context) { + return UserInfoStage.USER_INFO_ENDPOINT == context.getStage(); + } + + /** + * Return claims (as used, for example, in JWT) for a given user ID. Default implementation returns minimal claims. + * + * @param context User info context object. + * @return Map of claims obtained for a given user ID. + */ + default Map fetchUserClaimsForUserId(@Nonnull UserInfoContext context) { + return Collections.emptyMap(); + } +} diff --git a/powerauth-restful-security-spring/pom.xml b/powerauth-restful-security-spring/pom.xml index a4965be6..8c6df5bc 100644 --- a/powerauth-restful-security-spring/pom.xml +++ b/powerauth-restful-security-spring/pom.xml @@ -30,7 +30,7 @@ io.getlime.security powerauth-restful-integration-parent - 1.4.0 + 1.5.0 @@ -45,7 +45,7 @@ io.getlime.security powerauth-rest-client-spring - ${powerauth-rest-client-spring.version} + ${powerauth.version} log4j-to-slf4j @@ -54,6 +54,13 @@ + + + org.junit.jupiter + junit-jupiter-engine + test + + diff --git a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/v3/ActivationController.java b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/ActivationController.java similarity index 78% rename from powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/v3/ActivationController.java rename to powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/ActivationController.java index ab6f80a9..93e41720 100644 --- a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/v3/ActivationController.java +++ b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/ActivationController.java @@ -17,34 +17,34 @@ * 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.v3; +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.crypto.lib.encryptor.ecies.model.EciesScope; import io.getlime.security.powerauth.http.PowerAuthSignatureHttpHeader; import io.getlime.security.powerauth.rest.api.spring.authentication.PowerAuthApiAuthentication; -import io.getlime.security.powerauth.rest.api.spring.encryption.EciesEncryptionContext; +import io.getlime.security.powerauth.rest.api.spring.encryption.EncryptionContext; +import io.getlime.security.powerauth.rest.api.spring.encryption.EncryptionScope; import io.getlime.security.powerauth.rest.api.spring.exception.PowerAuthActivationException; import io.getlime.security.powerauth.rest.api.spring.exception.PowerAuthAuthenticationException; import io.getlime.security.powerauth.rest.api.spring.exception.PowerAuthRecoveryException; -import io.getlime.security.powerauth.rest.api.spring.exception.authentication.PowerAuthInvalidRequestException; import io.getlime.security.powerauth.rest.api.spring.exception.authentication.PowerAuthSignatureInvalidException; -import io.getlime.security.powerauth.rest.api.model.request.v3.ActivationLayer1Request; -import io.getlime.security.powerauth.rest.api.model.request.v3.ActivationStatusRequest; -import io.getlime.security.powerauth.rest.api.model.response.v3.ActivationLayer1Response; -import io.getlime.security.powerauth.rest.api.model.response.v3.ActivationRemoveResponse; -import io.getlime.security.powerauth.rest.api.model.response.v3.ActivationStatusResponse; +import io.getlime.security.powerauth.rest.api.model.request.ActivationLayer1Request; +import io.getlime.security.powerauth.rest.api.model.request.ActivationStatusRequest; +import io.getlime.security.powerauth.rest.api.model.response.ActivationLayer1Response; +import io.getlime.security.powerauth.rest.api.model.response.ActivationRemoveResponse; +import io.getlime.security.powerauth.rest.api.model.response.ActivationStatusResponse; import io.getlime.security.powerauth.rest.api.spring.annotation.EncryptedRequestBody; import io.getlime.security.powerauth.rest.api.spring.annotation.PowerAuthEncryption; import io.getlime.security.powerauth.rest.api.spring.provider.PowerAuthAuthenticationProvider; -import io.getlime.security.powerauth.rest.api.spring.service.v3.ActivationService; +import io.getlime.security.powerauth.rest.api.spring.service.ActivationService; +import io.getlime.security.powerauth.rest.api.spring.util.PowerAuthVersionUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; /** * Controller implementing activation related end-points from the PowerAuth @@ -89,20 +89,20 @@ public void setAuthenticationProvider(PowerAuthAuthenticationProvider authentica /** * Create activation. * @param request Encrypted activation layer 1 request. - * @param eciesContext ECIES encryption context. + * @param context Encryption context. * @return Activation layer 1 response. * @throws PowerAuthActivationException In case activation fails. * @throws PowerAuthRecoveryException In case recovery PUK is invalid. */ - @RequestMapping(value = "create", method = RequestMethod.POST) - @PowerAuthEncryption(scope = EciesScope.APPLICATION_SCOPE) + @PostMapping("create") + @PowerAuthEncryption(scope = EncryptionScope.APPLICATION_SCOPE) public ActivationLayer1Response createActivation(@EncryptedRequestBody ActivationLayer1Request request, - EciesEncryptionContext eciesContext) throws PowerAuthActivationException, PowerAuthRecoveryException { - if (request == null || eciesContext == null) { + EncryptionContext context) throws PowerAuthActivationException, PowerAuthRecoveryException { + if (request == null || context == null) { logger.warn("Invalid request in activation create"); throw new PowerAuthActivationException(); } - return activationServiceV3.createActivation(request, eciesContext); + return activationServiceV3.createActivation(request, context); } /** @@ -111,7 +111,7 @@ public ActivationLayer1Response createActivation(@EncryptedRequestBody Activatio * @return PowerAuth RESTful response with {@link ActivationStatusResponse} payload. * @throws PowerAuthActivationException In case request fails. */ - @RequestMapping(value = "status", method = RequestMethod.POST) + @PostMapping("status") public ObjectResponse getActivationStatus(@RequestBody ObjectRequest request) throws PowerAuthActivationException { if (request.getRequestObject() == null || request.getRequestObject().getActivationId() == null) { @@ -130,7 +130,7 @@ public ObjectResponse getActivationStatus(@RequestBody * @throws PowerAuthActivationException In case activation access fails. * @throws PowerAuthAuthenticationException In case the signature validation fails. */ - @RequestMapping(value = "remove", method = RequestMethod.POST) + @PostMapping("remove") public ObjectResponse removeActivation( @RequestHeader(value = PowerAuthSignatureHttpHeader.HEADER_NAME) String signatureHeader, HttpServletRequest httpServletRequest) @@ -141,10 +141,8 @@ public ObjectResponse removeActivation( logger.debug("Signature validation failed"); throw new PowerAuthSignatureInvalidException(); } - if (!"3.0".equals(apiAuthentication.getVersion()) && !"3.1".equals(apiAuthentication.getVersion())) { - logger.warn("Endpoint does not support PowerAuth protocol version {}", apiAuthentication.getVersion()); - throw new PowerAuthInvalidRequestException(); - } + PowerAuthVersionUtil.checkUnsupportedVersion(apiAuthentication.getVersion()); + ActivationRemoveResponse response = activationServiceV3.removeActivation(apiAuthentication); return new ObjectResponse<>(response); } diff --git a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/v3/RecoveryController.java b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/RecoveryController.java similarity index 75% rename from powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/v3/RecoveryController.java rename to powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/RecoveryController.java index b4794e98..45c1258d 100644 --- a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/v3/RecoveryController.java +++ b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/RecoveryController.java @@ -17,23 +17,22 @@ * 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.v3; +package io.getlime.security.powerauth.rest.api.spring.controller; import io.getlime.security.powerauth.crypto.lib.enums.PowerAuthSignatureTypes; import io.getlime.security.powerauth.rest.api.spring.authentication.PowerAuthApiAuthentication; import io.getlime.security.powerauth.rest.api.spring.exception.PowerAuthAuthenticationException; import io.getlime.security.powerauth.rest.api.spring.exception.authentication.PowerAuthInvalidRequestException; import io.getlime.security.powerauth.rest.api.spring.exception.authentication.PowerAuthSignatureInvalidException; -import io.getlime.security.powerauth.rest.api.model.request.v3.EciesEncryptedRequest; -import io.getlime.security.powerauth.rest.api.model.response.v3.EciesEncryptedResponse; +import io.getlime.security.powerauth.rest.api.model.request.EciesEncryptedRequest; +import io.getlime.security.powerauth.rest.api.model.response.EciesEncryptedResponse; import io.getlime.security.powerauth.rest.api.spring.annotation.PowerAuth; -import io.getlime.security.powerauth.rest.api.spring.service.v3.RecoveryService; +import io.getlime.security.powerauth.rest.api.spring.service.RecoveryService; +import io.getlime.security.powerauth.rest.api.spring.util.PowerAuthVersionUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; + /** * Controller implementing recovery related end-points from the PowerAuth @@ -70,7 +69,7 @@ public RecoveryController(RecoveryService recoveryService) { * @return ECIES encrypted response. * @throws PowerAuthAuthenticationException In case confirm recovery fails. */ - @RequestMapping(value = "confirm", method = RequestMethod.POST) + @PostMapping("confirm") @PowerAuth(resourceId = "/pa/recovery/confirm", signatureType = { PowerAuthSignatureTypes.POSSESSION_KNOWLEDGE }) @@ -83,14 +82,11 @@ public EciesEncryptedResponse confirmRecoveryCode(@RequestBody EciesEncryptedReq if (authentication == null || authentication.getActivationContext().getActivationId() == null) { throw new PowerAuthSignatureInvalidException(); } - if (!"3.0".equals(authentication.getVersion()) && !"3.1".equals(authentication.getVersion())) { - logger.warn("Endpoint does not support PowerAuth protocol version {}", authentication.getVersion()); - throw new PowerAuthInvalidRequestException(); - } - if (request.getNonce() == null && !"3.0".equals(authentication.getVersion())) { - logger.warn("Missing nonce in ECIES request data"); - throw new PowerAuthInvalidRequestException(); - } + + PowerAuthVersionUtil.checkUnsupportedVersion(authentication.getVersion()); + PowerAuthVersionUtil.checkMissingRequiredNonce(authentication.getVersion(), request.getNonce()); + PowerAuthVersionUtil.checkMissingRequiredTimestamp(authentication.getVersion(), request.getTimestamp()); + return recoveryService.confirmRecoveryCode(request, authentication); } diff --git a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/v3/SecureVaultController.java b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/SecureVaultController.java similarity index 82% rename from powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/v3/SecureVaultController.java rename to powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/SecureVaultController.java index d74593f3..875c6cc6 100644 --- a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/v3/SecureVaultController.java +++ b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/SecureVaultController.java @@ -17,7 +17,7 @@ * 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.v3; +package io.getlime.security.powerauth.rest.api.spring.controller; import io.getlime.security.powerauth.http.PowerAuthSignatureHttpHeader; import io.getlime.security.powerauth.http.validator.InvalidPowerAuthHttpHeaderException; @@ -26,15 +26,16 @@ import io.getlime.security.powerauth.rest.api.spring.exception.PowerAuthSecureVaultException; import io.getlime.security.powerauth.rest.api.spring.exception.authentication.PowerAuthInvalidRequestException; import io.getlime.security.powerauth.rest.api.spring.exception.authentication.PowerAuthSignatureInvalidException; -import io.getlime.security.powerauth.rest.api.model.request.v3.EciesEncryptedRequest; -import io.getlime.security.powerauth.rest.api.model.response.v3.EciesEncryptedResponse; -import io.getlime.security.powerauth.rest.api.spring.service.v3.SecureVaultService; +import io.getlime.security.powerauth.rest.api.model.request.EciesEncryptedRequest; +import io.getlime.security.powerauth.rest.api.model.response.EciesEncryptedResponse; +import io.getlime.security.powerauth.rest.api.spring.service.SecureVaultService; +import io.getlime.security.powerauth.rest.api.spring.util.PowerAuthVersionUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; /** * Controller implementing secure vault related end-points from the @@ -74,7 +75,7 @@ public void setSecureVaultServiceV3(SecureVaultService secureVaultServiceV3) { * @throws PowerAuthAuthenticationException In case authentication fails. * @throws PowerAuthSecureVaultException In case unlocking the vault fails. */ - @RequestMapping(value = "unlock", method = RequestMethod.POST) + @PostMapping("unlock") public EciesEncryptedResponse unlockVault( @RequestHeader(value = PowerAuthSignatureHttpHeader.HEADER_NAME, defaultValue = "unknown") String signatureHeader, @RequestBody EciesEncryptedRequest request, @@ -98,14 +99,10 @@ public EciesEncryptedResponse unlockVault( throw new PowerAuthSignatureInvalidException(); } - if (!"3.0".equals(header.getVersion()) && !"3.1".equals(header.getVersion())) { - logger.warn("Endpoint does not support PowerAuth protocol version {}", header.getVersion()); - throw new PowerAuthInvalidRequestException(); - } - if (request.getNonce() == null && !"3.0".equals(header.getVersion())) { - logger.warn("Missing nonce in ECIES request data"); - throw new PowerAuthInvalidRequestException(); - } + PowerAuthVersionUtil.checkUnsupportedVersion(header.getVersion()); + PowerAuthVersionUtil.checkMissingRequiredNonce(header.getVersion(), request.getNonce()); + PowerAuthVersionUtil.checkMissingRequiredTimestamp(header.getVersion(), request.getTimestamp()); + 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 new file mode 100644 index 00000000..9e422a91 --- /dev/null +++ b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/ServerStatusController.java @@ -0,0 +1,58 @@ +/* + * PowerAuth integration libraries for RESTful API applications, examples 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 io.getlime.security.powerauth.rest.api.spring.controller; + +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.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Date; + +/** + * Controller that provides a user information. + *

PowerAuth protocol versions: + *

    + *
  • 3.0
  • + *
  • 3.1
  • + *
  • 3.2
  • + *
+ * + * @author Petr Dvorak, petr@wultra.com + */ +@RestController +@RequestMapping("pa/v3") +@Slf4j +public class ServerStatusController { + + /** + * Obtain server status. + * @return Server status. + */ + @PostMapping("status") + public ObjectResponse getServerStatus() { + final long serverTime = new Date().getTime(); + final ServerStatusResponse response = new ServerStatusResponse(serverTime); + return new ObjectResponse<>(response); + } + +} diff --git a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/v3/SignatureController.java b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/SignatureController.java similarity index 89% rename from powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/v3/SignatureController.java rename to powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/SignatureController.java index 242cc9d8..a30526f4 100644 --- a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/v3/SignatureController.java +++ b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/SignatureController.java @@ -17,13 +17,12 @@ * 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.v3; +package io.getlime.security.powerauth.rest.api.spring.controller; import io.getlime.core.rest.model.base.response.Response; import io.getlime.security.powerauth.crypto.lib.enums.PowerAuthSignatureTypes; import io.getlime.security.powerauth.rest.api.spring.authentication.PowerAuthApiAuthentication; import io.getlime.security.powerauth.rest.api.spring.exception.PowerAuthAuthenticationException; -import io.getlime.security.powerauth.rest.api.spring.exception.authentication.PowerAuthInvalidRequestException; import io.getlime.security.powerauth.rest.api.spring.exception.authentication.PowerAuthSignatureInvalidException; import io.getlime.security.powerauth.rest.api.spring.annotation.PowerAuth; import org.slf4j.Logger; @@ -32,6 +31,8 @@ import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; +import io.getlime.security.powerauth.rest.api.spring.util.PowerAuthVersionUtil; + /** * End-point for validating signatures. * @@ -68,10 +69,9 @@ public Response validateSignature(PowerAuthApiAuthentication auth) throws PowerA logger.debug("Signature validation failed"); throw new PowerAuthSignatureInvalidException(); } - if (!"3.0".equals(auth.getVersion()) && !"3.1".equals(auth.getVersion())) { - logger.warn("Endpoint does not support PowerAuth protocol version {}", auth.getVersion()); - throw new PowerAuthInvalidRequestException(); - } + + PowerAuthVersionUtil.checkUnsupportedVersion(auth.getVersion()); + return new Response(); } diff --git a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/v3/TokenController.java b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/TokenController.java similarity index 76% rename from powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/v3/TokenController.java rename to powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/TokenController.java index 48f3d8e7..23433749 100644 --- a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/v3/TokenController.java +++ b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/TokenController.java @@ -17,7 +17,7 @@ * 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.v3; +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; @@ -26,19 +26,17 @@ import io.getlime.security.powerauth.rest.api.spring.exception.PowerAuthAuthenticationException; import io.getlime.security.powerauth.rest.api.spring.exception.authentication.PowerAuthInvalidRequestException; import io.getlime.security.powerauth.rest.api.spring.exception.authentication.PowerAuthSignatureInvalidException; -import io.getlime.security.powerauth.rest.api.model.request.v3.EciesEncryptedRequest; -import io.getlime.security.powerauth.rest.api.model.request.v3.TokenRemoveRequest; -import io.getlime.security.powerauth.rest.api.model.response.v3.EciesEncryptedResponse; -import io.getlime.security.powerauth.rest.api.model.response.v3.TokenRemoveResponse; +import io.getlime.security.powerauth.rest.api.model.request.EciesEncryptedRequest; +import io.getlime.security.powerauth.rest.api.model.request.TokenRemoveRequest; +import io.getlime.security.powerauth.rest.api.model.response.EciesEncryptedResponse; +import io.getlime.security.powerauth.rest.api.model.response.TokenRemoveResponse; import io.getlime.security.powerauth.rest.api.spring.annotation.PowerAuth; -import io.getlime.security.powerauth.rest.api.spring.service.v3.TokenService; +import io.getlime.security.powerauth.rest.api.spring.service.TokenService; +import io.getlime.security.powerauth.rest.api.spring.util.PowerAuthVersionUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; /** * Controller responsible for publishing services related to simple token-based authentication. @@ -74,7 +72,7 @@ public void setTokenServiceV3(TokenService tokenServiceV3) { * @return ECIES encrypted create token response. * @throws PowerAuthAuthenticationException In case authentication fails or request is invalid. */ - @RequestMapping(value = "create", method = RequestMethod.POST) + @PostMapping("create") @PowerAuth(resourceId = "/pa/token/create", signatureType = { PowerAuthSignatureTypes.POSSESSION, PowerAuthSignatureTypes.POSSESSION_KNOWLEDGE, @@ -92,14 +90,10 @@ public EciesEncryptedResponse createToken(@RequestBody EciesEncryptedRequest req logger.debug("Signature validation failed"); throw new PowerAuthSignatureInvalidException(); } - if (!"3.0".equals(authentication.getVersion()) && !"3.1".equals(authentication.getVersion())) { - logger.warn("Endpoint does not support PowerAuth protocol version {}", authentication.getVersion()); - throw new PowerAuthInvalidRequestException(); - } - if (request.getNonce() == null && !"3.0".equals(authentication.getVersion())) { - logger.warn("Missing nonce in ECIES request data"); - throw new PowerAuthInvalidRequestException(); - } + PowerAuthVersionUtil.checkUnsupportedVersion(authentication.getVersion()); + PowerAuthVersionUtil.checkMissingRequiredNonce(authentication.getVersion(), request.getNonce()); + PowerAuthVersionUtil.checkMissingRequiredTimestamp(authentication.getVersion(), request.getTimestamp()); + return tokenServiceV3.createToken(request, authentication); } @@ -110,7 +104,7 @@ public EciesEncryptedResponse createToken(@RequestBody EciesEncryptedRequest req * @return Remove token response. * @throws PowerAuthAuthenticationException In case authentication fails or request is invalid. */ - @RequestMapping(value = "remove", method = RequestMethod.POST) + @PostMapping("remove") @PowerAuth(resourceId = "/pa/token/remove", signatureType = { PowerAuthSignatureTypes.POSSESSION, PowerAuthSignatureTypes.POSSESSION_KNOWLEDGE, @@ -126,10 +120,9 @@ public ObjectResponse removeToken(@RequestBody ObjectReques if (authentication == null || authentication.getActivationContext().getActivationId() == null) { throw new PowerAuthSignatureInvalidException(); } - if (!"3.0".equals(authentication.getVersion()) && !"3.1".equals(authentication.getVersion())) { - logger.warn("Endpoint does not support PowerAuth protocol version {}", authentication.getVersion()); - throw new PowerAuthInvalidRequestException(); - } + + PowerAuthVersionUtil.checkUnsupportedVersion(authentication.getVersion()); + TokenRemoveResponse response = tokenServiceV3.removeToken(request.getRequestObject(), authentication); return new ObjectResponse<>(response); } diff --git a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/v3/UpgradeController.java b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/UpgradeController.java similarity index 77% rename from powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/v3/UpgradeController.java rename to powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/UpgradeController.java index f0938ffd..4fb94ea8 100644 --- a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/v3/UpgradeController.java +++ b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/UpgradeController.java @@ -17,9 +17,10 @@ * 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.v3; +package io.getlime.security.powerauth.rest.api.spring.controller; import io.getlime.core.rest.model.base.response.Response; +import io.getlime.security.powerauth.crypto.lib.encryptor.model.EncryptorScope; import io.getlime.security.powerauth.http.PowerAuthEncryptionHttpHeader; import io.getlime.security.powerauth.http.PowerAuthSignatureHttpHeader; import io.getlime.security.powerauth.http.validator.InvalidPowerAuthHttpHeaderException; @@ -28,15 +29,16 @@ import io.getlime.security.powerauth.rest.api.spring.exception.PowerAuthAuthenticationException; import io.getlime.security.powerauth.rest.api.spring.exception.PowerAuthUpgradeException; import io.getlime.security.powerauth.rest.api.spring.exception.authentication.PowerAuthInvalidRequestException; -import io.getlime.security.powerauth.rest.api.model.request.v3.EciesEncryptedRequest; -import io.getlime.security.powerauth.rest.api.model.response.v3.EciesEncryptedResponse; -import io.getlime.security.powerauth.rest.api.spring.service.v3.UpgradeService; +import io.getlime.security.powerauth.rest.api.model.request.EciesEncryptedRequest; +import io.getlime.security.powerauth.rest.api.model.response.EciesEncryptedResponse; +import io.getlime.security.powerauth.rest.api.spring.service.UpgradeService; +import io.getlime.security.powerauth.rest.api.spring.util.PowerAuthVersionUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; /** * Controller responsible for upgrade. @@ -73,10 +75,10 @@ public void setUpgradeService(UpgradeService upgradeService) { * @return ECIES encrypted response. * @throws PowerAuthUpgradeException In case upgrade fails. */ - @RequestMapping(value = "start", method = RequestMethod.POST) + @PostMapping("start") public EciesEncryptedResponse upgradeStart(@RequestBody EciesEncryptedRequest request, - @RequestHeader(value = PowerAuthEncryptionHttpHeader.HEADER_NAME, defaultValue = "unknown") String encryptionHeader) - throws PowerAuthUpgradeException { + @RequestHeader(value = PowerAuthEncryptionHttpHeader.HEADER_NAME, defaultValue = "unknown") String encryptionHeader) + throws PowerAuthUpgradeException, PowerAuthInvalidRequestException { if (request == null) { logger.warn("Invalid request object in upgrade start"); @@ -88,22 +90,16 @@ public EciesEncryptedResponse upgradeStart(@RequestBody EciesEncryptedRequest re // Validate the encryption header try { - PowerAuthEncryptionHttpHeaderValidator.validate(header); + PowerAuthEncryptionHttpHeaderValidator.validate(header, EncryptorScope.ACTIVATION_SCOPE); } catch (InvalidPowerAuthHttpHeaderException ex) { logger.warn("Encryption validation failed, error: {}", ex.getMessage()); logger.debug(ex.getMessage(), ex); throw new PowerAuthUpgradeException(); } - if (!"3.0".equals(header.getVersion()) && !"3.1".equals(header.getVersion())) { - logger.warn("Endpoint does not support PowerAuth protocol version {}", header.getVersion()); - throw new PowerAuthUpgradeException(); - } - - if (request.getNonce() == null && !"3.0".equals(header.getVersion())) { - logger.warn("Missing nonce in ECIES request data"); - throw new PowerAuthUpgradeException(); - } + PowerAuthVersionUtil.checkUnsupportedVersion(header.getVersion()); + PowerAuthVersionUtil.checkMissingRequiredNonce(header.getVersion(), request.getNonce()); + PowerAuthVersionUtil.checkMissingRequiredTimestamp(header.getVersion(), request.getTimestamp()); return upgradeService.upgradeStart(request, header); @@ -118,7 +114,7 @@ public EciesEncryptedResponse upgradeStart(@RequestBody EciesEncryptedRequest re * @throws PowerAuthAuthenticationException In case request signature is invalid. * @throws PowerAuthUpgradeException In case commit fails. */ - @RequestMapping(value = "commit", method = RequestMethod.POST) + @PostMapping("commit") public Response upgradeCommit(@RequestHeader(value = PowerAuthSignatureHttpHeader.HEADER_NAME) String signatureHeader, HttpServletRequest httpServletRequest) throws PowerAuthAuthenticationException, PowerAuthUpgradeException { @@ -135,10 +131,7 @@ public Response upgradeCommit(@RequestHeader(value = PowerAuthSignatureHttpHeade throw new PowerAuthUpgradeException(); } - if (!"3.0".equals(header.getVersion()) && !"3.1".equals(header.getVersion())) { - logger.warn("Endpoint does not support PowerAuth protocol version {}", header.getVersion()); - throw new PowerAuthInvalidRequestException(); - } + PowerAuthVersionUtil.checkUnsupportedVersion(header.getVersion()); return upgradeService.upgradeCommit(signatureHeader, httpServletRequest); } 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 new file mode 100644 index 00000000..f922524b --- /dev/null +++ b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/UserInfoController.java @@ -0,0 +1,87 @@ +/* + * PowerAuth integration libraries for RESTful API applications, examples 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 io.getlime.security.powerauth.rest.api.spring.controller; + +import io.getlime.security.powerauth.rest.api.model.request.UserInfoRequest; +import io.getlime.security.powerauth.rest.api.spring.annotation.EncryptedRequestBody; +import io.getlime.security.powerauth.rest.api.spring.annotation.PowerAuthEncryption; +import io.getlime.security.powerauth.rest.api.spring.encryption.EncryptionContext; +import io.getlime.security.powerauth.rest.api.spring.encryption.EncryptionScope; +import io.getlime.security.powerauth.rest.api.spring.exception.PowerAuthEncryptionException; +import io.getlime.security.powerauth.rest.api.spring.exception.PowerAuthUserInfoException; +import io.getlime.security.powerauth.rest.api.spring.service.UserInfoService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Map; + +/** + * Controller that provides a user information. + *

PowerAuth protocol versions: + *

    + *
  • 3.0
  • + *
  • 3.1
  • + *
  • 3.2
  • + *
+ * + * @author Petr Dvorak, petr@wultra.com + */ +@RestController +@RequestMapping("/pa/v3/user") +@Slf4j +public class UserInfoController { + + private final UserInfoService userInfoService; + + /** + * Default constructor. + * @param userInfoService User info service. + */ + @Autowired + public UserInfoController(UserInfoService userInfoService) { + this.userInfoService = userInfoService; + } + + /** + * Fetch user info. + * + * @param request Request with user info service. + * @param encryptionContext PowerAuth ECIES encryption context. + * @return Encrypted user info claims. + * @throws PowerAuthUserInfoException In case there is an error while fetching claims. + * @throws PowerAuthEncryptionException In case of failed encryption. + */ + @PowerAuthEncryption(scope = EncryptionScope.ACTIVATION_SCOPE) + @PostMapping("info") + public Map claims(@EncryptedRequestBody UserInfoRequest request, EncryptionContext encryptionContext) throws PowerAuthUserInfoException, PowerAuthEncryptionException { + if (encryptionContext == null) { + logger.error("Encryption failed"); + throw new PowerAuthEncryptionException("Encryption failed"); + } + + return userInfoService.fetchUserClaimsByActivationId( + encryptionContext.getActivationId() + ); + } + +} diff --git a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/v2/ActivationController.java b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/v2/ActivationController.java deleted file mode 100644 index 145335b0..00000000 --- a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/v2/ActivationController.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * PowerAuth integration libraries for RESTful API applications, examples and - * related software components - * - * Copyright (C) 2018 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.v2; - -import io.getlime.core.rest.model.base.request.ObjectRequest; -import io.getlime.core.rest.model.base.response.ObjectResponse; -import io.getlime.security.powerauth.http.PowerAuthSignatureHttpHeader; -import io.getlime.security.powerauth.rest.api.spring.authentication.PowerAuthApiAuthentication; -import io.getlime.security.powerauth.rest.api.spring.exception.PowerAuthActivationException; -import io.getlime.security.powerauth.rest.api.spring.exception.PowerAuthAuthenticationException; -import io.getlime.security.powerauth.rest.api.spring.exception.authentication.PowerAuthInvalidRequestException; -import io.getlime.security.powerauth.rest.api.spring.exception.authentication.PowerAuthSignatureInvalidException; -import io.getlime.security.powerauth.rest.api.model.request.v2.ActivationCreateRequest; -import io.getlime.security.powerauth.rest.api.model.request.v3.ActivationStatusRequest; -import io.getlime.security.powerauth.rest.api.model.response.v2.ActivationCreateResponse; -import io.getlime.security.powerauth.rest.api.model.response.v3.ActivationRemoveResponse; -import io.getlime.security.powerauth.rest.api.model.response.v3.ActivationStatusResponse; -import io.getlime.security.powerauth.rest.api.spring.provider.PowerAuthAuthenticationProvider; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.*; - -/** - * Controller implementing activation related end-points from the PowerAuth - * Standard API. - * - *

PowerAuth protocol versions: - *

    - *
  • 2.0
  • - *
  • 2.1
  • - *
- * - * @author Petr Dvorak, petr@wultra.com - * - */ -@RestController("activationControllerV2") -@RequestMapping(value = "/pa/activation") -public class ActivationController { - - private static final Logger logger = LoggerFactory.getLogger(ActivationController.class); - - private io.getlime.security.powerauth.rest.api.spring.service.v2.ActivationService activationServiceV2; - private io.getlime.security.powerauth.rest.api.spring.service.v3.ActivationService activationServiceV3; - - private PowerAuthAuthenticationProvider authenticationProvider; - - /** - * Set the activation service via setter injection. - * @param activationServiceV2 Activation service (v2). - */ - @Autowired - public void setActivationServiceV2(io.getlime.security.powerauth.rest.api.spring.service.v2.ActivationService activationServiceV2) { - this.activationServiceV2 = activationServiceV2; - } - - /** - * Set the activation service via setter injection. - * @param activationServiceV3 Activation service (v3). - */ - @Autowired - public void setActivationServiceV3(io.getlime.security.powerauth.rest.api.spring.service.v3.ActivationService activationServiceV3) { - this.activationServiceV3 = activationServiceV3; - } - - /** - * Set the authentication provider via setter injection. - * @param authenticationProvider Authentication provider. - */ - @Autowired - public void setAuthenticationProvider(PowerAuthAuthenticationProvider authenticationProvider) { - this.authenticationProvider = authenticationProvider; - } - - /** - * Create a new activation. - * @param request PowerAuth RESTful request with {@link ActivationCreateRequest} payload. - * @return PowerAuth RESTful response with {@link ActivationCreateResponse} payload. - * @throws PowerAuthActivationException In case creating activation fails. - */ - @RequestMapping(value = "create", method = RequestMethod.POST) - public ObjectResponse createActivation( - @RequestBody ObjectRequest request - ) throws PowerAuthActivationException { - if (request.getRequestObject() == null || request.getRequestObject().getActivationIdShort() == null) { - logger.warn("Invalid request object in activation create"); - throw new PowerAuthActivationException(); - } - ActivationCreateResponse response = activationServiceV2.createActivation(request.getRequestObject()); - return new ObjectResponse<>(response); - } - - /** - * Get activation status. - * @param request PowerAuth RESTful request with {@link ActivationStatusRequest} payload. - * @return PowerAuth RESTful response with {@link ActivationStatusResponse} payload. - * @throws PowerAuthActivationException In case request fails. - */ - @RequestMapping(value = "status", method = RequestMethod.POST) - public ObjectResponse getActivationStatus( - @RequestBody ObjectRequest request - ) throws PowerAuthActivationException { - if (request.getRequestObject() == null || request.getRequestObject().getActivationId() == null) { - logger.warn("Invalid request object in activation status"); - throw new PowerAuthActivationException(); - } - ActivationStatusResponse response = activationServiceV3.getActivationStatus(request.getRequestObject()); - return new ObjectResponse<>(response); - } - - /** - * Remove activation. - * @param signatureHeader PowerAuth signature HTTP header. - * @return PowerAuth RESTful response with {@link ActivationRemoveResponse} payload. - * @throws PowerAuthActivationException In case activation access fails. - * @throws PowerAuthAuthenticationException In case the signature validation fails. - */ - @RequestMapping(value = "remove", method = RequestMethod.POST) - public ObjectResponse removeActivation( - @RequestHeader(value = PowerAuthSignatureHttpHeader.HEADER_NAME) String signatureHeader - ) throws PowerAuthActivationException, PowerAuthAuthenticationException { - // Request body needs to be set to null because the SDK uses null for the signature, although {} is sent as request body - PowerAuthApiAuthentication apiAuthentication = authenticationProvider.validateRequestSignature("POST", null, "/pa/activation/remove", signatureHeader); - if (apiAuthentication == null || apiAuthentication.getActivationContext().getActivationId() == null) { - logger.debug("Signature validation failed"); - throw new PowerAuthSignatureInvalidException(); - } - if (!"2.0".equals(apiAuthentication.getVersion()) && !"2.1".equals(apiAuthentication.getVersion())) { - logger.warn("Endpoint does not support PowerAuth protocol version {}", apiAuthentication.getVersion()); - throw new PowerAuthInvalidRequestException(); - } - ActivationRemoveResponse response = activationServiceV3.removeActivation(apiAuthentication); - return new ObjectResponse<>(response); - } - -} diff --git a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/v2/SecureVaultController.java b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/v2/SecureVaultController.java deleted file mode 100644 index bfd57d36..00000000 --- a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/v2/SecureVaultController.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * PowerAuth integration libraries for RESTful API applications, examples and - * related software components - * - * Copyright (C) 2018 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.v2; - -import io.getlime.core.rest.model.base.request.ObjectRequest; -import io.getlime.core.rest.model.base.response.ObjectResponse; -import io.getlime.security.powerauth.http.PowerAuthSignatureHttpHeader; -import io.getlime.security.powerauth.http.validator.InvalidPowerAuthHttpHeaderException; -import io.getlime.security.powerauth.http.validator.PowerAuthSignatureHttpHeaderValidator; -import io.getlime.security.powerauth.rest.api.spring.exception.PowerAuthAuthenticationException; -import io.getlime.security.powerauth.rest.api.spring.exception.PowerAuthSecureVaultException; -import io.getlime.security.powerauth.rest.api.spring.exception.authentication.PowerAuthInvalidRequestException; -import io.getlime.security.powerauth.rest.api.spring.exception.authentication.PowerAuthSignatureInvalidException; -import io.getlime.security.powerauth.rest.api.model.request.v2.VaultUnlockRequest; -import io.getlime.security.powerauth.rest.api.model.response.v2.VaultUnlockResponse; -import io.getlime.security.powerauth.rest.api.spring.service.v2.SecureVaultService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.*; - -import javax.servlet.http.HttpServletRequest; - -/** - * Controller implementing secure vault related end-points from the - * PowerAuth Standard API. - * - *

PowerAuth protocol versions: - *

    - *
  • 2.0
  • - *
  • 2.1
  • - *
- * - * @author Petr Dvorak, petr@wultra.com - */ -@RestController("secureVaultControllerV2") -@RequestMapping(value = "/pa/vault") -public class SecureVaultController { - - private static final Logger logger = LoggerFactory.getLogger(SecureVaultController.class); - - private SecureVaultService secureVaultServiceV2; - - /** - * Set the secure vault service via setter injection. - * @param secureVaultServiceV2 Secure vault service. - */ - @Autowired - public void setSecureVaultServiceV2(SecureVaultService secureVaultServiceV2) { - this.secureVaultServiceV2 = secureVaultServiceV2; - } - - /** - * Request the vault unlock key. - * @param signatureHeader PowerAuth signature HTTP header. - * @param request Vault unlock request data. - * @param httpServletRequest HTTP servlet request. - * @return PowerAuth RESTful response with {@link VaultUnlockResponse} payload. - * @throws PowerAuthAuthenticationException In case authentication fails. - * @throws PowerAuthSecureVaultException In case unlocking the vault fails. - */ - @RequestMapping(value = "unlock", method = RequestMethod.POST) - public ObjectResponse unlockVault( - @RequestHeader(value = PowerAuthSignatureHttpHeader.HEADER_NAME, defaultValue = "unknown") String signatureHeader, - @RequestBody(required=false) ObjectRequest request, - HttpServletRequest httpServletRequest) - throws PowerAuthAuthenticationException, PowerAuthSecureVaultException { - - // Request object is not validated - it is optional for version 2 - - // Parse the header - PowerAuthSignatureHttpHeader header = new PowerAuthSignatureHttpHeader().fromValue(signatureHeader); - - // Validate the header - try { - PowerAuthSignatureHttpHeaderValidator.validate(header); - } catch (InvalidPowerAuthHttpHeaderException ex) { - logger.warn("Signature HTTP header validation failed, error: {}", ex.getMessage()); - logger.debug(ex.getMessage(), ex); - throw new PowerAuthSignatureInvalidException(); - } - - if (!"2.0".equals(header.getVersion()) && !"2.1".equals(header.getVersion())) { - logger.warn("Endpoint does not support PowerAuth protocol version {}", header.getVersion()); - throw new PowerAuthInvalidRequestException(); - } - - VaultUnlockResponse response = secureVaultServiceV2.vaultUnlock(signatureHeader, request.getRequestObject(), httpServletRequest); - return new ObjectResponse<>(response); - } - -} diff --git a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/v2/SignatureController.java b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/v2/SignatureController.java deleted file mode 100644 index 751b6166..00000000 --- a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/v2/SignatureController.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * PowerAuth integration libraries for RESTful API applications, examples and - * related software components - * - * Copyright (C) 2018 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.v2; - -import io.getlime.core.rest.model.base.response.Response; -import io.getlime.security.powerauth.crypto.lib.enums.PowerAuthSignatureTypes; -import io.getlime.security.powerauth.rest.api.spring.authentication.PowerAuthApiAuthentication; -import io.getlime.security.powerauth.rest.api.spring.exception.PowerAuthAuthenticationException; -import io.getlime.security.powerauth.rest.api.spring.exception.authentication.PowerAuthInvalidRequestException; -import io.getlime.security.powerauth.rest.api.spring.exception.authentication.PowerAuthSignatureInvalidException; -import io.getlime.security.powerauth.rest.api.spring.annotation.PowerAuth; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RestController; - -/** - * End-point for validating signatures. - * - *

PowerAuth protocol versions: - *

    - *
  • 2.0
  • - *
  • 2.1
  • - *
- * - * @author Roman Strobl, roman.strobl@wultra.com - * - */ -@RestController("signatureControllerV2") -@RequestMapping(value = "/pa/signature") -public class SignatureController { - - private static final Logger logger = LoggerFactory.getLogger(SignatureController.class); - - /** - * Validate signature by validating any data sent in request to this end-point. - * @param auth Automatically injected PowerAuth authentication object. - * @return API response with success. - * @throws PowerAuthAuthenticationException In case any error occurs, including signature validation errors. - */ - @RequestMapping(value = "validate", method = {RequestMethod.GET, RequestMethod.POST, RequestMethod.PUT, RequestMethod.DELETE}) - @PowerAuth(resourceId = "/pa/signature/validate", signatureType = { - PowerAuthSignatureTypes.POSSESSION_KNOWLEDGE, - PowerAuthSignatureTypes.POSSESSION_BIOMETRY, - PowerAuthSignatureTypes.POSSESSION_KNOWLEDGE_BIOMETRY - }) - public Response validateSignature(PowerAuthApiAuthentication auth) throws PowerAuthAuthenticationException { - - if (auth == null || auth.getActivationContext().getActivationId() == null) { - logger.debug("Signature validation failed"); - throw new PowerAuthSignatureInvalidException(); - } - if (!"2.0".equals(auth.getVersion()) && !"2.1".equals(auth.getVersion())) { - logger.warn("Endpoint does not support PowerAuth protocol version {}", auth.getVersion()); - throw new PowerAuthInvalidRequestException(); - } - return new Response(); - } - -} diff --git a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/v2/TokenController.java b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/v2/TokenController.java deleted file mode 100644 index 837be333..00000000 --- a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/controller/v2/TokenController.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * PowerAuth integration libraries for RESTful API applications, examples and - * related software components - * - * Copyright (C) 2018 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.v2; - -import io.getlime.core.rest.model.base.request.ObjectRequest; -import io.getlime.core.rest.model.base.response.ObjectResponse; -import io.getlime.security.powerauth.crypto.lib.enums.PowerAuthSignatureTypes; -import io.getlime.security.powerauth.rest.api.spring.authentication.PowerAuthApiAuthentication; -import io.getlime.security.powerauth.rest.api.spring.exception.PowerAuthAuthenticationException; -import io.getlime.security.powerauth.rest.api.spring.exception.authentication.PowerAuthInvalidRequestException; -import io.getlime.security.powerauth.rest.api.spring.exception.authentication.PowerAuthSignatureInvalidException; -import io.getlime.security.powerauth.rest.api.model.request.v2.TokenCreateRequest; -import io.getlime.security.powerauth.rest.api.model.request.v3.TokenRemoveRequest; -import io.getlime.security.powerauth.rest.api.model.response.v2.TokenCreateResponse; -import io.getlime.security.powerauth.rest.api.model.response.v3.TokenRemoveResponse; -import io.getlime.security.powerauth.rest.api.spring.annotation.PowerAuth; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RestController; - -/** - * Controller responsible for publishing services related to simple token-based authentication. - * - *

PowerAuth protocol versions: - *

    - *
  • 2.0
  • - *
  • 2.1
  • - *
- * - * @author Petr Dvorak, petr@wultra.com - */ -@RestController("tokenControllerV2") -@RequestMapping("/pa/token") -public class TokenController { - - private static final Logger logger = LoggerFactory.getLogger(TokenController.class); - - private io.getlime.security.powerauth.rest.api.spring.service.v2.TokenService tokenServiceV2; - private io.getlime.security.powerauth.rest.api.spring.service.v3.TokenService tokenServiceV3; - - /** - * Set the token verification service via setter injection. - * @param tokenServiceV2 Token verification service (v2). - */ - @Autowired - public void setTokenServiceV2(io.getlime.security.powerauth.rest.api.spring.service.v2.TokenService tokenServiceV2) { - this.tokenServiceV2 = tokenServiceV2; - } - - /** - * Set the token verification service via setter injection. - * @param tokenServiceV3 Token verification service (v3). - */ - @Autowired - public void setTokenServiceV3(io.getlime.security.powerauth.rest.api.spring.service.v3.TokenService tokenServiceV3) { - this.tokenServiceV3 = tokenServiceV3; - } - - /** - * Create token. - * @param request Create token request. - * @param authentication PowerAuth API authentication object. - * @return Create token response. - * @throws PowerAuthAuthenticationException In case authentication fails or request is invalid. - */ - @RequestMapping(value = "create", method = RequestMethod.POST) - @PowerAuth(resourceId = "/pa/token/create", signatureType = { - PowerAuthSignatureTypes.POSSESSION, - PowerAuthSignatureTypes.POSSESSION_KNOWLEDGE, - PowerAuthSignatureTypes.POSSESSION_BIOMETRY, - PowerAuthSignatureTypes.POSSESSION_KNOWLEDGE_BIOMETRY - }) - public ObjectResponse createToken( - @RequestBody ObjectRequest request, PowerAuthApiAuthentication authentication) throws PowerAuthAuthenticationException { - if (request.getRequestObject() == null) { - logger.warn("Invalid request object in create token"); - throw new PowerAuthInvalidRequestException(); - } - if (authentication == null || authentication.getActivationContext().getActivationId() == null) { - logger.debug("Signature validation failed"); - throw new PowerAuthSignatureInvalidException(); - } - if (!"2.0".equals(authentication.getVersion()) && !"2.1".equals(authentication.getVersion())) { - logger.warn("Endpoint does not support PowerAuth protocol version {}", authentication.getVersion()); - throw new PowerAuthInvalidRequestException(); - } - TokenCreateResponse response = tokenServiceV2.createToken(request.getRequestObject(), authentication); - return new ObjectResponse<>(response); - } - - /** - * Remove token. - * @param request Remove token request. - * @param authentication PowerAuth API authentication object. - * @return Remove token response. - * @throws PowerAuthAuthenticationException In case authentication fails or request is invalid. - */ - @RequestMapping(value = "remove", method = RequestMethod.POST) - @PowerAuth(resourceId = "/pa/token/remove", signatureType = { - PowerAuthSignatureTypes.POSSESSION, - PowerAuthSignatureTypes.POSSESSION_KNOWLEDGE, - PowerAuthSignatureTypes.POSSESSION_BIOMETRY, - PowerAuthSignatureTypes.POSSESSION_KNOWLEDGE_BIOMETRY - }) - public ObjectResponse removeToken(@RequestBody ObjectRequest request, PowerAuthApiAuthentication authentication) throws PowerAuthAuthenticationException { - if (request.getRequestObject() == null) { - logger.warn("Invalid request object in create token"); - throw new PowerAuthInvalidRequestException(); - } - if (authentication == null || authentication.getActivationContext().getActivationId() == null) { - logger.debug("Signature validation failed"); - throw new PowerAuthSignatureInvalidException(); - } - if (!"2.0".equals(authentication.getVersion()) && !"2.1".equals(authentication.getVersion())) { - logger.warn("Endpoint does not support PowerAuth protocol version {}", authentication.getVersion()); - throw new PowerAuthInvalidRequestException(); - } - TokenRemoveResponse response = tokenServiceV3.removeToken(request.getRequestObject(), authentication); - return new ObjectResponse<>(response); - } - -} 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 c1a0967d..20635bd2 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 @@ -120,4 +120,16 @@ public class PowerAuthExceptionHandler { return new ErrorResponse(ex.getDefaultCode(), ex.getDefaultError()); } + /** + * Handle {@link PowerAuthUserInfoException} exceptions. + * @param ex Exception instance. + * @return Error response. + */ + @ExceptionHandler(value = PowerAuthUserInfoException.class) + @ResponseStatus(value = HttpStatus.BAD_REQUEST) + public @ResponseBody ErrorResponse handlePowerAuthUserInfoException(PowerAuthUserInfoException ex) { + logger.warn(ex.getMessage(), ex); + return new ErrorResponse(ex.getDefaultCode(), ex.getMessage()); + } + } diff --git a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/v3/ActivationService.java b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/ActivationService.java similarity index 75% rename from powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/v3/ActivationService.java rename to powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/ActivationService.java index 1c50bc0d..1d2b9cf0 100644 --- a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/v3/ActivationService.java +++ b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/ActivationService.java @@ -17,37 +17,39 @@ * 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.v3; +package io.getlime.security.powerauth.rest.api.spring.service; import com.wultra.security.powerauth.client.PowerAuthClient; +import com.wultra.security.powerauth.client.model.enumeration.ActivationStatus; import com.wultra.security.powerauth.client.model.error.PowerAuthClientException; import com.wultra.security.powerauth.client.model.error.PowerAuthErrorRecovery; -import com.wultra.security.powerauth.client.v3.*; +import com.wultra.security.powerauth.client.model.request.*; +import com.wultra.security.powerauth.client.model.response.*; +import io.getlime.security.powerauth.rest.api.model.entity.ActivationType; +import io.getlime.security.powerauth.rest.api.model.entity.UserInfoStage; +import io.getlime.security.powerauth.rest.api.model.request.ActivationLayer1Request; +import io.getlime.security.powerauth.rest.api.model.request.ActivationStatusRequest; +import io.getlime.security.powerauth.rest.api.model.request.EciesEncryptedRequest; +import io.getlime.security.powerauth.rest.api.model.response.ActivationLayer1Response; +import io.getlime.security.powerauth.rest.api.model.response.ActivationRemoveResponse; +import io.getlime.security.powerauth.rest.api.model.response.ActivationStatusResponse; +import io.getlime.security.powerauth.rest.api.model.response.EciesEncryptedResponse; import io.getlime.security.powerauth.rest.api.spring.application.PowerAuthApplicationConfiguration; import io.getlime.security.powerauth.rest.api.spring.authentication.PowerAuthApiAuthentication; -import io.getlime.security.powerauth.rest.api.spring.converter.v3.ActivationContextConverter; -import io.getlime.security.powerauth.rest.api.spring.encryption.EciesEncryptionContext; +import io.getlime.security.powerauth.rest.api.spring.converter.ActivationContextConverter; +import io.getlime.security.powerauth.rest.api.spring.encryption.EncryptionContext; import io.getlime.security.powerauth.rest.api.spring.exception.PowerAuthActivationException; import io.getlime.security.powerauth.rest.api.spring.exception.PowerAuthRecoveryException; import io.getlime.security.powerauth.rest.api.spring.exception.authentication.PowerAuthInvalidRequestException; import io.getlime.security.powerauth.rest.api.spring.model.ActivationContext; +import io.getlime.security.powerauth.rest.api.spring.model.UserInfoContext; import io.getlime.security.powerauth.rest.api.spring.provider.CustomActivationProvider; -import io.getlime.security.powerauth.rest.api.model.entity.ActivationType; -import io.getlime.security.powerauth.rest.api.model.request.v3.ActivationLayer1Request; -import io.getlime.security.powerauth.rest.api.model.request.v3.ActivationStatusRequest; -import io.getlime.security.powerauth.rest.api.model.request.v3.EciesEncryptedRequest; -import io.getlime.security.powerauth.rest.api.model.response.v3.ActivationLayer1Response; -import io.getlime.security.powerauth.rest.api.model.response.v3.ActivationRemoveResponse; -import io.getlime.security.powerauth.rest.api.model.response.v3.ActivationStatusResponse; -import io.getlime.security.powerauth.rest.api.model.response.v3.EciesEncryptedResponse; -import io.getlime.security.powerauth.rest.api.spring.service.HttpCustomizationService; +import io.getlime.security.powerauth.rest.api.spring.provider.UserInfoProvider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import javax.xml.datatype.DatatypeFactory; -import javax.xml.datatype.XMLGregorianCalendar; import java.time.Instant; import java.util.*; @@ -72,6 +74,7 @@ public class ActivationService { private PowerAuthApplicationConfiguration applicationConfiguration; private CustomActivationProvider activationProvider; + private UserInfoProvider userInfoProvider; /** @@ -105,6 +108,15 @@ public void setPowerAuthActivationProvider(CustomActivationProvider activationPr this.activationProvider = activationProvider; } + /** + * Set user info provider via setter injection. + * @param userInfoProvider User info provider. + */ + @Autowired(required = false) + public void setUserInfoProvider(UserInfoProvider userInfoProvider) { + this.userInfoProvider = userInfoProvider; + } + /** * Create activation. * @@ -114,7 +126,7 @@ public void setPowerAuthActivationProvider(CustomActivationProvider activationPr * @throws PowerAuthActivationException In case create activation fails. * @throws PowerAuthRecoveryException In case activation recovery fails. */ - public ActivationLayer1Response createActivation(ActivationLayer1Request request, EciesEncryptionContext eciesContext) throws PowerAuthActivationException, PowerAuthRecoveryException { + public ActivationLayer1Response createActivation(ActivationLayer1Request request, EncryptionContext eciesContext) throws PowerAuthActivationException, PowerAuthRecoveryException { try { final String applicationKey = eciesContext.getApplicationKey(); @@ -123,18 +135,13 @@ public ActivationLayer1Response createActivation(ActivationLayer1Request request final String encryptedData = activationData.getEncryptedData(); final String mac = activationData.getMac(); final String nonce = activationData.getNonce(); + final Long timestamp = activationData.getTimestamp(); final Map identity = request.getIdentityAttributes(); final Map customAttributes = (request.getCustomAttributes() != null) ? request.getCustomAttributes() : new HashMap<>(); - // Validate inner encryption - if (nonce == null && !"3.0".equals(eciesContext.getVersion())) { - logger.warn("Missing nonce for protocol version: {}", eciesContext.getVersion()); - throw new PowerAuthActivationException(); - } - switch (request.getType()) { // Regular activation which uses "code" identity attribute - case CODE: { + case CODE -> { // Check if identity attributes are present if (identity == null || identity.isEmpty()) { @@ -153,35 +160,49 @@ public ActivationLayer1Response createActivation(ActivationLayer1Request request // Create context for passing parameters between activation provider calls final Map context = new LinkedHashMap<>(); - // Decide if the recovery codes should be generated - Boolean shouldGenerateRecoveryCodes = null; - if (activationProvider != null) { - shouldGenerateRecoveryCodes = activationProvider.shouldCreateRecoveryCodes(identity, customAttributes, ActivationType.CODE, context); - } - // Call PrepareActivation method on PA server final PrepareActivationRequest prepareRequest = new PrepareActivationRequest(); prepareRequest.setActivationCode(activationCode); prepareRequest.setApplicationKey(applicationKey); - prepareRequest.setGenerateRecoveryCodes(shouldGenerateRecoveryCodes); + prepareRequest.setGenerateRecoveryCodes(shouldGenerateRecoveryCodes(identity, customAttributes, context)); prepareRequest.setEphemeralPublicKey(ephemeralPublicKey); prepareRequest.setEncryptedData(encryptedData); prepareRequest.setMac(mac); prepareRequest.setNonce(nonce); + prepareRequest.setProtocolVersion(eciesContext.getVersion()); + prepareRequest.setTimestamp(timestamp); final PrepareActivationResponse response = powerAuthClient.prepareActivation( prepareRequest, httpCustomizationService.getQueryParams(), httpCustomizationService.getHttpHeaders() ); + final String userId = response.getUserId(); + final String activationId = response.getActivationId(); + final String applicationId = response.getApplicationId(); + + // Process user info + Map userInfo = null; + if (userInfoProvider != null) { + final UserInfoContext userInfoContext = UserInfoContext.builder() + .stage(UserInfoStage.ACTIVATION_PROCESS_ACTIVATION_CODE) + .userId(userId) + .activationId(activationId) + .applicationId(applicationId) + .build(); + if (userInfoProvider.shouldReturnUserInfo(userInfoContext)) { + userInfo = userInfoProvider.fetchUserClaimsForUserId(userInfoContext); + } + } + Map processedCustomAttributes = customAttributes; // In case a custom activation provider is enabled, process custom attributes and save any flags if (activationProvider != null) { - processedCustomAttributes = activationProvider.processCustomActivationAttributes(customAttributes, response.getActivationId(), response.getUserId(), response.getApplicationId(), ActivationType.CODE, context); - List activationFlags = activationProvider.getActivationFlags(identity, processedCustomAttributes, response.getActivationId(), response.getUserId(), response.getApplicationId(), ActivationType.CODE, context); + processedCustomAttributes = activationProvider.processCustomActivationAttributes(customAttributes, activationId, userId, applicationId, ActivationType.CODE, context); + final List activationFlags = activationProvider.getActivationFlags(identity, processedCustomAttributes, activationId, userId, applicationId, ActivationType.CODE, context); if (activationFlags != null && !activationFlags.isEmpty()) { final AddActivationFlagsRequest flagsRequest = new AddActivationFlagsRequest(); - flagsRequest.setActivationId(response.getActivationId()); + flagsRequest.setActivationId(activationId); flagsRequest.getActivationFlags().addAll(activationFlags); powerAuthClient.addActivationFlags( flagsRequest, @@ -197,9 +218,9 @@ public ActivationLayer1Response createActivation(ActivationLayer1Request request notifyActivationCommit = true; } else { // Otherwise check if activation should be committed instantly and if yes, perform commit. - if (activationProvider != null && activationProvider.shouldAutoCommitActivation(identity, customAttributes, response.getActivationId(), response.getUserId(), response.getApplicationId(), ActivationType.CODE, context)) { + if (activationProvider != null && activationProvider.shouldAutoCommitActivation(identity, customAttributes, activationId, userId, applicationId, ActivationType.CODE, context)) { final CommitActivationRequest commitRequest = new CommitActivationRequest(); - commitRequest.setActivationId(response.getActivationId()); + commitRequest.setActivationId(activationId); commitRequest.setExternalUserId(null); final CommitActivationResponse commitResponse = powerAuthClient.commitActivation( commitRequest, @@ -212,15 +233,17 @@ public ActivationLayer1Response createActivation(ActivationLayer1Request request } // Notify activation provider about an activation commit. if (activationProvider != null && notifyActivationCommit) { - activationProvider.activationWasCommitted(identity, customAttributes, response.getActivationId(), response.getUserId(), response.getApplicationId(), ActivationType.CODE, context); + activationProvider.activationWasCommitted(identity, customAttributes, activationId, userId, applicationId, ActivationType.CODE, context); } // Prepare and return encrypted response - return prepareEncryptedResponse(response.getEncryptedData(), response.getMac(), processedCustomAttributes); + return prepareEncryptedResponse(response.getEncryptedData(), response.getMac(), + response.getNonce(), response.getTimestamp(), processedCustomAttributes, userInfo); } + // Custom activation - case CUSTOM: { + case CUSTOM -> { // Check if there is a custom activation provider available, return an error in case it is not available. // Only for CUSTOM activations, proceeding without an activation provider does not make a sensible use-case. if (activationProvider == null) { @@ -247,25 +270,22 @@ public ActivationLayer1Response createActivation(ActivationLayer1Request request } // Decide if the recovery codes should be generated - final Boolean shouldGenerateRecoveryCodes = activationProvider.shouldCreateRecoveryCodes(identity, customAttributes, ActivationType.CODE, context); + final boolean shouldGenerateRecoveryCodes = activationProvider.shouldCreateRecoveryCodes(identity, customAttributes, ActivationType.CODE, context); // Resolve maxFailedCount and activationExpireTimestamp parameters, null value means use value configured on PowerAuth server final Integer maxFailed = activationProvider.getMaxFailedAttemptCount(identity, customAttributes, userId, ActivationType.CUSTOM, context); final Long maxFailedCount = maxFailed == null ? null : maxFailed.longValue(); final Long activationValidityPeriod = activationProvider.getValidityPeriodDuringActivation(identity, customAttributes, userId, ActivationType.CUSTOM, context); - XMLGregorianCalendar activationExpireXml = null; + Date activationExpire = null; if (activationValidityPeriod != null) { - Instant now = Instant.now(); - Instant expiration = now.plusMillis(activationValidityPeriod); - GregorianCalendar c = new GregorianCalendar(); - c.setTimeInMillis(expiration.toEpochMilli()); - activationExpireXml = DatatypeFactory.newInstance().newXMLGregorianCalendar(c); + final Instant expiration = Instant.now().plusMillis(activationValidityPeriod); + activationExpire = Date.from(expiration); } // Create activation for a looked up user and application related to the given application key final CreateActivationRequest createRequest = new CreateActivationRequest(); createRequest.setUserId(userId); - createRequest.setTimestampActivationExpire(activationExpireXml); + createRequest.setTimestampActivationExpire(activationExpire); createRequest.setGenerateRecoveryCodes(shouldGenerateRecoveryCodes); createRequest.setMaxFailureCount(maxFailedCount); createRequest.setApplicationKey(applicationKey); @@ -273,20 +293,39 @@ public ActivationLayer1Response createActivation(ActivationLayer1Request request createRequest.setEncryptedData(encryptedData); createRequest.setMac(mac); createRequest.setNonce(nonce); + createRequest.setProtocolVersion(eciesContext.getVersion()); + createRequest.setTimestamp(timestamp); final CreateActivationResponse response = powerAuthClient.createActivation( createRequest, httpCustomizationService.getQueryParams(), httpCustomizationService.getHttpHeaders() ); + final String activationId = response.getActivationId(); + final String applicationId = response.getApplicationId(); + + // Process user info + Map userInfo = null; + if (userInfoProvider != null) { + final UserInfoContext userInfoContext = UserInfoContext.builder() + .stage(UserInfoStage.ACTIVATION_PROCESS_CUSTOM) + .userId(userId) + .activationId(activationId) + .applicationId(applicationId) + .build(); + if (userInfoProvider.shouldReturnUserInfo(userInfoContext)) { + userInfo = userInfoProvider.fetchUserClaimsForUserId(userInfoContext); + } + } + // Process custom attributes using a custom logic - final Map processedCustomAttributes = activationProvider.processCustomActivationAttributes(customAttributes, response.getActivationId(), userId, response.getApplicationId(), ActivationType.CUSTOM, context); + final Map processedCustomAttributes = activationProvider.processCustomActivationAttributes(customAttributes, activationId, userId, applicationId, ActivationType.CUSTOM, context); // Save activation flags in case the provider specified any flags - final List activationFlags = activationProvider.getActivationFlags(identity, processedCustomAttributes, response.getActivationId(), userId, response.getApplicationId(), ActivationType.CUSTOM, context); + final List activationFlags = activationProvider.getActivationFlags(identity, processedCustomAttributes, activationId, userId, applicationId, ActivationType.CUSTOM, context); if (activationFlags != null && !activationFlags.isEmpty()) { final AddActivationFlagsRequest flagsRequest = new AddActivationFlagsRequest(); - flagsRequest.setActivationId(response.getActivationId()); + flagsRequest.setActivationId(activationId); flagsRequest.getActivationFlags().addAll(activationFlags); powerAuthClient.addActivationFlags( flagsRequest, @@ -296,9 +335,9 @@ public ActivationLayer1Response createActivation(ActivationLayer1Request request } // Check if activation should be committed instantly and if yes, perform commit - if (activationProvider.shouldAutoCommitActivation(identity, customAttributes, response.getActivationId(), userId, response.getApplicationId(), ActivationType.CUSTOM, context)) { + if (activationProvider.shouldAutoCommitActivation(identity, customAttributes, activationId, userId, applicationId, ActivationType.CUSTOM, context)) { final CommitActivationRequest commitRequest = new CommitActivationRequest(); - commitRequest.setActivationId(response.getActivationId()); + commitRequest.setActivationId(activationId); commitRequest.setExternalUserId(null); final CommitActivationResponse commitResponse = powerAuthClient.commitActivation( commitRequest, @@ -306,24 +345,18 @@ public ActivationLayer1Response createActivation(ActivationLayer1Request request httpCustomizationService.getHttpHeaders() ); if (commitResponse.isActivated()) { - activationProvider.activationWasCommitted(identity, customAttributes, response.getActivationId(), userId, response.getApplicationId(), ActivationType.CUSTOM, context); + activationProvider.activationWasCommitted(identity, customAttributes, activationId, userId, applicationId, ActivationType.CUSTOM, context); } } // Prepare encrypted activation data - final EciesEncryptedResponse encryptedActivationData = new EciesEncryptedResponse(response.getEncryptedData(), response.getMac()); - - // Prepare the created activation response data - final ActivationLayer1Response responseL1 = new ActivationLayer1Response(); - responseL1.setCustomAttributes(processedCustomAttributes); - responseL1.setActivationData(encryptedActivationData); - - // Return response - return responseL1; + return prepareEncryptedResponse(response.getEncryptedData(), response.getMac(), + response.getNonce(), response.getTimestamp(), processedCustomAttributes, userInfo); } + // Activation using recovery code - case RECOVERY: { + case RECOVERY -> { // Check if identity attributes are present if (identity == null || identity.isEmpty()) { @@ -368,20 +401,40 @@ public ActivationLayer1Response createActivation(ActivationLayer1Request request recoveryRequest.setEncryptedData(encryptedData); recoveryRequest.setMac(mac); recoveryRequest.setNonce(nonce); - final RecoveryCodeActivationResponse recoveryResponse = powerAuthClient.createActivationUsingRecoveryCode( + recoveryRequest.setProtocolVersion(eciesContext.getVersion()); + recoveryRequest.setTimestamp(timestamp); + final RecoveryCodeActivationResponse response = powerAuthClient.createActivationUsingRecoveryCode( recoveryRequest, httpCustomizationService.getQueryParams(), httpCustomizationService.getHttpHeaders() ); + final String userId = response.getUserId(); + final String activationId = response.getActivationId(); + final String applicationId = response.getApplicationId(); + + // Process user info + Map userInfo = null; + if (userInfoProvider != null) { + final UserInfoContext userInfoContext = UserInfoContext.builder() + .stage(UserInfoStage.ACTIVATION_PROCESS_RECOVERY) + .userId(userId) + .activationId(activationId) + .applicationId(applicationId) + .build(); + if (userInfoProvider.shouldReturnUserInfo(userInfoContext)) { + userInfo = userInfoProvider.fetchUserClaimsForUserId(userInfoContext); + } + } + Map processedCustomAttributes = customAttributes; // In case a custom activation provider is enabled, process custom attributes and save any flags if (activationProvider != null) { - processedCustomAttributes = activationProvider.processCustomActivationAttributes(customAttributes, recoveryResponse.getActivationId(), recoveryResponse.getUserId(), recoveryResponse.getApplicationId(), ActivationType.RECOVERY, context); - final List activationFlags = activationProvider.getActivationFlags(identity, processedCustomAttributes, recoveryResponse.getActivationId(), recoveryResponse.getUserId(), recoveryResponse.getApplicationId(), ActivationType.RECOVERY, context); + processedCustomAttributes = activationProvider.processCustomActivationAttributes(customAttributes, activationId, userId, applicationId, ActivationType.RECOVERY, context); + final List activationFlags = activationProvider.getActivationFlags(identity, processedCustomAttributes, activationId, userId, applicationId, ActivationType.RECOVERY, context); if (activationFlags != null && !activationFlags.isEmpty()) { final AddActivationFlagsRequest flagsRequest = new AddActivationFlagsRequest(); - flagsRequest.setActivationId(recoveryResponse.getActivationId()); + flagsRequest.setActivationId(activationId); flagsRequest.getActivationFlags().addAll(activationFlags); powerAuthClient.addActivationFlags( flagsRequest, @@ -392,9 +445,9 @@ public ActivationLayer1Response createActivation(ActivationLayer1Request request } // Automatically commit activation by default, the optional activation provider can override automatic commit - if (activationProvider == null || activationProvider.shouldAutoCommitActivation(identity, customAttributes, recoveryResponse.getActivationId(), recoveryResponse.getUserId(), recoveryResponse.getApplicationId(), ActivationType.RECOVERY, context)) { + if (activationProvider == null || activationProvider.shouldAutoCommitActivation(identity, customAttributes, activationId, userId, applicationId, ActivationType.RECOVERY, context)) { final CommitActivationRequest commitRequest = new CommitActivationRequest(); - commitRequest.setActivationId(recoveryResponse.getActivationId()); + commitRequest.setActivationId(activationId); commitRequest.setExternalUserId(null); final CommitActivationResponse commitResponse = powerAuthClient.commitActivation( commitRequest, @@ -402,21 +455,21 @@ public ActivationLayer1Response createActivation(ActivationLayer1Request request httpCustomizationService.getHttpHeaders() ); if (activationProvider != null && commitResponse.isActivated()) { - activationProvider.activationWasCommitted(identity, customAttributes, recoveryResponse.getActivationId(), recoveryResponse.getUserId(), recoveryResponse.getApplicationId(), ActivationType.RECOVERY, context); + activationProvider.activationWasCommitted(identity, customAttributes, activationId, userId, applicationId, ActivationType.RECOVERY, context); } } // Prepare and return encrypted response - return prepareEncryptedResponse(recoveryResponse.getEncryptedData(), recoveryResponse.getMac(), processedCustomAttributes); + return prepareEncryptedResponse(response.getEncryptedData(), response.getMac(), + response.getNonce(), response.getTimestamp(), processedCustomAttributes, userInfo); } - - default: + default -> { logger.warn("Invalid activation request"); throw new PowerAuthInvalidRequestException(); + } } } catch (PowerAuthClientException ex) { - if (ex.getPowerAuthError() instanceof PowerAuthErrorRecovery) { - final PowerAuthErrorRecovery errorRecovery = (PowerAuthErrorRecovery) ex.getPowerAuthError(); + if (ex.getPowerAuthError() instanceof final PowerAuthErrorRecovery errorRecovery) { logger.debug("Invalid recovery code, current PUK index: {}", errorRecovery.getCurrentRecoveryPukIndex()); throw new PowerAuthRecoveryException(ex.getMessage(), "INVALID_RECOVERY_CODE", errorRecovery.getCurrentRecoveryPukIndex()); } @@ -435,6 +488,13 @@ public ActivationLayer1Response createActivation(ActivationLayer1Request request } } + private boolean shouldGenerateRecoveryCodes(final Map identity, final Map customAttributes, final Map context) throws PowerAuthActivationException { + if (activationProvider == null) { + return true; + } + return activationProvider.shouldCreateRecoveryCodes(identity, customAttributes, ActivationType.CODE, context); + } + /** * Get activation status. * @@ -529,14 +589,17 @@ public ActivationRemoveResponse removeActivation(PowerAuthApiAuthentication apiA * @param processedCustomAttributes Custom attributes to be returned. * @return Encrypted response object. */ - private ActivationLayer1Response prepareEncryptedResponse(String encryptedData, String mac, Map processedCustomAttributes) { + private ActivationLayer1Response prepareEncryptedResponse(String encryptedData, String mac, String nonce, Long timestmap, Map processedCustomAttributes, Map userInfo) { // Prepare encrypted response object for layer 2 final EciesEncryptedResponse encryptedResponseL2 = new EciesEncryptedResponse(); encryptedResponseL2.setEncryptedData(encryptedData); encryptedResponseL2.setMac(mac); + encryptedResponseL2.setNonce(nonce); + encryptedResponseL2.setTimestamp(timestmap); // The response is encrypted once more before sent to client using ResponseBodyAdvice final ActivationLayer1Response responseL1 = new ActivationLayer1Response(); + responseL1.setUserInfo(userInfo); responseL1.setCustomAttributes(processedCustomAttributes); responseL1.setActivationData(encryptedResponseL2); return responseL1; diff --git a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/v3/RecoveryService.java b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/RecoveryService.java similarity index 84% rename from powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/v3/RecoveryService.java rename to powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/RecoveryService.java index 7517c094..0ea79a6f 100644 --- a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/v3/RecoveryService.java +++ b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/RecoveryService.java @@ -17,19 +17,18 @@ * 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.v3; +package io.getlime.security.powerauth.rest.api.spring.service; import com.wultra.security.powerauth.client.PowerAuthClient; -import com.wultra.security.powerauth.client.v3.ConfirmRecoveryCodeRequest; -import com.wultra.security.powerauth.client.v3.ConfirmRecoveryCodeResponse; +import com.wultra.security.powerauth.client.model.request.ConfirmRecoveryCodeRequest; +import com.wultra.security.powerauth.client.model.response.ConfirmRecoveryCodeResponse; import io.getlime.security.powerauth.http.PowerAuthSignatureHttpHeader; +import io.getlime.security.powerauth.rest.api.model.request.EciesEncryptedRequest; +import io.getlime.security.powerauth.rest.api.model.response.EciesEncryptedResponse; import io.getlime.security.powerauth.rest.api.spring.authentication.PowerAuthApiAuthentication; import io.getlime.security.powerauth.rest.api.spring.exception.PowerAuthAuthenticationException; import io.getlime.security.powerauth.rest.api.spring.exception.authentication.PowerAuthInvalidRequestException; import io.getlime.security.powerauth.rest.api.spring.exception.authentication.PowerAuthRecoveryConfirmationException; -import io.getlime.security.powerauth.rest.api.model.request.v3.EciesEncryptedRequest; -import io.getlime.security.powerauth.rest.api.model.response.v3.EciesEncryptedResponse; -import io.getlime.security.powerauth.rest.api.spring.service.HttpCustomizationService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -77,8 +76,7 @@ public EciesEncryptedResponse confirmRecoveryCode(EciesEncryptedRequest request, final String activationId = authentication.getActivationContext().getActivationId(); final PowerAuthSignatureHttpHeader httpHeader = (PowerAuthSignatureHttpHeader) authentication.getHttpHeader(); final String applicationKey = httpHeader.getApplicationKey(); - if (activationId == null || applicationKey == null || request.getEphemeralPublicKey() == null - || request.getEncryptedData() == null || request.getMac() == null) { + if (activationId == null || applicationKey == null) { logger.warn("PowerAuth confirm recovery failed because of invalid request"); throw new PowerAuthInvalidRequestException(); } @@ -89,6 +87,8 @@ public EciesEncryptedResponse confirmRecoveryCode(EciesEncryptedRequest request, confirmRequest.setEncryptedData(request.getEncryptedData()); confirmRequest.setMac(request.getMac()); confirmRequest.setNonce(request.getNonce()); + confirmRequest.setProtocolVersion(httpHeader.getVersion()); + confirmRequest.setTimestamp(request.getTimestamp()); final ConfirmRecoveryCodeResponse paResponse = powerAuthClient.confirmRecoveryCode( confirmRequest, httpCustomizationService.getQueryParams(), @@ -98,7 +98,11 @@ public EciesEncryptedResponse confirmRecoveryCode(EciesEncryptedRequest request, logger.warn("PowerAuth confirm recovery failed because of invalid activation ID in response"); throw new PowerAuthInvalidRequestException(); } - return new EciesEncryptedResponse(paResponse.getEncryptedData(), paResponse.getMac()); + return new EciesEncryptedResponse( + paResponse.getEncryptedData(), + paResponse.getMac(), + paResponse.getNonce(), + paResponse.getTimestamp()); } catch (Exception ex) { logger.warn("PowerAuth confirm recovery failed, error: {}", ex.getMessage()); logger.debug(ex.getMessage(), ex); diff --git a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/v3/SecureVaultService.java b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/SecureVaultService.java similarity index 80% rename from powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/v3/SecureVaultService.java rename to powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/SecureVaultService.java index 5d6f8cf9..f0304ba6 100644 --- a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/v3/SecureVaultService.java +++ b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/SecureVaultService.java @@ -17,30 +17,29 @@ * 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.v3; +package io.getlime.security.powerauth.rest.api.spring.service; -import com.google.common.io.BaseEncoding; import com.wultra.security.powerauth.client.PowerAuthClient; -import com.wultra.security.powerauth.client.v3.SignatureType; -import com.wultra.security.powerauth.client.v3.VaultUnlockRequest; -import com.wultra.security.powerauth.client.v3.VaultUnlockResponse; +import com.wultra.security.powerauth.client.model.enumeration.SignatureType; +import com.wultra.security.powerauth.client.model.request.VaultUnlockRequest; +import com.wultra.security.powerauth.client.model.response.VaultUnlockResponse; import io.getlime.security.powerauth.http.PowerAuthHttpBody; import io.getlime.security.powerauth.http.PowerAuthSignatureHttpHeader; +import io.getlime.security.powerauth.rest.api.model.request.EciesEncryptedRequest; +import io.getlime.security.powerauth.rest.api.model.response.EciesEncryptedResponse; +import io.getlime.security.powerauth.rest.api.spring.converter.SignatureTypeConverter; import io.getlime.security.powerauth.rest.api.spring.exception.PowerAuthAuthenticationException; import io.getlime.security.powerauth.rest.api.spring.exception.PowerAuthSecureVaultException; import io.getlime.security.powerauth.rest.api.spring.exception.authentication.PowerAuthSignatureInvalidException; import io.getlime.security.powerauth.rest.api.spring.exception.authentication.PowerAuthSignatureTypeInvalidException; -import io.getlime.security.powerauth.rest.api.model.request.v3.EciesEncryptedRequest; -import io.getlime.security.powerauth.rest.api.model.response.v3.EciesEncryptedResponse; -import io.getlime.security.powerauth.rest.api.spring.converter.v3.SignatureTypeConverter; import io.getlime.security.powerauth.rest.api.spring.provider.PowerAuthAuthenticationProvider; -import io.getlime.security.powerauth.rest.api.spring.service.HttpCustomizationService; +import jakarta.servlet.http.HttpServletRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import javax.servlet.http.HttpServletRequest; +import java.util.Base64; /** * Service implementing secure vault functionality. @@ -101,15 +100,9 @@ public EciesEncryptedResponse vaultUnlock(PowerAuthSignatureHttpHeader header, final String signatureVersion = header.getVersion(); final String nonce = header.getNonce(); - // Fetch data from the request - final String ephemeralPublicKey = request.getEphemeralPublicKey(); - final String encryptedData = request.getEncryptedData(); - final String mac = request.getMac(); - final String eciesNonce = request.getNonce(); - // Prepare data for signature to allow signature verification on PowerAuth server final byte[] requestBodyBytes = authenticationProvider.extractRequestBodyBytes(httpServletRequest); - final String data = PowerAuthHttpBody.getSignatureBaseString("POST", "/pa/vault/unlock", BaseEncoding.base64().decode(nonce), requestBodyBytes); + final String data = PowerAuthHttpBody.getSignatureBaseString("POST", "/pa/vault/unlock", Base64.getDecoder().decode(nonce), requestBodyBytes); // Verify signature and get encrypted vault encryption key from PowerAuth server final VaultUnlockRequest unlockRequest = new VaultUnlockRequest(); @@ -119,10 +112,11 @@ public EciesEncryptedResponse vaultUnlock(PowerAuthSignatureHttpHeader header, unlockRequest.setSignatureType(signatureType); unlockRequest.setSignatureVersion(signatureVersion); unlockRequest.setSignedData(data); - unlockRequest.setEphemeralPublicKey(ephemeralPublicKey); - unlockRequest.setEncryptedData(encryptedData); - unlockRequest.setMac(mac); - unlockRequest.setNonce(eciesNonce); + unlockRequest.setEphemeralPublicKey(request.getEphemeralPublicKey()); + unlockRequest.setEncryptedData(request.getEncryptedData()); + unlockRequest.setMac(request.getMac()); + unlockRequest.setNonce(request.getNonce()); + unlockRequest.setTimestamp(request.getTimestamp()); final VaultUnlockResponse paResponse = powerAuthClient.unlockVault( unlockRequest, httpCustomizationService.getQueryParams(), @@ -134,7 +128,11 @@ public EciesEncryptedResponse vaultUnlock(PowerAuthSignatureHttpHeader header, throw new PowerAuthSignatureInvalidException(); } - return new EciesEncryptedResponse(paResponse.getEncryptedData(), paResponse.getMac()); + return new EciesEncryptedResponse( + paResponse.getEncryptedData(), + paResponse.getMac(), + paResponse.getNonce(), + paResponse.getTimestamp()); } catch (PowerAuthAuthenticationException ex) { throw ex; } catch (Exception ex) { diff --git a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/v3/TokenService.java b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/TokenService.java similarity index 83% rename from powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/v3/TokenService.java rename to powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/TokenService.java index 05a8d8c1..56312032 100644 --- a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/v3/TokenService.java +++ b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/TokenService.java @@ -17,25 +17,24 @@ * 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.v3; +package io.getlime.security.powerauth.rest.api.spring.service; import com.wultra.security.powerauth.client.PowerAuthClient; -import com.wultra.security.powerauth.client.v3.CreateTokenRequest; -import com.wultra.security.powerauth.client.v3.CreateTokenResponse; -import com.wultra.security.powerauth.client.v3.RemoveTokenRequest; -import com.wultra.security.powerauth.client.v3.SignatureType; +import com.wultra.security.powerauth.client.model.enumeration.SignatureType; +import com.wultra.security.powerauth.client.model.request.CreateTokenRequest; +import com.wultra.security.powerauth.client.model.request.RemoveTokenRequest; +import com.wultra.security.powerauth.client.model.response.CreateTokenResponse; import io.getlime.security.powerauth.crypto.lib.enums.PowerAuthSignatureTypes; import io.getlime.security.powerauth.http.PowerAuthSignatureHttpHeader; +import io.getlime.security.powerauth.rest.api.model.request.EciesEncryptedRequest; +import io.getlime.security.powerauth.rest.api.model.request.TokenRemoveRequest; +import io.getlime.security.powerauth.rest.api.model.response.EciesEncryptedResponse; +import io.getlime.security.powerauth.rest.api.model.response.TokenRemoveResponse; import io.getlime.security.powerauth.rest.api.spring.authentication.PowerAuthApiAuthentication; +import io.getlime.security.powerauth.rest.api.spring.converter.SignatureTypeConverter; import io.getlime.security.powerauth.rest.api.spring.exception.PowerAuthAuthenticationException; import io.getlime.security.powerauth.rest.api.spring.exception.authentication.PowerAuthSignatureTypeInvalidException; import io.getlime.security.powerauth.rest.api.spring.exception.authentication.PowerAuthTokenErrorException; -import io.getlime.security.powerauth.rest.api.model.request.v3.EciesEncryptedRequest; -import io.getlime.security.powerauth.rest.api.model.request.v3.TokenRemoveRequest; -import io.getlime.security.powerauth.rest.api.model.response.v3.EciesEncryptedResponse; -import io.getlime.security.powerauth.rest.api.model.response.v3.TokenRemoveResponse; -import io.getlime.security.powerauth.rest.api.spring.converter.v3.SignatureTypeConverter; -import io.getlime.security.powerauth.rest.api.spring.service.HttpCustomizationService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -85,12 +84,6 @@ public EciesEncryptedResponse createToken(EciesEncryptedRequest request, // Fetch activation ID and signature type final PowerAuthSignatureTypes signatureFactors = authentication.getAuthenticationContext().getSignatureType(); - // Fetch data from the request - final String ephemeralPublicKey = request.getEphemeralPublicKey(); - final String encryptedData = request.getEncryptedData(); - final String mac = request.getMac(); - final String nonce = request.getNonce(); - // Prepare a signature type converter final SignatureTypeConverter converter = new SignatureTypeConverter(); final SignatureType signatureType = converter.convertFrom(signatureFactors); @@ -108,11 +101,13 @@ public EciesEncryptedResponse createToken(EciesEncryptedRequest request, final CreateTokenRequest tokenRequest = new CreateTokenRequest(); tokenRequest.setActivationId(activationId); tokenRequest.setApplicationKey(applicationKey); - tokenRequest.setEphemeralPublicKey(ephemeralPublicKey); - tokenRequest.setEncryptedData(encryptedData); - tokenRequest.setMac(mac); - tokenRequest.setNonce(nonce); + tokenRequest.setEphemeralPublicKey(request.getEphemeralPublicKey()); + tokenRequest.setEncryptedData(request.getEncryptedData()); + tokenRequest.setMac(request.getMac()); + tokenRequest.setNonce(request.getNonce()); tokenRequest.setSignatureType(signatureType); + tokenRequest.setProtocolVersion(httpHeader.getVersion()); + tokenRequest.setTimestamp(request.getTimestamp()); final CreateTokenResponse token = powerAuthClient.createToken( tokenRequest, httpCustomizationService.getQueryParams(), @@ -123,6 +118,8 @@ public EciesEncryptedResponse createToken(EciesEncryptedRequest request, final EciesEncryptedResponse response = new EciesEncryptedResponse(); response.setMac(token.getMac()); response.setEncryptedData(token.getEncryptedData()); + response.setNonce(token.getNonce()); + response.setTimestamp(token.getTimestamp()); return response; } catch (Exception ex) { logger.warn("Creating PowerAuth token failed, error: {}", ex.getMessage()); diff --git a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/v3/UpgradeService.java b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/UpgradeService.java similarity index 87% rename from powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/v3/UpgradeService.java rename to powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/UpgradeService.java index 15aca850..c8bfa948 100644 --- a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/v3/UpgradeService.java +++ b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/UpgradeService.java @@ -17,29 +17,31 @@ * 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.v3; +package io.getlime.security.powerauth.rest.api.spring.service; import com.wultra.security.powerauth.client.PowerAuthClient; -import com.wultra.security.powerauth.client.v3.*; +import com.wultra.security.powerauth.client.model.request.CommitUpgradeRequest; +import com.wultra.security.powerauth.client.model.request.StartUpgradeRequest; +import com.wultra.security.powerauth.client.model.response.CommitUpgradeResponse; +import com.wultra.security.powerauth.client.model.response.StartUpgradeResponse; import io.getlime.core.rest.model.base.response.Response; import io.getlime.security.powerauth.crypto.lib.enums.PowerAuthSignatureTypes; import io.getlime.security.powerauth.http.PowerAuthEncryptionHttpHeader; import io.getlime.security.powerauth.http.PowerAuthSignatureHttpHeader; +import io.getlime.security.powerauth.rest.api.model.request.EciesEncryptedRequest; +import io.getlime.security.powerauth.rest.api.model.response.EciesEncryptedResponse; import io.getlime.security.powerauth.rest.api.spring.authentication.PowerAuthApiAuthentication; import io.getlime.security.powerauth.rest.api.spring.exception.PowerAuthAuthenticationException; import io.getlime.security.powerauth.rest.api.spring.exception.PowerAuthUpgradeException; import io.getlime.security.powerauth.rest.api.spring.exception.authentication.PowerAuthInvalidRequestException; import io.getlime.security.powerauth.rest.api.spring.exception.authentication.PowerAuthSignatureInvalidException; -import io.getlime.security.powerauth.rest.api.model.request.v3.EciesEncryptedRequest; -import io.getlime.security.powerauth.rest.api.model.response.v3.EciesEncryptedResponse; import io.getlime.security.powerauth.rest.api.spring.provider.PowerAuthAuthenticationProvider; -import io.getlime.security.powerauth.rest.api.spring.service.HttpCustomizationService; +import jakarta.servlet.http.HttpServletRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import javax.servlet.http.HttpServletRequest; import java.util.Collections; import java.util.List; @@ -87,12 +89,6 @@ public EciesEncryptedResponse upgradeStart(EciesEncryptedRequest request, PowerA throws PowerAuthUpgradeException { try { - // Fetch data from the request - final String ephemeralPublicKey = request.getEphemeralPublicKey(); - final String encryptedData = request.getEncryptedData(); - final String mac = request.getMac(); - final String nonce = request.getNonce(); - // Get ECIES headers final String activationId = header.getActivationId(); final String applicationKey = header.getApplicationKey(); @@ -101,10 +97,12 @@ public EciesEncryptedResponse upgradeStart(EciesEncryptedRequest request, PowerA final StartUpgradeRequest upgradeRequest = new StartUpgradeRequest(); upgradeRequest.setActivationId(activationId); upgradeRequest.setApplicationKey(applicationKey); - upgradeRequest.setEphemeralPublicKey(ephemeralPublicKey); - upgradeRequest.setEncryptedData(encryptedData); - upgradeRequest.setMac(mac); - upgradeRequest.setNonce(nonce); + upgradeRequest.setEphemeralPublicKey(request.getEphemeralPublicKey()); + upgradeRequest.setEncryptedData(request.getEncryptedData()); + upgradeRequest.setMac(request.getMac()); + upgradeRequest.setNonce(request.getNonce()); + upgradeRequest.setProtocolVersion(header.getVersion()); + upgradeRequest.setTimestamp(request.getTimestamp()); final StartUpgradeResponse upgradeResponse = powerAuthClient.startUpgrade( upgradeRequest, httpCustomizationService.getQueryParams(), @@ -115,6 +113,8 @@ public EciesEncryptedResponse upgradeStart(EciesEncryptedRequest request, PowerA final EciesEncryptedResponse response = new EciesEncryptedResponse(); response.setMac(upgradeResponse.getMac()); response.setEncryptedData(upgradeResponse.getEncryptedData()); + response.setNonce(upgradeResponse.getNonce()); + response.setTimestamp(upgradeResponse.getTimestamp()); return response; } catch (Exception ex) { logger.warn("PowerAuth upgrade start failed, error: {}", ex.getMessage()); diff --git a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/UserInfoService.java b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/UserInfoService.java new file mode 100644 index 00000000..126730d8 --- /dev/null +++ b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/UserInfoService.java @@ -0,0 +1,106 @@ +/* + * PowerAuth integration libraries for RESTful API applications, examples 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 io.getlime.security.powerauth.rest.api.spring.service; + +import com.wultra.security.powerauth.client.PowerAuthClient; +import com.wultra.security.powerauth.client.model.enumeration.ActivationStatus; +import com.wultra.security.powerauth.client.model.error.PowerAuthClientException; +import com.wultra.security.powerauth.client.model.response.GetActivationStatusResponse; +import io.getlime.security.powerauth.rest.api.model.entity.UserInfoStage; +import io.getlime.security.powerauth.rest.api.spring.exception.PowerAuthUserInfoException; +import io.getlime.security.powerauth.rest.api.spring.model.UserInfoContext; +import io.getlime.security.powerauth.rest.api.spring.provider.UserInfoProvider; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.Collections; +import java.util.Map; + +/** + * Service for obtaining user info as claims map. + * + * @author Petr Dvorak, petr@wultra.com + */ +@Service +public class UserInfoService { + + private UserInfoProvider userInfoProvider; + private final PowerAuthClient powerAuthClient; + + /** + * Service constructor. + * @param powerAuthClient PowerAuthClient instance. + */ + @Autowired + public UserInfoService(PowerAuthClient powerAuthClient) { + this.powerAuthClient = powerAuthClient; + } + + /** + * Setter with optional user info provider bean. + * @param userInfoProvider User info provider. + */ + @Autowired(required = false) + public void setActivationProvider(UserInfoProvider userInfoProvider) { + this.userInfoProvider = userInfoProvider; + } + + /** + * Fetch user info as a map of claims. Returns empty map by default, i.e., if user info provider is not registered. + * + * @param activationId Activation ID. + * @return Map of claims. + * @throws PowerAuthUserInfoException In case there is an error while fetching claims. + */ + public Map fetchUserClaimsByActivationId(String activationId) throws PowerAuthUserInfoException { + try { + + if (userInfoProvider == null) { + return Collections.emptyMap(); + } + + // Fetch activation details + final GetActivationStatusResponse activationStatusResponse = powerAuthClient.getActivationStatus(activationId); + final String userId = activationStatusResponse.getUserId(); + final String applicationId = activationStatusResponse.getApplicationId(); + final ActivationStatus activationStatus = activationStatusResponse.getActivationStatus(); + + if (ActivationStatus.ACTIVE != activationStatus) { // only allow active state for now + throw new PowerAuthUserInfoException("Invalid activation status: " + activationStatus + ", for activation: " + activationId); + } + + final UserInfoContext userInfoContext = UserInfoContext.builder() + .stage(UserInfoStage.USER_INFO_ENDPOINT) + .userId(userId) + .activationId(activationId) + .applicationId(applicationId) + .build(); + if (userInfoProvider.shouldReturnUserInfo(userInfoContext)) { + return userInfoProvider.fetchUserClaimsForUserId(userInfoContext); + } else { + return Collections.emptyMap(); + } + + } catch (PowerAuthClientException ex) { + throw new PowerAuthUserInfoException("Fetching user claims failed, activation ID: " + activationId, ex); + } + } + +} diff --git a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/v2/ActivationService.java b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/v2/ActivationService.java deleted file mode 100644 index 018da600..00000000 --- a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/v2/ActivationService.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * PowerAuth integration libraries for RESTful API applications, examples and - * related software components - * - * Copyright (C) 2018 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.v2; - -import com.wultra.security.powerauth.client.PowerAuthClient; -import com.wultra.security.powerauth.client.v2.PrepareActivationRequest; -import com.wultra.security.powerauth.client.v2.PrepareActivationResponse; -import io.getlime.security.powerauth.rest.api.spring.exception.PowerAuthActivationException; -import io.getlime.security.powerauth.rest.api.model.request.v2.ActivationCreateRequest; -import io.getlime.security.powerauth.rest.api.model.response.v2.ActivationCreateResponse; -import io.getlime.security.powerauth.rest.api.spring.service.HttpCustomizationService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -/** - * Service implementing activation functionality. - * - *

PowerAuth protocol versions: - *

    - *
  • 2.0
  • - *
  • 2.1
  • - *
- * - * @author Roman Strobl, roman.strobl@wultra.com - * - */ -@Service("activationServiceV2") -public class ActivationService { - - private static final Logger logger = LoggerFactory.getLogger(ActivationService.class); - - private final PowerAuthClient powerAuthClient; - private final HttpCustomizationService httpCustomizationService; - - /** - * Service constructor. - * @param powerAuthClient PowerAuth client. - * @param httpCustomizationService HTTP customization service. - */ - @Autowired - public ActivationService(PowerAuthClient powerAuthClient, HttpCustomizationService httpCustomizationService) { - this.powerAuthClient = powerAuthClient; - this.httpCustomizationService = httpCustomizationService; - } - - /** - * Create activation. - * @param request Create activation request. - * @return Create activation response. - * @throws PowerAuthActivationException In case create activation fails. - */ - public ActivationCreateResponse createActivation(ActivationCreateRequest request) throws PowerAuthActivationException { - try { - final String activationIDShort = request.getActivationIdShort(); - final String activationNonce = request.getActivationNonce(); - final String cDevicePublicKey = request.getEncryptedDevicePublicKey(); - final String activationName = request.getActivationName(); - final String extras = request.getExtras(); - final String applicationKey = request.getApplicationKey(); - final String applicationSignature = request.getApplicationSignature(); - final String clientEphemeralKey = request.getEphemeralPublicKey(); - - final PrepareActivationRequest prepareRequest = new PrepareActivationRequest(); - prepareRequest.setActivationIdShort(activationIDShort); - prepareRequest.setActivationName(activationName); - prepareRequest.setActivationNonce(activationNonce); - prepareRequest.setEphemeralPublicKey(clientEphemeralKey); - prepareRequest.setEncryptedDevicePublicKey(cDevicePublicKey); - prepareRequest.setExtras(extras); - prepareRequest.setApplicationKey(applicationKey); - prepareRequest.setApplicationSignature(applicationSignature); - final PrepareActivationResponse paResponse = powerAuthClient.v2().prepareActivation( - prepareRequest, - httpCustomizationService.getQueryParams(), - httpCustomizationService.getHttpHeaders() - ); - - final ActivationCreateResponse response = new ActivationCreateResponse(); - response.setActivationId(paResponse.getActivationId()); - response.setActivationNonce(paResponse.getActivationNonce()); - response.setEncryptedServerPublicKey(paResponse.getEncryptedServerPublicKey()); - response.setEncryptedServerPublicKeySignature(paResponse.getEncryptedServerPublicKeySignature()); - response.setEphemeralPublicKey(paResponse.getEphemeralPublicKey()); - - return response; - } catch (Exception ex) { - logger.warn("Creating PowerAuth activation failed, error: {}", ex.getMessage()); - logger.debug(ex.getMessage(), ex); - throw new PowerAuthActivationException(); - } - } - -} diff --git a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/v2/SecureVaultService.java b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/v2/SecureVaultService.java deleted file mode 100644 index 67233b91..00000000 --- a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/v2/SecureVaultService.java +++ /dev/null @@ -1,172 +0,0 @@ -/* - * PowerAuth integration libraries for RESTful API applications, examples and - * related software components - * - * Copyright (C) 2018 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.v2; - -import com.google.common.io.BaseEncoding; -import com.wultra.security.powerauth.client.PowerAuthClient; -import com.wultra.security.powerauth.client.v2.SignatureType; -import io.getlime.security.powerauth.http.PowerAuthHttpBody; -import io.getlime.security.powerauth.http.PowerAuthSignatureHttpHeader; -import io.getlime.security.powerauth.http.validator.InvalidPowerAuthHttpHeaderException; -import io.getlime.security.powerauth.http.validator.PowerAuthSignatureHttpHeaderValidator; -import io.getlime.security.powerauth.rest.api.spring.exception.PowerAuthAuthenticationException; -import io.getlime.security.powerauth.rest.api.spring.exception.PowerAuthSecureVaultException; -import io.getlime.security.powerauth.rest.api.spring.exception.authentication.PowerAuthSignatureInvalidException; -import io.getlime.security.powerauth.rest.api.spring.exception.authentication.PowerAuthSignatureTypeInvalidException; -import io.getlime.security.powerauth.rest.api.model.request.v2.VaultUnlockRequest; -import io.getlime.security.powerauth.rest.api.model.response.v2.VaultUnlockResponse; -import io.getlime.security.powerauth.rest.api.spring.converter.v2.SignatureTypeConverter; -import io.getlime.security.powerauth.rest.api.spring.provider.PowerAuthAuthenticationProvider; -import io.getlime.security.powerauth.rest.api.spring.service.HttpCustomizationService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import javax.servlet.http.HttpServletRequest; - -/** - * Service implementing secure vault functionality. - * - *

PowerAuth protocol versions: - *

    - *
  • 2.0
  • - *
  • 2.1
  • - *
- * - * @author Roman Strobl, roman.strobl@wultra.com - * - */ -@Service("secureVaultServiceV2") -public class SecureVaultService { - - private static final Logger logger = LoggerFactory.getLogger(SecureVaultService.class); - - private final PowerAuthClient powerAuthClient; - private final PowerAuthAuthenticationProvider authenticationProvider; - private final HttpCustomizationService httpCustomizationService; - - /** - * Service constructor. - * @param powerAuthClient PowerAuth client. - * @param authenticationProvider Authentication provider. - * @param httpCustomizationService HTTP customization service. - */ - @Autowired - public SecureVaultService(PowerAuthClient powerAuthClient, PowerAuthAuthenticationProvider authenticationProvider, HttpCustomizationService httpCustomizationService) { - this.powerAuthClient = powerAuthClient; - this.authenticationProvider = authenticationProvider; - this.httpCustomizationService = httpCustomizationService; - } - - /** - * Unlock secure vault. - * @param signatureHeader PowerAuth signature HTTP header. - * @param request Vault unlock request. - * @param httpServletRequest HTTP servlet request. - * @return Vault unlock response. - * @throws PowerAuthSecureVaultException In case vault unlock fails. - * @throws PowerAuthAuthenticationException In case authentication fails. - */ - public VaultUnlockResponse vaultUnlock(String signatureHeader, - VaultUnlockRequest request, - HttpServletRequest httpServletRequest) throws PowerAuthSecureVaultException, PowerAuthAuthenticationException { - try { - // Parse the header - final PowerAuthSignatureHttpHeader header = new PowerAuthSignatureHttpHeader().fromValue(signatureHeader); - - // Validate the header - try { - PowerAuthSignatureHttpHeaderValidator.validate(header); - } catch (InvalidPowerAuthHttpHeaderException ex) { - logger.warn("Signature HTTP header validation failed, error: {}", ex.getMessage()); - logger.debug(ex.getMessage(), ex); - throw new PowerAuthSignatureTypeInvalidException(); - } - - final SignatureTypeConverter converter = new SignatureTypeConverter(); - - final String activationId = header.getActivationId(); - final String applicationKey = header.getApplicationKey(); - final String signature = header.getSignature(); - final SignatureType signatureType = converter.convertFrom(header.getSignatureType()); - if (signatureType == null) { - logger.warn("Invalid signature type: {}", header.getSignatureType()); - throw new PowerAuthSignatureTypeInvalidException(); - } - final String nonce = header.getNonce(); - - String reason = null; - byte[] requestBodyBytes; - - if ("2.0".equals(header.getVersion())) { - // Version 2.0 requires null data in signature for vault unlock. - requestBodyBytes = null; - } else if ("2.1".equals(header.getVersion())) { - // Version 2.1 or higher requires request data in signature (POST request body) for vault unlock. - if (request != null) { - // Send vault unlock reason, in case it is available. - if (request.getReason() != null) { - reason = request.getReason(); - } - } - - // Use POST request body as data for signature. - requestBodyBytes = authenticationProvider.extractRequestBodyBytes(httpServletRequest); - } else { - logger.warn("Invalid protocol version in secure vault: {}", header.getVersion()); - throw new PowerAuthSecureVaultException(); - } - - final String data = PowerAuthHttpBody.getSignatureBaseString("POST", "/pa/vault/unlock", BaseEncoding.base64().decode(nonce), requestBodyBytes); - - final com.wultra.security.powerauth.client.v2.VaultUnlockRequest unlockRequest = new com.wultra.security.powerauth.client.v2.VaultUnlockRequest(); - unlockRequest.setActivationId(activationId); - unlockRequest.setApplicationKey(applicationKey); - unlockRequest.setData(data); - unlockRequest.setSignature(signature); - unlockRequest.setSignatureType(signatureType); - unlockRequest.setReason(reason); - final com.wultra.security.powerauth.client.v2.VaultUnlockResponse paResponse = powerAuthClient.v2().unlockVault( - unlockRequest, - httpCustomizationService.getQueryParams(), - httpCustomizationService.getHttpHeaders() - ); - - if (!paResponse.isSignatureValid()) { - logger.debug("Signature validation failed"); - throw new PowerAuthSignatureInvalidException(); - } - - final VaultUnlockResponse response = new VaultUnlockResponse(); - response.setActivationId(paResponse.getActivationId()); - response.setEncryptedVaultEncryptionKey(paResponse.getEncryptedVaultEncryptionKey()); - - return response; - } catch (PowerAuthAuthenticationException ex) { - throw ex; - } catch (Exception ex) { - logger.warn("PowerAuth vault unlock failed, error: {}", ex.getMessage()); - logger.debug(ex.getMessage(), ex); - throw new PowerAuthSecureVaultException(); - } - } - -} diff --git a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/v2/TokenService.java b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/v2/TokenService.java deleted file mode 100644 index 0f5c5be7..00000000 --- a/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/service/v2/TokenService.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * PowerAuth integration libraries for RESTful API applications, examples and - * related software components - * - * Copyright (C) 2018 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.v2; - -import com.wultra.security.powerauth.client.PowerAuthClient; -import com.wultra.security.powerauth.client.v2.CreateTokenResponse; -import com.wultra.security.powerauth.client.v2.CreateTokenRequest; -import io.getlime.security.powerauth.crypto.lib.enums.PowerAuthSignatureTypes; -import io.getlime.security.powerauth.rest.api.spring.authentication.PowerAuthApiAuthentication; -import io.getlime.security.powerauth.rest.api.spring.exception.PowerAuthAuthenticationException; -import io.getlime.security.powerauth.rest.api.spring.exception.authentication.PowerAuthTokenErrorException; -import io.getlime.security.powerauth.rest.api.model.request.v2.TokenCreateRequest; -import io.getlime.security.powerauth.rest.api.model.response.v2.TokenCreateResponse; -import io.getlime.security.powerauth.rest.api.spring.converter.v2.SignatureTypeConverter; -import io.getlime.security.powerauth.rest.api.spring.service.HttpCustomizationService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -/** - * Service implementing token functionality. - * - *

PowerAuth protocol versions: - *

    - *
  • 2.0
  • - *
  • 2.1
  • - *
- * - * @author Roman Strobl, roman.strobl@wultra.com - * - */ -@Service("tokenServiceV2") -public class TokenService { - - private static final Logger logger = LoggerFactory.getLogger(TokenService.class); - - private final PowerAuthClient powerAuthClient; - private final HttpCustomizationService httpCustomizationService; - - /** - * Service constructor. - * @param powerAuthClient PowerAuth client. - * @param httpCustomizationService HTTP customization service. - */ - @Autowired - public TokenService(PowerAuthClient powerAuthClient, HttpCustomizationService httpCustomizationService) { - this.powerAuthClient = powerAuthClient; - this.httpCustomizationService = httpCustomizationService; - } - - /** - * Create token. - * @param request Create token request. - * @param authentication PowerAuth API authentication. - * @return Create token response. - * @throws PowerAuthAuthenticationException In case token could not be created. - */ - public TokenCreateResponse createToken(TokenCreateRequest request, PowerAuthApiAuthentication authentication) throws PowerAuthAuthenticationException { - try { - // Fetch activation ID and signature type - final String activationId = authentication.getActivationContext().getActivationId(); - final PowerAuthSignatureTypes signatureFactors = authentication.getAuthenticationContext().getSignatureType(); - - // Fetch data from the request - final String ephemeralPublicKey = request.getEphemeralPublicKey(); - - // Prepare a signature type converter - SignatureTypeConverter converter = new SignatureTypeConverter(); - - // Create a token - final CreateTokenRequest tokenRequest = new CreateTokenRequest(); - tokenRequest.setActivationId(activationId); - tokenRequest.setEphemeralPublicKey(ephemeralPublicKey); - tokenRequest.setSignatureType(converter.convertFrom(signatureFactors)); - final CreateTokenResponse token = powerAuthClient.v2().createToken( - tokenRequest, - httpCustomizationService.getQueryParams(), - httpCustomizationService.getHttpHeaders() - ); - - // Prepare a response - final TokenCreateResponse response = new TokenCreateResponse(); - response.setMac(token.getMac()); - response.setEncryptedData(token.getEncryptedData()); - return response; - } catch (Exception ex) { - logger.warn("Creating PowerAuth token failed, error: {}", ex.getMessage()); - logger.debug(ex.getMessage(), ex); - throw new PowerAuthTokenErrorException(); - } - } - -} 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 new file mode 100644 index 00000000..cad9ecf7 --- /dev/null +++ b/powerauth-restful-security-spring/src/main/java/io/getlime/security/powerauth/rest/api/spring/util/PowerAuthVersionUtil.java @@ -0,0 +1,149 @@ +/* + * PowerAuth integration libraries for RESTful API applications, examples 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 io.getlime.security.powerauth.rest.api.spring.util; + +import io.getlime.security.powerauth.rest.api.spring.exception.authentication.PowerAuthInvalidRequestException; +import lombok.extern.slf4j.Slf4j; + +import java.util.Set; + +/** + * Utility class to assist with PowerAuth version checks and related functionalities. + * This class provides methods to validate different aspects of the PowerAuth protocol, + * such as version checks, nonce verification, and timestamp checks. + *

+ * Note: The usage of these utility methods ensures the protocol adheres to the correct + * PowerAuth versions and avoids potential issues in processing requests. + *

+ * @author Jan Dusil, jan.dusil@wultra.com + */ +@Slf4j +public final class PowerAuthVersionUtil { + + /** + * Prevent instantiation of utility class. + */ + private PowerAuthVersionUtil() { + throw new IllegalStateException("Utility class"); + } + + /** + * Set containing all the supported versions of PowerAuth. + */ + private static final Set SUPPORTED_VERSIONS = Set.of("3.0", "3.1", "3.2"); + + /** + * Check if the provided version string is "3.0". + * + * @param version Version string to be checked. + * @return true if the version is "3.0", false otherwise. + */ + private static boolean isVersion3_0(final String version) { + return "3.0".equals(version); + } + + /** + * Check if the provided version string is "3.1". + * + * @param version Version string to be checked. + * @return true if the version is "3.1", false otherwise. + */ + private static boolean isVersion3_1(final String version) { + return "3.1".equals(version); + } + + /** + * Checks if the provided PowerAuth protocol version is unsupported. + * Throws an exception if the version is unsupported. + * + * @param version Version string to be checked. + * @throws PowerAuthInvalidRequestException If the provided version is unsupported. + */ + public static void checkUnsupportedVersion(String version) throws PowerAuthInvalidRequestException { + if (isUnsupportedVersion(version)) { + logger.warn("Endpoint does not support PowerAuth protocol version {}", version); + throw new PowerAuthInvalidRequestException("Endpoint does not support PowerAuth protocol version " + version); + } + } + + /** + * Checks if nonce is missing for the provided PowerAuth protocol version. + * Throws an exception if nonce is required and missing. + * + * @param version Version string to be checked. + * @param nonce Nonce string to be verified. + * @throws PowerAuthInvalidRequestException If nonce is required and missing. + */ + public static void checkMissingRequiredNonce(String version, String nonce) throws PowerAuthInvalidRequestException { + if (isMissingRequiredNonce(version, nonce)) { + logger.warn("Missing nonce in ECIES request data"); + throw new PowerAuthInvalidRequestException("Missing nonce in ECIES request data"); + } + } + + /** + * Checks if timestamp is missing for the provided PowerAuth protocol version. + * Throws an exception if the timestamp is required and missing. + * + * @param version Version string to be checked. + * @param timestamp Timestamp value to be verified. + * @throws PowerAuthInvalidRequestException If timestamp is required and missing. + */ + public static void checkMissingRequiredTimestamp(String version, Long timestamp) throws PowerAuthInvalidRequestException { + if (isMissingRequiredTimestamp(version, timestamp)) { + logger.warn("Missing timestamp in ECIES request data for version {}", version); + throw new PowerAuthInvalidRequestException("Missing timestamp in ECIES request data for version " + version); + } + } + + /** + * Checks if the provided PowerAuth protocol version is unsupported. + * + * @param version Version string to be checked. + * @return true if the version is unsupported, false otherwise. + */ + private static boolean isUnsupportedVersion(String version) { + return !SUPPORTED_VERSIONS.contains(version); + } + + /** + * Checks if nonce is missing for the provided PowerAuth protocol version. + * + * @param version Version string to be checked. + * @param nonce Nonce string to be verified. + * @return true if nonce is required and missing, false otherwise. + */ + private static boolean isMissingRequiredNonce(String version, String nonce) { + return nonce == null && !isVersion3_0(version); + } + + /** + * Checks if timestamp is missing for the provided PowerAuth protocol version. + * + * @param version Version string to be checked. + * @param timestamp Timestamp value to be verified. + * @return true if timestamp is required and missing, false otherwise. + */ + private static boolean isMissingRequiredTimestamp(String version, Long timestamp) { + return timestamp == null && + !isVersion3_0(version) && + !isVersion3_1(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 new file mode 100644 index 00000000..6d15f81a --- /dev/null +++ b/powerauth-restful-security-spring/src/test/java/io/getlime/security/powerauth/rest/api/spring/PowerAuthVersionUtilTest.java @@ -0,0 +1,65 @@ +/* + * PowerAuth integration libraries for RESTful API applications, examples 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 io.getlime.security.powerauth.rest.api.spring; + +import io.getlime.security.powerauth.rest.api.spring.exception.authentication.PowerAuthInvalidRequestException; +import io.getlime.security.powerauth.rest.api.spring.util.PowerAuthVersionUtil; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertThrows; + +/** + * This class provides tests for the {@link PowerAuthVersionUtil} utility class, + * ensuring that the PowerAuth version checks and related functionalities work as expected. + * + * @author Jan Dusil, jan.dusil@wultra.com + */ +class PowerAuthVersionUtilTest { + + /** + * Tests the behavior of checking unsupported PowerAuth versions. + */ + @Test + void testUnsupportedVersion() { + assertThrows(PowerAuthInvalidRequestException.class, () -> PowerAuthVersionUtil.checkUnsupportedVersion("4.0")); + assertDoesNotThrow(() -> PowerAuthVersionUtil.checkUnsupportedVersion("3.1")); + } + + /** + * Tests the behavior of checking for missing required nonces based on the PowerAuth version. + */ + @Test + void testMissingRequiredNonce() { + assertThrows(PowerAuthInvalidRequestException.class, () -> PowerAuthVersionUtil.checkMissingRequiredNonce("3.1", null)); + assertDoesNotThrow(() -> PowerAuthVersionUtil.checkMissingRequiredNonce("3.0", null)); + assertDoesNotThrow(() -> PowerAuthVersionUtil.checkMissingRequiredNonce("3.1", "testNonce")); + } + + /** + * Tests the behavior of checking for missing required timestamps based on the PowerAuth version. + */ + @Test + void testMissingRequiredTimestamp() { + assertThrows(PowerAuthInvalidRequestException.class, () -> PowerAuthVersionUtil.checkMissingRequiredTimestamp("3.2", null)); + assertDoesNotThrow(() -> PowerAuthVersionUtil.checkMissingRequiredTimestamp("3.1", null)); + assertDoesNotThrow(() -> PowerAuthVersionUtil.checkMissingRequiredTimestamp("3.2", 1630234567890L)); + } +} \ No newline at end of file