diff --git a/amphora-service/README.md b/amphora-service/README.md index cd8fa58..b59e2df 100644 --- a/amphora-service/README.md +++ b/amphora-service/README.md @@ -104,5 +104,5 @@ DB_USER=user DB_PASSWORD=secret MINIO_ENDPOINT=http://localhost:9000 EOF -docker run --env-file amphora.conf iotspecs/amphora-service +docker run --env-file amphora.conf iotspecs/amphora-service ``` diff --git a/amphora-service/charts/amphora/values.yaml b/amphora-service/charts/amphora/values.yaml index 556700b..914e792 100644 --- a/amphora-service/charts/amphora/values.yaml +++ b/amphora-service/charts/amphora/values.yaml @@ -79,4 +79,4 @@ auth: opa: defaultPolicyPackage: "carbynestack.def" - endpoint: "http://opa.default.svc.cluster.local:8081/" \ No newline at end of file + endpoint: "http://opa.default.svc.cluster.local:8081/" diff --git a/amphora-service/src/main/java/io/carbynestack/amphora/service/calculation/SecretShareUtil.java b/amphora-service/src/main/java/io/carbynestack/amphora/service/calculation/SecretShareUtil.java index 713a375..0536909 100644 --- a/amphora-service/src/main/java/io/carbynestack/amphora/service/calculation/SecretShareUtil.java +++ b/amphora-service/src/main/java/io/carbynestack/amphora/service/calculation/SecretShareUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2024 - for information on the respective copyright owner + * Copyright (c) 2021 - for information on the respective copyright owner * see the NOTICE file and/or the repository https://github.com/carbynestack/amphora. * * SPDX-License-Identifier: Apache-2.0 @@ -13,7 +13,6 @@ import io.carbynestack.amphora.common.MaskedInput; import io.carbynestack.amphora.common.MaskedInputData; import io.carbynestack.amphora.common.SecretShare; -import io.carbynestack.amphora.common.Tag; import io.carbynestack.castor.common.entities.Field; import io.carbynestack.castor.common.entities.InputMask; import io.carbynestack.castor.common.entities.Share; diff --git a/amphora-service/src/main/java/io/carbynestack/amphora/service/config/AuthProperties.java b/amphora-service/src/main/java/io/carbynestack/amphora/service/config/AuthProperties.java index 8e448da..c985b0b 100644 --- a/amphora-service/src/main/java/io/carbynestack/amphora/service/config/AuthProperties.java +++ b/amphora-service/src/main/java/io/carbynestack/amphora/service/config/AuthProperties.java @@ -7,7 +7,6 @@ package io.carbynestack.amphora.service.config; - import lombok.Data; import lombok.experimental.Accessors; import org.springframework.boot.context.properties.ConfigurationProperties; @@ -18,5 +17,5 @@ @Data @Accessors(chain = true) public class AuthProperties { - private String userIdFieldName; + private String userIdFieldName; } diff --git a/amphora-service/src/main/java/io/carbynestack/amphora/service/config/OpaConfig.java b/amphora-service/src/main/java/io/carbynestack/amphora/service/config/OpaConfig.java index de8cedd..d415d9e 100644 --- a/amphora-service/src/main/java/io/carbynestack/amphora/service/config/OpaConfig.java +++ b/amphora-service/src/main/java/io/carbynestack/amphora/service/config/OpaConfig.java @@ -9,11 +9,10 @@ import io.carbynestack.amphora.service.opa.JwtReader; import io.carbynestack.amphora.service.opa.OpaClient; +import java.net.URI; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import java.net.URI; - @Configuration public class OpaConfig { @@ -25,8 +24,8 @@ JwtReader jwtReader(AuthProperties authProperties) { @Bean OpaClient opaClient(OpaProperties opaProperties) { return OpaClient.builder() - .opaServiceUri(URI.create(opaProperties.getEndpoint())) - .defaultPolicyPackage(opaProperties.getDefaultPolicyPackage()) - .build(); + .opaServiceUri(URI.create(opaProperties.getEndpoint())) + .defaultPolicyPackage(opaProperties.getDefaultPolicyPackage()) + .build(); } } diff --git a/amphora-service/src/main/java/io/carbynestack/amphora/service/exceptions/CsOpaException.java b/amphora-service/src/main/java/io/carbynestack/amphora/service/exceptions/CsOpaException.java index 1513f40..1412fb2 100644 --- a/amphora-service/src/main/java/io/carbynestack/amphora/service/exceptions/CsOpaException.java +++ b/amphora-service/src/main/java/io/carbynestack/amphora/service/exceptions/CsOpaException.java @@ -8,7 +8,7 @@ package io.carbynestack.amphora.service.exceptions; public class CsOpaException extends Exception { - public CsOpaException(String message) { - super(message); - } + public CsOpaException(String message) { + super(message); + } } diff --git a/amphora-service/src/main/java/io/carbynestack/amphora/service/exceptions/UnauthorizedException.java b/amphora-service/src/main/java/io/carbynestack/amphora/service/exceptions/UnauthorizedException.java index 9828698..ea9e8e6 100644 --- a/amphora-service/src/main/java/io/carbynestack/amphora/service/exceptions/UnauthorizedException.java +++ b/amphora-service/src/main/java/io/carbynestack/amphora/service/exceptions/UnauthorizedException.java @@ -8,7 +8,7 @@ package io.carbynestack.amphora.service.exceptions; public class UnauthorizedException extends Exception { - public UnauthorizedException(String message) { - super(message); - } + public UnauthorizedException(String message) { + super(message); + } } diff --git a/amphora-service/src/main/java/io/carbynestack/amphora/service/opa/JwtReader.java b/amphora-service/src/main/java/io/carbynestack/amphora/service/opa/JwtReader.java index fba703a..041d0dc 100644 --- a/amphora-service/src/main/java/io/carbynestack/amphora/service/opa/JwtReader.java +++ b/amphora-service/src/main/java/io/carbynestack/amphora/service/opa/JwtReader.java @@ -12,58 +12,57 @@ import com.fasterxml.jackson.databind.ObjectMapper; import io.carbynestack.amphora.service.exceptions.UnauthorizedException; import io.vavr.control.Option; - import java.util.Base64; public class JwtReader { - static ObjectMapper mapper = new ObjectMapper(); - private final String userIdField; + static ObjectMapper mapper = new ObjectMapper(); + private final String userIdField; - public JwtReader(String userIdField) { - this.userIdField = userIdField; - } + public JwtReader(String userIdField) { + this.userIdField = userIdField; + } - public String extractUserIdFromAuthHeader(String header) throws UnauthorizedException { - return extractFieldFromAuthHeader(header, userIdField); - } + public String extractUserIdFromAuthHeader(String header) throws UnauthorizedException { + return extractFieldFromAuthHeader(header, userIdField); + } - private static String extractFieldFromAuthHeader(String header, String field) throws UnauthorizedException { - return tokenFromHeader(header) - .flatMap(JwtReader::dataNodeFromToken) - .flatMap(node -> fieldFromNode(node, field)) - .getOrElseThrow(() -> new UnauthorizedException("No token provided")); - } + private static String extractFieldFromAuthHeader(String header, String field) + throws UnauthorizedException { + return tokenFromHeader(header) + .flatMap(JwtReader::dataNodeFromToken) + .flatMap(node -> fieldFromNode(node, field)) + .getOrElseThrow(() -> new UnauthorizedException("No token provided")); + } - private static Option dataNodeFromToken(String token) { - String[] parts = token.split("\\."); - if (parts.length != 3) { - return Option.none(); - } - try { - String jwt = new String(Base64.getDecoder().decode(parts[1])); - return Option.of(mapper.reader().readTree(jwt)); - } catch (JsonProcessingException e) { - return Option.none(); - } + private static Option dataNodeFromToken(String token) { + String[] parts = token.split("\\."); + if (parts.length != 3) { + return Option.none(); + } + try { + String jwt = new String(Base64.getDecoder().decode(parts[1])); + return Option.of(mapper.reader().readTree(jwt)); + } catch (JsonProcessingException e) { + return Option.none(); } + } - private static Option tokenFromHeader(String header) { - if (header != null && header.startsWith("Bearer ")) { - return Option.of(header.substring(7)); - } - return Option.none(); + private static Option tokenFromHeader(String header) { + if (header != null && header.startsWith("Bearer ")) { + return Option.of(header.substring(7)); } + return Option.none(); + } - private static Option fieldFromNode(JsonNode node, String fieldName) { - JsonNode field = node; - try { - for(String f : fieldName.split("\\.")) { - field = field.get(f); - } - return Option.of(field.asText()); - } catch (NullPointerException e) { - return Option.none(); - } + private static Option fieldFromNode(JsonNode node, String fieldName) { + JsonNode field = node; + try { + for (String f : fieldName.split("\\.")) { + field = field.get(f); + } + return Option.of(field.asText()); + } catch (NullPointerException e) { + return Option.none(); } + } } - diff --git a/amphora-service/src/main/java/io/carbynestack/amphora/service/opa/OpaClient.java b/amphora-service/src/main/java/io/carbynestack/amphora/service/opa/OpaClient.java index 30ba7b9..fe9c40e 100644 --- a/amphora-service/src/main/java/io/carbynestack/amphora/service/opa/OpaClient.java +++ b/amphora-service/src/main/java/io/carbynestack/amphora/service/opa/OpaClient.java @@ -10,58 +10,54 @@ import io.carbynestack.amphora.common.Tag; import io.carbynestack.httpclient.CsHttpClient; import io.carbynestack.httpclient.CsHttpClientException; -import lombok.Builder; -import lombok.extern.slf4j.Slf4j; - import java.net.URI; import java.util.List; +import lombok.Builder; +import lombok.extern.slf4j.Slf4j; @Slf4j public class OpaClient { - private final CsHttpClient csHttpClient; - private final URI opaServiceUri; - private final String defaultPolicyPackage; - - @Builder - public OpaClient(URI opaServiceUri, String defaultPolicyPackage) { - this(CsHttpClient.createDefault(), opaServiceUri, defaultPolicyPackage); + private final CsHttpClient csHttpClient; + private final URI opaServiceUri; + private final String defaultPolicyPackage; + + @Builder + public OpaClient(URI opaServiceUri, String defaultPolicyPackage) { + this(CsHttpClient.createDefault(), opaServiceUri, defaultPolicyPackage); + } + + OpaClient(CsHttpClient httpClient, URI opaServiceUri, String defaultPolicyPackage) { + this.csHttpClient = httpClient; + this.opaServiceUri = opaServiceUri; + this.defaultPolicyPackage = defaultPolicyPackage; + } + + /** + * Evaluate the OPA policy package with the given action, subject and tags. + * + * @param policyPackage The OPA policy package to evaluate. + * @param action The action to evaluate. + * @param subject The subject attempting to perform the action. + * @param tags The tags describing the accessed object. + * @return True if the subject can perform the action, false otherwise (or if an error occurred). + */ + public boolean isAllowed(String policyPackage, String action, String subject, List tags) { + OpaRequestBody body = OpaRequestBody.builder().subject(subject).tags(tags).build(); + try { + return csHttpClient + .postForObject( + opaServiceUri.resolve( + String.format("/v1/data/%s/%s", policyPackage.replace(".", "/"), action)), + new OpaRequest(body), + OpaResult.class) + .isAllowed(); + } catch (CsHttpClientException e) { + log.error("Error occurred while evaluating OPA policy package", e); } + return false; + } - OpaClient(CsHttpClient httpClient, URI opaServiceUri, String defaultPolicyPackage) { - this.csHttpClient = httpClient; - this.opaServiceUri = opaServiceUri; - this.defaultPolicyPackage = defaultPolicyPackage; - } - - /** - * Evaluate the OPA policy package with the given action, subject and tags. - * - * @param policyPackage The OPA policy package to evaluate. - * @param action The action to evaluate. - * @param subject The subject attempting to perform the action. - * @param tags The tags describing the accessed object. - * @return True if the subject can perform the action, false otherwise (or if an error occurred). - */ - public boolean isAllowed(String policyPackage, String action, String subject, List tags) { - OpaRequestBody body = OpaRequestBody.builder() - .subject(subject) - .tags(tags) - .build(); - try { - return csHttpClient.postForObject(opaServiceUri.resolve( - String.format("/v1/data/%s/%s", - policyPackage.replace(".", "/"), - action)), - new OpaRequest(body), - OpaResult.class) - .isAllowed(); - } catch (CsHttpClientException e) { - log.error("Error occurred while evaluating OPA policy package: {}", e.getMessage()); - } - return false; - } - - public OpaClientRequest newRequest() { - return new OpaClientRequest(this, defaultPolicyPackage); - } -} \ No newline at end of file + public OpaClientRequest newRequest() { + return new OpaClientRequest(this, defaultPolicyPackage); + } +} diff --git a/amphora-service/src/main/java/io/carbynestack/amphora/service/opa/OpaClientRequest.java b/amphora-service/src/main/java/io/carbynestack/amphora/service/opa/OpaClientRequest.java index a2f2c98..3e68ad4 100644 --- a/amphora-service/src/main/java/io/carbynestack/amphora/service/opa/OpaClientRequest.java +++ b/amphora-service/src/main/java/io/carbynestack/amphora/service/opa/OpaClientRequest.java @@ -9,37 +9,35 @@ import io.carbynestack.amphora.common.Tag; import io.carbynestack.amphora.service.exceptions.CsOpaException; +import java.util.List; +import java.util.Objects; import lombok.Setter; import lombok.experimental.Accessors; import org.apache.logging.log4j.util.Strings; -import java.util.List; -import java.util.Objects; - @Setter() @Accessors(chain = true, fluent = true) public class OpaClientRequest { - private String withPolicyPackage; - private String withSubject; - private List withTags; - private String withAction; + private String withPolicyPackage; + private String withSubject; + private List withTags; + private String withAction; - private final OpaClient opaClient; + private final OpaClient opaClient; - public OpaClientRequest(OpaClient opaClient, String defaultPolicyPackage) { - this.withPolicyPackage = defaultPolicyPackage; - this.opaClient = opaClient; - } + public OpaClientRequest(OpaClient opaClient, String defaultPolicyPackage) { + this.withPolicyPackage = defaultPolicyPackage; + this.opaClient = opaClient; + } - public boolean evaluate() throws CsOpaException { - if(Strings.isEmpty(withSubject)) { - throw new CsOpaException("Subject is required to evaluate the policy"); - } - if(Strings.isEmpty(withAction)) { - throw new CsOpaException("Action is required to evaluate the policy"); - } - withTags.removeIf(Objects::isNull); - return opaClient.isAllowed(withPolicyPackage, withAction, withSubject, withTags); + public boolean evaluate() throws CsOpaException { + if (Strings.isEmpty(withSubject)) { + throw new CsOpaException("Subject is required to evaluate the policy"); } + if (Strings.isEmpty(withAction)) { + throw new CsOpaException("Action is required to evaluate the policy"); + } + withTags.removeIf(Objects::isNull); + return opaClient.isAllowed(withPolicyPackage, withAction, withSubject, withTags); + } } - diff --git a/amphora-service/src/main/java/io/carbynestack/amphora/service/opa/OpaRequest.java b/amphora-service/src/main/java/io/carbynestack/amphora/service/opa/OpaRequest.java index 6f276b5..12fa776 100644 --- a/amphora-service/src/main/java/io/carbynestack/amphora/service/opa/OpaRequest.java +++ b/amphora-service/src/main/java/io/carbynestack/amphora/service/opa/OpaRequest.java @@ -11,10 +11,9 @@ @Getter class OpaRequest { - OpaRequestBody input; - - public OpaRequest(OpaRequestBody input) { - this.input = input; - } + OpaRequestBody input; + public OpaRequest(OpaRequestBody input) { + this.input = input; + } } diff --git a/amphora-service/src/main/java/io/carbynestack/amphora/service/opa/OpaRequestBody.java b/amphora-service/src/main/java/io/carbynestack/amphora/service/opa/OpaRequestBody.java index ffd591b..2fc2b18 100644 --- a/amphora-service/src/main/java/io/carbynestack/amphora/service/opa/OpaRequestBody.java +++ b/amphora-service/src/main/java/io/carbynestack/amphora/service/opa/OpaRequestBody.java @@ -8,19 +8,18 @@ package io.carbynestack.amphora.service.opa; import io.carbynestack.amphora.common.Tag; +import java.util.List; import lombok.Builder; import lombok.Value; -import java.util.List; - @Value public class OpaRequestBody { - String subject; - List tags; + String subject; + List tags; - @Builder - public OpaRequestBody(String subject, List tags) { - this.subject = subject; - this.tags = tags; - } + @Builder + public OpaRequestBody(String subject, List tags) { + this.subject = subject; + this.tags = tags; + } } diff --git a/amphora-service/src/main/java/io/carbynestack/amphora/service/opa/OpaResult.java b/amphora-service/src/main/java/io/carbynestack/amphora/service/opa/OpaResult.java index da0d2e0..4c17f01 100644 --- a/amphora-service/src/main/java/io/carbynestack/amphora/service/opa/OpaResult.java +++ b/amphora-service/src/main/java/io/carbynestack/amphora/service/opa/OpaResult.java @@ -10,10 +10,9 @@ import lombok.Setter; public class OpaResult { - @Setter - private boolean result; + @Setter private boolean result; - boolean isAllowed() { - return result; - } + boolean isAllowed() { + return result; + } } diff --git a/amphora-service/src/main/java/io/carbynestack/amphora/service/opa/OpaService.java b/amphora-service/src/main/java/io/carbynestack/amphora/service/opa/OpaService.java index d8c5618..07c2c00 100644 --- a/amphora-service/src/main/java/io/carbynestack/amphora/service/opa/OpaService.java +++ b/amphora-service/src/main/java/io/carbynestack/amphora/service/opa/OpaService.java @@ -9,140 +9,146 @@ import io.carbynestack.amphora.common.Tag; import io.carbynestack.amphora.service.exceptions.CsOpaException; +import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import java.util.List; - @Service public class OpaService { - public static final String POLICY_PACKAGE_TAG_KEY = "accessPolicy"; - public static final String OWNER_TAG_KEY = "owner"; + public static final String POLICY_PACKAGE_TAG_KEY = "accessPolicy"; + public static final String OWNER_TAG_KEY = "owner"; - static final String READ_SECRET_ACTION_NAME = "read"; - static final String USE_SECRET_ACTION_NAME = "use"; - static final String DELETE_SECRET_ACTION_NAME = "delete"; - static final String CREATE_TAG_ACTION_NAME = "tag/create"; - static final String READ_TAG_ACTION_NAME = "tag/read"; - static final String UPDATE_TAG_ACTION_NAME = "tag/update"; - static final String DELETE_TAG_ACTION_NAME = "tag/delete"; + static final String READ_SECRET_ACTION_NAME = "read"; + static final String USE_SECRET_ACTION_NAME = "use"; + static final String DELETE_SECRET_ACTION_NAME = "delete"; + static final String CREATE_TAG_ACTION_NAME = "tag/create"; + static final String READ_TAG_ACTION_NAME = "tag/read"; + static final String UPDATE_TAG_ACTION_NAME = "tag/update"; + static final String DELETE_TAG_ACTION_NAME = "tag/delete"; - private final OpaClient opaClient; + private final OpaClient opaClient; - @Autowired - public OpaService(OpaClient opaClient) { - this.opaClient = opaClient; - } + @Autowired + public OpaService(OpaClient opaClient) { + this.opaClient = opaClient; + } - /** - * Check if the subject can read the secret described by the given tags evaluating the OPA policy package. - * The policy package is extracted from the tags if present. If not present, the default policy package is used. - * - * @param subject The subject attempting to read the secret. - * @param tags The tags describing the referenced secret. - * @return True if the subject can read the secret, false otherwise. - * @throws CsOpaException If an error occurred while evaluating the policy. - */ - public boolean canReadSecret(String subject, List tags) throws CsOpaException { - return isAllowed(subject, READ_SECRET_ACTION_NAME, tags); - } + /** + * Check if the subject can read the secret described by the given tags evaluating the OPA policy + * package. The policy package is extracted from the tags if present. If not present, the default + * policy package is used. + * + * @param subject The subject attempting to read the secret. + * @param tags The tags describing the referenced secret. + * @return True if the subject can read the secret, false otherwise. + * @throws CsOpaException If an error occurred while evaluating the policy. + */ + public boolean canReadSecret(String subject, List tags) throws CsOpaException { + return isAllowed(subject, READ_SECRET_ACTION_NAME, tags); + } - /** - * Check if the subject can use the secret described by the given tags evaluating the OPA policy package. - * The policy package is extracted from the tags if present. If not present, the default policy package is used. - * - * @param subject The subject attempting to use the secret. - * @param tags The tags describing the referenced secret. - * @return True if the subject can use the secret, false otherwise. - * @throws CsOpaException If an error occurred while evaluating the policy. - */ - public boolean canUseSecret(String subject, List tags) throws CsOpaException { - return isAllowed(subject, USE_SECRET_ACTION_NAME, tags); - } + /** + * Check if the subject can use the secret described by the given tags evaluating the OPA policy + * package. The policy package is extracted from the tags if present. If not present, the default + * policy package is used. + * + * @param subject The subject attempting to use the secret. + * @param tags The tags describing the referenced secret. + * @return True if the subject can use the secret, false otherwise. + * @throws CsOpaException If an error occurred while evaluating the policy. + */ + public boolean canUseSecret(String subject, List tags) throws CsOpaException { + return isAllowed(subject, USE_SECRET_ACTION_NAME, tags); + } - /** - * Check if the subject can delete the secret described by the given tags evaluating the OPA policy package. - * The policy package is extracted from the tags if present. If not present, the default policy package is used. - * - * @param subject The subject attempting to delete the secret. - * @param tags The tags describing the referenced secret. - * @return True if the subject can delete the secret, false otherwise. - * @throws CsOpaException If an error occurred while evaluating the policy. - */ - public boolean canDeleteSecret(String subject, List tags) throws CsOpaException { - return isAllowed(subject, DELETE_SECRET_ACTION_NAME, tags); - } + /** + * Check if the subject can delete the secret described by the given tags evaluating the OPA + * policy package. The policy package is extracted from the tags if present. If not present, the + * default policy package is used. + * + * @param subject The subject attempting to delete the secret. + * @param tags The tags describing the referenced secret. + * @return True if the subject can delete the secret, false otherwise. + * @throws CsOpaException If an error occurred while evaluating the policy. + */ + public boolean canDeleteSecret(String subject, List tags) throws CsOpaException { + return isAllowed(subject, DELETE_SECRET_ACTION_NAME, tags); + } - /** - * Check if the subject can create the given tags evaluating the OPA policy package. - * The policy package is extracted from the tags if present. If not present, the default policy package is used. - * - * @param subject The subject attempting to create the tags. - * @param tags The tags to create. - * @return True if the subject can create the tags, false otherwise. - * @throws CsOpaException If an error occurred while evaluating the policy. - */ - public boolean canCreateTags(String subject, List tags) throws CsOpaException { - return isAllowed(subject, CREATE_TAG_ACTION_NAME, tags); - } + /** + * Check if the subject can create the given tags evaluating the OPA policy package. The policy + * package is extracted from the tags if present. If not present, the default policy package is + * used. + * + * @param subject The subject attempting to create the tags. + * @param tags The tags to create. + * @return True if the subject can create the tags, false otherwise. + * @throws CsOpaException If an error occurred while evaluating the policy. + */ + public boolean canCreateTags(String subject, List tags) throws CsOpaException { + return isAllowed(subject, CREATE_TAG_ACTION_NAME, tags); + } - /** - * Check if the subject can read the given tags evaluating the OPA policy package. - * The policy package is extracted from the tags if present. If not present, the default policy package is used. - * - * @param subject The subject attempting to read the tags. - * @param tags The tags to read. - * @return True if the subject can read the tags, false otherwise. - * @throws CsOpaException If an error occurred while evaluating the policy. - */ - public boolean canReadTags(String subject, List tags) throws CsOpaException { - return isAllowed(subject, READ_TAG_ACTION_NAME, tags); - } + /** + * Check if the subject can read the given tags evaluating the OPA policy package. The policy + * package is extracted from the tags if present. If not present, the default policy package is + * used. + * + * @param subject The subject attempting to read the tags. + * @param tags The tags to read. + * @return True if the subject can read the tags, false otherwise. + * @throws CsOpaException If an error occurred while evaluating the policy. + */ + public boolean canReadTags(String subject, List tags) throws CsOpaException { + return isAllowed(subject, READ_TAG_ACTION_NAME, tags); + } - /** - * Check if the subject can update the given tags evaluating the OPA policy package. - * The policy package is extracted from the tags if present. If not present, the default policy package is used. - * - * @param subject The subject attempting to update the tags. - * @param tags The tags to update. - * @return True if the subject can update the tags, false otherwise. - * @throws CsOpaException If an error occurred while evaluating the policy. - */ - public boolean canUpdateTags(String subject, List tags) throws CsOpaException { - return isAllowed(subject, UPDATE_TAG_ACTION_NAME, tags); - } + /** + * Check if the subject can update the given tags evaluating the OPA policy package. The policy + * package is extracted from the tags if present. If not present, the default policy package is + * used. + * + * @param subject The subject attempting to update the tags. + * @param tags The tags to update. + * @return True if the subject can update the tags, false otherwise. + * @throws CsOpaException If an error occurred while evaluating the policy. + */ + public boolean canUpdateTags(String subject, List tags) throws CsOpaException { + return isAllowed(subject, UPDATE_TAG_ACTION_NAME, tags); + } - /** - * Check if the subject can delete the given tags evaluating the OPA policy package. - * The policy package is extracted from the tags if present. If not present, the default policy package is used. - * - * @param subject The subject attempting to delete the tags. - * @param tags The tags to delete. - * @return True if the subject can delete the tags, false otherwise. - * @throws CsOpaException If an error occurred while evaluating the policy. - */ - public boolean canDeleteTags(String subject, List tags) throws CsOpaException { - return isAllowed(subject, DELETE_TAG_ACTION_NAME, tags); - } + /** + * Check if the subject can delete the given tags evaluating the OPA policy package. The policy + * package is extracted from the tags if present. If not present, the default policy package is + * used. + * + * @param subject The subject attempting to delete the tags. + * @param tags The tags to delete. + * @return True if the subject can delete the tags, false otherwise. + * @throws CsOpaException If an error occurred while evaluating the policy. + */ + public boolean canDeleteTags(String subject, List tags) throws CsOpaException { + return isAllowed(subject, DELETE_TAG_ACTION_NAME, tags); + } - /** - * Check if the subject can perform the given action evaluating the OPA policy package. - * The policy package is extracted from the tags if present. If not present, the default policy package is used. - * - * @param action The action to evaluate. - * @param subject The subject attempting to perform the action. - * @param tags The tags describing the accessed object. - * @return True if the subject can perform the action, false otherwise. - * @throws CsOpaException If an error occurred while evaluating the policy. - */ - boolean isAllowed(String subject, String action, List tags) throws CsOpaException { - OpaClientRequest request = opaClient.newRequest() - .withSubject(subject) - .withAction(action) - .withTags(tags); - tags.stream().filter(tag -> tag.getKey().equals(POLICY_PACKAGE_TAG_KEY)) - .findFirst() - .ifPresent(tag -> request.withPolicyPackage(tag.getValue())); - return request.evaluate(); - } + /** + * Check if the subject can perform the given action evaluating the OPA policy package. The policy + * package is extracted from the tags if present. If not present, the default policy package is + * used. + * + * @param action The action to evaluate. + * @param subject The subject attempting to perform the action. + * @param tags The tags describing the accessed object. + * @return True if the subject can perform the action, false otherwise. + * @throws CsOpaException If an error occurred while evaluating the policy. + */ + boolean isAllowed(String subject, String action, List tags) throws CsOpaException { + OpaClientRequest request = + opaClient.newRequest().withSubject(subject).withAction(action).withTags(tags); + tags.stream() + .filter(tag -> tag.getKey().equals(POLICY_PACKAGE_TAG_KEY)) + .findFirst() + .ifPresent(tag -> request.withPolicyPackage(tag.getValue())); + return request.evaluate(); + } } diff --git a/amphora-service/src/main/java/io/carbynestack/amphora/service/persistence/metadata/StorageService.java b/amphora-service/src/main/java/io/carbynestack/amphora/service/persistence/metadata/StorageService.java index 6d257dc..5a85a14 100644 --- a/amphora-service/src/main/java/io/carbynestack/amphora/service/persistence/metadata/StorageService.java +++ b/amphora-service/src/main/java/io/carbynestack/amphora/service/persistence/metadata/StorageService.java @@ -7,6 +7,10 @@ package io.carbynestack.amphora.service.persistence.metadata; +import static io.carbynestack.amphora.service.opa.OpaService.OWNER_TAG_KEY; +import static io.carbynestack.amphora.service.persistence.metadata.TagEntity.setFromTagList; +import static io.carbynestack.amphora.service.persistence.metadata.TagEntity.setToTagList; + import com.google.common.collect.Lists; import io.carbynestack.amphora.common.*; import io.carbynestack.amphora.common.exceptions.AmphoraServiceException; @@ -24,6 +28,8 @@ import io.carbynestack.castor.common.entities.InputMask; import io.carbynestack.castor.common.entities.TupleList; import io.vavr.control.Option; +import java.util.*; +import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; @@ -35,13 +41,6 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; -import java.util.*; -import java.util.stream.Collectors; - -import static io.carbynestack.amphora.service.opa.OpaService.OWNER_TAG_KEY; -import static io.carbynestack.amphora.service.persistence.metadata.TagEntity.setFromTagList; -import static io.carbynestack.amphora.service.persistence.metadata.TagEntity.setToTagList; - /** * A service to persist and manipulate {@link SecretEntity SecretEntities} and related data like * {@link TagEntity TagEntities} and {@link SecretShare SecretShares}. @@ -51,20 +50,19 @@ @RequiredArgsConstructor(onConstructor_ = @Autowired) public class StorageService { public static final String CREATION_DATE_KEY = "creation-date"; - public static final List RESERVED_TAG_KEYS = Lists.newArrayList( - CREATION_DATE_KEY, - OWNER_TAG_KEY); + public static final List RESERVED_TAG_KEYS = + Lists.newArrayList(CREATION_DATE_KEY, OWNER_TAG_KEY); public static final String TAGS_WITH_THE_SAME_KEY_DEFINED_EXCEPTION_MSG = - "Two or more tags with the same key defined."; + "Two or more tags with the same key defined."; public static final String SECRET_WITH_ID_EXISTS_EXCEPTION_MSG = - "A secret with the given id already exists."; + "A secret with the given id already exists."; public static final String IS_RESERVED_KEY_EXCEPTION_MSG = "\"%s\" is a reserved key."; public static final String NO_SECRET_WITH_ID_EXISTS_EXCEPTION_MSG = - "No secret with the given id #%s exists."; + "No secret with the given id #%s exists."; public static final String NO_TAG_WITH_KEY_EXISTS_FOR_SECRET_WITH_ID_EXCEPTION_MSG = - "No tag with key \"%s\" exists for secret with id #%s."; + "No tag with key \"%s\" exists for secret with id #%s."; public static final String TAG_WITH_KEY_EXISTS_FOR_SECRET_EXCEPTION_MSG = - "A tag with key \"%s\" already exists for secret #%s"; + "A tag with key \"%s\" already exists for secret #%s"; private final SecretEntityRepository secretEntityRepository; private final InputMaskCachingService inputMaskStore; @@ -83,7 +81,8 @@ public class StorageService { * persisting the secret without further notice. * * @param maskedInput the {@link MaskedInput} to persist - * @param authorizedUserId the id of the authenticated user becoming the owner of the persisted {@link SecretShare} + * @param authorizedUserId the id of the authenticated user becoming the owner of the persisted + * {@link SecretShare} * @return the id of the new {@link SecretShare} as {@link String} * @throws AlreadyExistsException if an {@link SecretShare} with the given id already exists. * @throws IllegalArgumentException if one or more {@link Tag}s with the same {@link Tag#getKey() @@ -101,15 +100,18 @@ public String createSecret(MaskedInput maskedInput, String authorizedUserId) { throw new IllegalArgumentException(TAGS_WITH_THE_SAME_KEY_DEFINED_EXCEPTION_MSG); } TupleList, Field.Gfp> inputMasks = - inputMaskStore.getCachedInputMasks(maskedInput.getSecretId()); + inputMaskStore.getCachedInputMasks(maskedInput.getSecretId()); SecretShare secretShare = - secretShareUtil.convertToSecretShare( - maskedInput, - spdzProperties.getMacKey(), - inputMasks, - amphoraServiceProperties.getPlayerId() != 0); - String secretId = persistSecretShare(secretShare, - Collections.singletonList(Tag.builder().key(OWNER_TAG_KEY).value(authorizedUserId).build())); + secretShareUtil.convertToSecretShare( + maskedInput, + spdzProperties.getMacKey(), + inputMasks, + amphoraServiceProperties.getPlayerId() != 0); + String secretId = + persistSecretShare( + secretShare, + Collections.singletonList( + Tag.builder().key(OWNER_TAG_KEY).value(authorizedUserId).build())); inputMaskStore.removeInputMasks(secretShare.getSecretId()); return secretId; } @@ -137,9 +139,9 @@ public String storeSecretShare(SecretShare secretShare) { } List reservedTags = new ArrayList<>(); secretShare.getTags().stream() - .filter(t -> t.getKey().equals(OWNER_TAG_KEY)) - .findFirst() - .ifPresent(reservedTags::add); + .filter(t -> t.getKey().equals(OWNER_TAG_KEY)) + .findFirst() + .ifPresent(reservedTags::add); return persistSecretShare(secretShare, reservedTags); } @@ -150,18 +152,18 @@ public String storeSecretShare(SecretShare secretShare) { private String persistSecretShare(SecretShare secretShare, List reservedTags) { List tags = dropReservedTags(new ArrayList<>(secretShare.getTags())); tags.add( - Tag.builder() - .key(StorageService.CREATION_DATE_KEY) - .value(Long.toString(System.currentTimeMillis())) - .build()); + Tag.builder() + .key(StorageService.CREATION_DATE_KEY) + .value(Long.toString(System.currentTimeMillis())) + .build()); tags.addAll(reservedTags); Set tagEntities = setFromTagList(tags); String persistedSecretId = - secretEntityRepository - .save(new SecretEntity(secretShare.getSecretId().toString(), tagEntities)) - .getSecretId(); + secretEntityRepository + .save(new SecretEntity(secretShare.getSecretId().toString(), tagEntities)) + .getSecretId(); secretShareDataStore.storeSecretShareData( - UUID.fromString(persistedSecretId), secretShare.getData()); + UUID.fromString(persistedSecretId), secretShare.getData()); return persistedSecretId; } @@ -181,12 +183,12 @@ private static boolean hasDuplicateKey(List tags) { private static List dropReservedTags(List tags) { if (!CollectionUtils.isEmpty(tags)) { List itemsToDrop = - tags.stream().filter(StorageService::tagIsReserved).collect(Collectors.toList()); + tags.stream().filter(StorageService::tagIsReserved).collect(Collectors.toList()); itemsToDrop.forEach( - t -> { - log.debug("Dropped tag {} for using reserved key.", t.toString()); - tags.remove(t); - }); + t -> { + log.debug("Dropped tag {} for using reserved key.", t.toString()); + tags.remove(t); + }); } return tags; } @@ -208,8 +210,8 @@ public Page getSecretList(Sort sort) { @Transactional(readOnly = true) public Page getSecretList(List tagFilters, Pageable pageable) { return secretEntityRepository - .findAll(SecretEntitySpecification.with(tagFilters), pageable) - .map(SecretEntity::toMetadata); + .findAll(SecretEntitySpecification.with(tagFilters), pageable) + .map(SecretEntity::toMetadata); } @Transactional(readOnly = true) @@ -225,16 +227,19 @@ public Page getSecretList(List tagFilters, Sort sort) { * if no secret with the given id exists. * @throws AmphoraServiceException if an {@link SecretShare} exists but could not be retrieved. * @throws NotFoundException if no {@link SecretShare} with the given id exists - * @throws UnauthorizedException if the requesting program is not authorized to access the {@link SecretShare} + * @throws UnauthorizedException if the requesting program is not authorized to access the {@link + * SecretShare} */ @Transactional(readOnly = true) - public SecretShare useSecretShare(UUID secretId, String programId) throws UnauthorizedException, CsOpaException { - SecretEntity secretEntity = secretEntityRepository - .findById(secretId.toString()) - .orElseThrow( - () -> - new NotFoundException( - String.format(NO_SECRET_WITH_ID_EXISTS_EXCEPTION_MSG, secretId))); + public SecretShare useSecretShare(UUID secretId, String programId) + throws UnauthorizedException, CsOpaException { + SecretEntity secretEntity = + secretEntityRepository + .findById(secretId.toString()) + .orElseThrow( + () -> + new NotFoundException( + String.format(NO_SECRET_WITH_ID_EXISTS_EXCEPTION_MSG, secretId))); if (!opaService.canUseSecret(programId, setToTagList(secretEntity.getTags()))) { throw new UnauthorizedException("Requesting program is not authorized to access the secret"); } @@ -243,10 +248,10 @@ public SecretShare useSecretShare(UUID secretId, String programId) throws Unauth /** * Retrieves an {@link SecretShare} with a given id. - *

- * This method requires the authenticated user to be authorized to perform the operation. The authorization is - * checked by the {@link OpaService#canReadSecret(String, List)} method using the {@link Tag}s of - * the related {@link SecretEntity}. + * + *

This method requires the authenticated user to be authorized to perform the operation. The + * authorization is checked by the {@link OpaService#canReadSecret(String, List)} method using the + * {@link Tag}s of the related {@link SecretEntity}. * * @param secretId id of the {@link SecretShare} to retrieve * @param authorizedUserId the id of the authenticated user requesting the operation @@ -258,15 +263,17 @@ public SecretShare useSecretShare(UUID secretId, String programId) throws Unauth * @throws CsOpaException if an error occurred while evaluating the policy */ @Transactional(readOnly = true) - public SecretShare getSecretShare(UUID secretId, String authorizedUserId) throws CsOpaException, UnauthorizedException { - SecretEntity secretEntity = secretEntityRepository + public SecretShare getSecretShare(UUID secretId, String authorizedUserId) + throws CsOpaException, UnauthorizedException { + SecretEntity secretEntity = + secretEntityRepository .findById(secretId.toString()) .orElseThrow( - () -> - new NotFoundException( - String.format(NO_SECRET_WITH_ID_EXISTS_EXCEPTION_MSG, secretId))); + () -> + new NotFoundException( + String.format(NO_SECRET_WITH_ID_EXISTS_EXCEPTION_MSG, secretId))); - if(!opaService.canReadSecret(authorizedUserId, setToTagList(secretEntity.getTags()))) { + if (!opaService.canReadSecret(authorizedUserId, setToTagList(secretEntity.getTags()))) { throw new UnauthorizedException("User is not authorized to read this secret"); } return getSecretShareForEntity(secretEntity); @@ -274,19 +281,19 @@ public SecretShare getSecretShare(UUID secretId, String authorizedUserId) throws private SecretShare getSecretShareForEntity(SecretEntity entity) { return SecretShare.builder() - .secretId(UUID.fromString(entity.getSecretId())) - .data(secretShareDataStore.getSecretShareData(UUID.fromString(entity.getSecretId()))) - .tags(setToTagList(entity.getTags())) - .build(); + .secretId(UUID.fromString(entity.getSecretId())) + .data(secretShareDataStore.getSecretShareData(UUID.fromString(entity.getSecretId()))) + .tags(setToTagList(entity.getTags())) + .build(); } /** * Removes an {@link SecretEntity} and all related information ({@link TagEntity tags} and {@link * SecretShare data}) from the storage. - *

- * This method requires the authenticated user to be authorized to perform the operation. The authorization is - * checked by the {@link OpaService#canDeleteSecret(String, List)} method using the {@link Tag}s of - * the related {@link SecretEntity}. + * + *

This method requires the authenticated user to be authorized to perform the operation. The + * authorization is checked by the {@link OpaService#canDeleteSecret(String, List)} method using + * the {@link Tag}s of the related {@link SecretEntity}. * * @param secretId the id of the secret to be removed. * @param authorizedUserId the id of the authenticated user requesting the deletion @@ -296,14 +303,18 @@ private SecretShare getSecretShareForEntity(SecretEntity entity) { * @throws CsOpaException if an error occurred while evaluating the policy */ @Transactional - public void deleteSecret(UUID secretId, String authorizedUserId) throws CsOpaException, UnauthorizedException { + public void deleteSecret(UUID secretId, String authorizedUserId) + throws CsOpaException, UnauthorizedException { // Better to accept String as input once - instead of repeatedly converting it. - SecretEntity secretEntity = secretEntityRepository.findById(secretId.toString()) - .orElseThrow(() -> - new NotFoundException( - String.format(NO_SECRET_WITH_ID_EXISTS_EXCEPTION_MSG, secretId))); - if(!opaService.canDeleteSecret(authorizedUserId, setToTagList(secretEntity.getTags()))) { - throw new UnauthorizedException("User is not authorized to delete this secret"); + SecretEntity secretEntity = + secretEntityRepository + .findById(secretId.toString()) + .orElseThrow( + () -> + new NotFoundException( + String.format(NO_SECRET_WITH_ID_EXISTS_EXCEPTION_MSG, secretId))); + if (!opaService.canDeleteSecret(authorizedUserId, setToTagList(secretEntity.getTags()))) { + throw new UnauthorizedException("User is not authorized to delete this secret"); } secretEntityRepository.deleteBySecretId(secretId.toString()); secretShareDataStore.deleteSecretShareData(secretId); @@ -311,10 +322,10 @@ public void deleteSecret(UUID secretId, String authorizedUserId) throws CsOpaExc /** * Persists a {@link Tag} related to a specified {@link SecretShare} - *

- * This method requires the authenticated user to be authorized to perform the operation. The authorization is - * checked by the {@link OpaService#canCreateTags(String, List)} method using the {@link Tag}s of - * the related {@link SecretEntity}. + * + *

This method requires the authenticated user to be authorized to perform the operation. The + * authorization is checked by the {@link OpaService#canCreateTags(String, List)} method using the + * {@link Tag}s of the related {@link SecretEntity}. * * @param secretId id of the secret this {@link Tag} belongs to * @param tag the tag to persist @@ -326,40 +337,41 @@ public void deleteSecret(UUID secretId, String authorizedUserId) throws CsOpaExc * exists. */ @Transactional - public String storeTag(UUID secretId, Tag tag, String authorizedUserId) throws CsOpaException, UnauthorizedException { + public String storeTag(UUID secretId, Tag tag, String authorizedUserId) + throws CsOpaException, UnauthorizedException { if (tagIsReserved(tag)) { throw new IllegalArgumentException( - String.format(IS_RESERVED_KEY_EXCEPTION_MSG, tag.getKey())); + String.format(IS_RESERVED_KEY_EXCEPTION_MSG, tag.getKey())); } SecretEntity secretEntity = - secretEntityRepository - .findById(secretId.toString()) - .orElseThrow( - () -> - new NotFoundException( - String.format(NO_SECRET_WITH_ID_EXISTS_EXCEPTION_MSG, secretId))); + secretEntityRepository + .findById(secretId.toString()) + .orElseThrow( + () -> + new NotFoundException( + String.format(NO_SECRET_WITH_ID_EXISTS_EXCEPTION_MSG, secretId))); if (!opaService.canCreateTags(authorizedUserId, setToTagList(secretEntity.getTags()))) { - throw new UnauthorizedException("User is not authorized to create tags for this secret"); + throw new UnauthorizedException("User is not authorized to create tags for this secret"); } tagRepository - .findBySecretAndKey(secretEntity, tag.getKey()) - .ifPresent( - t -> { - throw new AlreadyExistsException( - String.format( - TAG_WITH_KEY_EXISTS_FOR_SECRET_EXCEPTION_MSG, tag.getKey(), secretId)); - }); + .findBySecretAndKey(secretEntity, tag.getKey()) + .ifPresent( + t -> { + throw new AlreadyExistsException( + String.format( + TAG_WITH_KEY_EXISTS_FOR_SECRET_EXCEPTION_MSG, tag.getKey(), secretId)); + }); return tagRepository.save(TagEntity.fromTag(tag).setSecret(secretEntity)).getKey(); } /** * Replaces the {@link Tag}s for a {@link SecretEntity} with the given id. - *

- * This method requires the authenticated user to be authorized to perform the operation. The authorization is - * checked by the {@link OpaService#canUpdateTags(String, List)} method using the {@link Tag}s of - * the related {@link SecretEntity}. - *

- * {@link Tag}s that use a reserved tag {@link #RESERVED_TAG_KEYS} will be removed before + * + *

This method requires the authenticated user to be authorized to perform the operation. The + * authorization is checked by the {@link OpaService#canUpdateTags(String, List)} method using the + * {@link Tag}s of the related {@link SecretEntity}. + * + *

{@link Tag}s that use a reserved tag {@link #RESERVED_TAG_KEYS} will be removed before * persisting the secret without further notice. * * @param secretId the id of the {@link SecretEntity} whose tags should be replaced. @@ -372,23 +384,28 @@ public String storeTag(UUID secretId, Tag tag, String authorizedUserId) throws C * @throws CsOpaException if an error occurred while evaluating the policy */ @Transactional - public void replaceTags(UUID secretId, List tags, String authorizedUserId) throws CsOpaException, UnauthorizedException { + public void replaceTags(UUID secretId, List tags, String authorizedUserId) + throws CsOpaException, UnauthorizedException { if (hasDuplicateKey(tags)) { throw new IllegalArgumentException(TAGS_WITH_THE_SAME_KEY_DEFINED_EXCEPTION_MSG); } - SecretEntity secretEntityReference = secretEntityRepository.findById(secretId.toString()) - .orElseThrow(() -> + SecretEntity secretEntityReference = + secretEntityRepository + .findById(secretId.toString()) + .orElseThrow( + () -> new NotFoundException( - String.format(NO_SECRET_WITH_ID_EXISTS_EXCEPTION_MSG, secretId))); - if (!opaService.canUpdateTags(authorizedUserId, setToTagList(secretEntityReference.getTags()))) { - throw new UnauthorizedException("User is not authorized to update tags for this secret"); + String.format(NO_SECRET_WITH_ID_EXISTS_EXCEPTION_MSG, secretId))); + if (!opaService.canUpdateTags( + authorizedUserId, setToTagList(secretEntityReference.getTags()))) { + throw new UnauthorizedException("User is not authorized to update tags for this secret"); } List existingReservedTags = - RESERVED_TAG_KEYS.stream() - .map(key -> tagRepository.findBySecretAndKey(secretEntityReference, key)) - .filter(Optional::isPresent) - .map(Optional::get) - .collect(Collectors.toList()); + RESERVED_TAG_KEYS.stream() + .map(key -> tagRepository.findBySecretAndKey(secretEntityReference, key)) + .filter(Optional::isPresent) + .map(Optional::get) + .collect(Collectors.toList()); List newTags = dropReservedTags(new ArrayList<>(tags)); tagRepository.deleteBySecret(secretEntityReference); Set newTagList = setFromTagList(newTags); @@ -399,10 +416,10 @@ public void replaceTags(UUID secretId, List tags, String authorizedUserId) /** * Returns all {@link Tag}s associated to an {@link SecretEntity} with the given id. - *

- * This method requires the authenticated user to be authorized to perform the operation. The authorization is - * checked by the {@link OpaService#canReadTags(String, List)} method using the {@link Tag}s of - * the related {@link SecretEntity}. + * + *

This method requires the authenticated user to be authorized to perform the operation. The + * authorization is checked by the {@link OpaService#canReadTags(String, List)} method using the + * {@link Tag}s of the related {@link SecretEntity}. * * @param secretId the id of the {@link SecretEntity} whose tags should be retrieved. * @param authorizedUserId the id of the authenticated user requesting the operation @@ -412,16 +429,17 @@ public void replaceTags(UUID secretId, List tags, String authorizedUserId) * @throws CsOpaException if an error occurred while evaluating the policy */ @Transactional(readOnly = true) - public List retrieveTags(UUID secretId, String authorizedUserId) throws CsOpaException, UnauthorizedException { + public List retrieveTags(UUID secretId, String authorizedUserId) + throws CsOpaException, UnauthorizedException { SecretEntity secretEntity = - secretEntityRepository - .findById(secretId.toString()) - .orElseThrow( - () -> - new NotFoundException( - String.format(NO_SECRET_WITH_ID_EXISTS_EXCEPTION_MSG, secretId))); + secretEntityRepository + .findById(secretId.toString()) + .orElseThrow( + () -> + new NotFoundException( + String.format(NO_SECRET_WITH_ID_EXISTS_EXCEPTION_MSG, secretId))); if (!opaService.canReadTags(authorizedUserId, setToTagList(secretEntity.getTags()))) { - throw new UnauthorizedException("User is not authorized to read tags for this secret"); + throw new UnauthorizedException("User is not authorized to read tags for this secret"); } return setToTagList(secretEntity.getTags()); } @@ -429,10 +447,10 @@ public List retrieveTags(UUID secretId, String authorizedUserId) throws CsO /** * Returns a single {@link Tag}s associated to an {@link SecretEntity} with the given id, and a * specified {@link Tag#getKey() key}. - *

- * This method requires the authenticated user to be authorized to perform the operation. The authorization is - * checked by the {@link OpaService#canReadTags(String, List)} method using the {@link Tag}s of - * the related {@link SecretEntity}. + * + *

This method requires the authenticated user to be authorized to perform the operation. The + * authorization is checked by the {@link OpaService#canReadTags(String, List)} method using the + * {@link Tag}s of the related {@link SecretEntity}. * * @param secretId the id of the {@link SecretShare} whose {@link Tag} to be retrieved. * @param key the {@link Tag#getKey() key} of the {@link Tag} to be retrieved. @@ -444,30 +462,34 @@ public List retrieveTags(UUID secretId, String authorizedUserId) throws CsO * @throws CsOpaException if an error occurred while evaluating the policy */ @Transactional(readOnly = true) - public Tag retrieveTag(UUID secretId, String key, String authorizedUserId) throws CsOpaException, UnauthorizedException { - SecretEntity secretEntityReference = secretEntityRepository.findById(secretId.toString()) - .orElseThrow(() -> + public Tag retrieveTag(UUID secretId, String key, String authorizedUserId) + throws CsOpaException, UnauthorizedException { + SecretEntity secretEntityReference = + secretEntityRepository + .findById(secretId.toString()) + .orElseThrow( + () -> new NotFoundException( - String.format(NO_SECRET_WITH_ID_EXISTS_EXCEPTION_MSG, secretId))); + String.format(NO_SECRET_WITH_ID_EXISTS_EXCEPTION_MSG, secretId))); if (!opaService.canReadTags(authorizedUserId, setToTagList(secretEntityReference.getTags()))) { - throw new UnauthorizedException("User is not authorized to read tags for this secret"); + throw new UnauthorizedException("User is not authorized to read tags for this secret"); } return tagRepository - .findBySecretAndKey(secretEntityReference, key) - .map(TagEntity::toTag) - .orElseThrow( - () -> - new NotFoundException( - String.format( - NO_TAG_WITH_KEY_EXISTS_FOR_SECRET_WITH_ID_EXCEPTION_MSG, key, secretId))); + .findBySecretAndKey(secretEntityReference, key) + .map(TagEntity::toTag) + .orElseThrow( + () -> + new NotFoundException( + String.format( + NO_TAG_WITH_KEY_EXISTS_FOR_SECRET_WITH_ID_EXCEPTION_MSG, key, secretId))); } /** * Updates an existing {@link Tag} linked to an {@link SecretEntity} with the given id. - *

- * This method requires the authenticated user to be authorized to perform the operation. The authorization is - * checked by the {@link OpaService#canUpdateTags(String, List)} method using the {@link Tag}s of - * the related {@link SecretEntity}. + * + *

This method requires the authenticated user to be authorized to perform the operation. The + * authorization is checked by the {@link OpaService#canUpdateTags(String, List)} method using the + * {@link Tag}s of the related {@link SecretEntity}. * * @param secretId the id of the {@link SecretShare} whose {@link Tag} to be updated. * @param tag the new tag @@ -479,38 +501,43 @@ public Tag retrieveTag(UUID secretId, String key, String authorizedUserId) throw * @throws CsOpaException if an error occurred while evaluating the policy */ @Transactional - public void updateTag(UUID secretId, Tag tag, String authorizedUserId) throws CsOpaException, UnauthorizedException { + public void updateTag(UUID secretId, Tag tag, String authorizedUserId) + throws CsOpaException, UnauthorizedException { if (tagIsReserved(tag)) { throw new IllegalArgumentException( - String.format(IS_RESERVED_KEY_EXCEPTION_MSG, tag.getKey())); + String.format(IS_RESERVED_KEY_EXCEPTION_MSG, tag.getKey())); } - SecretEntity secretEntityReference = secretEntityRepository.findById(secretId.toString()) - .orElseThrow(() -> + SecretEntity secretEntityReference = + secretEntityRepository + .findById(secretId.toString()) + .orElseThrow( + () -> new NotFoundException( - String.format(NO_SECRET_WITH_ID_EXISTS_EXCEPTION_MSG, secretId))); - if (!opaService.canUpdateTags(authorizedUserId, setToTagList(secretEntityReference.getTags()))) { - throw new UnauthorizedException("User is not authorized to update tags for this secret"); + String.format(NO_SECRET_WITH_ID_EXISTS_EXCEPTION_MSG, secretId))); + if (!opaService.canUpdateTags( + authorizedUserId, setToTagList(secretEntityReference.getTags()))) { + throw new UnauthorizedException("User is not authorized to update tags for this secret"); } TagEntity existingTag = - tagRepository - .findBySecretAndKey(secretEntityReference, tag.getKey()) - .orElseThrow( - () -> - new NotFoundException( - String.format( - NO_TAG_WITH_KEY_EXISTS_FOR_SECRET_WITH_ID_EXCEPTION_MSG, - tag.getKey(), - secretId))); + tagRepository + .findBySecretAndKey(secretEntityReference, tag.getKey()) + .orElseThrow( + () -> + new NotFoundException( + String.format( + NO_TAG_WITH_KEY_EXISTS_FOR_SECRET_WITH_ID_EXCEPTION_MSG, + tag.getKey(), + secretId))); tagRepository.save( - existingTag.setValue(tag.getValue()).setValueType(tag.getValueType().toString())); + existingTag.setValue(tag.getValue()).setValueType(tag.getValueType().toString())); } /** * Deletes an existing {@link Tag} linked to an {@link SecretEntity} with the given id. - *

- * This method requires the authenticated user to be authorized to perform the operation. The authorization is - * checked by the {@link OpaService#canDeleteTags(String, List)} method using the {@link Tag}s of - * the related {@link SecretEntity}. + * + *

This method requires the authenticated user to be authorized to perform the operation. The + * authorization is checked by the {@link OpaService#canDeleteTags(String, List)} method using the + * {@link Tag}s of the related {@link SecretEntity}. * * @param secretId the id of the {@link SecretShare} whose {@link Tag} to be deleted. * @param key the {@link Tag#getKey() key} of the {@link Tag} to be deleted. @@ -522,25 +549,34 @@ public void updateTag(UUID secretId, Tag tag, String authorizedUserId) throws Cs * @throws CsOpaException if an error occurred while evaluating the policy */ @Transactional - public void deleteTag(UUID secretId, String key, String authorizedUserId) throws CsOpaException, UnauthorizedException { + public void deleteTag(UUID secretId, String key, String authorizedUserId) + throws CsOpaException, UnauthorizedException { if (RESERVED_TAG_KEYS.contains(key)) { throw new IllegalArgumentException(String.format(IS_RESERVED_KEY_EXCEPTION_MSG, key)); } - SecretEntity secretEntityReference = secretEntityRepository.findById(secretId.toString()) - .orElseThrow(() -> + SecretEntity secretEntityReference = + secretEntityRepository + .findById(secretId.toString()) + .orElseThrow( + () -> new NotFoundException( - String.format(NO_SECRET_WITH_ID_EXISTS_EXCEPTION_MSG, secretId))); + String.format(NO_SECRET_WITH_ID_EXISTS_EXCEPTION_MSG, secretId))); - if (!opaService.canDeleteTags(authorizedUserId, setToTagList(secretEntityReference.getTags()))) { + if (!opaService.canDeleteTags( + authorizedUserId, setToTagList(secretEntityReference.getTags()))) { throw new UnauthorizedException("User is not authorized to delete tags for this secret"); } - secretEntityReference.getTags().remove(tagRepository - .findBySecretAndKey(secretEntityReference, key).orElseThrow( + secretEntityReference + .getTags() + .remove( + tagRepository + .findBySecretAndKey(secretEntityReference, key) + .orElseThrow( () -> - new NotFoundException( - String.format( - NO_TAG_WITH_KEY_EXISTS_FOR_SECRET_WITH_ID_EXCEPTION_MSG, - key, - secretId)))); + new NotFoundException( + String.format( + NO_TAG_WITH_KEY_EXISTS_FOR_SECRET_WITH_ID_EXCEPTION_MSG, + key, + secretId)))); } } diff --git a/amphora-service/src/main/java/io/carbynestack/amphora/service/rest/IntraVcpController.java b/amphora-service/src/main/java/io/carbynestack/amphora/service/rest/IntraVcpController.java index 7120826..f35d027 100644 --- a/amphora-service/src/main/java/io/carbynestack/amphora/service/rest/IntraVcpController.java +++ b/amphora-service/src/main/java/io/carbynestack/amphora/service/rest/IntraVcpController.java @@ -6,6 +6,9 @@ */ package io.carbynestack.amphora.service.rest; +import static io.carbynestack.amphora.common.rest.AmphoraRestApiEndpoints.*; +import static org.springframework.util.Assert.notNull; + import io.carbynestack.amphora.common.SecretShare; import io.carbynestack.amphora.common.Tag; import io.carbynestack.amphora.common.exceptions.AmphoraServiceException; @@ -14,6 +17,8 @@ import io.carbynestack.amphora.service.exceptions.NotFoundException; import io.carbynestack.amphora.service.exceptions.UnauthorizedException; import io.carbynestack.amphora.service.persistence.metadata.StorageService; +import java.net.URI; +import java.util.UUID; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; @@ -24,12 +29,6 @@ import org.springframework.web.bind.annotation.*; import org.springframework.web.servlet.support.ServletUriComponentsBuilder; -import java.net.URI; -import java.util.UUID; - -import static io.carbynestack.amphora.common.rest.AmphoraRestApiEndpoints.*; -import static org.springframework.util.Assert.notNull; - @Slf4j @RestController @RequiredArgsConstructor(onConstructor_ = @Autowired) @@ -69,12 +68,14 @@ public ResponseEntity uploadSecretShare(@RequestBody SecretShare secretShar * @return {@link HttpStatus#OK} with the {@link SecretShare} if successful. * @throws AmphoraServiceException if an {@link SecretShare} exists but could not be retrieved. * @throws NotFoundException if no {@link SecretShare} with the given id exists - * @throws UnauthorizedException if the requesting Program is not authorized to access the {@link SecretShare} + * @throws UnauthorizedException if the requesting Program is not authorized to access the {@link + * SecretShare} * @throws CsOpaException if an error occurred while evaluating the OPA policy */ @GetMapping(path = "/{" + SECRET_ID_PARAMETER + "}") - public ResponseEntity downloadSecretShare(@PathVariable UUID secretId, - @RequestParam String programId) throws UnauthorizedException, CsOpaException { + public ResponseEntity downloadSecretShare( + @PathVariable UUID secretId, @RequestParam String programId) + throws UnauthorizedException, CsOpaException { notNull(programId, "ProgramId must not be null"); return new ResponseEntity<>(storageService.useSecretShare(secretId, programId), HttpStatus.OK); diff --git a/amphora-service/src/main/java/io/carbynestack/amphora/service/rest/MaskedInputController.java b/amphora-service/src/main/java/io/carbynestack/amphora/service/rest/MaskedInputController.java index 919ef54..c4bce67 100644 --- a/amphora-service/src/main/java/io/carbynestack/amphora/service/rest/MaskedInputController.java +++ b/amphora-service/src/main/java/io/carbynestack/amphora/service/rest/MaskedInputController.java @@ -16,10 +16,9 @@ import io.carbynestack.amphora.common.Tag; import io.carbynestack.amphora.service.exceptions.AlreadyExistsException; import io.carbynestack.amphora.service.exceptions.UnauthorizedException; +import io.carbynestack.amphora.service.opa.JwtReader; import io.carbynestack.amphora.service.persistence.metadata.StorageService; import java.net.URI; - -import io.carbynestack.amphora.service.opa.JwtReader; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; @@ -52,16 +51,17 @@ public class MaskedInputController { * @throws AlreadyExistsException if an {@link SecretShare} with the given id already exists. */ @PostMapping - public ResponseEntity upload(@RequestHeader("Authorization") String authorizationHeader, - @RequestBody MaskedInput maskedInput) throws UnauthorizedException { + public ResponseEntity upload( + @RequestHeader("Authorization") String authorizationHeader, + @RequestBody MaskedInput maskedInput) + throws UnauthorizedException { notNull(maskedInput, "MaskedInput must not be null"); notEmpty(maskedInput.getData(), "MaskedInput data must not be empty"); return new ResponseEntity<>( ServletUriComponentsBuilder.fromCurrentRequestUri() .pathSegment( - storageService.createSecret( - maskedInput, - jwtReader.extractUserIdFromAuthHeader(authorizationHeader))) + storageService.createSecret( + maskedInput, jwtReader.extractUserIdFromAuthHeader(authorizationHeader))) .build() .toUri(), CREATED); diff --git a/amphora-service/src/main/java/io/carbynestack/amphora/service/rest/RestControllerExceptionHandler.java b/amphora-service/src/main/java/io/carbynestack/amphora/service/rest/RestControllerExceptionHandler.java index 71fb037..e2dcb68 100644 --- a/amphora-service/src/main/java/io/carbynestack/amphora/service/rest/RestControllerExceptionHandler.java +++ b/amphora-service/src/main/java/io/carbynestack/amphora/service/rest/RestControllerExceptionHandler.java @@ -53,9 +53,9 @@ protected ResponseEntity handleBadRequestException(Exception e) @ExceptionHandler({UnauthorizedException.class}) protected ResponseEntity handleUnauthorizedException(UnauthorizedException e) throws JsonProcessingException { - logger.debug("Handling Unauthorized Error", e); - return new ResponseEntity<>( - OBJECT_WRITER.writeValueAsString(e.getMessage()), HttpStatus.UNAUTHORIZED); + logger.debug("Handling Unauthorized Error", e); + return new ResponseEntity<>( + OBJECT_WRITER.writeValueAsString(e.getMessage()), HttpStatus.UNAUTHORIZED); } @ExceptionHandler({AmphoraServiceException.class, CastorServiceException.class, Exception.class}) diff --git a/amphora-service/src/main/java/io/carbynestack/amphora/service/rest/SecretShareController.java b/amphora-service/src/main/java/io/carbynestack/amphora/service/rest/SecretShareController.java index d8719fe..d7fcfc2 100644 --- a/amphora-service/src/main/java/io/carbynestack/amphora/service/rest/SecretShareController.java +++ b/amphora-service/src/main/java/io/carbynestack/amphora/service/rest/SecretShareController.java @@ -15,8 +15,8 @@ import io.carbynestack.amphora.service.exceptions.CsOpaException; import io.carbynestack.amphora.service.exceptions.NotFoundException; import io.carbynestack.amphora.service.exceptions.UnauthorizedException; -import io.carbynestack.amphora.service.persistence.metadata.StorageService; import io.carbynestack.amphora.service.opa.JwtReader; +import io.carbynestack.amphora.service.persistence.metadata.StorageService; import io.vavr.control.Try; import java.io.UnsupportedEncodingException; import java.util.*; @@ -111,10 +111,12 @@ public ResponseEntity getObjectList( public ResponseEntity getSecretShare( @RequestHeader("Authorization") String authorizationHeader, @PathVariable final UUID secretId, - @RequestParam(value = REQUEST_ID_PARAMETER) final UUID requestId) throws UnauthorizedException, CsOpaException { + @RequestParam(value = REQUEST_ID_PARAMETER) final UUID requestId) + throws UnauthorizedException, CsOpaException { Assert.notNull(requestId, "Request identifier must not be omitted"); - SecretShare secretShare = storageService.getSecretShare(secretId, - jwtReader.extractUserIdFromAuthHeader(authorizationHeader)); + SecretShare secretShare = + storageService.getSecretShare( + secretId, jwtReader.extractUserIdFromAuthHeader(authorizationHeader)); OutputDeliveryObject outputDeliveryObject = outputDeliveryService.computeOutputDeliveryObject(secretShare, requestId); return new ResponseEntity<>( @@ -131,10 +133,10 @@ public ResponseEntity getSecretShare( */ @DeleteMapping(path = "/{" + SECRET_ID_PARAMETER + "}") public ResponseEntity deleteSecretShare( - @RequestHeader("Authorization") String authorizationHeader, - @PathVariable UUID secretId) throws UnauthorizedException, CsOpaException { - storageService.deleteSecret(secretId, - jwtReader.extractUserIdFromAuthHeader(authorizationHeader)); + @RequestHeader("Authorization") String authorizationHeader, @PathVariable UUID secretId) + throws UnauthorizedException, CsOpaException { + storageService.deleteSecret( + secretId, jwtReader.extractUserIdFromAuthHeader(authorizationHeader)); return new ResponseEntity<>(HttpStatus.OK); } diff --git a/amphora-service/src/main/java/io/carbynestack/amphora/service/rest/TagsController.java b/amphora-service/src/main/java/io/carbynestack/amphora/service/rest/TagsController.java index cc4d0b9..d9895bd 100644 --- a/amphora-service/src/main/java/io/carbynestack/amphora/service/rest/TagsController.java +++ b/amphora-service/src/main/java/io/carbynestack/amphora/service/rest/TagsController.java @@ -14,12 +14,11 @@ import io.carbynestack.amphora.service.exceptions.CsOpaException; import io.carbynestack.amphora.service.exceptions.NotFoundException; import io.carbynestack.amphora.service.exceptions.UnauthorizedException; +import io.carbynestack.amphora.service.opa.JwtReader; import io.carbynestack.amphora.service.persistence.metadata.StorageService; import java.net.URI; import java.util.List; import java.util.UUID; - -import io.carbynestack.amphora.service.opa.JwtReader; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; @@ -47,13 +46,12 @@ public class TagsController { */ @GetMapping public ResponseEntity> getTags( - @RequestHeader("Authorization") String authorizationHeader, - @PathVariable UUID secretId) throws UnauthorizedException, CsOpaException { + @RequestHeader("Authorization") String authorizationHeader, @PathVariable UUID secretId) + throws UnauthorizedException, CsOpaException { return new ResponseEntity<>( - storageService.retrieveTags( - secretId, - jwtReader.extractUserIdFromAuthHeader(authorizationHeader)), - HttpStatus.OK); + storageService.retrieveTags( + secretId, jwtReader.extractUserIdFromAuthHeader(authorizationHeader)), + HttpStatus.OK); } /** @@ -71,16 +69,16 @@ public ResponseEntity> getTags( @Transactional @PostMapping public ResponseEntity createTag( - @RequestHeader("Authorization") String authorizationHeader, - @PathVariable UUID secretId, @RequestBody Tag tag) throws UnauthorizedException, CsOpaException { + @RequestHeader("Authorization") String authorizationHeader, + @PathVariable UUID secretId, + @RequestBody Tag tag) + throws UnauthorizedException, CsOpaException { Assert.notNull(tag, "Tag must not be empty"); return new ResponseEntity<>( ServletUriComponentsBuilder.fromCurrentRequestUri() .pathSegment( - storageService.storeTag( - secretId, - tag, - jwtReader.extractUserIdFromAuthHeader(authorizationHeader))) + storageService.storeTag( + secretId, tag, jwtReader.extractUserIdFromAuthHeader(authorizationHeader))) .build() .toUri(), HttpStatus.CREATED); @@ -103,13 +101,13 @@ public ResponseEntity createTag( @Transactional @PutMapping public ResponseEntity updateTags( - @RequestHeader("Authorization") String authorizationHeader, - @PathVariable UUID secretId, @RequestBody List tags) throws UnauthorizedException, CsOpaException { + @RequestHeader("Authorization") String authorizationHeader, + @PathVariable UUID secretId, + @RequestBody List tags) + throws UnauthorizedException, CsOpaException { Assert.notEmpty(tags, "At least one tag must be given."); storageService.replaceTags( - secretId, - tags, - jwtReader.extractUserIdFromAuthHeader(authorizationHeader)); + secretId, tags, jwtReader.extractUserIdFromAuthHeader(authorizationHeader)); return new ResponseEntity<>(HttpStatus.OK); } @@ -124,14 +122,14 @@ public ResponseEntity updateTags( */ @GetMapping(path = "/{" + TAG_KEY_PARAMETER + ":.+}") public ResponseEntity getTag( - @RequestHeader("Authorization") String authorizationHeader, - @PathVariable UUID secretId, @PathVariable String tagKey) throws UnauthorizedException, CsOpaException { + @RequestHeader("Authorization") String authorizationHeader, + @PathVariable UUID secretId, + @PathVariable String tagKey) + throws UnauthorizedException, CsOpaException { return new ResponseEntity<>( - storageService.retrieveTag( - secretId, - tagKey, - jwtReader.extractUserIdFromAuthHeader(authorizationHeader)), - HttpStatus.OK); + storageService.retrieveTag( + secretId, tagKey, jwtReader.extractUserIdFromAuthHeader(authorizationHeader)), + HttpStatus.OK); } /** @@ -152,17 +150,18 @@ public ResponseEntity getTag( @Transactional @PutMapping(path = "/{" + TAG_KEY_PARAMETER + ":.+}") public ResponseEntity putTag( - @RequestHeader("Authorization") String authorizationHeader, - @PathVariable UUID secretId, @PathVariable String tagKey, @RequestBody Tag tag) throws UnauthorizedException, CsOpaException { + @RequestHeader("Authorization") String authorizationHeader, + @PathVariable UUID secretId, + @PathVariable String tagKey, + @RequestBody Tag tag) + throws UnauthorizedException, CsOpaException { Assert.notNull(tag, "Tag must not be empty"); if (!tagKey.equals(tag.getKey())) { throw new IllegalArgumentException( String.format("The defined key and tag data do not match.%n%s <> %s", tagKey, tag)); } storageService.updateTag( - secretId, - tag, - jwtReader.extractUserIdFromAuthHeader(authorizationHeader)); + secretId, tag, jwtReader.extractUserIdFromAuthHeader(authorizationHeader)); return new ResponseEntity<>(HttpStatus.OK); } @@ -180,11 +179,12 @@ public ResponseEntity putTag( @Transactional @DeleteMapping(path = "/{" + TAG_KEY_PARAMETER + ":.+}") public ResponseEntity deleteTag( - @RequestHeader("Authorization") String authorizationHeader, - @PathVariable UUID secretId, @PathVariable String tagKey) throws UnauthorizedException, CsOpaException { - storageService.deleteTag(secretId, - tagKey, - jwtReader.extractUserIdFromAuthHeader(authorizationHeader)); + @RequestHeader("Authorization") String authorizationHeader, + @PathVariable UUID secretId, + @PathVariable String tagKey) + throws UnauthorizedException, CsOpaException { + storageService.deleteTag( + secretId, tagKey, jwtReader.extractUserIdFromAuthHeader(authorizationHeader)); return new ResponseEntity<>(HttpStatus.OK); } } diff --git a/amphora-service/src/test/java/io/carbynestack/amphora/service/AmphoraServiceSystemTest.java b/amphora-service/src/test/java/io/carbynestack/amphora/service/AmphoraServiceSystemTest.java index 299d5f0..14c83ee 100644 --- a/amphora-service/src/test/java/io/carbynestack/amphora/service/AmphoraServiceSystemTest.java +++ b/amphora-service/src/test/java/io/carbynestack/amphora/service/AmphoraServiceSystemTest.java @@ -24,7 +24,6 @@ import io.carbynestack.amphora.common.Tag; import io.carbynestack.amphora.service.exceptions.UnauthorizedException; import io.carbynestack.amphora.service.opa.OpaClient; -import io.carbynestack.amphora.service.persistence.metadata.StorageService; import io.carbynestack.amphora.service.testconfig.PersistenceTestEnvironment; import io.carbynestack.amphora.service.testconfig.ReusableMinioContainer; import io.carbynestack.amphora.service.testconfig.ReusablePostgreSQLContainer; @@ -40,7 +39,6 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; @@ -66,8 +64,9 @@ public class AmphoraServiceSystemTest { private final UUID testSecretId2 = UUID.fromString("82a73814-321c-4261-abcd-27c6c0ebfb27"); private final UUID testSecretId3 = UUID.fromString("82a73814-321c-4261-abcd-27c6c0ebfb28"); private final UUID testSecretId4 = UUID.fromString("82a73814-321c-4261-abcd-27c6c0ebfb29"); - private final String bearerToken = "eyJhbGciOiJSUzI1NiIsImtpZCI6ImM5Njk0OTgyLWQzMTAtNDBkOC04ZDk4LTczOWI1ZGZjNWUyNiIsInR5cCI6IkpXVCJ9.eyJhbXIiOlsicGFzc3dvcmQiXSwiYXRfaGFzaCI6InowbjhudTNJQ19HaXN3bmFTWjgwZ2ciLCJhdWQiOlsiOGExYTIwNzUtMzY3Yi00ZGU1LTgyODgtMGMyNzQ1OTMzMmI3Il0sImF1dGhfdGltZSI6MTczMTUwMDQ0OSwiZXhwIjoxNzMxNTA0NDIyLCJpYXQiOjE3MzE1MDA4MjIsImlzcyI6Imh0dHA6Ly8xNzIuMTguMS4xMjguc3NsaXAuaW8vaWFtL29hdXRoIiwianRpIjoiZTlhMmQxYzQtZGViNy00MTgwLWE0M2YtN2QwNTZhYjNlNTk3Iiwibm9uY2UiOiJnV1JVZjhxTERaeDZpOFNhMXpMdm9IX2tSQ01OWll2WTE0WTFsLWNBU0tVIiwicmF0IjoxNzMxNTAwODIyLCJzaWQiOiJlNGVkOTc2Mi0yMmNlLTQyYzEtOTU3NC01MDVkYjAyMThhNDYiLCJzdWIiOiJhZmMwMTE3Zi1jOWNkLTRkOGMtYWNlZS1mYTE0MzNjYTBmZGQifQ.OACqa6WjpAeZbHR54b3p7saUk9plTdXlZsou41E-gfC7WxCG7ZEKfDPKXUky-r20oeIt1Ov3S2QL6Kefe5dTXEC6nhKGxeClg8ys56_FPcx_neI-p09_pSWOkMx7DHP65giaP7UubyyInVpE-2Eu1o6TpoheahNQfCahKDsJmJ-4Vvts3wA79UMfOI0WHO4vLaaG6DRAZQK_dv7ltw3p_WlncpaQAtHwY9iVhtdB3LtAI39EjplCoAF0c9uQO6W7KHWUlj24l2kc564bsJgZSrYvezw6b2-FY7YisVnicSyAORpeqhWEpLltH3D8I1NtHlSYMJhWuVZbBhAm7Iz6q1-W-Q9ttvdPchdwPSASFRkrjrdIyQf6MsFrItKzUxYck57EYL4GkyN9MWvMNxL1UTtkzGsFEczUVsJFm8OQpulYXIFZksmnPTBB0KuUUvEZ-xih8V1HsMRoHvbiCLaDJwjOFKzPevVggsSMysPKR52UAZJDZLTeHBnVCtQ3rro6T0RxNg94lXypz0AmfsGnoTF34u4FmMxzoeFZ9N5zmEpOnMRqLs7Sb3FnLL-IMitc9_2bsHuFbBJl8KbiGHBQihK5v5SIa292L7P9ChsxomWVhM29qHNFuXQMwFUr57hmveNh2Fz9mduZ5h2hLUuDf5xc6u9rSxy3_e3t_xBuUT4"; - private final String authorizedUserId ="afc0117f-c9cd-4d8c-acee-fa1433ca0fdd"; + private final String bearerToken = + "eyJhbGciOiJSUzI1NiIsImtpZCI6ImM5Njk0OTgyLWQzMTAtNDBkOC04ZDk4LTczOWI1ZGZjNWUyNiIsInR5cCI6IkpXVCJ9.eyJhbXIiOlsicGFzc3dvcmQiXSwiYXRfaGFzaCI6InowbjhudTNJQ19HaXN3bmFTWjgwZ2ciLCJhdWQiOlsiOGExYTIwNzUtMzY3Yi00ZGU1LTgyODgtMGMyNzQ1OTMzMmI3Il0sImF1dGhfdGltZSI6MTczMTUwMDQ0OSwiZXhwIjoxNzMxNTA0NDIyLCJpYXQiOjE3MzE1MDA4MjIsImlzcyI6Imh0dHA6Ly8xNzIuMTguMS4xMjguc3NsaXAuaW8vaWFtL29hdXRoIiwianRpIjoiZTlhMmQxYzQtZGViNy00MTgwLWE0M2YtN2QwNTZhYjNlNTk3Iiwibm9uY2UiOiJnV1JVZjhxTERaeDZpOFNhMXpMdm9IX2tSQ01OWll2WTE0WTFsLWNBU0tVIiwicmF0IjoxNzMxNTAwODIyLCJzaWQiOiJlNGVkOTc2Mi0yMmNlLTQyYzEtOTU3NC01MDVkYjAyMThhNDYiLCJzdWIiOiJhZmMwMTE3Zi1jOWNkLTRkOGMtYWNlZS1mYTE0MzNjYTBmZGQifQ.OACqa6WjpAeZbHR54b3p7saUk9plTdXlZsou41E-gfC7WxCG7ZEKfDPKXUky-r20oeIt1Ov3S2QL6Kefe5dTXEC6nhKGxeClg8ys56_FPcx_neI-p09_pSWOkMx7DHP65giaP7UubyyInVpE-2Eu1o6TpoheahNQfCahKDsJmJ-4Vvts3wA79UMfOI0WHO4vLaaG6DRAZQK_dv7ltw3p_WlncpaQAtHwY9iVhtdB3LtAI39EjplCoAF0c9uQO6W7KHWUlj24l2kc564bsJgZSrYvezw6b2-FY7YisVnicSyAORpeqhWEpLltH3D8I1NtHlSYMJhWuVZbBhAm7Iz6q1-W-Q9ttvdPchdwPSASFRkrjrdIyQf6MsFrItKzUxYck57EYL4GkyN9MWvMNxL1UTtkzGsFEczUVsJFm8OQpulYXIFZksmnPTBB0KuUUvEZ-xih8V1HsMRoHvbiCLaDJwjOFKzPevVggsSMysPKR52UAZJDZLTeHBnVCtQ3rro6T0RxNg94lXypz0AmfsGnoTF34u4FmMxzoeFZ9N5zmEpOnMRqLs7Sb3FnLL-IMitc9_2bsHuFbBJl8KbiGHBQihK5v5SIa292L7P9ChsxomWVhM29qHNFuXQMwFUr57hmveNh2Fz9mduZ5h2hLUuDf5xc6u9rSxy3_e3t_xBuUT4"; + private final String authorizedUserId = "afc0117f-c9cd-4d8c-acee-fa1433ca0fdd"; @Container public static ReusableRedisContainer reusableRedisContainer = @@ -81,8 +80,7 @@ public class AmphoraServiceSystemTest { public static ReusablePostgreSQLContainer reusablePostgreSQLContainer = ReusablePostgreSQLContainer.getInstance(); - @MockBean - private OpaClient opaClientMock; + @MockBean private OpaClient opaClientMock; @Autowired private TestRestTemplate restTemplate; @@ -227,8 +225,12 @@ void givenSuccessfulRequest_whenDeleteSecret_thenReturnRemoveAndDoNoLongerReturn HttpHeaders headers = new HttpHeaders(); headers.setBearerAuth(bearerToken); HttpEntity entity = new HttpEntity<>(headers); - ResponseEntity response = restTemplate.exchange(new URI(String.format("/secret-shares/%s", testSecretShare1.getSecretId())), - HttpMethod.DELETE, entity, Void.class); + ResponseEntity response = + restTemplate.exchange( + new URI(String.format("/secret-shares/%s", testSecretShare1.getSecretId())), + HttpMethod.DELETE, + entity, + Void.class); assertTrue("Request must be successful.", response.getStatusCode().is2xxSuccessful()); MetadataPage responsePostDel = restTemplate.getForObject(SECRET_SHARES_ENDPOINT, MetadataPage.class); diff --git a/amphora-service/src/test/java/io/carbynestack/amphora/service/calculation/SecretShareUtilTest.java b/amphora-service/src/test/java/io/carbynestack/amphora/service/calculation/SecretShareUtilTest.java index d469288..44512b5 100644 --- a/amphora-service/src/test/java/io/carbynestack/amphora/service/calculation/SecretShareUtilTest.java +++ b/amphora-service/src/test/java/io/carbynestack/amphora/service/calculation/SecretShareUtilTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023-2024 - for information on the respective copyright owner + * Copyright (c) 2023 - for information on the respective copyright owner * see the NOTICE file and/or the repository https://github.com/carbynestack/amphora. * * SPDX-License-Identifier: Apache-2.0 @@ -19,8 +19,10 @@ import io.carbynestack.mpspdz.integration.MpSpdzIntegrationUtils; import java.math.BigInteger; import java.nio.ByteBuffer; -import java.util.*; - +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.UUID; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; diff --git a/amphora-service/src/test/java/io/carbynestack/amphora/service/opa/JwtReaderTest.java b/amphora-service/src/test/java/io/carbynestack/amphora/service/opa/JwtReaderTest.java index 7f90826..33e8f2a 100644 --- a/amphora-service/src/test/java/io/carbynestack/amphora/service/opa/JwtReaderTest.java +++ b/amphora-service/src/test/java/io/carbynestack/amphora/service/opa/JwtReaderTest.java @@ -7,62 +7,73 @@ package io.carbynestack.amphora.service.opa; +import static org.junit.Assert.assertThrows; +import static org.junit.jupiter.api.Assertions.assertEquals; + import io.carbynestack.amphora.service.exceptions.UnauthorizedException; +import java.nio.charset.StandardCharsets; import org.bouncycastle.util.encoders.Base64; import org.junit.jupiter.api.Test; -import java.nio.charset.StandardCharsets; - -import static org.junit.Assert.assertThrows; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - class JwtReaderTest { - @Test - void givenTokenProvided_whenExtractSubject_thenReturnSubject() throws UnauthorizedException { - JwtReader jwtReader = new JwtReader("sub"); - String header = "Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6ImM5Njk0OTgyLWQzMTAtNDBkOC04ZDk4LTczOWI1ZGZjNWUyNiIsInR5cCI6IkpXVCJ9.eyJhbXIiOlsicGFzc3dvcmQiXSwiYXRfaGFzaCI6InowbjhudTNJQ19HaXN3bmFTWjgwZ2ciLCJhdWQiOlsiOGExYTIwNzUtMzY3Yi00ZGU1LTgyODgtMGMyNzQ1OTMzMmI3Il0sImF1dGhfdGltZSI6MTczMTUwMDQ0OSwiZXhwIjoxNzMxNTA0NDIyLCJpYXQiOjE3MzE1MDA4MjIsImlzcyI6Imh0dHA6Ly8xNzIuMTguMS4xMjguc3NsaXAuaW8vaWFtL29hdXRoIiwianRpIjoiZTlhMmQxYzQtZGViNy00MTgwLWE0M2YtN2QwNTZhYjNlNTk3Iiwibm9uY2UiOiJnV1JVZjhxTERaeDZpOFNhMXpMdm9IX2tSQ01OWll2WTE0WTFsLWNBU0tVIiwicmF0IjoxNzMxNTAwODIyLCJzaWQiOiJlNGVkOTc2Mi0yMmNlLTQyYzEtOTU3NC01MDVkYjAyMThhNDYiLCJzdWIiOiJhZmMwMTE3Zi1jOWNkLTRkOGMtYWNlZS1mYTE0MzNjYTBmZGQifQ.OACqa6WjpAeZbHR54b3p7saUk9plTdXlZsou41E-gfC7WxCG7ZEKfDPKXUky-r20oeIt1Ov3S2QL6Kefe5dTXEC6nhKGxeClg8ys56_FPcx_neI-p09_pSWOkMx7DHP65giaP7UubyyInVpE-2Eu1o6TpoheahNQfCahKDsJmJ-4Vvts3wA79UMfOI0WHO4vLaaG6DRAZQK_dv7ltw3p_WlncpaQAtHwY9iVhtdB3LtAI39EjplCoAF0c9uQO6W7KHWUlj24l2kc564bsJgZSrYvezw6b2-FY7YisVnicSyAORpeqhWEpLltH3D8I1NtHlSYMJhWuVZbBhAm7Iz6q1-W-Q9ttvdPchdwPSASFRkrjrdIyQf6MsFrItKzUxYck57EYL4GkyN9MWvMNxL1UTtkzGsFEczUVsJFm8OQpulYXIFZksmnPTBB0KuUUvEZ-xih8V1HsMRoHvbiCLaDJwjOFKzPevVggsSMysPKR52UAZJDZLTeHBnVCtQ3rro6T0RxNg94lXypz0AmfsGnoTF34u4FmMxzoeFZ9N5zmEpOnMRqLs7Sb3FnLL-IMitc9_2bsHuFbBJl8KbiGHBQihK5v5SIa292L7P9ChsxomWVhM29qHNFuXQMwFUr57hmveNh2Fz9mduZ5h2hLUuDf5xc6u9rSxy3_e3t_xBuUT4"; - String result = jwtReader.extractUserIdFromAuthHeader(header); - String expectedSubject = "afc0117f-c9cd-4d8c-acee-fa1433ca0fdd"; - assertEquals(expectedSubject, result); - } + @Test + void givenTokenProvided_whenExtractSubject_thenReturnSubject() throws UnauthorizedException { + JwtReader jwtReader = new JwtReader("sub"); + String header = + "Bearer" + + " eyJhbGciOiJSUzI1NiIsImtpZCI6ImM5Njk0OTgyLWQzMTAtNDBkOC04ZDk4LTczOWI1ZGZjNWUyNiIsInR5cCI6IkpXVCJ9.eyJhbXIiOlsicGFzc3dvcmQiXSwiYXRfaGFzaCI6InowbjhudTNJQ19HaXN3bmFTWjgwZ2ciLCJhdWQiOlsiOGExYTIwNzUtMzY3Yi00ZGU1LTgyODgtMGMyNzQ1OTMzMmI3Il0sImF1dGhfdGltZSI6MTczMTUwMDQ0OSwiZXhwIjoxNzMxNTA0NDIyLCJpYXQiOjE3MzE1MDA4MjIsImlzcyI6Imh0dHA6Ly8xNzIuMTguMS4xMjguc3NsaXAuaW8vaWFtL29hdXRoIiwianRpIjoiZTlhMmQxYzQtZGViNy00MTgwLWE0M2YtN2QwNTZhYjNlNTk3Iiwibm9uY2UiOiJnV1JVZjhxTERaeDZpOFNhMXpMdm9IX2tSQ01OWll2WTE0WTFsLWNBU0tVIiwicmF0IjoxNzMxNTAwODIyLCJzaWQiOiJlNGVkOTc2Mi0yMmNlLTQyYzEtOTU3NC01MDVkYjAyMThhNDYiLCJzdWIiOiJhZmMwMTE3Zi1jOWNkLTRkOGMtYWNlZS1mYTE0MzNjYTBmZGQifQ.OACqa6WjpAeZbHR54b3p7saUk9plTdXlZsou41E-gfC7WxCG7ZEKfDPKXUky-r20oeIt1Ov3S2QL6Kefe5dTXEC6nhKGxeClg8ys56_FPcx_neI-p09_pSWOkMx7DHP65giaP7UubyyInVpE-2Eu1o6TpoheahNQfCahKDsJmJ-4Vvts3wA79UMfOI0WHO4vLaaG6DRAZQK_dv7ltw3p_WlncpaQAtHwY9iVhtdB3LtAI39EjplCoAF0c9uQO6W7KHWUlj24l2kc564bsJgZSrYvezw6b2-FY7YisVnicSyAORpeqhWEpLltH3D8I1NtHlSYMJhWuVZbBhAm7Iz6q1-W-Q9ttvdPchdwPSASFRkrjrdIyQf6MsFrItKzUxYck57EYL4GkyN9MWvMNxL1UTtkzGsFEczUVsJFm8OQpulYXIFZksmnPTBB0KuUUvEZ-xih8V1HsMRoHvbiCLaDJwjOFKzPevVggsSMysPKR52UAZJDZLTeHBnVCtQ3rro6T0RxNg94lXypz0AmfsGnoTF34u4FmMxzoeFZ9N5zmEpOnMRqLs7Sb3FnLL-IMitc9_2bsHuFbBJl8KbiGHBQihK5v5SIa292L7P9ChsxomWVhM29qHNFuXQMwFUr57hmveNh2Fz9mduZ5h2hLUuDf5xc6u9rSxy3_e3t_xBuUT4"; + String result = jwtReader.extractUserIdFromAuthHeader(header); + String expectedSubject = "afc0117f-c9cd-4d8c-acee-fa1433ca0fdd"; + assertEquals(expectedSubject, result); + } - @Test - void givenNoTokenProvided_whenExtractSubject_thenThrowUnauthorizedException() throws UnauthorizedException { - JwtReader jwtReader = new JwtReader("sub"); - String invalidToken = "{\"auth_time\": 1731500449,\n" + - " \"exp\": 1731504422,\n" + - " \"iat\": 1731500822,\n" + - " \"something\": {\n" + - " \"what\": \"is this\"\n"+ - " }}"; - assertThrows(UnauthorizedException.class, () -> jwtReader.extractUserIdFromAuthHeader( + @Test + void givenInvalidTokenProvided_whenExtractSubject_thenThrowUnauthorizedException() + throws UnauthorizedException { + JwtReader jwtReader = new JwtReader("sub"); + String invalidToken = + "{\"auth_time\": 1731500449,\n" + + " \"exp\": 1731504422,\n" + + " \"iat\": 1731500822,\n" + + " \"something\": {\n" + + " \"what\": \"is this\"\n" + + " }}"; + assertThrows( + UnauthorizedException.class, + () -> + jwtReader.extractUserIdFromAuthHeader( String.format( - "Bearer header.%s.signature", - Base64.toBase64String(invalidToken.getBytes(StandardCharsets.UTF_8))))); - } + "Bearer header.%s.signature", + Base64.toBase64String(invalidToken.getBytes(StandardCharsets.UTF_8))))); + } - @Test - void givenJwtOfInvalidFormat_whenExtractSubject_thenThrowUnauthorizedException() { - JwtReader jwtReader = new JwtReader("sub"); - assertThrows(UnauthorizedException.class, () -> - jwtReader.extractUserIdFromAuthHeader("Bearer invalid.jwt_missing_dot_token")); - } + @Test + void givenJwtOfInvalidFormat_whenExtractSubject_thenThrowUnauthorizedException() { + JwtReader jwtReader = new JwtReader("sub"); + assertThrows( + UnauthorizedException.class, + () -> jwtReader.extractUserIdFromAuthHeader("Bearer invalid.jwt_missing_dot_token")); + } - @Test - void givenJwtDataFieldOfInvalidFormat_whenExtractSubject_thenThrowUnauthorizedException() { - JwtReader jwtReader = new JwtReader("sub"); - String invalidDataJson = "{"; - assertThrows(UnauthorizedException.class, () -> - jwtReader.extractUserIdFromAuthHeader( - String.format("header.%s.signature", Base64.toBase64String(invalidDataJson.getBytes(StandardCharsets.UTF_8))))); - } + @Test + void givenJwtDataFieldOfInvalidFormat_whenExtractSubject_thenThrowUnauthorizedException() { + JwtReader jwtReader = new JwtReader("sub"); + String invalidDataJson = "{"; + assertThrows( + UnauthorizedException.class, + () -> + jwtReader.extractUserIdFromAuthHeader( + String.format( + "header.%s.signature", + Base64.toBase64String(invalidDataJson.getBytes(StandardCharsets.UTF_8))))); + } - @Test - void givenInvalidAuthHeader_whenExtractSubject_thenThrowUnauthorizedException() { - JwtReader jwtReader = new JwtReader("sub"); - assertThrows(UnauthorizedException.class, () -> - jwtReader.extractUserIdFromAuthHeader("invalid_auth_header missing Bearer prefix")); - } -} \ No newline at end of file + @Test + void givenInvalidAuthHeader_whenExtractSubject_thenThrowUnauthorizedException() { + JwtReader jwtReader = new JwtReader("sub"); + assertThrows( + UnauthorizedException.class, + () -> jwtReader.extractUserIdFromAuthHeader("invalid_auth_header missing Bearer prefix")); + } +} diff --git a/amphora-service/src/test/java/io/carbynestack/amphora/service/opa/OpaClientTest.java b/amphora-service/src/test/java/io/carbynestack/amphora/service/opa/OpaClientTest.java index 72b76ba..ec77015 100644 --- a/amphora-service/src/test/java/io/carbynestack/amphora/service/opa/OpaClientTest.java +++ b/amphora-service/src/test/java/io/carbynestack/amphora/service/opa/OpaClientTest.java @@ -7,11 +7,21 @@ package io.carbynestack.amphora.service.opa; +import static io.carbynestack.amphora.service.opa.OpaService.READ_SECRET_ACTION_NAME; +import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.*; + import com.google.common.collect.Lists; import io.carbynestack.amphora.common.Tag; import io.carbynestack.amphora.service.exceptions.CsOpaException; import io.carbynestack.httpclient.CsHttpClient; import io.carbynestack.httpclient.CsHttpClientException; +import java.net.URI; +import java.util.List; import org.hamcrest.MatcherAssert; import org.hamcrest.Matchers; import org.junit.jupiter.api.BeforeEach; @@ -21,150 +31,147 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import java.net.URI; -import java.util.List; - -import static io.carbynestack.amphora.service.opa.OpaService.READ_SECRET_ACTION_NAME; -import static org.junit.Assert.fail; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.*; - @ExtendWith(MockitoExtension.class) class OpaClientTest { - private static final URI OPA_SERVICE_URI = URI.create("http://localhost:8081"); - private static final String POLICY_PACKAGE = "play"; - private static final String DEFAULT_POLICY_PACKAGE = "default"; - private static final String SUBJECT = "me"; - private static final List TAGS = Lists.newArrayList( - Tag.builder().key("created").value("yesterday").build(), - Tag.builder().key("owner").value("me").build() - ); - private static final OpaResult POSITIVE_RESULT; - static { - POSITIVE_RESULT = new OpaResult(); - POSITIVE_RESULT.setResult(true); + private static final URI OPA_SERVICE_URI = URI.create("http://localhost:8081"); + private static final String POLICY_PACKAGE = "play"; + private static final String DEFAULT_POLICY_PACKAGE = "default"; + private static final String SUBJECT = "me"; + private static final List TAGS = + Lists.newArrayList( + Tag.builder().key("created").value("yesterday").build(), + Tag.builder().key("owner").value("me").build()); + private static final OpaResult POSITIVE_RESULT; + + static { + POSITIVE_RESULT = new OpaResult(); + POSITIVE_RESULT.setResult(true); + } + + private static final OpaResult NEGATIVE_RESULT = new OpaResult(); + + @Mock private CsHttpClient csHttpClientMock = mock(CsHttpClient.class); + + @BeforeEach + public void setUp() { + reset(csHttpClientMock); + } + + @Test + void givenValidRequest_whenEvaluate_thenReturnTrue() + throws CsOpaException, CsHttpClientException { + ArgumentCaptor uriCaptor = ArgumentCaptor.forClass(URI.class); + ArgumentCaptor requestCaptor = ArgumentCaptor.forClass(OpaRequest.class); + when(csHttpClientMock.postForObject( + uriCaptor.capture(), requestCaptor.capture(), eq(OpaResult.class))) + .thenReturn(NEGATIVE_RESULT); + + OpaClient opaClient = new OpaClient(csHttpClientMock, OPA_SERVICE_URI, DEFAULT_POLICY_PACKAGE); + opaClient + .newRequest() + .withPolicyPackage(POLICY_PACKAGE) + .withAction(READ_SECRET_ACTION_NAME) + .withSubject(SUBJECT) + .withTags(TAGS) + .evaluate(); + + URI actualUri = uriCaptor.getValue(); + MatcherAssert.assertThat(actualUri.toString(), Matchers.startsWith(OPA_SERVICE_URI.toString())); + MatcherAssert.assertThat( + actualUri.toString(), + Matchers.endsWith( + String.format("/v1/data/%s/%s", POLICY_PACKAGE, READ_SECRET_ACTION_NAME))); + OpaRequestBody actualRequestBody = requestCaptor.getValue().getInput(); + assertEquals(SUBJECT, actualRequestBody.getSubject()); + assertEquals(TAGS, actualRequestBody.getTags()); + } + + @Test + void givenNoPolicyPackageDefined_whenEvaluate_thenReturnUseDefaultPackage() + throws CsOpaException, CsHttpClientException { + ArgumentCaptor uriCaptor = ArgumentCaptor.forClass(URI.class); + ArgumentCaptor requestCaptor = ArgumentCaptor.forClass(OpaRequest.class); + when(csHttpClientMock.postForObject( + uriCaptor.capture(), requestCaptor.capture(), eq(OpaResult.class))) + .thenReturn(NEGATIVE_RESULT); + + OpaClient opaClient = new OpaClient(csHttpClientMock, OPA_SERVICE_URI, DEFAULT_POLICY_PACKAGE); + opaClient + .newRequest() + .withAction(READ_SECRET_ACTION_NAME) + .withSubject(SUBJECT) + .withTags(TAGS) + .evaluate(); + + URI actualUri = uriCaptor.getValue(); + MatcherAssert.assertThat(actualUri.toString(), Matchers.startsWith(OPA_SERVICE_URI.toString())); + MatcherAssert.assertThat( + actualUri.toString(), + Matchers.endsWith( + String.format("/v1/data/%s/%s", DEFAULT_POLICY_PACKAGE, READ_SECRET_ACTION_NAME))); + OpaRequestBody actualRequestBody = requestCaptor.getValue().getInput(); + assertEquals(SUBJECT, actualRequestBody.getSubject()); + assertEquals(TAGS, actualRequestBody.getTags()); + } + + @Test + void givenOpaReturnsFalse_whenEvaluate_thenReturnFalse() + throws CsHttpClientException, CsOpaException { + ArgumentCaptor uriCaptor = ArgumentCaptor.forClass(URI.class); + ArgumentCaptor requestCaptor = ArgumentCaptor.forClass(OpaRequest.class); + when(csHttpClientMock.postForObject( + uriCaptor.capture(), requestCaptor.capture(), eq(OpaResult.class))) + .thenReturn(NEGATIVE_RESULT); + + OpaClient opaClient = new OpaClient(csHttpClientMock, OPA_SERVICE_URI, DEFAULT_POLICY_PACKAGE); + boolean result = + opaClient + .newRequest() + .withAction(READ_SECRET_ACTION_NAME) + .withSubject(SUBJECT) + .withTags(TAGS) + .evaluate(); + + assertFalse(result, "must not be allowed"); + } + + @Test + void givenNoSubjectDefined_whenEvaluate_thenThrowException() { + OpaClient opaClient = new OpaClient(csHttpClientMock, OPA_SERVICE_URI, DEFAULT_POLICY_PACKAGE); + try { + opaClient.newRequest().withAction(READ_SECRET_ACTION_NAME).withTags(TAGS).evaluate(); + fail("must throw exception"); + } catch (CsOpaException e) { + assertEquals("Subject is required to evaluate the policy", e.getMessage()); } - private static final OpaResult NEGATIVE_RESULT = new OpaResult(); - - @Mock - private CsHttpClient csHttpClientMock = mock(CsHttpClient.class); - - @BeforeEach - public void setUp() { - reset(csHttpClientMock); - } - - @Test - void givenValidRequest_whenEvaluate_thenReturnTrue() throws CsOpaException, CsHttpClientException { - ArgumentCaptor uriCaptor = ArgumentCaptor.forClass(URI.class); - ArgumentCaptor requestCaptor = ArgumentCaptor.forClass(OpaRequest.class); - when(csHttpClientMock.postForObject(uriCaptor.capture(), requestCaptor.capture(), eq(OpaResult.class))) - .thenReturn(NEGATIVE_RESULT); - - OpaClient opaClient = new OpaClient(csHttpClientMock, OPA_SERVICE_URI, DEFAULT_POLICY_PACKAGE); - opaClient.newRequest() - .withPolicyPackage(POLICY_PACKAGE) - .withAction(READ_SECRET_ACTION_NAME) - .withSubject(SUBJECT) - .withTags(TAGS) - .evaluate(); - - URI actualUri = uriCaptor.getValue(); - MatcherAssert.assertThat(actualUri.toString(), - Matchers.startsWith(OPA_SERVICE_URI.toString())); - MatcherAssert.assertThat( - actualUri.toString(), - Matchers.endsWith(String.format("/v1/data/%s/%s", POLICY_PACKAGE, READ_SECRET_ACTION_NAME))); - OpaRequestBody actualRequestBody = requestCaptor.getValue().getInput(); - assertEquals(SUBJECT, actualRequestBody.getSubject()); - assertEquals(TAGS, actualRequestBody.getTags()); - } - - @Test - void givenNoPolicyPackageDefined_whenEvaluate_thenReturnUseDefaultPackage() throws CsOpaException, CsHttpClientException { - ArgumentCaptor uriCaptor = ArgumentCaptor.forClass(URI.class); - ArgumentCaptor requestCaptor = ArgumentCaptor.forClass(OpaRequest.class); - when(csHttpClientMock.postForObject(uriCaptor.capture(), requestCaptor.capture(), eq(OpaResult.class))) - .thenReturn(NEGATIVE_RESULT); - - OpaClient opaClient = new OpaClient(csHttpClientMock, OPA_SERVICE_URI, DEFAULT_POLICY_PACKAGE); - opaClient.newRequest() - .withAction(READ_SECRET_ACTION_NAME) - .withSubject(SUBJECT) - .withTags(TAGS) - .evaluate(); - - URI actualUri = uriCaptor.getValue(); - MatcherAssert.assertThat(actualUri.toString(), - Matchers.startsWith(OPA_SERVICE_URI.toString())); - MatcherAssert.assertThat( - actualUri.toString(), - Matchers.endsWith(String.format("/v1/data/%s/%s", DEFAULT_POLICY_PACKAGE, READ_SECRET_ACTION_NAME))); - OpaRequestBody actualRequestBody = requestCaptor.getValue().getInput(); - assertEquals(SUBJECT, actualRequestBody.getSubject()); - assertEquals(TAGS, actualRequestBody.getTags()); - } - - @Test - void givenOpaReturnsFalse_whenEvaluate_thenReturnFalse() throws CsHttpClientException, CsOpaException { - ArgumentCaptor uriCaptor = ArgumentCaptor.forClass(URI.class); - ArgumentCaptor requestCaptor = ArgumentCaptor.forClass(OpaRequest.class); - when(csHttpClientMock.postForObject(uriCaptor.capture(), requestCaptor.capture(), eq(OpaResult.class))) - .thenReturn(NEGATIVE_RESULT); - - OpaClient opaClient =new OpaClient(csHttpClientMock, OPA_SERVICE_URI, DEFAULT_POLICY_PACKAGE); - boolean result = opaClient.newRequest() - .withAction(READ_SECRET_ACTION_NAME) - .withSubject(SUBJECT) - .withTags(TAGS) - .evaluate(); - - assertFalse(result, "must not be allowed"); - } - - @Test - void givenNoSubjectDefined_whenEvaluate_thenThrowException() { - OpaClient opaClient = new OpaClient(csHttpClientMock, OPA_SERVICE_URI, DEFAULT_POLICY_PACKAGE); - try { - opaClient.newRequest() - .withAction(READ_SECRET_ACTION_NAME) - .withTags(TAGS) - .evaluate(); - fail("must throw exception"); - } catch (CsOpaException e) { - assertEquals("Subject is required to evaluate the policy", e.getMessage()); - } - } - - @Test - void givenNoActionDefined_whenEvaluate_thenThrowException() { - OpaClient opaClient = new OpaClient(csHttpClientMock, OPA_SERVICE_URI, DEFAULT_POLICY_PACKAGE); - try { - opaClient.newRequest() - .withSubject(SUBJECT) - .withTags(TAGS) - .evaluate(); - fail("must throw exception"); - } catch (CsOpaException e) { - assertEquals("Action is required to evaluate the policy", e.getMessage()); - } - } - - @Test - void givenClientThrows_whenEvaluate_thenReturnFalse() throws CsHttpClientException, CsOpaException { - when(csHttpClientMock.postForObject(any(), any(), eq(OpaResult.class))) - .thenThrow(new CsHttpClientException("")); - - OpaClient opaClient =new OpaClient(csHttpClientMock, OPA_SERVICE_URI, DEFAULT_POLICY_PACKAGE); - boolean result = opaClient.newRequest() - .withAction(READ_SECRET_ACTION_NAME) - .withSubject(SUBJECT) - .withTags(TAGS) - .evaluate(); - assertFalse(result, "must not be allowed"); + } + + @Test + void givenNoActionDefined_whenEvaluate_thenThrowException() { + OpaClient opaClient = new OpaClient(csHttpClientMock, OPA_SERVICE_URI, DEFAULT_POLICY_PACKAGE); + try { + opaClient.newRequest().withSubject(SUBJECT).withTags(TAGS).evaluate(); + fail("must throw exception"); + } catch (CsOpaException e) { + assertEquals("Action is required to evaluate the policy", e.getMessage()); } -} \ No newline at end of file + } + + @Test + void givenClientThrows_whenEvaluate_thenReturnFalse() + throws CsHttpClientException, CsOpaException { + when(csHttpClientMock.postForObject(any(), any(), eq(OpaResult.class))) + .thenThrow(new CsHttpClientException("")); + + OpaClient opaClient = new OpaClient(csHttpClientMock, OPA_SERVICE_URI, DEFAULT_POLICY_PACKAGE); + boolean result = + opaClient + .newRequest() + .withAction(READ_SECRET_ACTION_NAME) + .withSubject(SUBJECT) + .withTags(TAGS) + .evaluate(); + assertFalse(result, "must not be allowed"); + } +} diff --git a/amphora-service/src/test/java/io/carbynestack/amphora/service/opa/OpaResultTest.java b/amphora-service/src/test/java/io/carbynestack/amphora/service/opa/OpaResultTest.java index a87c03d..a3aeab3 100644 --- a/amphora-service/src/test/java/io/carbynestack/amphora/service/opa/OpaResultTest.java +++ b/amphora-service/src/test/java/io/carbynestack/amphora/service/opa/OpaResultTest.java @@ -7,25 +7,25 @@ package io.carbynestack.amphora.service.opa; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - class OpaResultTest { - private final ObjectMapper objectMapper = new ObjectMapper(); + private final ObjectMapper objectMapper = new ObjectMapper(); - @Test - void givenResultIsTrue_whenParsed_thenIsAllowedShouldBeTrue() throws JsonProcessingException { - OpaResult result = objectMapper.readValue("{\"result\": true}", OpaResult.class); - assertTrue(result.isAllowed(), "isAllowed must be true"); - } + @Test + void givenResultIsTrue_whenParsed_thenIsAllowedShouldBeTrue() throws JsonProcessingException { + OpaResult result = objectMapper.readValue("{\"result\": true}", OpaResult.class); + assertTrue(result.isAllowed(), "isAllowed must be true"); + } - @Test - void givenResultIsEmpty_whenParsed_thenIsAllowedShouldBeFalse() throws JsonProcessingException { - OpaResult result = objectMapper.readValue("{}", OpaResult.class); - assertFalse(result.isAllowed(), "isAllowed must be false"); - } -} \ No newline at end of file + @Test + void givenResultIsEmpty_whenParsed_thenIsAllowedShouldBeFalse() throws JsonProcessingException { + OpaResult result = objectMapper.readValue("{}", OpaResult.class); + assertFalse(result.isAllowed(), "isAllowed must be false"); + } +} diff --git a/amphora-service/src/test/java/io/carbynestack/amphora/service/opa/OpaServiceTest.java b/amphora-service/src/test/java/io/carbynestack/amphora/service/opa/OpaServiceTest.java index 6dad392..c4d7759 100644 --- a/amphora-service/src/test/java/io/carbynestack/amphora/service/opa/OpaServiceTest.java +++ b/amphora-service/src/test/java/io/carbynestack/amphora/service/opa/OpaServiceTest.java @@ -7,9 +7,17 @@ package io.carbynestack.amphora.service.opa; +import static io.carbynestack.amphora.service.opa.OpaService.READ_SECRET_ACTION_NAME; +import static io.carbynestack.amphora.service.opa.OpaService.USE_SECRET_ACTION_NAME; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + import com.google.common.collect.Lists; import io.carbynestack.amphora.common.Tag; import io.carbynestack.amphora.service.exceptions.CsOpaException; +import java.util.List; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -17,184 +25,162 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import java.util.List; - -import static io.carbynestack.amphora.service.opa.OpaService.READ_SECRET_ACTION_NAME; -import static io.carbynestack.amphora.service.opa.OpaService.USE_SECRET_ACTION_NAME; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.*; - @ExtendWith(MockitoExtension.class) class OpaServiceTest { - private static final String POLICY_PACKAGE = "play"; - private static final String DEFAULT_POLICY_PACKAGE = "default"; - private static final String SUBJECT = "me"; - private static final List TAGS = Lists.newArrayList( - Tag.builder().key("created").value("yesterday").build(), - Tag.builder().key("owner").value("me").build() - ); - private static final Tag POLICY_TAG = Tag.builder() - .key(OpaService.POLICY_PACKAGE_TAG_KEY) - .value(POLICY_PACKAGE).build(); - private static final OpaResult POSITIVE_RESULT; - static { - POSITIVE_RESULT = new OpaResult(); - POSITIVE_RESULT.setResult(true); - } - - @Mock - private OpaClient opaClientMock = mock(OpaClient.class); - - @BeforeEach - public void setUp() { - reset(opaClientMock); - when(opaClientMock.newRequest()).thenReturn(new OpaClientRequest(opaClientMock, DEFAULT_POLICY_PACKAGE)); - } - - @Test - void givenPolicyDefinedInTag_whenIsAllowed_thenUsePolicyPackageProvided() throws CsOpaException { - ArgumentCaptor packageCaptor = ArgumentCaptor.forClass(String.class); - ArgumentCaptor actionCaptor = ArgumentCaptor.forClass(String.class); - ArgumentCaptor subjectCaptor = ArgumentCaptor.forClass(String.class); - ArgumentCaptor> tagsCaptor = ArgumentCaptor.forClass(List.class); - when(opaClientMock.isAllowed( - packageCaptor.capture(), actionCaptor.capture(), subjectCaptor.capture(), tagsCaptor.capture())) - .thenReturn(true); - - OpaService service = new OpaService(opaClientMock); - List testTags = Lists.newArrayList(TAGS); - testTags.add(POLICY_TAG); - boolean result = service.isAllowed(SUBJECT, READ_SECRET_ACTION_NAME, testTags); - - assertTrue(result, "must be allowed"); - String actualPackage = packageCaptor.getValue(); - assertEquals(POLICY_TAG.getValue(), actualPackage); - String actualAction = actionCaptor.getValue(); - assertEquals(READ_SECRET_ACTION_NAME, actualAction); - String actualSubject = subjectCaptor.getValue(); - assertEquals(SUBJECT, actualSubject); - List actualTags = tagsCaptor.getValue(); - assertEquals(testTags, actualTags); - } - - @Test - public void givenNoPolicyDefinedInTag_whenIsAllowed_thenUseDefaultPolicyPackage() throws CsOpaException { - ArgumentCaptor packageCaptor = ArgumentCaptor.forClass(String.class); - ArgumentCaptor> tagsCaptor = ArgumentCaptor.forClass(List.class); - when(opaClientMock.isAllowed( - packageCaptor.capture(), any(), any(), tagsCaptor.capture())) - .thenReturn(true); - - OpaService service = new OpaService(opaClientMock); - boolean result = service.isAllowed(READ_SECRET_ACTION_NAME, SUBJECT, TAGS); - - assertTrue(result, "must be allowed"); - String actualPackage = packageCaptor.getValue(); - assertEquals(DEFAULT_POLICY_PACKAGE, actualPackage); - List actualTags = tagsCaptor.getValue(); - assertEquals(TAGS, actualTags); - } - - @Test - public void whenCanReadSecret_thenUseProperAction() throws CsOpaException { - ArgumentCaptor actionCaptor = ArgumentCaptor.forClass(String.class); - when(opaClientMock.isAllowed( - any(), actionCaptor.capture(), any(), any())) - .thenReturn(true); - - OpaService service = new OpaService(opaClientMock); - service.canReadSecret(SUBJECT, TAGS); - - String actualAction = actionCaptor.getValue(); - assertEquals(READ_SECRET_ACTION_NAME, actualAction); - - } - - @Test - public void whenCanUseSecret_thenUseProperAction() throws CsOpaException { - ArgumentCaptor actionCaptor = ArgumentCaptor.forClass(String.class); - when(opaClientMock.isAllowed( - any(), actionCaptor.capture(), any(), any())) - .thenReturn(true); - - OpaService service = new OpaService(opaClientMock); - service.canUseSecret(SUBJECT, TAGS); - - String actualAction = actionCaptor.getValue(); - assertEquals(USE_SECRET_ACTION_NAME, actualAction); - - } - - @Test - public void whenCanDeleteSecret_thenUseProperAction() throws CsOpaException { - ArgumentCaptor actionCaptor = ArgumentCaptor.forClass(String.class); - when(opaClientMock.isAllowed( - any(), actionCaptor.capture(), any(), any())) - .thenReturn(true); - - OpaService service = new OpaService(opaClientMock); - service.canDeleteSecret(SUBJECT, TAGS); - - String actualAction = actionCaptor.getValue(); - assertEquals(OpaService.DELETE_SECRET_ACTION_NAME, actualAction); - } - - @Test - public void whenCanCreateTags_thenUseProperAction() throws CsOpaException { - ArgumentCaptor actionCaptor = ArgumentCaptor.forClass(String.class); - when(opaClientMock.isAllowed( - any(), actionCaptor.capture(), any(), any())) - .thenReturn(true); - - OpaService service = new OpaService(opaClientMock); - service.canCreateTags(SUBJECT, TAGS); - - String actualAction = actionCaptor.getValue(); - assertEquals(OpaService.CREATE_TAG_ACTION_NAME, actualAction); - } - - @Test - public void whenCanReadTags_thenUseProperAction() throws CsOpaException { - ArgumentCaptor actionCaptor = ArgumentCaptor.forClass(String.class); - when(opaClientMock.isAllowed( - any(), actionCaptor.capture(), any(), any())) - .thenReturn(true); - - OpaService service = new OpaService(opaClientMock); - service.canReadTags(SUBJECT, TAGS); - - String actualAction = actionCaptor.getValue(); - assertEquals(OpaService.READ_TAG_ACTION_NAME, actualAction); - } - - @Test - public void whenCanUpdateTags_thenUseProperAction() throws CsOpaException { - ArgumentCaptor actionCaptor = ArgumentCaptor.forClass(String.class); - when(opaClientMock.isAllowed( - any(), actionCaptor.capture(), any(), any())) - .thenReturn(true); - - OpaService service = new OpaService(opaClientMock); - service.canUpdateTags(SUBJECT, TAGS); - - String actualAction = actionCaptor.getValue(); - assertEquals(OpaService.UPDATE_TAG_ACTION_NAME, actualAction); - } - - @Test - public void whenCanDeleteTags_thenUseProperAction() throws CsOpaException { - ArgumentCaptor actionCaptor = ArgumentCaptor.forClass(String.class); - when(opaClientMock.isAllowed( - any(), actionCaptor.capture(), any(), any())) - .thenReturn(true); - - OpaService service = new OpaService(opaClientMock); - service.canDeleteTags(SUBJECT, TAGS); - - String actualAction = actionCaptor.getValue(); - assertEquals(OpaService.DELETE_TAG_ACTION_NAME, actualAction); - } -} \ No newline at end of file + private static final String POLICY_PACKAGE = "play"; + private static final String DEFAULT_POLICY_PACKAGE = "default"; + private static final String SUBJECT = "me"; + private static final List TAGS = + Lists.newArrayList( + Tag.builder().key("created").value("yesterday").build(), + Tag.builder().key("owner").value("me").build()); + private static final Tag POLICY_TAG = + Tag.builder().key(OpaService.POLICY_PACKAGE_TAG_KEY).value(POLICY_PACKAGE).build(); + private static final OpaResult POSITIVE_RESULT; + + static { + POSITIVE_RESULT = new OpaResult(); + POSITIVE_RESULT.setResult(true); + } + + @Mock private OpaClient opaClientMock = mock(OpaClient.class); + + @BeforeEach + public void setUp() { + reset(opaClientMock); + when(opaClientMock.newRequest()) + .thenReturn(new OpaClientRequest(opaClientMock, DEFAULT_POLICY_PACKAGE)); + } + + @Test + void givenPolicyDefinedInTag_whenIsAllowed_thenUsePolicyPackageProvided() throws CsOpaException { + ArgumentCaptor packageCaptor = ArgumentCaptor.forClass(String.class); + ArgumentCaptor actionCaptor = ArgumentCaptor.forClass(String.class); + ArgumentCaptor subjectCaptor = ArgumentCaptor.forClass(String.class); + ArgumentCaptor> tagsCaptor = ArgumentCaptor.forClass(List.class); + when(opaClientMock.isAllowed( + packageCaptor.capture(), + actionCaptor.capture(), + subjectCaptor.capture(), + tagsCaptor.capture())) + .thenReturn(true); + + OpaService service = new OpaService(opaClientMock); + List testTags = Lists.newArrayList(TAGS); + testTags.add(POLICY_TAG); + boolean result = service.isAllowed(SUBJECT, READ_SECRET_ACTION_NAME, testTags); + + assertTrue(result, "must be allowed"); + String actualPackage = packageCaptor.getValue(); + assertEquals(POLICY_TAG.getValue(), actualPackage); + String actualAction = actionCaptor.getValue(); + assertEquals(READ_SECRET_ACTION_NAME, actualAction); + String actualSubject = subjectCaptor.getValue(); + assertEquals(SUBJECT, actualSubject); + List actualTags = tagsCaptor.getValue(); + assertEquals(testTags, actualTags); + } + + @Test + public void givenNoPolicyDefinedInTag_whenIsAllowed_thenUseDefaultPolicyPackage() + throws CsOpaException { + ArgumentCaptor packageCaptor = ArgumentCaptor.forClass(String.class); + ArgumentCaptor> tagsCaptor = ArgumentCaptor.forClass(List.class); + when(opaClientMock.isAllowed(packageCaptor.capture(), any(), any(), tagsCaptor.capture())) + .thenReturn(true); + + OpaService service = new OpaService(opaClientMock); + boolean result = service.isAllowed(READ_SECRET_ACTION_NAME, SUBJECT, TAGS); + + assertTrue(result, "must be allowed"); + String actualPackage = packageCaptor.getValue(); + assertEquals(DEFAULT_POLICY_PACKAGE, actualPackage); + List actualTags = tagsCaptor.getValue(); + assertEquals(TAGS, actualTags); + } + + @Test + public void whenCanReadSecret_thenUseProperAction() throws CsOpaException { + ArgumentCaptor actionCaptor = ArgumentCaptor.forClass(String.class); + when(opaClientMock.isAllowed(any(), actionCaptor.capture(), any(), any())).thenReturn(true); + + OpaService service = new OpaService(opaClientMock); + service.canReadSecret(SUBJECT, TAGS); + + String actualAction = actionCaptor.getValue(); + assertEquals(READ_SECRET_ACTION_NAME, actualAction); + } + + @Test + public void whenCanUseSecret_thenUseProperAction() throws CsOpaException { + ArgumentCaptor actionCaptor = ArgumentCaptor.forClass(String.class); + when(opaClientMock.isAllowed(any(), actionCaptor.capture(), any(), any())).thenReturn(true); + + OpaService service = new OpaService(opaClientMock); + service.canUseSecret(SUBJECT, TAGS); + + String actualAction = actionCaptor.getValue(); + assertEquals(USE_SECRET_ACTION_NAME, actualAction); + } + + @Test + public void whenCanDeleteSecret_thenUseProperAction() throws CsOpaException { + ArgumentCaptor actionCaptor = ArgumentCaptor.forClass(String.class); + when(opaClientMock.isAllowed(any(), actionCaptor.capture(), any(), any())).thenReturn(true); + + OpaService service = new OpaService(opaClientMock); + service.canDeleteSecret(SUBJECT, TAGS); + + String actualAction = actionCaptor.getValue(); + assertEquals(OpaService.DELETE_SECRET_ACTION_NAME, actualAction); + } + + @Test + public void whenCanCreateTags_thenUseProperAction() throws CsOpaException { + ArgumentCaptor actionCaptor = ArgumentCaptor.forClass(String.class); + when(opaClientMock.isAllowed(any(), actionCaptor.capture(), any(), any())).thenReturn(true); + + OpaService service = new OpaService(opaClientMock); + service.canCreateTags(SUBJECT, TAGS); + + String actualAction = actionCaptor.getValue(); + assertEquals(OpaService.CREATE_TAG_ACTION_NAME, actualAction); + } + + @Test + public void whenCanReadTags_thenUseProperAction() throws CsOpaException { + ArgumentCaptor actionCaptor = ArgumentCaptor.forClass(String.class); + when(opaClientMock.isAllowed(any(), actionCaptor.capture(), any(), any())).thenReturn(true); + + OpaService service = new OpaService(opaClientMock); + service.canReadTags(SUBJECT, TAGS); + + String actualAction = actionCaptor.getValue(); + assertEquals(OpaService.READ_TAG_ACTION_NAME, actualAction); + } + + @Test + public void whenCanUpdateTags_thenUseProperAction() throws CsOpaException { + ArgumentCaptor actionCaptor = ArgumentCaptor.forClass(String.class); + when(opaClientMock.isAllowed(any(), actionCaptor.capture(), any(), any())).thenReturn(true); + + OpaService service = new OpaService(opaClientMock); + service.canUpdateTags(SUBJECT, TAGS); + + String actualAction = actionCaptor.getValue(); + assertEquals(OpaService.UPDATE_TAG_ACTION_NAME, actualAction); + } + + @Test + public void whenCanDeleteTags_thenUseProperAction() throws CsOpaException { + ArgumentCaptor actionCaptor = ArgumentCaptor.forClass(String.class); + when(opaClientMock.isAllowed(any(), actionCaptor.capture(), any(), any())).thenReturn(true); + + OpaService service = new OpaService(opaClientMock); + service.canDeleteTags(SUBJECT, TAGS); + + String actualAction = actionCaptor.getValue(); + assertEquals(OpaService.DELETE_TAG_ACTION_NAME, actualAction); + } +} diff --git a/amphora-service/src/test/java/io/carbynestack/amphora/service/persistence/metadata/StorageIT.java b/amphora-service/src/test/java/io/carbynestack/amphora/service/persistence/metadata/StorageIT.java index f9b7be6..2f98655 100644 --- a/amphora-service/src/test/java/io/carbynestack/amphora/service/persistence/metadata/StorageIT.java +++ b/amphora-service/src/test/java/io/carbynestack/amphora/service/persistence/metadata/StorageIT.java @@ -51,8 +51,6 @@ import org.springframework.data.domain.Sort; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.transaction.annotation.Isolation; -import org.springframework.transaction.annotation.Transactional; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; @@ -67,7 +65,7 @@ public class StorageIT { private final UUID testSecretId = UUID.fromString("3bcf8308-8f50-4d24-a37b-b0075bb5e779"); private final UUID testSecretId2 = UUID.fromString("0e7cd962-d98e-4eea-82ae-4641399c9ad7"); private final Tag testTag = Tag.builder().key("TEST_KEY").value("TEST_VALUE").build(); - private final String authorizedUserId ="afc0117f-c9cd-4d8c-acee-fa1433ca0fdd"; + private final String authorizedUserId = "afc0117f-c9cd-4d8c-acee-fa1433ca0fdd"; @Container public static ReusableRedisContainer reusableRedisContainer = @@ -92,8 +90,7 @@ public class StorageIT { @Autowired private MinioClient minioClient; @Autowired private MinioProperties minioProperties; - @MockBean - private OpaClient opaClientMock; + @MockBean private OpaClient opaClientMock; @BeforeEach public void setUp() { @@ -108,14 +105,16 @@ private SecretEntity persistObjectWithIdAndTags(UUID id, Tag... tags) { } @Test - void givenSuccessfulRequest_whenStoreTag_thenPersist() throws CsOpaException, UnauthorizedException { + void givenSuccessfulRequest_whenStoreTag_thenPersist() + throws CsOpaException, UnauthorizedException { persistObjectWithIdAndTags(testSecretId, testTag); storageService.storeTag( - testSecretId, Tag.builder().key("ANOTHER_KEY").value(testTag.getValue()).build(), + testSecretId, + Tag.builder().key("ANOTHER_KEY").value(testTag.getValue()).build(), authorizedUserId); - assertEquals(testTag, - storageService.retrieveTag(testSecretId, testTag.getKey(),authorizedUserId)); + assertEquals( + testTag, storageService.retrieveTag(testSecretId, testTag.getKey(), authorizedUserId)); } @Test @@ -130,8 +129,9 @@ void givenSuccessfulRequest_whenGetObjectList_thenReturnExpectedResult() { @Test void givenNoObjectWithReferencedIdDefined_whenRetrieveTags_thenThrowNotFoundException() { NotFoundException nfe = - assertThrows(NotFoundException.class, () -> - storageService.retrieveTags(testSecretId, authorizedUserId)); + assertThrows( + NotFoundException.class, + () -> storageService.retrieveTags(testSecretId, authorizedUserId)); assertEquals( String.format(NO_SECRET_WITH_ID_EXISTS_EXCEPTION_MSG, testSecretId), nfe.getMessage()); } @@ -139,14 +139,16 @@ void givenNoObjectWithReferencedIdDefined_whenRetrieveTags_thenThrowNotFoundExce @Test void givenSecretIdUnknown_whenStoreTag_thenThrowNotFoundException() { NotFoundException nfe = - assertThrows(NotFoundException.class, () -> - storageService.storeTag(unknownId, testTag, authorizedUserId)); + assertThrows( + NotFoundException.class, + () -> storageService.storeTag(unknownId, testTag, authorizedUserId)); assertEquals( String.format(NO_SECRET_WITH_ID_EXISTS_EXCEPTION_MSG, unknownId), nfe.getMessage()); } @Test - void givenSuccessfulRequests_whenStoreAndRetrieveTag_thenPersistAndReturnExpectedContent() throws CsOpaException, UnauthorizedException { + void givenSuccessfulRequests_whenStoreAndRetrieveTag_thenPersistAndReturnExpectedContent() + throws CsOpaException, UnauthorizedException { persistObjectWithIdAndTags(testSecretId); storageService.storeTag(testSecretId, testTag, authorizedUserId); List tags = storageService.retrieveTags(testSecretId, authorizedUserId); @@ -155,9 +157,11 @@ void givenSuccessfulRequests_whenStoreAndRetrieveTag_thenPersistAndReturnExpecte } @Test - void givenObjectWithoutTagsDefined_whenRetrieveTags_thenReturnEmptyList() throws CsOpaException, UnauthorizedException { + void givenObjectWithoutTagsDefined_whenRetrieveTags_thenReturnEmptyList() + throws CsOpaException, UnauthorizedException { persistObjectWithIdAndTags(testSecretId); - assertEquals(Collections.emptyList(), storageService.retrieveTags(testSecretId, authorizedUserId)); + assertEquals( + Collections.emptyList(), storageService.retrieveTags(testSecretId, authorizedUserId)); } @SneakyThrows @@ -170,8 +174,9 @@ void givenObjectWithoutTagsDefined_whenRetrieveSecretShare_thenReturnEmptyListFo .object(testSecretId.toString()) .stream(new ByteArrayInputStream(new byte[0]), 0, -1) .build()); - assertEquals(Collections.emptyList(), - storageService.getSecretShare(testSecretId, authorizedUserId).getTags()); + assertEquals( + Collections.emptyList(), + storageService.getSecretShare(testSecretId, authorizedUserId).getTags()); } @Test @@ -179,8 +184,8 @@ void givenObjectHasNoDataPersisted_whenGetSecretShare_thenThrowAmphoraServiceExc persistObjectWithIdAndTags(testSecretId); AmphoraServiceException ase = assertThrows( - AmphoraServiceException.class, () -> - storageService.getSecretShare(testSecretId, authorizedUserId)); + AmphoraServiceException.class, + () -> storageService.getSecretShare(testSecretId, authorizedUserId)); assertEquals( String.format( GET_DATA_FOR_SECRET_EXCEPTION_MSG, testSecretId, "The specified key does not exist."), @@ -201,7 +206,8 @@ void givenSecretIdUnknown_whenReplaceTags_thenThrowNotFoundException() { } @Test - void givenSuccessfulRequest_whenDeleteTag_thenDoNoLongerReturn() throws CsOpaException, UnauthorizedException { + void givenSuccessfulRequest_whenDeleteTag_thenDoNoLongerReturn() + throws CsOpaException, UnauthorizedException { SecretEntity secretEntity = persistObjectWithIdAndTags(testSecretId, testTag); Tag expectedTag = Tag.builder().key(testTag.getKey() + "new").value(testTag.getValue()).build(); TagEntity expectedTagEntity = TagEntity.fromTag(expectedTag).setSecret(secretEntity); @@ -232,8 +238,8 @@ void givenObjectHasNoTagWithRequestedKey_whenDeleteKey_thenThrowNotFoundExceptio NotFoundException nfe = assertThrows( - NotFoundException.class, () -> - storageService.deleteTag(testSecretId, unknownKey, authorizedUserId)); + NotFoundException.class, + () -> storageService.deleteTag(testSecretId, unknownKey, authorizedUserId)); assertEquals( String.format( NO_TAG_WITH_KEY_EXISTS_FOR_SECRET_WITH_ID_EXCEPTION_MSG, unknownKey, testSecretId), @@ -241,7 +247,8 @@ void givenObjectHasNoTagWithRequestedKey_whenDeleteKey_thenThrowNotFoundExceptio } @Test - void givenMultipleObjectsWIthIdenticalTag_whenDeleteTagOnOneObject_thenKeepTagForOtherObjects() throws CsOpaException, UnauthorizedException { + void givenMultipleObjectsWIthIdenticalTag_whenDeleteTagOnOneObject_thenKeepTagForOtherObjects() + throws CsOpaException, UnauthorizedException { persistObjectWithIdAndTags(testSecretId, testTag); persistObjectWithIdAndTags(testSecretId2, testTag); storageService.deleteTag(testSecretId, testTag.getKey(), authorizedUserId); @@ -261,7 +268,9 @@ void givenMultipleObjectsWIthIdenticalTag_whenDeleteTagOnOneObject_thenKeepTagFo @Test void givenAnUnknownId_whenStoringATag_thenThrow() { NotFoundException nfe = - assertThrows(NotFoundException.class, () -> storageService.storeTag(testSecretId, testTag, authorizedUserId)); + assertThrows( + NotFoundException.class, + () -> storageService.storeTag(testSecretId, testTag, authorizedUserId)); assertEquals( String.format(NO_SECRET_WITH_ID_EXISTS_EXCEPTION_MSG, testSecretId), nfe.getMessage()); } diff --git a/amphora-service/src/test/java/io/carbynestack/amphora/service/persistence/metadata/StorageServiceTest.java b/amphora-service/src/test/java/io/carbynestack/amphora/service/persistence/metadata/StorageServiceTest.java index 66b7d4f..e4aa8a1 100644 --- a/amphora-service/src/test/java/io/carbynestack/amphora/service/persistence/metadata/StorageServiceTest.java +++ b/amphora-service/src/test/java/io/carbynestack/amphora/service/persistence/metadata/StorageServiceTest.java @@ -7,6 +7,18 @@ package io.carbynestack.amphora.service.persistence.metadata; +import static io.carbynestack.amphora.service.persistence.metadata.StorageService.*; +import static io.carbynestack.amphora.service.persistence.metadata.TagEntity.setToTagList; +import static io.carbynestack.amphora.service.util.CreationDateTagMatchers.containsCreationDateTag; +import static io.carbynestack.castor.common.entities.Field.GFP; +import static java.util.Arrays.asList; +import static java.util.Collections.*; +import static org.hamcrest.CoreMatchers.*; +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; +import static org.mockito.Mockito.any; + import io.carbynestack.amphora.common.*; import io.carbynestack.amphora.common.exceptions.AmphoraServiceException; import io.carbynestack.amphora.service.calculation.SecretShareUtil; @@ -22,6 +34,8 @@ import io.carbynestack.castor.common.entities.InputMask; import io.carbynestack.castor.common.entities.TupleList; import io.carbynestack.mpspdz.integration.MpSpdzIntegrationUtils; +import java.util.*; +import java.util.stream.Collectors; import org.apache.commons.lang3.RandomUtils; import org.hamcrest.MatcherAssert; import org.junit.jupiter.api.Test; @@ -32,21 +46,6 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.data.domain.*; -import java.util.*; -import java.util.stream.Collectors; - -import static io.carbynestack.amphora.service.persistence.metadata.StorageService.*; -import static io.carbynestack.amphora.service.persistence.metadata.TagEntity.setToTagList; -import static io.carbynestack.amphora.service.util.CreationDateTagMatchers.containsCreationDateTag; -import static io.carbynestack.castor.common.entities.Field.GFP; -import static java.util.Arrays.asList; -import static java.util.Collections.*; -import static org.hamcrest.CoreMatchers.*; -import static org.hamcrest.Matchers.containsInAnyOrder; -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.*; - @ExtendWith(MockitoExtension.class) class StorageServiceTest { private final UUID testSecretId = UUID.fromString("3bcf8308-8f50-4d24-a37b-b0075bb5e779"); @@ -55,7 +54,7 @@ class StorageServiceTest { private final Tag testTag2 = Tag.builder().key("SUPER_KEY").value("MY#SUPER,VALUE").build(); private final Tag testTagReservedCreationDateKey = Tag.builder().key(StorageService.RESERVED_TAG_KEYS.get(0)).value("MY#SUPER,VALUE").build(); - private final String authorizedSubject ="afc0117f-c9cd-4d8c-acee-fa1433ca0fdd"; + private final String authorizedSubject = "afc0117f-c9cd-4d8c-acee-fa1433ca0fdd"; @Mock private SecretEntityRepository secretEntityRepository; @Mock private InputMaskCachingService inputMaskStore; @@ -82,8 +81,8 @@ void givenIdIsAlreadyInUse_whenCreateSecret_thenThrowAlreadyExistsException() { AlreadyExistsException aee = assertThrows( - AlreadyExistsException.class, () -> - storageService.createSecret(testMaskedInput, authorizedSubject)); + AlreadyExistsException.class, + () -> storageService.createSecret(testMaskedInput, authorizedSubject)); assertEquals(SECRET_WITH_ID_EXISTS_EXCEPTION_MSG, aee.getMessage()); } @@ -180,7 +179,9 @@ void givenSuccessfulRequest_whenCreateObject_thenReturnSecretId() { when(secretEntityRepository.save(secretEntityArgumentCaptor.capture())) .thenReturn(persistedSecretEntity); - assertEquals(maskedInput.getSecretId().toString(), storageService.createSecret(maskedInput, authorizedSubject)); + assertEquals( + maskedInput.getSecretId().toString(), + storageService.createSecret(maskedInput, authorizedSubject)); verify(secretEntityRepository, times(1)).existsById(maskedInput.getSecretId().toString()); verify(inputMaskStore, times(1)).getCachedInputMasks(maskedInput.getSecretId()); verify(secretEntityRepository, times(1)).save(secretEntityArgumentCaptor.capture()); @@ -390,29 +391,36 @@ void givenNoSecretShareWithGivenIdInDatabase_whenGetSecretShare_thenThrowNotFoun when(secretEntityRepository.findById(testSecretId.toString())).thenReturn(Optional.empty()); NotFoundException nfe = - assertThrows(NotFoundException.class, () -> storageService.getSecretShare(testSecretId, authorizedSubject)); + assertThrows( + NotFoundException.class, + () -> storageService.getSecretShare(testSecretId, authorizedSubject)); assertEquals( String.format(NO_SECRET_WITH_ID_EXISTS_EXCEPTION_MSG, testSecretId), nfe.getMessage()); } @Test - void givenSubjectHasNoAccess_whenGetSecretShare_thenThrowUnauthorizedException() throws CsOpaException { + void givenSubjectHasNoAccess_whenGetSecretShare_thenThrowUnauthorizedException() + throws CsOpaException { SecretEntity secretEntity = new SecretEntity(testSecretId.toString(), emptySet()); when(secretEntityRepository.findById(testSecretId.toString())) - .thenReturn(Optional.of(secretEntity)); + .thenReturn(Optional.of(secretEntity)); when(opaService.canReadSecret(authorizedSubject, emptyList())).thenReturn(false); UnauthorizedException ue = - assertThrows(UnauthorizedException.class, () -> storageService.getSecretShare(testSecretId, authorizedSubject)); + assertThrows( + UnauthorizedException.class, + () -> storageService.getSecretShare(testSecretId, authorizedSubject)); assertEquals("User is not authorized to read this secret", ue.getMessage()); } @Test - void givenDataCannotBeRetrieved_whenGetSecretShare_thenThrowAmphoraServiceException() throws CsOpaException { + void givenDataCannotBeRetrieved_whenGetSecretShare_thenThrowAmphoraServiceException() + throws CsOpaException { AmphoraServiceException expectedAse = new AmphoraServiceException("Expected this one"); TagEntity tagEntity = TagEntity.fromTag(testTag); SecretEntity secretEntity = new SecretEntity(testSecretId.toString(), singleton(tagEntity)); - when(opaService.canReadSecret(authorizedSubject, setToTagList(secretEntity.getTags()))).thenReturn(true); + when(opaService.canReadSecret(authorizedSubject, setToTagList(secretEntity.getTags()))) + .thenReturn(true); when(secretEntityRepository.findById(testSecretId.toString())) .thenReturn(Optional.of(secretEntity)); when(secretShareDataStore.getSecretShareData(testSecretId)).thenThrow(expectedAse); @@ -424,7 +432,8 @@ void givenDataCannotBeRetrieved_whenGetSecretShare_thenThrowAmphoraServiceExcept } @Test - void givenSuccessfulRequest_whenGetSecretShare_thenReturnContent() throws CsOpaException, UnauthorizedException { + void givenSuccessfulRequest_whenGetSecretShare_thenReturnContent() + throws CsOpaException, UnauthorizedException { List expectedTags = singletonList(testTag); byte[] expectedData = RandomUtils.nextBytes(MpSpdzIntegrationUtils.SHARE_WIDTH); SecretEntity existingSecretEntity = @@ -439,7 +448,8 @@ void givenSuccessfulRequest_whenGetSecretShare_thenReturnContent() throws CsOpaE .thenReturn(true); SecretShare actualSecretShare = - storageService.getSecretShare(UUID.fromString(existingSecretEntity.getSecretId()), authorizedSubject); + storageService.getSecretShare( + UUID.fromString(existingSecretEntity.getSecretId()), authorizedSubject); assertEquals( UUID.fromString(existingSecretEntity.getSecretId()), actualSecretShare.getSecretId()); assertEquals(expectedTags, actualSecretShare.getTags()); @@ -451,9 +461,11 @@ void givenNoSecretShareWithGivenIdInDatabase_whenUseSecretShare_thenThrowNotFoun when(secretEntityRepository.findById(testSecretId.toString())).thenReturn(Optional.empty()); NotFoundException nfe = - assertThrows(NotFoundException.class, () -> storageService.useSecretShare(testSecretId, authorizedSubject)); + assertThrows( + NotFoundException.class, + () -> storageService.useSecretShare(testSecretId, authorizedSubject)); assertEquals( - String.format(NO_SECRET_WITH_ID_EXISTS_EXCEPTION_MSG, testSecretId), nfe.getMessage()); + String.format(NO_SECRET_WITH_ID_EXISTS_EXCEPTION_MSG, testSecretId), nfe.getMessage()); } @Test @@ -461,66 +473,77 @@ void givenSubjectIsNotAuthorized_whenUseSecretShare_thenThrowUnauthorizedExcepti TagEntity tagEntity = TagEntity.fromTag(testTag); SecretEntity secretEntity = new SecretEntity(testSecretId.toString(), singleton(tagEntity)); when(secretEntityRepository.findById(testSecretId.toString())) - .thenReturn(Optional.of(secretEntity)); + .thenReturn(Optional.of(secretEntity)); - assertThrows(UnauthorizedException.class, () -> storageService.useSecretShare(testSecretId, authorizedSubject)); + assertThrows( + UnauthorizedException.class, + () -> storageService.useSecretShare(testSecretId, authorizedSubject)); } @Test - void givenDataCannotBeRetrieved_whenUseSecretShare_thenThrowAmphoraServiceException() throws CsOpaException { + void givenDataCannotBeRetrieved_whenUseSecretShare_thenThrowAmphoraServiceException() + throws CsOpaException { AmphoraServiceException expectedAse = new AmphoraServiceException("Expected this one"); TagEntity tagEntity = TagEntity.fromTag(testTag); SecretEntity secretEntity = new SecretEntity(testSecretId.toString(), singleton(tagEntity)); when(secretEntityRepository.findById(testSecretId.toString())) - .thenReturn(Optional.of(secretEntity)); + .thenReturn(Optional.of(secretEntity)); when(opaService.canUseSecret(authorizedSubject, setToTagList(secretEntity.getTags()))) - .thenReturn(true); + .thenReturn(true); when(secretShareDataStore.getSecretShareData(testSecretId)).thenThrow(expectedAse); assertThrows( - AmphoraServiceException.class, - () -> storageService.useSecretShare(testSecretId, authorizedSubject), - expectedAse.getMessage()); + AmphoraServiceException.class, + () -> storageService.useSecretShare(testSecretId, authorizedSubject), + expectedAse.getMessage()); } @Test - void givenSuccessfulRequest_whenUseSecretShare_thenReturnContent() throws CsOpaException, UnauthorizedException { + void givenSuccessfulRequest_whenUseSecretShare_thenReturnContent() + throws CsOpaException, UnauthorizedException { List expectedTags = singletonList(testTag); byte[] expectedData = RandomUtils.nextBytes(MpSpdzIntegrationUtils.SHARE_WIDTH); SecretEntity existingSecretEntity = - new SecretEntity(testSecretId.toString(), TagEntity.setFromTagList(expectedTags)); + new SecretEntity(testSecretId.toString(), TagEntity.setFromTagList(expectedTags)); when(secretEntityRepository.findById(existingSecretEntity.getSecretId())) - .thenReturn(Optional.of(existingSecretEntity)); + .thenReturn(Optional.of(existingSecretEntity)); when(opaService.canUseSecret(authorizedSubject, setToTagList(existingSecretEntity.getTags()))) - .thenReturn(true); + .thenReturn(true); when(secretShareDataStore.getSecretShareData( UUID.fromString(existingSecretEntity.getSecretId()))) - .thenReturn(expectedData); + .thenReturn(expectedData); SecretShare actualSecretShare = - storageService.useSecretShare(UUID.fromString(existingSecretEntity.getSecretId()), authorizedSubject); + storageService.useSecretShare( + UUID.fromString(existingSecretEntity.getSecretId()), authorizedSubject); assertEquals( - UUID.fromString(existingSecretEntity.getSecretId()), actualSecretShare.getSecretId()); + UUID.fromString(existingSecretEntity.getSecretId()), actualSecretShare.getSecretId()); assertEquals(expectedTags, actualSecretShare.getTags()); assertEquals(expectedData, actualSecretShare.getData()); } @Test - void givenNoSecretShareWithGivenIdInDatabase_whenDeleteObject_thenThrowNotFoundException() { NotFoundException nfe = - assertThrows(NotFoundException.class, () -> storageService.deleteSecret(testSecretId, authorizedSubject)); + void givenNoSecretShareWithGivenIdInDatabase_whenDeleteObject_thenThrowNotFoundException() { + NotFoundException nfe = + assertThrows( + NotFoundException.class, + () -> storageService.deleteSecret(testSecretId, authorizedSubject)); assertEquals( String.format(NO_SECRET_WITH_ID_EXISTS_EXCEPTION_MSG, testSecretId), nfe.getMessage()); } @Test - void givenSubjectHasNoAccess_whenDeleteObject_thenThrowUnauthorizedException() throws CsOpaException { + void givenSubjectHasNoAccess_whenDeleteObject_thenThrowUnauthorizedException() + throws CsOpaException { SecretEntity secretEntity = new SecretEntity(testSecretId.toString(), emptySet()); when(secretEntityRepository.findById(testSecretId.toString())) - .thenReturn(Optional.of(secretEntity)); + .thenReturn(Optional.of(secretEntity)); UnauthorizedException ue = - assertThrows(UnauthorizedException.class, () -> storageService.deleteSecret(testSecretId, authorizedSubject)); + assertThrows( + UnauthorizedException.class, + () -> storageService.deleteSecret(testSecretId, authorizedSubject)); assertEquals("User is not authorized to delete this secret", ue.getMessage()); } @@ -529,7 +552,8 @@ void givenDeleteObjectDataFails_whenDeleteObject_thenThrowGivenException() throw AmphoraServiceException expectedAse = new AmphoraServiceException("Expected this one"); TagEntity tagEntity = TagEntity.fromTag(testTag); SecretEntity secretEntity = new SecretEntity(testSecretId.toString(), singleton(tagEntity)); - when(opaService.canDeleteSecret(authorizedSubject, setToTagList(secretEntity.getTags()))).thenReturn(true); + when(opaService.canDeleteSecret(authorizedSubject, setToTagList(secretEntity.getTags()))) + .thenReturn(true); when(secretEntityRepository.findById(testSecretId.toString())) .thenReturn(Optional.of(secretEntity)); when(secretEntityRepository.deleteBySecretId(testSecretId.toString())).thenReturn(1L); @@ -542,16 +566,18 @@ void givenDeleteObjectDataFails_whenDeleteObject_thenThrowGivenException() throw } @Test - void givenSuccessfulRequest_whenDeleteObject_thenDeleteObjectAndData() throws CsOpaException, UnauthorizedException { + void givenSuccessfulRequest_whenDeleteObject_thenDeleteObjectAndData() + throws CsOpaException, UnauthorizedException { TagEntity existingTagEntity = TagEntity.fromTag(testTag); SecretEntity existingSecretEntity = - new SecretEntity(testSecretId.toString(), singleton(existingTagEntity)); + new SecretEntity(testSecretId.toString(), singleton(existingTagEntity)); when(secretEntityRepository.findById(testSecretId.toString())) - .thenReturn(Optional.of(existingSecretEntity)); + .thenReturn(Optional.of(existingSecretEntity)); when(secretEntityRepository.deleteBySecretId(testSecretId.toString())).thenReturn(1L); - when(opaService.canDeleteSecret(authorizedSubject, setToTagList(existingSecretEntity.getTags()))) - .thenReturn(true); + when(opaService.canDeleteSecret( + authorizedSubject, setToTagList(existingSecretEntity.getTags()))) + .thenReturn(true); storageService.deleteSecret(testSecretId, authorizedSubject); verify(secretShareDataStore, times(1)).deleteSecretShareData(testSecretId); @@ -562,7 +588,9 @@ void givenTagHasReservedKey_whenStoreTag_thenThrowIllegalArgumentException() { IllegalArgumentException iae = assertThrows( IllegalArgumentException.class, - () -> storageService.storeTag(testSecretId, testTagReservedCreationDateKey, authorizedSubject)); + () -> + storageService.storeTag( + testSecretId, testTagReservedCreationDateKey, authorizedSubject)); assertEquals( String.format(IS_RESERVED_KEY_EXCEPTION_MSG, testTagReservedCreationDateKey.getKey()), iae.getMessage()); @@ -571,23 +599,28 @@ void givenTagHasReservedKey_whenStoreTag_thenThrowIllegalArgumentException() { @Test void givenNoSecretShareWithGivenIdInDatabase_whenStoreTag_thenThrowNotFoundException() { NotFoundException nfe = - assertThrows(NotFoundException.class, () -> storageService.storeTag(testSecretId, testTag, authorizedSubject)); + assertThrows( + NotFoundException.class, + () -> storageService.storeTag(testSecretId, testTag, authorizedSubject)); assertEquals( String.format(NO_SECRET_WITH_ID_EXISTS_EXCEPTION_MSG, testSecretId), nfe.getMessage()); } @Test - void givenObjectAlreadyHasTagWithGivenKey_whenStoreTag_thenThrowAlreadyExistsException() throws CsOpaException { + void givenObjectAlreadyHasTagWithGivenKey_whenStoreTag_thenThrowAlreadyExistsException() + throws CsOpaException { SecretEntity existingSecretEntity = new SecretEntity().setSecretId(testSecretId.toString()); TagEntity existingTagEntity = TagEntity.fromTag(testTag); - when(secretEntityRepository.findById(testSecretId.toString())).thenReturn(Optional.of(existingSecretEntity)); + when(secretEntityRepository.findById(testSecretId.toString())) + .thenReturn(Optional.of(existingSecretEntity)); when(tagRepository.findBySecretAndKey(existingSecretEntity, testTag.getKey())) .thenReturn(Optional.of(existingTagEntity)); when(opaService.canCreateTags(authorizedSubject, setToTagList(existingSecretEntity.getTags()))) - .thenReturn(true); + .thenReturn(true); AlreadyExistsException aee = assertThrows( - AlreadyExistsException.class, () -> storageService.storeTag(testSecretId, testTag, authorizedSubject)); + AlreadyExistsException.class, + () -> storageService.storeTag(testSecretId, testTag, authorizedSubject)); assertEquals( String.format( TAG_WITH_KEY_EXISTS_FOR_SECRET_EXCEPTION_MSG, @@ -600,30 +633,36 @@ void givenObjectAlreadyHasTagWithGivenKey_whenStoreTag_thenThrowAlreadyExistsExc void givenSubjectHasNoAccess_whenStoreTag_thenThrowUnauthorizedException() throws CsOpaException { SecretEntity secretEntity = new SecretEntity(testSecretId.toString(), emptySet()); when(secretEntityRepository.findById(testSecretId.toString())) - .thenReturn(Optional.of(secretEntity)); + .thenReturn(Optional.of(secretEntity)); UnauthorizedException ue = - assertThrows(UnauthorizedException.class, () -> - storageService.storeTag(UUID.fromString(secretEntity.getSecretId()), testTag, authorizedSubject)); + assertThrows( + UnauthorizedException.class, + () -> + storageService.storeTag( + UUID.fromString(secretEntity.getSecretId()), testTag, authorizedSubject)); assertEquals("User is not authorized to create tags for this secret", ue.getMessage()); } @Test - void givenSuccessfulRequest_whenStoreTag_thenPersistTag() throws CsOpaException, UnauthorizedException { + void givenSuccessfulRequest_whenStoreTag_thenPersistTag() + throws CsOpaException, UnauthorizedException { SecretEntity existingSecretEntity = new SecretEntity().setSecretId(testSecretId.toString()); TagEntity expectedTagEntity = TagEntity.fromTag(testTag); ArgumentCaptor tagEntityArgumentCaptor = ArgumentCaptor.forClass(TagEntity.class); - when(secretEntityRepository.findById(testSecretId.toString())).thenReturn(Optional.of(existingSecretEntity)); + when(secretEntityRepository.findById(testSecretId.toString())) + .thenReturn(Optional.of(existingSecretEntity)); when(tagRepository.findBySecretAndKey(existingSecretEntity, testTag.getKey())) .thenReturn(Optional.empty()); when(tagRepository.save(any())).thenReturn(expectedTagEntity); when(opaService.canCreateTags(authorizedSubject, setToTagList(existingSecretEntity.getTags()))) - .thenReturn(true); + .thenReturn(true); assertEquals( expectedTagEntity.getKey(), - storageService.storeTag(UUID.fromString(existingSecretEntity.getSecretId()), testTag, authorizedSubject)); + storageService.storeTag( + UUID.fromString(existingSecretEntity.getSecretId()), testTag, authorizedSubject)); verify(tagRepository, times(1)).save(tagEntityArgumentCaptor.capture()); TagEntity actualTagEntity = tagEntityArgumentCaptor.getValue(); @@ -653,27 +692,34 @@ void givenNoSecretShareWithGivenIdInDatabase_whenReplaceTags_thenThrowNotFoundEx List emptyTags = emptyList(); NotFoundException nfe = assertThrows( - NotFoundException.class, () -> storageService.replaceTags(testSecretId, emptyTags, authorizedSubject)); + NotFoundException.class, + () -> storageService.replaceTags(testSecretId, emptyTags, authorizedSubject)); assertEquals( String.format(NO_SECRET_WITH_ID_EXISTS_EXCEPTION_MSG, testSecretId), nfe.getMessage()); } @Test - void givenSubjectHasNoAccess_whenReplaceTags_thenThrowUnauthorizedException() throws CsOpaException { + void givenSubjectHasNoAccess_whenReplaceTags_thenThrowUnauthorizedException() + throws CsOpaException { List tagListWithReservedKey = asList(testTag, testTagReservedCreationDateKey); SecretEntity secretEntity = new SecretEntity(testSecretId.toString(), emptySet()); when(secretEntityRepository.findById(testSecretId.toString())) - .thenReturn(Optional.of(secretEntity)); + .thenReturn(Optional.of(secretEntity)); UnauthorizedException ue = - assertThrows(UnauthorizedException.class, () -> - storageService.replaceTags( - UUID.fromString(secretEntity.getSecretId()), tagListWithReservedKey, authorizedSubject)); + assertThrows( + UnauthorizedException.class, + () -> + storageService.replaceTags( + UUID.fromString(secretEntity.getSecretId()), + tagListWithReservedKey, + authorizedSubject)); assertEquals("User is not authorized to update tags for this secret", ue.getMessage()); } @Test - void givenListHasTagWithReservedKey_whenReplaceTags_thenReplaceByExistingTagAndPersist() throws CsOpaException, UnauthorizedException { + void givenListHasTagWithReservedKey_whenReplaceTags_thenReplaceByExistingTagAndPersist() + throws CsOpaException, UnauthorizedException { List tagListWithReservedKey = asList(testTag, testTagReservedCreationDateKey); TagEntity existingCreationTagEntity = TagEntity.fromTag( @@ -685,14 +731,17 @@ void givenListHasTagWithReservedKey_whenReplaceTags_thenReplaceByExistingTagAndP SecretEntity existingSecretEntity = new SecretEntity(testSecretId.toString(), emptySet()); ArgumentCaptor> tagEntitySetArgumentCaptor = ArgumentCaptor.forClass(Set.class); - when(secretEntityRepository.findById(testSecretId.toString())).thenReturn(Optional.of(existingSecretEntity)); + when(secretEntityRepository.findById(testSecretId.toString())) + .thenReturn(Optional.of(existingSecretEntity)); when(tagRepository.findBySecretAndKey(existingSecretEntity, existingCreationTagEntity.getKey())) .thenReturn(Optional.of(existingCreationTagEntity)); when(opaService.canUpdateTags(authorizedSubject, setToTagList(existingSecretEntity.getTags()))) - .thenReturn(true); + .thenReturn(true); storageService.replaceTags( - UUID.fromString(existingSecretEntity.getSecretId()), tagListWithReservedKey, authorizedSubject); + UUID.fromString(existingSecretEntity.getSecretId()), + tagListWithReservedKey, + authorizedSubject); verify(tagRepository, times(1)).deleteBySecret(existingSecretEntity); verify(tagRepository, times(1)).saveAll(tagEntitySetArgumentCaptor.capture()); @@ -710,25 +759,32 @@ void givenNoSecretShareWithGivenIdInDatabase_whenRetrieveTags_thenThrowNotFoundE when(secretEntityRepository.findById(testSecretId.toString())).thenReturn(Optional.empty()); NotFoundException nfe = - assertThrows(NotFoundException.class, () -> storageService.retrieveTags(testSecretId, authorizedSubject)); + assertThrows( + NotFoundException.class, + () -> storageService.retrieveTags(testSecretId, authorizedSubject)); assertEquals( String.format(NO_SECRET_WITH_ID_EXISTS_EXCEPTION_MSG, testSecretId), nfe.getMessage()); } @Test - void givenSubjectHasNoAccess_whenRetrieveTags_thenThrowUnauthorizedException() throws CsOpaException { + void givenSubjectHasNoAccess_whenRetrieveTags_thenThrowUnauthorizedException() + throws CsOpaException { SecretEntity secretEntity = new SecretEntity(testSecretId.toString(), emptySet()); when(secretEntityRepository.findById(testSecretId.toString())) - .thenReturn(Optional.of(secretEntity)); + .thenReturn(Optional.of(secretEntity)); UnauthorizedException ue = - assertThrows(UnauthorizedException.class, () -> - storageService.retrieveTags(UUID.fromString(secretEntity.getSecretId()), authorizedSubject)); + assertThrows( + UnauthorizedException.class, + () -> + storageService.retrieveTags( + UUID.fromString(secretEntity.getSecretId()), authorizedSubject)); assertEquals("User is not authorized to read tags for this secret", ue.getMessage()); } @Test - void givenSuccessfulRequest_whenRetrieveTags_thenReturnContent() throws CsOpaException, UnauthorizedException { + void givenSuccessfulRequest_whenRetrieveTags_thenReturnContent() + throws CsOpaException, UnauthorizedException { List expectedTags = asList(testTag, testTag2); SecretEntity existingSecretEntity = new SecretEntity(testSecretId.toString(), TagEntity.setFromTagList(expectedTags)); @@ -738,7 +794,8 @@ void givenSuccessfulRequest_whenRetrieveTags_thenReturnContent() throws CsOpaExc .thenReturn(true); MatcherAssert.assertThat( - storageService.retrieveTags(UUID.fromString(existingSecretEntity.getSecretId()), authorizedSubject), + storageService.retrieveTags( + UUID.fromString(existingSecretEntity.getSecretId()), authorizedSubject), containsInAnyOrder(expectedTags.toArray())); } @@ -746,7 +803,9 @@ void givenSuccessfulRequest_whenRetrieveTags_thenReturnContent() throws CsOpaExc void givenNoSecretShareWithGivenIdInDatabase_whenRetrieveTag_thenThrowNotFoundException() { String key = testTag.getKey(); NotFoundException nfe = - assertThrows(NotFoundException.class, () -> storageService.retrieveTag(testSecretId, key, authorizedSubject)); + assertThrows( + NotFoundException.class, + () -> storageService.retrieveTag(testSecretId, key, authorizedSubject)); assertEquals( String.format(NO_SECRET_WITH_ID_EXISTS_EXCEPTION_MSG, testSecretId), nfe.getMessage()); } @@ -766,29 +825,33 @@ void givenNoTagWithGivenKeyInDatabaseForGivenObject_whenRetrieveTag_thenThrowNot } @Test - void givenSubjectHasNoAccess_whenRetrieveTag_thenThrowUnauthorizedException() throws CsOpaException { + void givenSubjectHasNoAccess_whenRetrieveTag_thenThrowUnauthorizedException() + throws CsOpaException { SecretEntity secretEntity = new SecretEntity(testSecretId.toString(), emptySet()); when(secretEntityRepository.findById(testSecretId.toString())) - .thenReturn(Optional.of(secretEntity)); + .thenReturn(Optional.of(secretEntity)); UnauthorizedException ue = - assertThrows(UnauthorizedException.class, () -> - storageService.retrieveTag(testSecretId, testTag.getKey(), authorizedSubject)); + assertThrows( + UnauthorizedException.class, + () -> storageService.retrieveTag(testSecretId, testTag.getKey(), authorizedSubject)); assertEquals("User is not authorized to read tags for this secret", ue.getMessage()); } @Test - void givenSuccessfulRequest_whenRetrieveTag_thenReturnContent() throws CsOpaException, UnauthorizedException { + void givenSuccessfulRequest_whenRetrieveTag_thenReturnContent() + throws CsOpaException, UnauthorizedException { TagEntity existingTagEntity = TagEntity.fromTag(testTag); SecretEntity existingSecretEntity = new SecretEntity(testSecretId.toString(), singleton(existingTagEntity)); when(secretEntityRepository.findById(testSecretId.toString())) - .thenReturn(Optional.of(existingSecretEntity)); + .thenReturn(Optional.of(existingSecretEntity)); when(opaService.canReadTags(authorizedSubject, setToTagList(existingSecretEntity.getTags()))) - .thenReturn(true); + .thenReturn(true); when(tagRepository.findBySecretAndKey(existingSecretEntity, existingTagEntity.getKey())) .thenReturn(Optional.of(existingTagEntity)); - assertEquals(testTag, storageService.retrieveTag(testSecretId, testTag.getKey(), authorizedSubject)); + assertEquals( + testTag, storageService.retrieveTag(testSecretId, testTag.getKey(), authorizedSubject)); } @Test @@ -796,7 +859,9 @@ void givenTagHasReservedKey_whenUpdateTag_thenThrowIllegalArgumentException() { IllegalArgumentException iae = assertThrows( IllegalArgumentException.class, - () -> storageService.updateTag(testSecretId, testTagReservedCreationDateKey, authorizedSubject)); + () -> + storageService.updateTag( + testSecretId, testTagReservedCreationDateKey, authorizedSubject)); assertEquals( String.format(IS_RESERVED_KEY_EXCEPTION_MSG, testTagReservedCreationDateKey.getKey()), iae.getMessage()); @@ -806,7 +871,8 @@ void givenTagHasReservedKey_whenUpdateTag_thenThrowIllegalArgumentException() { void givenNoSecretShareWithGivenIdInDatabase_whenUpdateTag_thenThrowNotFoundException() { NotFoundException nfe = assertThrows( - NotFoundException.class, () -> storageService.updateTag(testSecretId, testTag, authorizedSubject)); + NotFoundException.class, + () -> storageService.updateTag(testSecretId, testTag, authorizedSubject)); assertEquals( String.format(NO_SECRET_WITH_ID_EXISTS_EXCEPTION_MSG, testSecretId), nfe.getMessage()); } @@ -825,33 +891,40 @@ void givenNoTagWithGivenKeyInDatabaseForGivenObject_whenUpdateTag_thenThrowNotFo } @Test - void givenSubjectHasNoAccess_whenUpdateTag_thenThrowUnauthorizedException() throws CsOpaException { + void givenSubjectHasNoAccess_whenUpdateTag_thenThrowUnauthorizedException() + throws CsOpaException { Tag newTag = - Tag.builder().key(testTag.getKey()).value("123").valueType(TagValueType.LONG).build(); + Tag.builder().key(testTag.getKey()).value("123").valueType(TagValueType.LONG).build(); SecretEntity secretEntity = new SecretEntity(testSecretId.toString(), emptySet()); when(secretEntityRepository.findById(testSecretId.toString())) - .thenReturn(Optional.of(secretEntity)); + .thenReturn(Optional.of(secretEntity)); UnauthorizedException ue = - assertThrows(UnauthorizedException.class, () -> - storageService.updateTag(UUID.fromString(secretEntity.getSecretId()), newTag, authorizedSubject)); + assertThrows( + UnauthorizedException.class, + () -> + storageService.updateTag( + UUID.fromString(secretEntity.getSecretId()), newTag, authorizedSubject)); assertEquals("User is not authorized to update tags for this secret", ue.getMessage()); } @Test - void givenSuccessfulRequest_whenUpdateTag_thenUpdateTag() throws CsOpaException, UnauthorizedException { + void givenSuccessfulRequest_whenUpdateTag_thenUpdateTag() + throws CsOpaException, UnauthorizedException { Tag newTag = Tag.builder().key(testTag.getKey()).value("123").valueType(TagValueType.LONG).build(); TagEntity existingTagEntity = TagEntity.fromTag(testTag); SecretEntity existingSecretEntity = new SecretEntity(testSecretId.toString(), singleton(existingTagEntity)); - when(secretEntityRepository.findById(testSecretId.toString())).thenReturn(Optional.of(existingSecretEntity)); + when(secretEntityRepository.findById(testSecretId.toString())) + .thenReturn(Optional.of(existingSecretEntity)); when(tagRepository.findBySecretAndKey(existingSecretEntity, testTag.getKey())) .thenReturn(Optional.of(existingTagEntity)); when(opaService.canUpdateTags(authorizedSubject, setToTagList(existingSecretEntity.getTags()))) - .thenReturn(true); + .thenReturn(true); - storageService.updateTag(UUID.fromString(existingSecretEntity.getSecretId()), newTag, authorizedSubject); + storageService.updateTag( + UUID.fromString(existingSecretEntity.getSecretId()), newTag, authorizedSubject); ArgumentCaptor tagEntityArgumentCaptor = ArgumentCaptor.forClass(TagEntity.class); verify(tagRepository, times(1)).save(tagEntityArgumentCaptor.capture()); @@ -876,7 +949,9 @@ void givenNoSecretShareWithGivenIdInDatabase_whenDeleteTag_thenThrowNotFoundExce String key = testTag.getKey(); NotFoundException nfe = - assertThrows(NotFoundException.class, () -> storageService.deleteTag(testSecretId, key, authorizedSubject)); + assertThrows( + NotFoundException.class, + () -> storageService.deleteTag(testSecretId, key, authorizedSubject)); assertEquals( String.format(NO_SECRET_WITH_ID_EXISTS_EXCEPTION_MSG, testSecretId), nfe.getMessage()); } @@ -896,33 +971,42 @@ void givenNoTagWithGivenKeyInDatabaseForGivenObject_whenDeleteTag_thenThrowNotFo } @Test - void givenSubjectHasNoAccess_whenDeleteTag_thenThrowUnauthorizedException() throws CsOpaException { + void givenSubjectHasNoAccess_whenDeleteTag_thenThrowUnauthorizedException() + throws CsOpaException { TagEntity tagEntityToDelete = TagEntity.fromTag(testTag); SecretEntity secretEntity = new SecretEntity(testSecretId.toString(), emptySet()); when(secretEntityRepository.findById(testSecretId.toString())) - .thenReturn(Optional.of(secretEntity)); + .thenReturn(Optional.of(secretEntity)); UnauthorizedException ue = - assertThrows(UnauthorizedException.class, () -> - storageService.deleteTag( - UUID.fromString(secretEntity.getSecretId()), tagEntityToDelete.getKey(), authorizedSubject)); + assertThrows( + UnauthorizedException.class, + () -> + storageService.deleteTag( + UUID.fromString(secretEntity.getSecretId()), + tagEntityToDelete.getKey(), + authorizedSubject)); assertEquals("User is not authorized to delete tags for this secret", ue.getMessage()); } @Test - void givenSuccessfulRequest_whenDeleteTag_thenDelete() throws CsOpaException, UnauthorizedException { + void givenSuccessfulRequest_whenDeleteTag_thenDelete() + throws CsOpaException, UnauthorizedException { TagEntity tagEntityToDelete = TagEntity.fromTag(testTag); SecretEntity existingSecretEntity = new SecretEntity(testSecretId.toString(), new HashSet<>(singleton(tagEntityToDelete))); - when(secretEntityRepository.findById(testSecretId.toString())).thenReturn(Optional.of(existingSecretEntity)); + when(secretEntityRepository.findById(testSecretId.toString())) + .thenReturn(Optional.of(existingSecretEntity)); when(tagRepository.findBySecretAndKey(existingSecretEntity, tagEntityToDelete.getKey())) .thenReturn(Optional.of(tagEntityToDelete)); when(opaService.canDeleteTags(authorizedSubject, setToTagList(existingSecretEntity.getTags()))) - .thenReturn(true); + .thenReturn(true); assertEquals(1, existingSecretEntity.getTags().size()); storageService.deleteTag( - UUID.fromString(existingSecretEntity.getSecretId()), tagEntityToDelete.getKey(), authorizedSubject); + UUID.fromString(existingSecretEntity.getSecretId()), + tagEntityToDelete.getKey(), + authorizedSubject); assertEquals(0, existingSecretEntity.getTags().size()); } } diff --git a/amphora-service/src/test/java/io/carbynestack/amphora/service/rest/IntraVcpControllerTest.java b/amphora-service/src/test/java/io/carbynestack/amphora/service/rest/IntraVcpControllerTest.java index 272fac8..3bbb130 100644 --- a/amphora-service/src/test/java/io/carbynestack/amphora/service/rest/IntraVcpControllerTest.java +++ b/amphora-service/src/test/java/io/carbynestack/amphora/service/rest/IntraVcpControllerTest.java @@ -6,10 +6,18 @@ */ package io.carbynestack.amphora.service.rest; +import static io.carbynestack.amphora.common.rest.AmphoraRestApiEndpoints.INTRA_VCP_OPERATIONS_SEGMENT; +import static io.carbynestack.amphora.service.util.ServletUriComponentsBuilderUtil.runInMockedHttpRequestContextForUri; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.when; + import io.carbynestack.amphora.common.SecretShare; import io.carbynestack.amphora.service.exceptions.CsOpaException; import io.carbynestack.amphora.service.exceptions.UnauthorizedException; import io.carbynestack.amphora.service.persistence.metadata.StorageService; +import java.net.URI; +import java.util.UUID; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; @@ -18,18 +26,9 @@ import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import java.net.URI; -import java.util.UUID; - -import static io.carbynestack.amphora.common.rest.AmphoraRestApiEndpoints.INTRA_VCP_OPERATIONS_SEGMENT; -import static io.carbynestack.amphora.service.util.ServletUriComponentsBuilderUtil.runInMockedHttpRequestContextForUri; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.Mockito.when; - @ExtendWith(MockitoExtension.class) class IntraVcpControllerTest { - private final String authorizedSubjectId ="afc0117f-c9cd-4d8c-acee-fa1433ca0fdd"; + private final String authorizedSubjectId = "afc0117f-c9cd-4d8c-acee-fa1433ca0fdd"; @Mock private StorageService storageService; @@ -63,11 +62,13 @@ void givenSuccessfulRequest_whenUploadSecretShare_thenReturnCreatedWithExpectedC } @Test - void givenSuccessfulRequest_whenDownloadSecretShare_thenReturnOkWithExpectedContent() throws CsOpaException, UnauthorizedException { + void givenSuccessfulRequest_whenDownloadSecretShare_thenReturnOkWithExpectedContent() + throws CsOpaException, UnauthorizedException { UUID secretShareId = UUID.fromString("3bcf8308-8f50-4d24-a37b-b0075bb5e779"); SecretShare expectedSecretShare = SecretShare.builder().secretId(secretShareId).build(); - when(storageService.useSecretShare(secretShareId, authorizedSubjectId)).thenReturn(expectedSecretShare); + when(storageService.useSecretShare(secretShareId, authorizedSubjectId)) + .thenReturn(expectedSecretShare); ResponseEntity actualResponse = intraVcpController.downloadSecretShare(secretShareId, authorizedSubjectId); diff --git a/amphora-service/src/test/java/io/carbynestack/amphora/service/rest/MaskedInputControllerTest.java b/amphora-service/src/test/java/io/carbynestack/amphora/service/rest/MaskedInputControllerTest.java index d119967..bd55671 100644 --- a/amphora-service/src/test/java/io/carbynestack/amphora/service/rest/MaskedInputControllerTest.java +++ b/amphora-service/src/test/java/io/carbynestack/amphora/service/rest/MaskedInputControllerTest.java @@ -6,11 +6,21 @@ */ package io.carbynestack.amphora.service.rest; +import static io.carbynestack.amphora.common.rest.AmphoraRestApiEndpoints.INTRA_VCP_OPERATIONS_SEGMENT; +import static io.carbynestack.amphora.service.util.ServletUriComponentsBuilderUtil.runInMockedHttpRequestContextForUri; +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + import io.carbynestack.amphora.common.MaskedInput; import io.carbynestack.amphora.common.MaskedInputData; import io.carbynestack.amphora.service.exceptions.UnauthorizedException; import io.carbynestack.amphora.service.opa.JwtReader; import io.carbynestack.amphora.service.persistence.metadata.StorageService; +import java.net.URI; +import java.util.UUID; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -18,36 +28,29 @@ import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import java.net.URI; -import java.util.UUID; - -import static io.carbynestack.amphora.common.rest.AmphoraRestApiEndpoints.INTRA_VCP_OPERATIONS_SEGMENT; -import static io.carbynestack.amphora.service.util.ServletUriComponentsBuilderUtil.runInMockedHttpRequestContextForUri; -import static java.util.Collections.emptyList; -import static java.util.Collections.singletonList; -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - @ExtendWith(MockitoExtension.class) class MaskedInputControllerTest { - private final String authHeader = "Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6ImM5Njk0OTgyLWQzMTAtNDBkOC04ZDk4LTczOWI1ZGZjNWUyNiIsInR5cCI6IkpXVCJ9.eyJhbXIiOlsicGFzc3dvcmQiXSwiYXRfaGFzaCI6InowbjhudTNJQ19HaXN3bmFTWjgwZ2ciLCJhdWQiOlsiOGExYTIwNzUtMzY3Yi00ZGU1LTgyODgtMGMyNzQ1OTMzMmI3Il0sImF1dGhfdGltZSI6MTczMTUwMDQ0OSwiZXhwIjoxNzMxNTA0NDIyLCJpYXQiOjE3MzE1MDA4MjIsImlzcyI6Imh0dHA6Ly8xNzIuMTguMS4xMjguc3NsaXAuaW8vaWFtL29hdXRoIiwianRpIjoiZTlhMmQxYzQtZGViNy00MTgwLWE0M2YtN2QwNTZhYjNlNTk3Iiwibm9uY2UiOiJnV1JVZjhxTERaeDZpOFNhMXpMdm9IX2tSQ01OWll2WTE0WTFsLWNBU0tVIiwicmF0IjoxNzMxNTAwODIyLCJzaWQiOiJlNGVkOTc2Mi0yMmNlLTQyYzEtOTU3NC01MDVkYjAyMThhNDYiLCJzdWIiOiJhZmMwMTE3Zi1jOWNkLTRkOGMtYWNlZS1mYTE0MzNjYTBmZGQifQ.OACqa6WjpAeZbHR54b3p7saUk9plTdXlZsou41E-gfC7WxCG7ZEKfDPKXUky-r20oeIt1Ov3S2QL6Kefe5dTXEC6nhKGxeClg8ys56_FPcx_neI-p09_pSWOkMx7DHP65giaP7UubyyInVpE-2Eu1o6TpoheahNQfCahKDsJmJ-4Vvts3wA79UMfOI0WHO4vLaaG6DRAZQK_dv7ltw3p_WlncpaQAtHwY9iVhtdB3LtAI39EjplCoAF0c9uQO6W7KHWUlj24l2kc564bsJgZSrYvezw6b2-FY7YisVnicSyAORpeqhWEpLltH3D8I1NtHlSYMJhWuVZbBhAm7Iz6q1-W-Q9ttvdPchdwPSASFRkrjrdIyQf6MsFrItKzUxYck57EYL4GkyN9MWvMNxL1UTtkzGsFEczUVsJFm8OQpulYXIFZksmnPTBB0KuUUvEZ-xih8V1HsMRoHvbiCLaDJwjOFKzPevVggsSMysPKR52UAZJDZLTeHBnVCtQ3rro6T0RxNg94lXypz0AmfsGnoTF34u4FmMxzoeFZ9N5zmEpOnMRqLs7Sb3FnLL-IMitc9_2bsHuFbBJl8KbiGHBQihK5v5SIa292L7P9ChsxomWVhM29qHNFuXQMwFUr57hmveNh2Fz9mduZ5h2hLUuDf5xc6u9rSxy3_e3t_xBuUT4"; - private final String authorizedUserId ="afc0117f-c9cd-4d8c-acee-fa1433ca0fdd"; + private final String authHeader = + "Bearer" + + " eyJhbGciOiJSUzI1NiIsImtpZCI6ImM5Njk0OTgyLWQzMTAtNDBkOC04ZDk4LTczOWI1ZGZjNWUyNiIsInR5cCI6IkpXVCJ9.eyJhbXIiOlsicGFzc3dvcmQiXSwiYXRfaGFzaCI6InowbjhudTNJQ19HaXN3bmFTWjgwZ2ciLCJhdWQiOlsiOGExYTIwNzUtMzY3Yi00ZGU1LTgyODgtMGMyNzQ1OTMzMmI3Il0sImF1dGhfdGltZSI6MTczMTUwMDQ0OSwiZXhwIjoxNzMxNTA0NDIyLCJpYXQiOjE3MzE1MDA4MjIsImlzcyI6Imh0dHA6Ly8xNzIuMTguMS4xMjguc3NsaXAuaW8vaWFtL29hdXRoIiwianRpIjoiZTlhMmQxYzQtZGViNy00MTgwLWE0M2YtN2QwNTZhYjNlNTk3Iiwibm9uY2UiOiJnV1JVZjhxTERaeDZpOFNhMXpMdm9IX2tSQ01OWll2WTE0WTFsLWNBU0tVIiwicmF0IjoxNzMxNTAwODIyLCJzaWQiOiJlNGVkOTc2Mi0yMmNlLTQyYzEtOTU3NC01MDVkYjAyMThhNDYiLCJzdWIiOiJhZmMwMTE3Zi1jOWNkLTRkOGMtYWNlZS1mYTE0MzNjYTBmZGQifQ.OACqa6WjpAeZbHR54b3p7saUk9plTdXlZsou41E-gfC7WxCG7ZEKfDPKXUky-r20oeIt1Ov3S2QL6Kefe5dTXEC6nhKGxeClg8ys56_FPcx_neI-p09_pSWOkMx7DHP65giaP7UubyyInVpE-2Eu1o6TpoheahNQfCahKDsJmJ-4Vvts3wA79UMfOI0WHO4vLaaG6DRAZQK_dv7ltw3p_WlncpaQAtHwY9iVhtdB3LtAI39EjplCoAF0c9uQO6W7KHWUlj24l2kc564bsJgZSrYvezw6b2-FY7YisVnicSyAORpeqhWEpLltH3D8I1NtHlSYMJhWuVZbBhAm7Iz6q1-W-Q9ttvdPchdwPSASFRkrjrdIyQf6MsFrItKzUxYck57EYL4GkyN9MWvMNxL1UTtkzGsFEczUVsJFm8OQpulYXIFZksmnPTBB0KuUUvEZ-xih8V1HsMRoHvbiCLaDJwjOFKzPevVggsSMysPKR52UAZJDZLTeHBnVCtQ3rro6T0RxNg94lXypz0AmfsGnoTF34u4FmMxzoeFZ9N5zmEpOnMRqLs7Sb3FnLL-IMitc9_2bsHuFbBJl8KbiGHBQihK5v5SIa292L7P9ChsxomWVhM29qHNFuXQMwFUr57hmveNh2Fz9mduZ5h2hLUuDf5xc6u9rSxy3_e3t_xBuUT4"; + private final String authorizedUserId = "afc0117f-c9cd-4d8c-acee-fa1433ca0fdd"; private final StorageService storageService = mock(StorageService.class); private final JwtReader jwtReader = mock(JwtReader.class); - private final MaskedInputController maskedInputController = new MaskedInputController(storageService, jwtReader); + private final MaskedInputController maskedInputController = + new MaskedInputController(storageService, jwtReader); @BeforeEach public void setUp() throws UnauthorizedException { - when(jwtReader.extractUserIdFromAuthHeader(authHeader)).thenReturn(authorizedUserId); + when(jwtReader.extractUserIdFromAuthHeader(authHeader)).thenReturn(authorizedUserId); } @Test void givenArgumentIsNull_whenUpload_thenThrowIllegalArgumentException() { IllegalArgumentException iae = - assertThrows(IllegalArgumentException.class, () -> maskedInputController.upload(authHeader, null)); + assertThrows( + IllegalArgumentException.class, () -> maskedInputController.upload(authHeader, null)); assertEquals("MaskedInput must not be null", iae.getMessage()); } @@ -58,7 +61,8 @@ void givenMaskedInputDataIsEmpty_whenUpload_thenThrowIllegalArgumentException() IllegalArgumentException iae = assertThrows( - IllegalArgumentException.class, () -> maskedInputController.upload(authHeader, maskedInput)); + IllegalArgumentException.class, + () -> maskedInputController.upload(authHeader, maskedInput)); assertEquals("MaskedInput data must not be empty", iae.getMessage()); } @@ -72,19 +76,20 @@ void givenSuccessfulRequest_whenUpload_thenReturnCreatedWithExpectedContent() { new MaskedInput( secretShareId, singletonList(MaskedInputData.of(new byte[16])), emptyList()); - when(storageService.createSecret(maskedInput, authorizedUserId)).thenReturn(secretShareId.toString()); + when(storageService.createSecret(maskedInput, authorizedUserId)) + .thenReturn(secretShareId.toString()); runInMockedHttpRequestContextForUri( expectedUri, () -> { - ResponseEntity actualResponse = null; - try { - actualResponse = maskedInputController.upload(authHeader, maskedInput); - } catch (UnauthorizedException e) { - fail("Unexpected exception thrown", e); - } + ResponseEntity actualResponse = null; + try { + actualResponse = maskedInputController.upload(authHeader, maskedInput); + } catch (UnauthorizedException e) { + fail("Unexpected exception thrown", e); + } - assertEquals(HttpStatus.CREATED, actualResponse.getStatusCode()); + assertEquals(HttpStatus.CREATED, actualResponse.getStatusCode()); assertEquals(expectedUri, actualResponse.getBody()); }); } diff --git a/amphora-service/src/test/java/io/carbynestack/amphora/service/rest/SecretShareControllerTest.java b/amphora-service/src/test/java/io/carbynestack/amphora/service/rest/SecretShareControllerTest.java index 367d749..2ed1ba8 100644 --- a/amphora-service/src/test/java/io/carbynestack/amphora/service/rest/SecretShareControllerTest.java +++ b/amphora-service/src/test/java/io/carbynestack/amphora/service/rest/SecretShareControllerTest.java @@ -7,12 +7,23 @@ package io.carbynestack.amphora.service.rest; +import static io.carbynestack.amphora.common.TagFilterOperator.EQUALS; +import static io.carbynestack.amphora.common.TagFilterOperator.LESS_THAN; +import static io.carbynestack.amphora.common.rest.AmphoraRestApiEndpoints.CRITERIA_SEPARATOR; +import static java.util.Arrays.asList; +import static java.util.Collections.emptyList; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.*; + import io.carbynestack.amphora.common.*; import io.carbynestack.amphora.service.calculation.OutputDeliveryService; import io.carbynestack.amphora.service.exceptions.CsOpaException; import io.carbynestack.amphora.service.exceptions.UnauthorizedException; import io.carbynestack.amphora.service.opa.JwtReader; import io.carbynestack.amphora.service.persistence.metadata.StorageService; +import java.util.List; +import java.util.UUID; import lombok.SneakyThrows; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -22,33 +33,24 @@ import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import java.util.List; -import java.util.UUID; - -import static io.carbynestack.amphora.common.TagFilterOperator.EQUALS; -import static io.carbynestack.amphora.common.TagFilterOperator.LESS_THAN; -import static io.carbynestack.amphora.common.rest.AmphoraRestApiEndpoints.CRITERIA_SEPARATOR; -import static java.util.Arrays.asList; -import static java.util.Collections.emptyList; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.Mockito.*; - @ExtendWith(MockitoExtension.class) class SecretShareControllerTest { - private final String authHeader = "Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6ImM5Njk0OTgyLWQzMTAtNDBkOC04ZDk4LTczOWI1ZGZjNWUyNiIsInR5cCI6IkpXVCJ9.eyJhbXIiOlsicGFzc3dvcmQiXSwiYXRfaGFzaCI6InowbjhudTNJQ19HaXN3bmFTWjgwZ2ciLCJhdWQiOlsiOGExYTIwNzUtMzY3Yi00ZGU1LTgyODgtMGMyNzQ1OTMzMmI3Il0sImF1dGhfdGltZSI6MTczMTUwMDQ0OSwiZXhwIjoxNzMxNTA0NDIyLCJpYXQiOjE3MzE1MDA4MjIsImlzcyI6Imh0dHA6Ly8xNzIuMTguMS4xMjguc3NsaXAuaW8vaWFtL29hdXRoIiwianRpIjoiZTlhMmQxYzQtZGViNy00MTgwLWE0M2YtN2QwNTZhYjNlNTk3Iiwibm9uY2UiOiJnV1JVZjhxTERaeDZpOFNhMXpMdm9IX2tSQ01OWll2WTE0WTFsLWNBU0tVIiwicmF0IjoxNzMxNTAwODIyLCJzaWQiOiJlNGVkOTc2Mi0yMmNlLTQyYzEtOTU3NC01MDVkYjAyMThhNDYiLCJzdWIiOiJhZmMwMTE3Zi1jOWNkLTRkOGMtYWNlZS1mYTE0MzNjYTBmZGQifQ.OACqa6WjpAeZbHR54b3p7saUk9plTdXlZsou41E-gfC7WxCG7ZEKfDPKXUky-r20oeIt1Ov3S2QL6Kefe5dTXEC6nhKGxeClg8ys56_FPcx_neI-p09_pSWOkMx7DHP65giaP7UubyyInVpE-2Eu1o6TpoheahNQfCahKDsJmJ-4Vvts3wA79UMfOI0WHO4vLaaG6DRAZQK_dv7ltw3p_WlncpaQAtHwY9iVhtdB3LtAI39EjplCoAF0c9uQO6W7KHWUlj24l2kc564bsJgZSrYvezw6b2-FY7YisVnicSyAORpeqhWEpLltH3D8I1NtHlSYMJhWuVZbBhAm7Iz6q1-W-Q9ttvdPchdwPSASFRkrjrdIyQf6MsFrItKzUxYck57EYL4GkyN9MWvMNxL1UTtkzGsFEczUVsJFm8OQpulYXIFZksmnPTBB0KuUUvEZ-xih8V1HsMRoHvbiCLaDJwjOFKzPevVggsSMysPKR52UAZJDZLTeHBnVCtQ3rro6T0RxNg94lXypz0AmfsGnoTF34u4FmMxzoeFZ9N5zmEpOnMRqLs7Sb3FnLL-IMitc9_2bsHuFbBJl8KbiGHBQihK5v5SIa292L7P9ChsxomWVhM29qHNFuXQMwFUr57hmveNh2Fz9mduZ5h2hLUuDf5xc6u9rSxy3_e3t_xBuUT4"; - private final String authorizedUserId ="afc0117f-c9cd-4d8c-acee-fa1433ca0fdd"; + private final String authHeader = + "Bearer" + + " eyJhbGciOiJSUzI1NiIsImtpZCI6ImM5Njk0OTgyLWQzMTAtNDBkOC04ZDk4LTczOWI1ZGZjNWUyNiIsInR5cCI6IkpXVCJ9.eyJhbXIiOlsicGFzc3dvcmQiXSwiYXRfaGFzaCI6InowbjhudTNJQ19HaXN3bmFTWjgwZ2ciLCJhdWQiOlsiOGExYTIwNzUtMzY3Yi00ZGU1LTgyODgtMGMyNzQ1OTMzMmI3Il0sImF1dGhfdGltZSI6MTczMTUwMDQ0OSwiZXhwIjoxNzMxNTA0NDIyLCJpYXQiOjE3MzE1MDA4MjIsImlzcyI6Imh0dHA6Ly8xNzIuMTguMS4xMjguc3NsaXAuaW8vaWFtL29hdXRoIiwianRpIjoiZTlhMmQxYzQtZGViNy00MTgwLWE0M2YtN2QwNTZhYjNlNTk3Iiwibm9uY2UiOiJnV1JVZjhxTERaeDZpOFNhMXpMdm9IX2tSQ01OWll2WTE0WTFsLWNBU0tVIiwicmF0IjoxNzMxNTAwODIyLCJzaWQiOiJlNGVkOTc2Mi0yMmNlLTQyYzEtOTU3NC01MDVkYjAyMThhNDYiLCJzdWIiOiJhZmMwMTE3Zi1jOWNkLTRkOGMtYWNlZS1mYTE0MzNjYTBmZGQifQ.OACqa6WjpAeZbHR54b3p7saUk9plTdXlZsou41E-gfC7WxCG7ZEKfDPKXUky-r20oeIt1Ov3S2QL6Kefe5dTXEC6nhKGxeClg8ys56_FPcx_neI-p09_pSWOkMx7DHP65giaP7UubyyInVpE-2Eu1o6TpoheahNQfCahKDsJmJ-4Vvts3wA79UMfOI0WHO4vLaaG6DRAZQK_dv7ltw3p_WlncpaQAtHwY9iVhtdB3LtAI39EjplCoAF0c9uQO6W7KHWUlj24l2kc564bsJgZSrYvezw6b2-FY7YisVnicSyAORpeqhWEpLltH3D8I1NtHlSYMJhWuVZbBhAm7Iz6q1-W-Q9ttvdPchdwPSASFRkrjrdIyQf6MsFrItKzUxYck57EYL4GkyN9MWvMNxL1UTtkzGsFEczUVsJFm8OQpulYXIFZksmnPTBB0KuUUvEZ-xih8V1HsMRoHvbiCLaDJwjOFKzPevVggsSMysPKR52UAZJDZLTeHBnVCtQ3rro6T0RxNg94lXypz0AmfsGnoTF34u4FmMxzoeFZ9N5zmEpOnMRqLs7Sb3FnLL-IMitc9_2bsHuFbBJl8KbiGHBQihK5v5SIa292L7P9ChsxomWVhM29qHNFuXQMwFUr57hmveNh2Fz9mduZ5h2hLUuDf5xc6u9rSxy3_e3t_xBuUT4"; + private final String authorizedUserId = "afc0117f-c9cd-4d8c-acee-fa1433ca0fdd"; private final OutputDeliveryService outputDeliveryService = mock(OutputDeliveryService.class); private final StorageService storageService = mock(StorageService.class); private final JwtReader jwtReader = mock(JwtReader.class); - private final SecretShareController secretShareController = new SecretShareController(storageService, outputDeliveryService, jwtReader); + private final SecretShareController secretShareController = + new SecretShareController(storageService, outputDeliveryService, jwtReader); @BeforeEach void setUp() throws UnauthorizedException { - when(jwtReader.extractUserIdFromAuthHeader(authHeader)).thenReturn(authorizedUserId); - reset(storageService, outputDeliveryService); + when(jwtReader.extractUserIdFromAuthHeader(authHeader)).thenReturn(authorizedUserId); + reset(storageService, outputDeliveryService); } @SneakyThrows @@ -164,7 +166,8 @@ void givenRequestIdArgumentIsNull_whenGetSecretShare_thenThrowIllegalArgumentExc } @Test - void givenSuccessfulRequest_whenGetSecretShare_thenReturnOkAndExpectedContent() throws CsOpaException, UnauthorizedException { + void givenSuccessfulRequest_whenGetSecretShare_thenReturnOkAndExpectedContent() + throws CsOpaException, UnauthorizedException { UUID secretId = UUID.fromString("3bcf8308-8f50-4d24-a37b-b0075bb5e779"); UUID requestId = UUID.fromString("d6d0f4ff-df28-4c96-b7df-95170320eaee"); SecretShare secretShare = SecretShare.builder().secretId(requestId).build(); @@ -186,9 +189,11 @@ void givenSuccessfulRequest_whenGetSecretShare_thenReturnOkAndExpectedContent() } @Test - void givenSuccessfulRequest_whenDeleteSecretShare_thenReturnOk() throws UnauthorizedException, CsOpaException { + void givenSuccessfulRequest_whenDeleteSecretShare_thenReturnOk() + throws UnauthorizedException, CsOpaException { UUID secretId = UUID.fromString("3bcf8308-8f50-4d24-a37b-b0075bb5e779"); - ResponseEntity actualResponse = secretShareController.deleteSecretShare(authHeader, secretId); + ResponseEntity actualResponse = + secretShareController.deleteSecretShare(authHeader, secretId); assertEquals(HttpStatus.OK, actualResponse.getStatusCode()); } diff --git a/amphora-service/src/test/java/io/carbynestack/amphora/service/rest/TagsControllerTest.java b/amphora-service/src/test/java/io/carbynestack/amphora/service/rest/TagsControllerTest.java index 1c74aac..f96440e 100644 --- a/amphora-service/src/test/java/io/carbynestack/amphora/service/rest/TagsControllerTest.java +++ b/amphora-service/src/test/java/io/carbynestack/amphora/service/rest/TagsControllerTest.java @@ -23,9 +23,7 @@ import java.net.URI; import java.util.List; import java.util.UUID; - import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; @@ -36,8 +34,10 @@ @ExtendWith(MockitoExtension.class) class TagsControllerTest { - private final String authHeader = "Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6ImM5Njk0OTgyLWQzMTAtNDBkOC04ZDk4LTczOWI1ZGZjNWUyNiIsInR5cCI6IkpXVCJ9.eyJhbXIiOlsicGFzc3dvcmQiXSwiYXRfaGFzaCI6InowbjhudTNJQ19HaXN3bmFTWjgwZ2ciLCJhdWQiOlsiOGExYTIwNzUtMzY3Yi00ZGU1LTgyODgtMGMyNzQ1OTMzMmI3Il0sImF1dGhfdGltZSI6MTczMTUwMDQ0OSwiZXhwIjoxNzMxNTA0NDIyLCJpYXQiOjE3MzE1MDA4MjIsImlzcyI6Imh0dHA6Ly8xNzIuMTguMS4xMjguc3NsaXAuaW8vaWFtL29hdXRoIiwianRpIjoiZTlhMmQxYzQtZGViNy00MTgwLWE0M2YtN2QwNTZhYjNlNTk3Iiwibm9uY2UiOiJnV1JVZjhxTERaeDZpOFNhMXpMdm9IX2tSQ01OWll2WTE0WTFsLWNBU0tVIiwicmF0IjoxNzMxNTAwODIyLCJzaWQiOiJlNGVkOTc2Mi0yMmNlLTQyYzEtOTU3NC01MDVkYjAyMThhNDYiLCJzdWIiOiJhZmMwMTE3Zi1jOWNkLTRkOGMtYWNlZS1mYTE0MzNjYTBmZGQifQ.OACqa6WjpAeZbHR54b3p7saUk9plTdXlZsou41E-gfC7WxCG7ZEKfDPKXUky-r20oeIt1Ov3S2QL6Kefe5dTXEC6nhKGxeClg8ys56_FPcx_neI-p09_pSWOkMx7DHP65giaP7UubyyInVpE-2Eu1o6TpoheahNQfCahKDsJmJ-4Vvts3wA79UMfOI0WHO4vLaaG6DRAZQK_dv7ltw3p_WlncpaQAtHwY9iVhtdB3LtAI39EjplCoAF0c9uQO6W7KHWUlj24l2kc564bsJgZSrYvezw6b2-FY7YisVnicSyAORpeqhWEpLltH3D8I1NtHlSYMJhWuVZbBhAm7Iz6q1-W-Q9ttvdPchdwPSASFRkrjrdIyQf6MsFrItKzUxYck57EYL4GkyN9MWvMNxL1UTtkzGsFEczUVsJFm8OQpulYXIFZksmnPTBB0KuUUvEZ-xih8V1HsMRoHvbiCLaDJwjOFKzPevVggsSMysPKR52UAZJDZLTeHBnVCtQ3rro6T0RxNg94lXypz0AmfsGnoTF34u4FmMxzoeFZ9N5zmEpOnMRqLs7Sb3FnLL-IMitc9_2bsHuFbBJl8KbiGHBQihK5v5SIa292L7P9ChsxomWVhM29qHNFuXQMwFUr57hmveNh2Fz9mduZ5h2hLUuDf5xc6u9rSxy3_e3t_xBuUT4"; - private final String authorizedUserId ="afc0117f-c9cd-4d8c-acee-fa1433ca0fdd"; + private final String authHeader = + "Bearer" + + " eyJhbGciOiJSUzI1NiIsImtpZCI6ImM5Njk0OTgyLWQzMTAtNDBkOC04ZDk4LTczOWI1ZGZjNWUyNiIsInR5cCI6IkpXVCJ9.eyJhbXIiOlsicGFzc3dvcmQiXSwiYXRfaGFzaCI6InowbjhudTNJQ19HaXN3bmFTWjgwZ2ciLCJhdWQiOlsiOGExYTIwNzUtMzY3Yi00ZGU1LTgyODgtMGMyNzQ1OTMzMmI3Il0sImF1dGhfdGltZSI6MTczMTUwMDQ0OSwiZXhwIjoxNzMxNTA0NDIyLCJpYXQiOjE3MzE1MDA4MjIsImlzcyI6Imh0dHA6Ly8xNzIuMTguMS4xMjguc3NsaXAuaW8vaWFtL29hdXRoIiwianRpIjoiZTlhMmQxYzQtZGViNy00MTgwLWE0M2YtN2QwNTZhYjNlNTk3Iiwibm9uY2UiOiJnV1JVZjhxTERaeDZpOFNhMXpMdm9IX2tSQ01OWll2WTE0WTFsLWNBU0tVIiwicmF0IjoxNzMxNTAwODIyLCJzaWQiOiJlNGVkOTc2Mi0yMmNlLTQyYzEtOTU3NC01MDVkYjAyMThhNDYiLCJzdWIiOiJhZmMwMTE3Zi1jOWNkLTRkOGMtYWNlZS1mYTE0MzNjYTBmZGQifQ.OACqa6WjpAeZbHR54b3p7saUk9plTdXlZsou41E-gfC7WxCG7ZEKfDPKXUky-r20oeIt1Ov3S2QL6Kefe5dTXEC6nhKGxeClg8ys56_FPcx_neI-p09_pSWOkMx7DHP65giaP7UubyyInVpE-2Eu1o6TpoheahNQfCahKDsJmJ-4Vvts3wA79UMfOI0WHO4vLaaG6DRAZQK_dv7ltw3p_WlncpaQAtHwY9iVhtdB3LtAI39EjplCoAF0c9uQO6W7KHWUlj24l2kc564bsJgZSrYvezw6b2-FY7YisVnicSyAORpeqhWEpLltH3D8I1NtHlSYMJhWuVZbBhAm7Iz6q1-W-Q9ttvdPchdwPSASFRkrjrdIyQf6MsFrItKzUxYck57EYL4GkyN9MWvMNxL1UTtkzGsFEczUVsJFm8OQpulYXIFZksmnPTBB0KuUUvEZ-xih8V1HsMRoHvbiCLaDJwjOFKzPevVggsSMysPKR52UAZJDZLTeHBnVCtQ3rro6T0RxNg94lXypz0AmfsGnoTF34u4FmMxzoeFZ9N5zmEpOnMRqLs7Sb3FnLL-IMitc9_2bsHuFbBJl8KbiGHBQihK5v5SIa292L7P9ChsxomWVhM29qHNFuXQMwFUr57hmveNh2Fz9mduZ5h2hLUuDf5xc6u9rSxy3_e3t_xBuUT4"; + private final String authorizedUserId = "afc0117f-c9cd-4d8c-acee-fa1433ca0fdd"; private final UUID testSecretId = UUID.fromString("3bcf8308-8f50-4d24-a37b-b0075bb5e779"); private final Tag testTag = Tag.builder().key("key").value("value").valueType(TagValueType.STRING).build(); @@ -48,7 +48,8 @@ class TagsControllerTest { @InjectMocks private TagsController tagsController; @Test - void givenSuccessfulRequest_whenGetTags_thenReturnOkWithExpectedContent() throws UnauthorizedException, CsOpaException { + void givenSuccessfulRequest_whenGetTags_thenReturnOkWithExpectedContent() + throws UnauthorizedException, CsOpaException { List expectedList = singletonList(testTag); when(jwtReader.extractUserIdFromAuthHeader(authHeader)).thenReturn(authorizedUserId); @@ -60,16 +61,19 @@ void givenSuccessfulRequest_whenGetTags_thenReturnOkWithExpectedContent() throws } @Test - void givenTagIsNull_whenCreateTag_thenThrowIllegalArgumentException() throws CsOpaException, UnauthorizedException { + void givenTagIsNull_whenCreateTag_thenThrowIllegalArgumentException() + throws CsOpaException, UnauthorizedException { IllegalArgumentException iae = assertThrows( - IllegalArgumentException.class, () -> tagsController.createTag(authHeader, testSecretId, null)); + IllegalArgumentException.class, + () -> tagsController.createTag(authHeader, testSecretId, null)); verify(storageService, never()).storeTag(any(), any(), eq(authorizedUserId)); assertEquals("Tag must not be empty", iae.getMessage()); } @Test - void givenSuccessfulRequest_whenCreateTag_thenReturnCreatedWithExpectedContent() throws UnauthorizedException, CsOpaException { + void givenSuccessfulRequest_whenCreateTag_thenReturnCreatedWithExpectedContent() + throws UnauthorizedException, CsOpaException { URI expectedUri = URI.create( "https://amphora.carbynestack.io" + INTRA_VCP_OPERATIONS_SEGMENT + "/" + testSecretId); @@ -79,12 +83,12 @@ void givenSuccessfulRequest_whenCreateTag_thenReturnCreatedWithExpectedContent() runInMockedHttpRequestContextForUri( expectedUri, () -> { - ResponseEntity actualResponse = null; - try { - actualResponse = tagsController.createTag(authHeader, testSecretId, testTag); - } catch (UnauthorizedException | CsOpaException e) { - Assertions.fail("unexpected exception thrown: " + e); - } + ResponseEntity actualResponse = null; + try { + actualResponse = tagsController.createTag(authHeader, testSecretId, testTag); + } catch (UnauthorizedException | CsOpaException e) { + Assertions.fail("unexpected exception thrown: " + e); + } assertEquals(HttpStatus.CREATED, actualResponse.getStatusCode()); assertEquals(expectedUri, actualResponse.getBody()); }); @@ -93,7 +97,8 @@ void givenSuccessfulRequest_whenCreateTag_thenReturnCreatedWithExpectedContent() } @Test - void givenTagsAreEmpty_whenUpdateTags_thenThrowIllegalArgumentException() throws CsOpaException, UnauthorizedException { + void givenTagsAreEmpty_whenUpdateTags_thenThrowIllegalArgumentException() + throws CsOpaException, UnauthorizedException { List emptyTags = emptyList(); IllegalArgumentException iae = assertThrows( @@ -104,38 +109,46 @@ void givenTagsAreEmpty_whenUpdateTags_thenThrowIllegalArgumentException() throws } @Test - void givenSuccessfulRequest_whenUpdateTags_thenReturnCreatedWithExpectedContent() throws UnauthorizedException, CsOpaException { + void givenSuccessfulRequest_whenUpdateTags_thenReturnCreatedWithExpectedContent() + throws UnauthorizedException, CsOpaException { List newTagList = singletonList(testTag); when(jwtReader.extractUserIdFromAuthHeader(authHeader)).thenReturn(authorizedUserId); - ResponseEntity actualResponse = tagsController.updateTags(authHeader, testSecretId, newTagList); + ResponseEntity actualResponse = + tagsController.updateTags(authHeader, testSecretId, newTagList); verify(storageService, times(1)).replaceTags(testSecretId, newTagList, authorizedUserId); assertEquals(HttpStatus.OK, actualResponse.getStatusCode()); } @Test - void givenSuccessfulRequest_whenGetTag_thenReturnOkWithExpectedContent() throws UnauthorizedException, CsOpaException { + void givenSuccessfulRequest_whenGetTag_thenReturnOkWithExpectedContent() + throws UnauthorizedException, CsOpaException { when(jwtReader.extractUserIdFromAuthHeader(authHeader)).thenReturn(authorizedUserId); - when(storageService.retrieveTag(testSecretId, testTag.getKey(), authorizedUserId)).thenReturn(testTag); + when(storageService.retrieveTag(testSecretId, testTag.getKey(), authorizedUserId)) + .thenReturn(testTag); - ResponseEntity actualResponse = tagsController.getTag(authHeader, testSecretId, testTag.getKey()); + ResponseEntity actualResponse = + tagsController.getTag(authHeader, testSecretId, testTag.getKey()); assertEquals(HttpStatus.OK, actualResponse.getStatusCode()); assertEquals(testTag, actualResponse.getBody()); } @Test - void givenTagIsNull_whenPutTag_thenTrowIllegalArgumentException() throws CsOpaException, UnauthorizedException { + void givenTagIsNull_whenPutTag_thenTrowIllegalArgumentException() + throws CsOpaException, UnauthorizedException { String key = testTag.getKey(); IllegalArgumentException iae = assertThrows( - IllegalArgumentException.class, () -> tagsController.putTag(authHeader, testSecretId, key, null)); + IllegalArgumentException.class, + () -> tagsController.putTag(authHeader, testSecretId, key, null)); verify(storageService, never()).updateTag(testSecretId, testTag, authorizedUserId); assertEquals("Tag must not be empty", iae.getMessage()); } @Test - void givenTagConfigurationDoesNotMatchAddressedKey_whenPutTag_thenTrowIllegalArgumentException() throws CsOpaException, UnauthorizedException { + void givenTagConfigurationDoesNotMatchAddressedKey_whenPutTag_thenTrowIllegalArgumentException() + throws CsOpaException, UnauthorizedException { String nonMatchingKey = testTag.getKey() + "_different"; IllegalArgumentException iae = assertThrows( @@ -149,7 +162,8 @@ void givenTagConfigurationDoesNotMatchAddressedKey_whenPutTag_thenTrowIllegalArg } @Test - void givenSuccessfulRequest_whenPutTag_thenReturnOk() throws UnauthorizedException, CsOpaException { + void givenSuccessfulRequest_whenPutTag_thenReturnOk() + throws UnauthorizedException, CsOpaException { when(jwtReader.extractUserIdFromAuthHeader(authHeader)).thenReturn(authorizedUserId); ResponseEntity actualResponse = @@ -159,10 +173,12 @@ void givenSuccessfulRequest_whenPutTag_thenReturnOk() throws UnauthorizedExcepti } @Test - void givenSuccessfulRequest_whenDeleteTag_thenReturnOk() throws UnauthorizedException, CsOpaException { + void givenSuccessfulRequest_whenDeleteTag_thenReturnOk() + throws UnauthorizedException, CsOpaException { when(jwtReader.extractUserIdFromAuthHeader(authHeader)).thenReturn(authorizedUserId); - ResponseEntity actualResponse = tagsController.deleteTag(authHeader, testSecretId, testTag.getKey()); + ResponseEntity actualResponse = + tagsController.deleteTag(authHeader, testSecretId, testTag.getKey()); verify(storageService, times(1)).deleteTag(testSecretId, testTag.getKey(), authorizedUserId); assertEquals(HttpStatus.OK, actualResponse.getStatusCode()); } diff --git a/amphora-service/src/test/resources/application-test.properties b/amphora-service/src/test/resources/application-test.properties index dedf86d..5531c64 100644 --- a/amphora-service/src/test/resources/application-test.properties +++ b/amphora-service/src/test/resources/application-test.properties @@ -13,7 +13,7 @@ spring.datasource.username=${POSTGRESQL_USERNAME} spring.datasource.password=${POSTGRESQL_PASSWORD} spring.jpa.database=postgresql spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect -spring.jpa.hi.hibernate.connection.autocommit=true +spring.jpa.hibernate.connection.autocommit=true spring.jpa.hibernate.ddl-auto=update spring.jpa.hibernate.hbm2ddl.auto=update diff --git a/amphora-service/src/test/resources/redis.conf b/amphora-service/src/test/resources/redis.conf index ae3a97d..1dafdb1 100644 --- a/amphora-service/src/test/resources/redis.conf +++ b/amphora-service/src/test/resources/redis.conf @@ -197,4 +197,4 @@ aof-load-truncated yes # # This is currently turned off by default in order to avoid the surprise # of a format change, but will at some point be used as the default. -aof-use-rdb-preamble no \ No newline at end of file +aof-use-rdb-preamble no