From b2fe0d25dc4c913ee406941037962ddfbe4a177a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20James=20Toussaint?= Date: Tue, 28 Jun 2022 15:10:17 +0200 Subject: [PATCH 001/293] Import latest common snapshot --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 0bc97ed4..21154a17 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ version=7.0.0 -iexecCommonVersion=5.9.3-NEXT-SNAPSHOT +iexecCommonVersion=7.0.0-NEXT-SNAPSHOT nexusUser= nexusPassword= From 438b661720b06d5b38bd3179dfc141ecd6be7ffd Mon Sep 17 00:00:00 2001 From: maxence Date: Mon, 11 Jul 2022 14:22:05 +0200 Subject: [PATCH 002/293] Add tasks [should be removed later] --- gramine.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 gramine.md diff --git a/gramine.md b/gramine.md new file mode 100644 index 00000000..6114cca5 --- /dev/null +++ b/gramine.md @@ -0,0 +1,28 @@ +# What should change in SMS to add Gramine feature? + +## Architecture + +- Move `com.iexec.sms.tee.session.[attestation|cas|palaemon]` package to `com.iexec.sms.tee.session.scone`. + +## Code +### `TeeController` class + +#### `generateTeeSession` method + +- Signature should get a new `OrderTag` parameter (in `WorkerpoolAuthorization`?) + +### `TeeSessionService` class + +#### `generateTeeSession` method + +- Signature should get a new `OrderTag` parameter + +### `PalaemonSessionService` class + +- Should be generified to provide a single secret filler service + +### `TeeWorkflowConfiguration` class + +- Rename all `preCompute[...]` and `postCompute[...]` fields to `sconePreCompute[...]` and `sconePostCompute[...]`. +- Add `graminePreCompute[...]` and `graminePostCompute[...]` fields. +- These changes should be made in `application.yml` too. \ No newline at end of file From 002165b4868cf25fc09a2adfb573132dcd9191d2 Mon Sep 17 00:00:00 2001 From: maxence Date: Mon, 11 Jul 2022 14:25:39 +0200 Subject: [PATCH 003/293] Move scone packages --- .../java/com/iexec/sms/tee/session/TeeSessionService.java | 6 +++--- .../attestation/AttestationSecurityConfig.java | 2 +- .../iexec/sms/tee/session/{ => scone}/cas/CasClient.java | 2 +- .../sms/tee/session/{ => scone}/cas/CasConfiguration.java | 2 +- .../{ => scone}/cas/CasConfigurationController.java | 2 +- .../{ => scone}/palaemon/PalaemonSessionRequest.java | 2 +- .../{ => scone}/palaemon/PalaemonSessionService.java | 4 ++-- .../com/iexec/sms/tee/session/TeeSessionServiceTests.java | 4 ++-- .../{ => scone}/palaemon/PalaemonSessionServiceTests.java | 8 +++++--- 9 files changed, 17 insertions(+), 15 deletions(-) rename src/main/java/com/iexec/sms/tee/session/{ => scone}/attestation/AttestationSecurityConfig.java (95%) rename src/main/java/com/iexec/sms/tee/session/{ => scone}/cas/CasClient.java (97%) rename src/main/java/com/iexec/sms/tee/session/{ => scone}/cas/CasConfiguration.java (97%) rename src/main/java/com/iexec/sms/tee/session/{ => scone}/cas/CasConfigurationController.java (96%) rename src/main/java/com/iexec/sms/tee/session/{ => scone}/palaemon/PalaemonSessionRequest.java (95%) rename src/main/java/com/iexec/sms/tee/session/{ => scone}/palaemon/PalaemonSessionService.java (99%) rename src/test/java/com/iexec/sms/tee/session/{ => scone}/palaemon/PalaemonSessionServiceTests.java (99%) diff --git a/src/main/java/com/iexec/sms/tee/session/TeeSessionService.java b/src/main/java/com/iexec/sms/tee/session/TeeSessionService.java index 22f552ea..bc75245f 100644 --- a/src/main/java/com/iexec/sms/tee/session/TeeSessionService.java +++ b/src/main/java/com/iexec/sms/tee/session/TeeSessionService.java @@ -18,9 +18,9 @@ import com.iexec.common.task.TaskDescription; import com.iexec.sms.blockchain.IexecHubService; -import com.iexec.sms.tee.session.cas.CasClient; -import com.iexec.sms.tee.session.palaemon.PalaemonSessionRequest; -import com.iexec.sms.tee.session.palaemon.PalaemonSessionService; +import com.iexec.sms.tee.session.scone.cas.CasClient; +import com.iexec.sms.tee.session.scone.palaemon.PalaemonSessionRequest; +import com.iexec.sms.tee.session.scone.palaemon.PalaemonSessionService; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.RandomStringUtils; import org.springframework.beans.factory.annotation.Value; diff --git a/src/main/java/com/iexec/sms/tee/session/attestation/AttestationSecurityConfig.java b/src/main/java/com/iexec/sms/tee/session/scone/attestation/AttestationSecurityConfig.java similarity index 95% rename from src/main/java/com/iexec/sms/tee/session/attestation/AttestationSecurityConfig.java rename to src/main/java/com/iexec/sms/tee/session/scone/attestation/AttestationSecurityConfig.java index ca750cb1..5f8b1720 100644 --- a/src/main/java/com/iexec/sms/tee/session/attestation/AttestationSecurityConfig.java +++ b/src/main/java/com/iexec/sms/tee/session/scone/attestation/AttestationSecurityConfig.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.iexec.sms.tee.session.attestation; +package com.iexec.sms.tee.session.scone.attestation; import lombok.Getter; import org.springframework.beans.factory.annotation.Value; diff --git a/src/main/java/com/iexec/sms/tee/session/cas/CasClient.java b/src/main/java/com/iexec/sms/tee/session/scone/cas/CasClient.java similarity index 97% rename from src/main/java/com/iexec/sms/tee/session/cas/CasClient.java rename to src/main/java/com/iexec/sms/tee/session/scone/cas/CasClient.java index acffcda3..08ad6d28 100644 --- a/src/main/java/com/iexec/sms/tee/session/cas/CasClient.java +++ b/src/main/java/com/iexec/sms/tee/session/scone/cas/CasClient.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.iexec.sms.tee.session.cas; +package com.iexec.sms.tee.session.scone.cas; import com.iexec.sms.ssl.TwoWaySslClient; import org.springframework.http.HttpEntity; diff --git a/src/main/java/com/iexec/sms/tee/session/cas/CasConfiguration.java b/src/main/java/com/iexec/sms/tee/session/scone/cas/CasConfiguration.java similarity index 97% rename from src/main/java/com/iexec/sms/tee/session/cas/CasConfiguration.java rename to src/main/java/com/iexec/sms/tee/session/scone/cas/CasConfiguration.java index f471b6ef..dd8f971f 100644 --- a/src/main/java/com/iexec/sms/tee/session/cas/CasConfiguration.java +++ b/src/main/java/com/iexec/sms/tee/session/scone/cas/CasConfiguration.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.iexec.sms.tee.session.cas; +package com.iexec.sms.tee.session.scone.cas; import lombok.AllArgsConstructor; import lombok.Getter; diff --git a/src/main/java/com/iexec/sms/tee/session/cas/CasConfigurationController.java b/src/main/java/com/iexec/sms/tee/session/scone/cas/CasConfigurationController.java similarity index 96% rename from src/main/java/com/iexec/sms/tee/session/cas/CasConfigurationController.java rename to src/main/java/com/iexec/sms/tee/session/scone/cas/CasConfigurationController.java index cfe8dfd5..758f9498 100644 --- a/src/main/java/com/iexec/sms/tee/session/cas/CasConfigurationController.java +++ b/src/main/java/com/iexec/sms/tee/session/scone/cas/CasConfigurationController.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.iexec.sms.tee.session.cas; +package com.iexec.sms.tee.session.scone.cas; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; diff --git a/src/main/java/com/iexec/sms/tee/session/palaemon/PalaemonSessionRequest.java b/src/main/java/com/iexec/sms/tee/session/scone/palaemon/PalaemonSessionRequest.java similarity index 95% rename from src/main/java/com/iexec/sms/tee/session/palaemon/PalaemonSessionRequest.java rename to src/main/java/com/iexec/sms/tee/session/scone/palaemon/PalaemonSessionRequest.java index 16c5b86a..2c08ada7 100644 --- a/src/main/java/com/iexec/sms/tee/session/palaemon/PalaemonSessionRequest.java +++ b/src/main/java/com/iexec/sms/tee/session/scone/palaemon/PalaemonSessionRequest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.iexec.sms.tee.session.palaemon; +package com.iexec.sms.tee.session.scone.palaemon; import com.iexec.common.task.TaskDescription; import lombok.AllArgsConstructor; diff --git a/src/main/java/com/iexec/sms/tee/session/palaemon/PalaemonSessionService.java b/src/main/java/com/iexec/sms/tee/session/scone/palaemon/PalaemonSessionService.java similarity index 99% rename from src/main/java/com/iexec/sms/tee/session/palaemon/PalaemonSessionService.java rename to src/main/java/com/iexec/sms/tee/session/scone/palaemon/PalaemonSessionService.java index d273976e..ab966d92 100644 --- a/src/main/java/com/iexec/sms/tee/session/palaemon/PalaemonSessionService.java +++ b/src/main/java/com/iexec/sms/tee/session/scone/palaemon/PalaemonSessionService.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.iexec.sms.tee.session.palaemon; +package com.iexec.sms.tee.session.scone.palaemon; import com.iexec.common.sms.secret.ReservedSecretKeyName; import com.iexec.common.task.TaskDescription; @@ -31,7 +31,7 @@ import com.iexec.sms.tee.challenge.TeeChallenge; import com.iexec.sms.tee.challenge.TeeChallengeService; import com.iexec.sms.tee.session.TeeSessionGenerationException; -import com.iexec.sms.tee.session.attestation.AttestationSecurityConfig; +import com.iexec.sms.tee.session.scone.attestation.AttestationSecurityConfig; import com.iexec.sms.tee.workflow.TeeWorkflowConfiguration; import com.iexec.sms.utils.EthereumCredentials; import lombok.extern.slf4j.Slf4j; diff --git a/src/test/java/com/iexec/sms/tee/session/TeeSessionServiceTests.java b/src/test/java/com/iexec/sms/tee/session/TeeSessionServiceTests.java index 30225d59..17dff49e 100644 --- a/src/test/java/com/iexec/sms/tee/session/TeeSessionServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/TeeSessionServiceTests.java @@ -2,8 +2,8 @@ import com.iexec.common.task.TaskDescription; import com.iexec.sms.blockchain.IexecHubService; -import com.iexec.sms.tee.session.cas.CasClient; -import com.iexec.sms.tee.session.palaemon.PalaemonSessionService; +import com.iexec.sms.tee.session.scone.cas.CasClient; +import com.iexec.sms.tee.session.scone.palaemon.PalaemonSessionService; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.Mock; diff --git a/src/test/java/com/iexec/sms/tee/session/palaemon/PalaemonSessionServiceTests.java b/src/test/java/com/iexec/sms/tee/session/scone/palaemon/PalaemonSessionServiceTests.java similarity index 99% rename from src/test/java/com/iexec/sms/tee/session/palaemon/PalaemonSessionServiceTests.java rename to src/test/java/com/iexec/sms/tee/session/scone/palaemon/PalaemonSessionServiceTests.java index feb11146..efceabff 100644 --- a/src/test/java/com/iexec/sms/tee/session/palaemon/PalaemonSessionServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/scone/palaemon/PalaemonSessionServiceTests.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.iexec.sms.tee.session.palaemon; +package com.iexec.sms.tee.session.scone.palaemon; import com.iexec.common.precompute.PreComputeUtils; import com.iexec.common.sms.secret.ReservedSecretKeyName; @@ -36,7 +36,9 @@ import com.iexec.sms.tee.challenge.TeeChallenge; import com.iexec.sms.tee.challenge.TeeChallengeService; import com.iexec.sms.tee.session.TeeSessionGenerationException; -import com.iexec.sms.tee.session.attestation.AttestationSecurityConfig; +import com.iexec.sms.tee.session.scone.attestation.AttestationSecurityConfig; +import com.iexec.sms.tee.session.scone.palaemon.PalaemonSessionRequest; +import com.iexec.sms.tee.session.scone.palaemon.PalaemonSessionService; import com.iexec.sms.tee.workflow.TeeWorkflowConfiguration; import com.iexec.sms.utils.EthereumCredentials; import lombok.extern.slf4j.Slf4j; @@ -61,7 +63,7 @@ import static com.iexec.common.worker.result.ResultUtils.*; import static com.iexec.sms.Web3jUtils.createEthereumAddress; import static com.iexec.sms.api.TeeSessionGenerationError.*; -import static com.iexec.sms.tee.session.palaemon.PalaemonSessionService.*; +import static com.iexec.sms.tee.session.scone.palaemon.PalaemonSessionService.*; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; From cf09aa5e1e5223612c66d6842fbb00d243534767 Mon Sep 17 00:00:00 2001 From: maxence Date: Mon, 11 Jul 2022 16:30:32 +0200 Subject: [PATCH 004/293] Split `PalaemonSessionService` into common and Scone specific code --- .../sms/tee/session/TeeSecretsService.java | 408 +++++++++ ...est.java => TeeSecretsSessionRequest.java} | 4 +- .../sms/tee/session/TeeSessionService.java | 3 +- .../palaemon/PalaemonSessionService.java | 381 +-------- .../tee/session/TeeSecretsServiceTests.java | 723 ++++++++++++++++ .../sms/tee/session/TeeSessionTestUtils.java | 196 +++++ .../palaemon/PalaemonSessionServiceTests.java | 779 +----------------- 7 files changed, 1384 insertions(+), 1110 deletions(-) create mode 100644 src/main/java/com/iexec/sms/tee/session/TeeSecretsService.java rename src/main/java/com/iexec/sms/tee/session/{scone/palaemon/PalaemonSessionRequest.java => TeeSecretsSessionRequest.java} (91%) create mode 100644 src/test/java/com/iexec/sms/tee/session/TeeSecretsServiceTests.java create mode 100644 src/test/java/com/iexec/sms/tee/session/TeeSessionTestUtils.java diff --git a/src/main/java/com/iexec/sms/tee/session/TeeSecretsService.java b/src/main/java/com/iexec/sms/tee/session/TeeSecretsService.java new file mode 100644 index 00000000..4de5dbb2 --- /dev/null +++ b/src/main/java/com/iexec/sms/tee/session/TeeSecretsService.java @@ -0,0 +1,408 @@ +/* + * Copyright 2022 IEXEC BLOCKCHAIN TECH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.iexec.sms.tee.session; + +import com.iexec.common.sms.secret.ReservedSecretKeyName; +import com.iexec.common.task.TaskDescription; +import com.iexec.common.tee.TeeEnclaveConfiguration; +import com.iexec.common.utils.IexecEnvUtils; +import com.iexec.sms.secret.Secret; +import com.iexec.sms.secret.compute.OnChainObjectType; +import com.iexec.sms.secret.compute.SecretOwnerRole; +import com.iexec.sms.secret.compute.TeeTaskComputeSecret; +import com.iexec.sms.secret.compute.TeeTaskComputeSecretService; +import com.iexec.sms.secret.web2.Web2SecretsService; +import com.iexec.sms.secret.web3.Web3SecretService; +import com.iexec.sms.tee.challenge.TeeChallenge; +import com.iexec.sms.tee.challenge.TeeChallengeService; +import com.iexec.sms.tee.workflow.TeeWorkflowConfiguration; +import com.iexec.sms.utils.EthereumCredentials; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +import static com.iexec.common.chain.DealParams.DROPBOX_RESULT_STORAGE_PROVIDER; +import static com.iexec.common.precompute.PreComputeUtils.IEXEC_DATASET_KEY; +import static com.iexec.common.precompute.PreComputeUtils.IS_DATASET_REQUIRED; +import static com.iexec.common.sms.secret.ReservedSecretKeyName.IEXEC_RESULT_ENCRYPTION_PUBLIC_KEY; +import static com.iexec.common.tee.TeeUtils.booleanToYesNo; +import static com.iexec.common.worker.result.ResultUtils.*; +import static com.iexec.sms.api.TeeSessionGenerationError.*; + +@Slf4j +@Service +public class TeeSecretsService { + + public static final String EMPTY_YML_VALUE = ""; + + // Generic + static final String SESSION_ID = "SESSION_ID"; + static final String INPUT_FILE_URLS = "INPUT_FILE_URLS"; + static final String INPUT_FILE_NAMES = "INPUT_FILE_NAMES"; + // PreCompute + static final String IS_PRE_COMPUTE_REQUIRED = "IS_PRE_COMPUTE_REQUIRED"; + static final String PRE_COMPUTE_MRENCLAVE = "PRE_COMPUTE_MRENCLAVE"; + // Compute + static final String APP_MRENCLAVE = "APP_MRENCLAVE"; + // PostCompute + static final String POST_COMPUTE_MRENCLAVE = "POST_COMPUTE_MRENCLAVE"; + // Secrets + static final String REQUESTER_SECRETS = "REQUESTER_SECRETS"; + // Env + private static final String ENV_PROPERTY = "env"; + + private final Web3SecretService web3SecretService; + private final Web2SecretsService web2SecretsService; + private final TeeChallengeService teeChallengeService; + private final TeeWorkflowConfiguration teeWorkflowConfig; + private final TeeTaskComputeSecretService teeTaskComputeSecretService; + + public TeeSecretsService( + Web3SecretService web3SecretService, + Web2SecretsService web2SecretsService, + TeeChallengeService teeChallengeService, + TeeWorkflowConfiguration teeWorkflowConfig, + TeeTaskComputeSecretService teeTaskComputeSecretService) { + this.web3SecretService = web3SecretService; + this.web2SecretsService = web2SecretsService; + this.teeChallengeService = teeChallengeService; + this.teeWorkflowConfig = teeWorkflowConfig; + this.teeTaskComputeSecretService = teeTaskComputeSecretService; + } + + /** + * Collect tokens required for different compute stages (pre, in, post). + * + * @param request session request details + * @return All common tokens for a session, whatever TEE technology is used + */ + public Map getSecretsTokens(TeeSecretsSessionRequest request) throws TeeSessionGenerationException { + if (request == null) { + throw new TeeSessionGenerationException( + NO_SESSION_REQUEST, + "Session request must not be null" + ); + } + if (request.getTaskDescription() == null) { + throw new TeeSessionGenerationException( + NO_TASK_DESCRIPTION, + "Task description must not be null" + ); + } + + TaskDescription taskDescription = request.getTaskDescription(); + Map secretsTokens = new HashMap<>(); + secretsTokens.put(SESSION_ID, request.getSessionId()); + // pre-compute + boolean isPreComputeRequired = taskDescription.containsDataset() || + !taskDescription.getInputFiles().isEmpty(); + secretsTokens.put(IS_PRE_COMPUTE_REQUIRED, isPreComputeRequired); + if (isPreComputeRequired) { + secretsTokens.putAll(getPreComputeTokens(request)); + } + // app + secretsTokens.putAll(getAppTokens(request)); + // post compute + secretsTokens.putAll(getPostComputeTokens(request)); + // env variables + Map env = IexecEnvUtils.getAllIexecEnv(taskDescription); + // Null value should be replaced by an empty string. + env.forEach((key, value) -> env.replace(key, null, EMPTY_YML_VALUE)); + secretsTokens.put(ENV_PROPERTY, env); + + return secretsTokens; + } + + /** + * Get tokens to be injected in the pre-compute enclave. + * + * @return map of pre-compute tokens + * @throws TeeSessionGenerationException if dataset secret is not found. + */ + public Map getPreComputeTokens(TeeSecretsSessionRequest request) + throws TeeSessionGenerationException { + TaskDescription taskDescription = request.getTaskDescription(); + String taskId = taskDescription.getChainTaskId(); + Map tokens = new HashMap<>(); + String fingerprint = teeWorkflowConfig.getPreComputeFingerprint(); + tokens.put(PRE_COMPUTE_MRENCLAVE, fingerprint); + tokens.put(IS_DATASET_REQUIRED, taskDescription.containsDataset()); + tokens.put(IEXEC_DATASET_KEY, EMPTY_YML_VALUE); + if (taskDescription.containsDataset()) { + String datasetKey = web3SecretService + .getSecret(taskDescription.getDatasetAddress(), true) + .orElseThrow(() -> new TeeSessionGenerationException( + PRE_COMPUTE_GET_DATASET_SECRET_FAILED, + "Empty dataset secret - taskId: " + taskId + )) + .getTrimmedValue(); + tokens.put(IEXEC_DATASET_KEY, datasetKey); + } else { + log.info("No dataset key needed for this task [taskId:{}]", taskId); + } + // extract + // this map will be empty (not null) if no input file is found + Map inputFileUrls = IexecEnvUtils.getAllIexecEnv(taskDescription) + .entrySet() + .stream() + .filter(e -> e.getKey().contains(IexecEnvUtils.IEXEC_INPUT_FILE_URL_PREFIX)) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + tokens.put(INPUT_FILE_URLS, inputFileUrls); + return tokens; + } + + /* + * Compute (App) + */ + public Map getAppTokens(TeeSecretsSessionRequest request) + throws TeeSessionGenerationException{ + TaskDescription taskDescription = request.getTaskDescription(); + if (taskDescription == null) { + throw new TeeSessionGenerationException( + NO_TASK_DESCRIPTION, + "Task description must no be null" + ); + } + + Map tokens = new HashMap<>(); + TeeEnclaveConfiguration enclaveConfig = taskDescription.getAppEnclaveConfiguration(); + if (enclaveConfig == null) { + throw new TeeSessionGenerationException( + APP_COMPUTE_NO_ENCLAVE_CONFIG, + "Enclave configuration must no be null" + ); + } + if (!enclaveConfig.getValidator().isValid()){ + throw new TeeSessionGenerationException( + APP_COMPUTE_INVALID_ENCLAVE_CONFIG, + "Invalid enclave configuration: " + + enclaveConfig.getValidator().validate().toString() + ); + } + + tokens.put(APP_MRENCLAVE, enclaveConfig.getFingerprint()); + // extract + // this map will be empty (not null) if no input file is found + Map inputFileNames = IexecEnvUtils.getComputeStageEnvMap(taskDescription) + .entrySet() + .stream() + .filter(e -> e.getKey().contains(IexecEnvUtils.IEXEC_INPUT_FILE_NAME_PREFIX)) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + tokens.put(INPUT_FILE_NAMES, inputFileNames); + + final Map computeSecrets = getApplicationComputeSecrets(taskDescription); + tokens.putAll(computeSecrets); + + return tokens; + } + + private Map getApplicationComputeSecrets(TaskDescription taskDescription) { + final Map tokens = new HashMap<>(); + final String applicationAddress = taskDescription.getAppAddress(); + + if (applicationAddress != null) { + final String secretIndex = "1"; + String appDeveloperSecret = + teeTaskComputeSecretService.getSecret( + OnChainObjectType.APPLICATION, + applicationAddress.toLowerCase(), + SecretOwnerRole.APPLICATION_DEVELOPER, + "", + secretIndex) + .map(TeeTaskComputeSecret::getValue) + .orElse(EMPTY_YML_VALUE); + tokens.put(IexecEnvUtils.IEXEC_APP_DEVELOPER_SECRET_PREFIX + secretIndex, appDeveloperSecret); + } + + if (taskDescription.getSecrets() == null || taskDescription.getRequester() == null) { + tokens.put(REQUESTER_SECRETS, Collections.emptyMap()); + return tokens; + } + + final HashMap requesterSecrets = new HashMap<>(); + for (Map.Entry secretEntry: taskDescription.getSecrets().entrySet()) { + try { + int requesterSecretIndex = Integer.parseInt(secretEntry.getKey()); + if (requesterSecretIndex <= 0) { + String message = "Application secret indices provided in the deal parameters must be positive numbers" + + " [providedApplicationSecretIndex:" + requesterSecretIndex + "]"; + log.warn(message); + throw new NumberFormatException(message); + } + } catch(NumberFormatException e) { + log.warn("Invalid entry found in deal parameters secrets map", e); + continue; + } + String requesterSecret = teeTaskComputeSecretService.getSecret( + OnChainObjectType.APPLICATION, + "", + SecretOwnerRole.REQUESTER, + taskDescription.getRequester().toLowerCase(), + secretEntry.getValue()) + .map(TeeTaskComputeSecret::getValue) + .orElse(EMPTY_YML_VALUE); + requesterSecrets.put(IexecEnvUtils.IEXEC_REQUESTER_SECRET_PREFIX + secretEntry.getKey(), requesterSecret); + } + tokens.put(REQUESTER_SECRETS, requesterSecrets); + + return tokens; + } + + /* + * Post-Compute (Result) + */ + public Map getPostComputeTokens(TeeSecretsSessionRequest request) + throws TeeSessionGenerationException { + TaskDescription taskDescription = request.getTaskDescription(); + if (taskDescription == null) { + throw new TeeSessionGenerationException(NO_TASK_DESCRIPTION, "Task description must not be null"); + } + + Map tokens = new HashMap<>(); + String teePostComputeFingerprint = teeWorkflowConfig.getPostComputeFingerprint(); + // ############################################################################### + // TODO: activate this when user specific post-compute is properly + // supported. See https://github.com/iExecBlockchainComputing/iexec-sms/issues/52. + // ############################################################################### + // // Use specific post-compute image if requested. + //if (taskDescription.containsPostCompute()) { + // teePostComputeFingerprint = taskDescription.getTeePostComputeFingerprint(); + // //add entrypoint too + //} + tokens.put(POST_COMPUTE_MRENCLAVE, teePostComputeFingerprint); + // encryption + Map encryptionTokens = getPostComputeEncryptionTokens(request); + tokens.putAll(encryptionTokens); + // storage + Map storageTokens = getPostComputeStorageTokens(request); + tokens.putAll(storageTokens); + // enclave signature + Map signTokens = getPostComputeSignTokens(request); + tokens.putAll(signTokens); + return tokens; + } + + Map getPostComputeEncryptionTokens(TeeSecretsSessionRequest request) + throws TeeSessionGenerationException { + TaskDescription taskDescription = request.getTaskDescription(); + String taskId = taskDescription.getChainTaskId(); + Map tokens = new HashMap<>(); + boolean shouldEncrypt = taskDescription.isResultEncryption(); + // TODO use boolean with quotes instead of yes/no + tokens.put(RESULT_ENCRYPTION, booleanToYesNo(shouldEncrypt)); + tokens.put(RESULT_ENCRYPTION_PUBLIC_KEY, EMPTY_YML_VALUE); + if (!shouldEncrypt) { + return tokens; + } + Optional beneficiaryResultEncryptionKeySecret = web2SecretsService.getSecret( + taskDescription.getBeneficiary(), + IEXEC_RESULT_ENCRYPTION_PUBLIC_KEY, + true); + if (beneficiaryResultEncryptionKeySecret.isEmpty()) { + throw new TeeSessionGenerationException( + POST_COMPUTE_GET_ENCRYPTION_TOKENS_FAILED_EMPTY_BENEFICIARY_KEY, + "Empty beneficiary encryption key - taskId: " + taskId + ); + } + String publicKeyValue = beneficiaryResultEncryptionKeySecret.get().getTrimmedValue(); + tokens.put(RESULT_ENCRYPTION_PUBLIC_KEY, publicKeyValue); // base64 encoded by client + return tokens; + } + + // TODO: We need a signature of the beneficiary to push + // to the beneficiary private storage space waiting for + // that feature we only allow to push to the requester + // private storage space + Map getPostComputeStorageTokens(TeeSecretsSessionRequest request) + throws TeeSessionGenerationException { + TaskDescription taskDescription = request.getTaskDescription(); + String taskId = taskDescription.getChainTaskId(); + Map tokens = new HashMap<>(); + boolean isCallbackRequested = taskDescription.containsCallback(); + tokens.put(RESULT_STORAGE_CALLBACK, booleanToYesNo(isCallbackRequested)); + tokens.put(RESULT_STORAGE_PROVIDER, EMPTY_YML_VALUE); + tokens.put(RESULT_STORAGE_PROXY, EMPTY_YML_VALUE); + tokens.put(RESULT_STORAGE_TOKEN, EMPTY_YML_VALUE); + if (isCallbackRequested) { + return tokens; + } + String storageProvider = taskDescription.getResultStorageProvider(); + String storageProxy = taskDescription.getResultStorageProxy(); + String keyName = storageProvider.equals(DROPBOX_RESULT_STORAGE_PROVIDER) + ? ReservedSecretKeyName.IEXEC_RESULT_DROPBOX_TOKEN + : ReservedSecretKeyName.IEXEC_RESULT_IEXEC_IPFS_TOKEN; + Optional requesterStorageTokenSecret = + web2SecretsService.getSecret(taskDescription.getRequester(), keyName, true); + if (requesterStorageTokenSecret.isEmpty()) { + log.error("Failed to get storage token [taskId:{}, storageProvider:{}, requester:{}]", + taskId, storageProvider, taskDescription.getRequester()); + throw new TeeSessionGenerationException( + POST_COMPUTE_GET_STORAGE_TOKENS_FAILED, + "Empty requester storage token - taskId: " + taskId); + } + String requesterStorageToken = requesterStorageTokenSecret.get().getTrimmedValue(); + tokens.put(RESULT_STORAGE_PROVIDER, storageProvider); + tokens.put(RESULT_STORAGE_PROXY, storageProxy); + tokens.put(RESULT_STORAGE_TOKEN, requesterStorageToken); + return tokens; + } + + Map getPostComputeSignTokens(TeeSecretsSessionRequest request) + throws TeeSessionGenerationException { + String taskId = request.getTaskDescription().getChainTaskId(); + String workerAddress = request.getWorkerAddress(); + Map tokens = new HashMap<>(); + if (StringUtils.isEmpty(workerAddress)) { + throw new TeeSessionGenerationException( + POST_COMPUTE_GET_SIGNATURE_TOKENS_FAILED_EMPTY_WORKER_ADDRESS, + "Empty worker address - taskId: " + taskId + ); + } + if (StringUtils.isEmpty(request.getEnclaveChallenge())) { + throw new TeeSessionGenerationException( + POST_COMPUTE_GET_SIGNATURE_TOKENS_FAILED_EMPTY_PUBLIC_ENCLAVE_CHALLENGE, + "Empty public enclave challenge - taskId: " + taskId + ); + } + Optional teeChallenge = teeChallengeService.getOrCreate(taskId, true); + if (teeChallenge.isEmpty()) { + throw new TeeSessionGenerationException( + POST_COMPUTE_GET_SIGNATURE_TOKENS_FAILED_EMPTY_TEE_CHALLENGE, + "Empty TEE challenge - taskId: " + taskId + ); + } + EthereumCredentials enclaveCredentials = teeChallenge.get().getCredentials(); + if (enclaveCredentials == null || enclaveCredentials.getPrivateKey().isEmpty()) { + throw new TeeSessionGenerationException( + POST_COMPUTE_GET_SIGNATURE_TOKENS_FAILED_EMPTY_TEE_CREDENTIALS, + "Empty TEE challenge credentials - taskId: " + taskId + ); + } + tokens.put(RESULT_TASK_ID, taskId); + tokens.put(RESULT_SIGN_WORKER_ADDRESS, workerAddress); + tokens.put(RESULT_SIGN_TEE_CHALLENGE_PRIVATE_KEY, enclaveCredentials.getPrivateKey()); + return tokens; + } + +} diff --git a/src/main/java/com/iexec/sms/tee/session/scone/palaemon/PalaemonSessionRequest.java b/src/main/java/com/iexec/sms/tee/session/TeeSecretsSessionRequest.java similarity index 91% rename from src/main/java/com/iexec/sms/tee/session/scone/palaemon/PalaemonSessionRequest.java rename to src/main/java/com/iexec/sms/tee/session/TeeSecretsSessionRequest.java index 2c08ada7..8423f637 100644 --- a/src/main/java/com/iexec/sms/tee/session/scone/palaemon/PalaemonSessionRequest.java +++ b/src/main/java/com/iexec/sms/tee/session/TeeSecretsSessionRequest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.iexec.sms.tee.session.scone.palaemon; +package com.iexec.sms.tee.session; import com.iexec.common.task.TaskDescription; import lombok.AllArgsConstructor; @@ -26,7 +26,7 @@ @Builder @NoArgsConstructor @AllArgsConstructor -public class PalaemonSessionRequest { +public class TeeSecretsSessionRequest { private String sessionId; private TaskDescription taskDescription; diff --git a/src/main/java/com/iexec/sms/tee/session/TeeSessionService.java b/src/main/java/com/iexec/sms/tee/session/TeeSessionService.java index bc75245f..f985127d 100644 --- a/src/main/java/com/iexec/sms/tee/session/TeeSessionService.java +++ b/src/main/java/com/iexec/sms/tee/session/TeeSessionService.java @@ -19,7 +19,6 @@ import com.iexec.common.task.TaskDescription; import com.iexec.sms.blockchain.IexecHubService; import com.iexec.sms.tee.session.scone.cas.CasClient; -import com.iexec.sms.tee.session.scone.palaemon.PalaemonSessionRequest; import com.iexec.sms.tee.session.scone.palaemon.PalaemonSessionService; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.RandomStringUtils; @@ -62,7 +61,7 @@ public String generateTeeSession( String.format("Failed to get task description [taskId:%s]", taskId) ); } - PalaemonSessionRequest request = PalaemonSessionRequest.builder() + TeeSecretsSessionRequest request = TeeSecretsSessionRequest.builder() .sessionId(sessionId) .taskDescription(taskDescription) .workerAddress(workerAddress) diff --git a/src/main/java/com/iexec/sms/tee/session/scone/palaemon/PalaemonSessionService.java b/src/main/java/com/iexec/sms/tee/session/scone/palaemon/PalaemonSessionService.java index ab966d92..60c8b521 100644 --- a/src/main/java/com/iexec/sms/tee/session/scone/palaemon/PalaemonSessionService.java +++ b/src/main/java/com/iexec/sms/tee/session/scone/palaemon/PalaemonSessionService.java @@ -16,24 +16,14 @@ package com.iexec.sms.tee.session.scone.palaemon; -import com.iexec.common.sms.secret.ReservedSecretKeyName; import com.iexec.common.task.TaskDescription; import com.iexec.common.tee.TeeEnclaveConfiguration; import com.iexec.common.utils.FileHelper; -import com.iexec.common.utils.IexecEnvUtils; -import com.iexec.sms.secret.Secret; -import com.iexec.sms.secret.compute.OnChainObjectType; -import com.iexec.sms.secret.compute.SecretOwnerRole; -import com.iexec.sms.secret.compute.TeeTaskComputeSecret; -import com.iexec.sms.secret.compute.TeeTaskComputeSecretService; -import com.iexec.sms.secret.web2.Web2SecretsService; -import com.iexec.sms.secret.web3.Web3SecretService; -import com.iexec.sms.tee.challenge.TeeChallenge; -import com.iexec.sms.tee.challenge.TeeChallengeService; +import com.iexec.sms.tee.session.TeeSecretsService; +import com.iexec.sms.tee.session.TeeSecretsSessionRequest; import com.iexec.sms.tee.session.TeeSessionGenerationException; import com.iexec.sms.tee.session.scone.attestation.AttestationSecurityConfig; import com.iexec.sms.tee.workflow.TeeWorkflowConfiguration; -import com.iexec.sms.utils.EthereumCredentials; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.apache.velocity.Template; @@ -45,71 +35,38 @@ import javax.annotation.PostConstruct; import java.io.FileNotFoundException; import java.io.StringWriter; -import java.util.Collections; import java.util.HashMap; import java.util.Map; -import java.util.Optional; -import java.util.stream.Collectors; - -import static com.iexec.common.chain.DealParams.DROPBOX_RESULT_STORAGE_PROVIDER; -import static com.iexec.common.precompute.PreComputeUtils.IEXEC_DATASET_KEY; -import static com.iexec.common.precompute.PreComputeUtils.IS_DATASET_REQUIRED; -import static com.iexec.common.sms.secret.ReservedSecretKeyName.IEXEC_RESULT_ENCRYPTION_PUBLIC_KEY; -import static com.iexec.common.tee.TeeUtils.booleanToYesNo; -import static com.iexec.common.worker.result.ResultUtils.*; -import static com.iexec.sms.api.TeeSessionGenerationError.*; @Slf4j @Service public class PalaemonSessionService { - public static final String EMPTY_YML_VALUE = ""; - // Internal values required for setting up a palaemon session // Generic - static final String SESSION_ID = "SESSION_ID"; - static final String INPUT_FILE_URLS = "INPUT_FILE_URLS"; - static final String INPUT_FILE_NAMES = "INPUT_FILE_NAMES"; static final String TOLERATED_INSECURE_OPTIONS = "TOLERATED_INSECURE_OPTIONS"; static final String IGNORED_SGX_ADVISORIES = "IGNORED_SGX_ADVISORIES"; + static final String APP_ARGS = "APP_ARGS"; + // PreCompute - static final String IS_PRE_COMPUTE_REQUIRED = "IS_PRE_COMPUTE_REQUIRED"; - static final String PRE_COMPUTE_MRENCLAVE = "PRE_COMPUTE_MRENCLAVE"; static final String PRE_COMPUTE_ENTRYPOINT = "PRE_COMPUTE_ENTRYPOINT"; - // Compute - static final String APP_MRENCLAVE = "APP_MRENCLAVE"; - static final String APP_ARGS = "APP_ARGS"; // PostCompute - static final String POST_COMPUTE_MRENCLAVE = "POST_COMPUTE_MRENCLAVE"; static final String POST_COMPUTE_ENTRYPOINT = "POST_COMPUTE_ENTRYPOINT"; - // Secrets - static final String REQUESTER_SECRETS = "REQUESTER_SECRETS"; - // Env - private static final String ENV_PROPERTY = "env"; - private final Web3SecretService web3SecretService; - private final Web2SecretsService web2SecretsService; - private final TeeChallengeService teeChallengeService; + private final TeeSecretsService teeSecretsService; private final TeeWorkflowConfiguration teeWorkflowConfig; private final AttestationSecurityConfig attestationSecurityConfig; - private final TeeTaskComputeSecretService teeTaskComputeSecretService; @Value("${scone.cas.palaemon}") private String palaemonTemplateFilePath; public PalaemonSessionService( - Web3SecretService web3SecretService, - Web2SecretsService web2SecretsService, - TeeChallengeService teeChallengeService, + TeeSecretsService teeSecretsService, TeeWorkflowConfiguration teeWorkflowConfig, - AttestationSecurityConfig attestationSecurityConfig, - TeeTaskComputeSecretService teeTaskComputeSecretService) { - this.web3SecretService = web3SecretService; - this.web2SecretsService = web2SecretsService; - this.teeChallengeService = teeChallengeService; + AttestationSecurityConfig attestationSecurityConfig) { + this.teeSecretsService = teeSecretsService; this.teeWorkflowConfig = teeWorkflowConfig; this.attestationSecurityConfig = attestationSecurityConfig; - this.teeTaskComputeSecretService = teeTaskComputeSecretService; } @PostConstruct @@ -133,330 +90,40 @@ void postConstruct() throws FileNotFoundException { * @param request session request details * @return session config in yaml string format */ - public String getSessionYml(PalaemonSessionRequest request) throws TeeSessionGenerationException { - if (request == null) { - throw new TeeSessionGenerationException( - NO_SESSION_REQUEST, - "Session request must not be null" - ); - } - if (request.getTaskDescription() == null) { - throw new TeeSessionGenerationException( - NO_TASK_DESCRIPTION, - "Task description must not be null" - ); - } + public String getSessionYml(TeeSecretsSessionRequest request) throws TeeSessionGenerationException { + Map tokens = teeSecretsService.getSecretsTokens(request); + tokens.putAll(getSpecificPalaemonTokens(request)); + // Merge template with tokens and return the result + return getFilledPalaemonTemplate(this.palaemonTemplateFilePath, tokens); + } + + Map getSpecificPalaemonTokens(TeeSecretsSessionRequest request) { + Map tokens = new HashMap<>(); + + // Add entrypoints + tokens.put(PRE_COMPUTE_ENTRYPOINT, teeWorkflowConfig.getPreComputeEntrypoint()); + tokens.put(POST_COMPUTE_ENTRYPOINT, teeWorkflowConfig.getPostComputeEntrypoint()); - TaskDescription taskDescription = request.getTaskDescription(); - Map palaemonTokens = new HashMap<>(); - palaemonTokens.put(SESSION_ID, request.getSessionId()); - // pre-compute - boolean isPreComputeRequired = taskDescription.containsDataset() || - !taskDescription.getInputFiles().isEmpty(); - palaemonTokens.put(IS_PRE_COMPUTE_REQUIRED, isPreComputeRequired); - if (isPreComputeRequired) { - palaemonTokens.putAll(getPreComputePalaemonTokens(request)); - } - // app - palaemonTokens.putAll(getAppPalaemonTokens(request)); - // post compute - palaemonTokens.putAll(getPostComputePalaemonTokens(request)); - // env variables - Map env = IexecEnvUtils.getAllIexecEnv(taskDescription); - // Null value should be replaced by an empty string. - env.forEach((key, value) -> env.replace(key, null, EMPTY_YML_VALUE)); - palaemonTokens.put(ENV_PROPERTY, env); // Add attestation security config String toleratedInsecureOptions = String.join(",", attestationSecurityConfig.getToleratedInsecureOptions()); String ignoredSgxAdvisories = String.join(",", attestationSecurityConfig.getIgnoredSgxAdvisories()); - palaemonTokens.put(TOLERATED_INSECURE_OPTIONS, toleratedInsecureOptions); - palaemonTokens.put(IGNORED_SGX_ADVISORIES, ignoredSgxAdvisories); - // Merge template with tokens and return the result - return getFilledPalaemonTemplate(this.palaemonTemplateFilePath, palaemonTokens); - } + tokens.put(TOLERATED_INSECURE_OPTIONS, toleratedInsecureOptions); + tokens.put(IGNORED_SGX_ADVISORIES, ignoredSgxAdvisories); - /** - * Get tokens to be injected in the pre-compute enclave. - * - * @return map of pre-compute tokens - * @throws TeeSessionGenerationException if dataset secret is not found. - */ - Map getPreComputePalaemonTokens(PalaemonSessionRequest request) - throws TeeSessionGenerationException { + // Add app args TaskDescription taskDescription = request.getTaskDescription(); - String taskId = taskDescription.getChainTaskId(); - Map tokens = new HashMap<>(); - String fingerprint = teeWorkflowConfig.getPreComputeFingerprint(); - tokens.put(PRE_COMPUTE_MRENCLAVE, fingerprint); - String entrypoint = teeWorkflowConfig.getPreComputeEntrypoint(); - tokens.put(PRE_COMPUTE_ENTRYPOINT, entrypoint); - tokens.put(IS_DATASET_REQUIRED, taskDescription.containsDataset()); - tokens.put(IEXEC_DATASET_KEY, EMPTY_YML_VALUE); - if (taskDescription.containsDataset()) { - String datasetKey = web3SecretService - .getSecret(taskDescription.getDatasetAddress(), true) - .orElseThrow(() -> new TeeSessionGenerationException( - PRE_COMPUTE_GET_DATASET_SECRET_FAILED, - "Empty dataset secret - taskId: " + taskId - )) - .getTrimmedValue(); - tokens.put(IEXEC_DATASET_KEY, datasetKey); - } else { - log.info("No dataset key needed for this task [taskId:{}]", taskId); - } - // extract - // this map will be empty (not null) if no input file is found - Map inputFileUrls = IexecEnvUtils.getAllIexecEnv(taskDescription) - .entrySet() - .stream() - .filter(e -> e.getKey().contains(IexecEnvUtils.IEXEC_INPUT_FILE_URL_PREFIX)) - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); - tokens.put(INPUT_FILE_URLS, inputFileUrls); - return tokens; - } - - /* - * Compute (App) - */ - Map getAppPalaemonTokens(PalaemonSessionRequest request) - throws TeeSessionGenerationException{ - TaskDescription taskDescription = request.getTaskDescription(); - if (taskDescription == null) { - throw new TeeSessionGenerationException( - NO_TASK_DESCRIPTION, - "Task description must no be null" - ); - } - - Map tokens = new HashMap<>(); TeeEnclaveConfiguration enclaveConfig = taskDescription.getAppEnclaveConfiguration(); - if (enclaveConfig == null) { - throw new TeeSessionGenerationException( - APP_COMPUTE_NO_ENCLAVE_CONFIG, - "Enclave configuration must no be null" - ); - } - if (!enclaveConfig.getValidator().isValid()){ - throw new TeeSessionGenerationException( - APP_COMPUTE_INVALID_ENCLAVE_CONFIG, - "Invalid enclave configuration: " + - enclaveConfig.getValidator().validate().toString() - ); - } - - tokens.put(APP_MRENCLAVE, enclaveConfig.getFingerprint()); String appArgs = enclaveConfig.getEntrypoint(); if (!StringUtils.isEmpty(taskDescription.getCmd())) { appArgs = appArgs + " " + taskDescription.getCmd(); } tokens.put(APP_ARGS, appArgs); - // extract - // this map will be empty (not null) if no input file is found - Map inputFileNames = IexecEnvUtils.getComputeStageEnvMap(taskDescription) - .entrySet() - .stream() - .filter(e -> e.getKey().contains(IexecEnvUtils.IEXEC_INPUT_FILE_NAME_PREFIX)) - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); - tokens.put(INPUT_FILE_NAMES, inputFileNames); - - final Map computeSecrets = getApplicationComputeSecrets(taskDescription); - tokens.putAll(computeSecrets); return tokens; } - private Map getApplicationComputeSecrets(TaskDescription taskDescription) { - final Map tokens = new HashMap<>(); - final String applicationAddress = taskDescription.getAppAddress(); - - if (applicationAddress != null) { - final String secretIndex = "1"; - String appDeveloperSecret = - teeTaskComputeSecretService.getSecret( - OnChainObjectType.APPLICATION, - applicationAddress.toLowerCase(), - SecretOwnerRole.APPLICATION_DEVELOPER, - "", - secretIndex) - .map(TeeTaskComputeSecret::getValue) - .orElse(EMPTY_YML_VALUE); - tokens.put(IexecEnvUtils.IEXEC_APP_DEVELOPER_SECRET_PREFIX + secretIndex, appDeveloperSecret); - } - - if (taskDescription.getSecrets() == null || taskDescription.getRequester() == null) { - tokens.put(REQUESTER_SECRETS, Collections.emptyMap()); - return tokens; - } - - final HashMap requesterSecrets = new HashMap<>(); - for (Map.Entry secretEntry: taskDescription.getSecrets().entrySet()) { - try { - int requesterSecretIndex = Integer.parseInt(secretEntry.getKey()); - if (requesterSecretIndex <= 0) { - String message = "Application secret indices provided in the deal parameters must be positive numbers" - + " [providedApplicationSecretIndex:" + requesterSecretIndex + "]"; - log.warn(message); - throw new NumberFormatException(message); - } - } catch(NumberFormatException e) { - log.warn("Invalid entry found in deal parameters secrets map", e); - continue; - } - String requesterSecret = teeTaskComputeSecretService.getSecret( - OnChainObjectType.APPLICATION, - "", - SecretOwnerRole.REQUESTER, - taskDescription.getRequester().toLowerCase(), - secretEntry.getValue()) - .map(TeeTaskComputeSecret::getValue) - .orElse(EMPTY_YML_VALUE); - requesterSecrets.put(IexecEnvUtils.IEXEC_REQUESTER_SECRET_PREFIX + secretEntry.getKey(), requesterSecret); - } - tokens.put(REQUESTER_SECRETS, requesterSecrets); - - return tokens; - } - - /* - * Post-Compute (Result) - */ - Map getPostComputePalaemonTokens(PalaemonSessionRequest request) - throws TeeSessionGenerationException { - TaskDescription taskDescription = request.getTaskDescription(); - if (taskDescription == null) { - throw new TeeSessionGenerationException(NO_TASK_DESCRIPTION, "Task description must not be null"); - } - - Map tokens = new HashMap<>(); - String teePostComputeFingerprint = teeWorkflowConfig.getPostComputeFingerprint(); - // ############################################################################### - // TODO: activate this when user specific post-compute is properly - // supported. See https://github.com/iExecBlockchainComputing/iexec-sms/issues/52. - // ############################################################################### - // // Use specific post-compute image if requested. - //if (taskDescription.containsPostCompute()) { - // teePostComputeFingerprint = taskDescription.getTeePostComputeFingerprint(); - // //add entrypoint too - //} - tokens.put(POST_COMPUTE_MRENCLAVE, teePostComputeFingerprint); - String entrypoint = teeWorkflowConfig.getPostComputeEntrypoint(); - tokens.put(POST_COMPUTE_ENTRYPOINT, entrypoint); - // encryption - Map encryptionTokens = getPostComputeEncryptionTokens(request); - tokens.putAll(encryptionTokens); - // storage - Map storageTokens = getPostComputeStorageTokens(request); - tokens.putAll(storageTokens); - // enclave signature - Map signTokens = getPostComputeSignTokens(request); - tokens.putAll(signTokens); - return tokens; - } - - Map getPostComputeEncryptionTokens(PalaemonSessionRequest request) - throws TeeSessionGenerationException { - TaskDescription taskDescription = request.getTaskDescription(); - String taskId = taskDescription.getChainTaskId(); - Map tokens = new HashMap<>(); - boolean shouldEncrypt = taskDescription.isResultEncryption(); - // TODO use boolean with quotes instead of yes/no - tokens.put(RESULT_ENCRYPTION, booleanToYesNo(shouldEncrypt)); - tokens.put(RESULT_ENCRYPTION_PUBLIC_KEY, EMPTY_YML_VALUE); - if (!shouldEncrypt) { - return tokens; - } - Optional beneficiaryResultEncryptionKeySecret = web2SecretsService.getSecret( - taskDescription.getBeneficiary(), - IEXEC_RESULT_ENCRYPTION_PUBLIC_KEY, - true); - if (beneficiaryResultEncryptionKeySecret.isEmpty()) { - throw new TeeSessionGenerationException( - POST_COMPUTE_GET_ENCRYPTION_TOKENS_FAILED_EMPTY_BENEFICIARY_KEY, - "Empty beneficiary encryption key - taskId: " + taskId - ); - } - String publicKeyValue = beneficiaryResultEncryptionKeySecret.get().getTrimmedValue(); - tokens.put(RESULT_ENCRYPTION_PUBLIC_KEY, publicKeyValue); // base64 encoded by client - return tokens; - } - - // TODO: We need a signature of the beneficiary to push - // to the beneficiary private storage space waiting for - // that feature we only allow to push to the requester - // private storage space - Map getPostComputeStorageTokens(PalaemonSessionRequest request) - throws TeeSessionGenerationException { - TaskDescription taskDescription = request.getTaskDescription(); - String taskId = taskDescription.getChainTaskId(); - Map tokens = new HashMap<>(); - boolean isCallbackRequested = taskDescription.containsCallback(); - tokens.put(RESULT_STORAGE_CALLBACK, booleanToYesNo(isCallbackRequested)); - tokens.put(RESULT_STORAGE_PROVIDER, EMPTY_YML_VALUE); - tokens.put(RESULT_STORAGE_PROXY, EMPTY_YML_VALUE); - tokens.put(RESULT_STORAGE_TOKEN, EMPTY_YML_VALUE); - if (isCallbackRequested) { - return tokens; - } - String storageProvider = taskDescription.getResultStorageProvider(); - String storageProxy = taskDescription.getResultStorageProxy(); - String keyName = storageProvider.equals(DROPBOX_RESULT_STORAGE_PROVIDER) - ? ReservedSecretKeyName.IEXEC_RESULT_DROPBOX_TOKEN - : ReservedSecretKeyName.IEXEC_RESULT_IEXEC_IPFS_TOKEN; - Optional requesterStorageTokenSecret = - web2SecretsService.getSecret(taskDescription.getRequester(), keyName, true); - if (requesterStorageTokenSecret.isEmpty()) { - log.error("Failed to get storage token [taskId:{}, storageProvider:{}, requester:{}]", - taskId, storageProvider, taskDescription.getRequester()); - throw new TeeSessionGenerationException( - POST_COMPUTE_GET_STORAGE_TOKENS_FAILED, - "Empty requester storage token - taskId: " + taskId); - } - String requesterStorageToken = requesterStorageTokenSecret.get().getTrimmedValue(); - tokens.put(RESULT_STORAGE_PROVIDER, storageProvider); - tokens.put(RESULT_STORAGE_PROXY, storageProxy); - tokens.put(RESULT_STORAGE_TOKEN, requesterStorageToken); - return tokens; - } - - Map getPostComputeSignTokens(PalaemonSessionRequest request) - throws TeeSessionGenerationException { - String taskId = request.getTaskDescription().getChainTaskId(); - String workerAddress = request.getWorkerAddress(); - Map tokens = new HashMap<>(); - if (StringUtils.isEmpty(workerAddress)) { - throw new TeeSessionGenerationException( - POST_COMPUTE_GET_SIGNATURE_TOKENS_FAILED_EMPTY_WORKER_ADDRESS, - "Empty worker address - taskId: " + taskId - ); - } - if (StringUtils.isEmpty(request.getEnclaveChallenge())) { - throw new TeeSessionGenerationException( - POST_COMPUTE_GET_SIGNATURE_TOKENS_FAILED_EMPTY_PUBLIC_ENCLAVE_CHALLENGE, - "Empty public enclave challenge - taskId: " + taskId - ); - } - Optional teeChallenge = teeChallengeService.getOrCreate(taskId, true); - if (teeChallenge.isEmpty()) { - throw new TeeSessionGenerationException( - POST_COMPUTE_GET_SIGNATURE_TOKENS_FAILED_EMPTY_TEE_CHALLENGE, - "Empty TEE challenge - taskId: " + taskId - ); - } - EthereumCredentials enclaveCredentials = teeChallenge.get().getCredentials(); - if (enclaveCredentials == null || enclaveCredentials.getPrivateKey().isEmpty()) { - throw new TeeSessionGenerationException( - POST_COMPUTE_GET_SIGNATURE_TOKENS_FAILED_EMPTY_TEE_CREDENTIALS, - "Empty TEE challenge credentials - taskId: " + taskId - ); - } - tokens.put(RESULT_TASK_ID, taskId); - tokens.put(RESULT_SIGN_WORKER_ADDRESS, workerAddress); - tokens.put(RESULT_SIGN_TEE_CHALLENGE_PRIVATE_KEY, enclaveCredentials.getPrivateKey()); - return tokens; - } - private String getFilledPalaemonTemplate(String templatePath, Map tokens) { VelocityEngine ve = new VelocityEngine(); ve.init(); diff --git a/src/test/java/com/iexec/sms/tee/session/TeeSecretsServiceTests.java b/src/test/java/com/iexec/sms/tee/session/TeeSecretsServiceTests.java new file mode 100644 index 00000000..20677951 --- /dev/null +++ b/src/test/java/com/iexec/sms/tee/session/TeeSecretsServiceTests.java @@ -0,0 +1,723 @@ +package com.iexec.sms.tee.session; + +import com.iexec.common.precompute.PreComputeUtils; +import com.iexec.common.sms.secret.ReservedSecretKeyName; +import com.iexec.common.task.TaskDescription; +import com.iexec.common.tee.TeeEnclaveConfiguration; +import com.iexec.common.tee.TeeEnclaveConfigurationValidator; +import com.iexec.common.utils.IexecEnvUtils; +import com.iexec.common.worker.result.ResultUtils; +import com.iexec.sms.api.TeeSessionGenerationError; +import com.iexec.sms.secret.Secret; +import com.iexec.sms.secret.compute.OnChainObjectType; +import com.iexec.sms.secret.compute.SecretOwnerRole; +import com.iexec.sms.secret.compute.TeeTaskComputeSecret; +import com.iexec.sms.secret.compute.TeeTaskComputeSecretService; +import com.iexec.sms.secret.web2.Web2SecretsService; +import com.iexec.sms.secret.web3.Web3Secret; +import com.iexec.sms.secret.web3.Web3SecretService; +import com.iexec.sms.tee.challenge.TeeChallenge; +import com.iexec.sms.tee.challenge.TeeChallengeService; +import com.iexec.sms.tee.workflow.TeeWorkflowConfiguration; +import com.iexec.sms.utils.EthereumCredentials; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.NullSource; +import org.junit.jupiter.params.provider.ValueSource; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.Spy; + +import java.security.GeneralSecurityException; +import java.util.*; + +import static com.iexec.common.chain.DealParams.DROPBOX_RESULT_STORAGE_PROVIDER; +import static com.iexec.common.precompute.PreComputeUtils.IEXEC_DATASET_KEY; +import static com.iexec.common.precompute.PreComputeUtils.IS_DATASET_REQUIRED; +import static com.iexec.common.sms.secret.ReservedSecretKeyName.IEXEC_RESULT_DROPBOX_TOKEN; +import static com.iexec.common.sms.secret.ReservedSecretKeyName.IEXEC_RESULT_ENCRYPTION_PUBLIC_KEY; +import static com.iexec.common.utils.IexecEnvUtils.*; +import static com.iexec.common.worker.result.ResultUtils.*; +import static com.iexec.sms.Web3jUtils.createEthereumAddress; +import static com.iexec.sms.api.TeeSessionGenerationError.*; +import static com.iexec.sms.tee.session.TeeSecretsService.SESSION_ID; +import static com.iexec.sms.tee.session.TeeSecretsService.*; +import static com.iexec.sms.tee.session.TeeSessionTestUtils.*; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +class TeeSecretsServiceTests { + private static final String APP_FINGERPRINT = "01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b"; + + private static final TeeEnclaveConfiguration enclaveConfig = + mock(TeeEnclaveConfiguration.class); + + @Mock + private Web3SecretService web3SecretService; + @Mock + private Web2SecretsService web2SecretsService; + @Mock + private TeeChallengeService teeChallengeService; + @Mock + private TeeWorkflowConfiguration teeWorkflowConfig; + @Mock private TeeTaskComputeSecretService teeTaskComputeSecretService; + + @Spy + @InjectMocks + private TeeSecretsService teeSecretsService; + + @BeforeEach + void beforeEach() { + MockitoAnnotations.openMocks(this); + when(enclaveConfig.getFingerprint()).thenReturn(APP_FINGERPRINT); + + when(enclaveConfig.getFingerprint()).thenReturn(APP_FINGERPRINT); + when(enclaveConfig.getEntrypoint()).thenReturn(APP_ENTRYPOINT); + } + + //region getSecretsTokens + @Test + void shouldGetSecretsTokens() throws Exception { + TeeSecretsSessionRequest request = createSessionRequest(createTaskDescription(enclaveConfig)); + doReturn(getPreComputeTokens()).when(teeSecretsService) + .getPreComputeTokens(request); + doReturn(getAppTokens()).when(teeSecretsService) + .getAppTokens(request); + doReturn(getPostComputeTokens()).when(teeSecretsService) + .getPostComputeTokens(request); + + Map actualTokens = teeSecretsService.getSecretsTokens(request); + + Map expectedEnvTokens = new HashMap<>(); + expectedEnvTokens.put(IEXEC_TASK_ID, "taskId"); + expectedEnvTokens.put(IEXEC_IN, "/iexec_in"); + expectedEnvTokens.put(IEXEC_OUT, "/iexec_out"); + expectedEnvTokens.put(IEXEC_INPUT_FILES_FOLDER, "/iexec_in"); + expectedEnvTokens.put("IEXEC_INPUT_FILE_NAME_1", "file1"); + expectedEnvTokens.put("IEXEC_INPUT_FILE_NAME_2", "file2"); + expectedEnvTokens.put(IEXEC_DATASET_URL, "http://datasetUrl"); + expectedEnvTokens.put(IEXEC_DATASET_FILENAME, "datasetName"); + expectedEnvTokens.put(IEXEC_DATASET_ADDRESS, "0xDatasetAddress"); + expectedEnvTokens.put(IEXEC_INPUT_FILES_NUMBER, "2"); + expectedEnvTokens.put("IEXEC_INPUT_FILE_URL_1", "http://host/file1"); + expectedEnvTokens.put("IEXEC_INPUT_FILE_URL_2", "http://host/file2"); + expectedEnvTokens.put(IEXEC_BOT_SIZE, "1"); + expectedEnvTokens.put(IEXEC_BOT_TASK_INDEX, "0"); + expectedEnvTokens.put(IEXEC_DATASET_CHECKSUM, "datasetChecksum"); + expectedEnvTokens.put(IEXEC_BOT_FIRST_INDEX, "0"); + + + Map expectedTokens = new HashMap<>(); + expectedTokens.put(APP_MRENCLAVE, "01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b"); + expectedTokens.put(PRE_COMPUTE_MRENCLAVE, "mrEnclave1"); + expectedTokens.put(POST_COMPUTE_MRENCLAVE, "mrEnclave3"); + expectedTokens.put(IS_DATASET_REQUIRED, true); + expectedTokens.put(IEXEC_DATASET_KEY, "datasetKey"); + expectedTokens.put(IS_PRE_COMPUTE_REQUIRED, true); + expectedTokens.put(RESULT_TASK_ID, "taskId"); + expectedTokens.put(RESULT_STORAGE_PROXY, "storageProxy"); + expectedTokens.put(RESULT_STORAGE_TOKEN, "storageToken"); + expectedTokens.put(RESULT_SIGN_WORKER_ADDRESS, request.getWorkerAddress()); + expectedTokens.put(RESULT_SIGN_TEE_CHALLENGE_PRIVATE_KEY, "teeChallengePrivateKey"); + expectedTokens.put(RESULT_STORAGE_PROVIDER, "ipfs"); + expectedTokens.put(RESULT_STORAGE_CALLBACK, "no"); + expectedTokens.put(RESULT_ENCRYPTION, "yes"); + expectedTokens.put(RESULT_ENCRYPTION_PUBLIC_KEY, "encryptionPublicKey"); + expectedTokens.put(INPUT_FILE_NAMES, Map.of( + "IEXEC_INPUT_FILE_NAME_1", "file1", + "IEXEC_INPUT_FILE_NAME_2", "file2" + )); + expectedTokens.put(INPUT_FILE_URLS, Map.of( + "IEXEC_INPUT_FILE_URL_1", "http://host/file1", + "IEXEC_INPUT_FILE_URL_2", "http://host/file2" + )); + expectedTokens.put("env", expectedEnvTokens); + expectedTokens.put(SESSION_ID, "sessionId"); + + assertRecursively(expectedTokens, actualTokens); + } + + @Test + void shouldNotGetSecretsTokensSinceRequestIsNull() { + final TeeSessionGenerationException exception = assertThrows( + TeeSessionGenerationException.class, + () -> teeSecretsService.getSecretsTokens(null) + ); + assertEquals(NO_SESSION_REQUEST, exception.getError()); + assertEquals("Session request must not be null", exception.getMessage()); + } + + @Test + void shouldNotGetSecretsTokensSinceTaskDescriptionIsMissing() { + TeeSecretsSessionRequest request = TeeSecretsSessionRequest.builder().build(); + + final TeeSessionGenerationException exception = assertThrows( + TeeSessionGenerationException.class, + () -> teeSecretsService.getSecretsTokens(request) + ); + assertEquals(NO_TASK_DESCRIPTION, exception.getError()); + assertEquals("Task description must not be null", exception.getMessage()); + } + //endregion + + //region getPreComputeTokens + @Test + void shouldGetPreComputeTokens() throws Exception { + TeeSecretsSessionRequest request = createSessionRequest(createTaskDescription(enclaveConfig)); + when(teeWorkflowConfig.getPreComputeFingerprint()) + .thenReturn(PRE_COMPUTE_FINGERPRINT); + when(teeWorkflowConfig.getPreComputeEntrypoint()) + .thenReturn(PRE_COMPUTE_ENTRYPOINT); + Web3Secret secret = new Web3Secret(DATASET_ADDRESS, DATASET_KEY); + when(web3SecretService.getSecret(DATASET_ADDRESS, true)) + .thenReturn(Optional.of(secret)); + + Map tokens = + teeSecretsService.getPreComputeTokens(request); + assertThat(tokens) + .containsExactlyInAnyOrderEntriesOf( + Map.of( + PRE_COMPUTE_MRENCLAVE, PRE_COMPUTE_FINGERPRINT, + PreComputeUtils.IEXEC_DATASET_KEY, secret.getTrimmedValue(), + PreComputeUtils.IS_DATASET_REQUIRED, true, + INPUT_FILE_URLS, + Map.of( + IexecEnvUtils.IEXEC_INPUT_FILE_URL_PREFIX + "1", INPUT_FILE_URL_1, + IexecEnvUtils.IEXEC_INPUT_FILE_URL_PREFIX + "2", INPUT_FILE_URL_2) + + ) + ); + } + + @Test + void shouldGetPreComputeTokensWithoutDataset() throws Exception { + TeeSecretsSessionRequest request = TeeSecretsSessionRequest.builder() + .sessionId(SESSION_ID) + .workerAddress(WORKER_ADDRESS) + .enclaveChallenge(ENCLAVE_CHALLENGE) + .taskDescription(TaskDescription.builder() + .chainTaskId(TASK_ID) + .inputFiles(List.of(INPUT_FILE_URL_1, INPUT_FILE_URL_2)) + .build()) + .build(); + when(teeWorkflowConfig.getPreComputeFingerprint()) + .thenReturn(PRE_COMPUTE_FINGERPRINT); + when(teeWorkflowConfig.getPreComputeEntrypoint()) + .thenReturn(PRE_COMPUTE_ENTRYPOINT); + + Map tokens = + teeSecretsService.getPreComputeTokens(request); + assertThat(tokens).isNotEmpty() + .containsExactlyInAnyOrderEntriesOf( + Map.of( + PRE_COMPUTE_MRENCLAVE, PRE_COMPUTE_FINGERPRINT, + PreComputeUtils.IEXEC_DATASET_KEY, "", + PreComputeUtils.IS_DATASET_REQUIRED, false, + INPUT_FILE_URLS, + Map.of( + IexecEnvUtils.IEXEC_INPUT_FILE_URL_PREFIX + "1", INPUT_FILE_URL_1, + IexecEnvUtils.IEXEC_INPUT_FILE_URL_PREFIX + "2", INPUT_FILE_URL_2) + + ) + ); + } + //endregion + + //region getAppTokens + @Test + void shouldGetAppTokensForAdvancedTaskDescription() { + TeeSecretsSessionRequest request = createSessionRequest(createTaskDescription(enclaveConfig)); + + String appAddress = request.getTaskDescription().getAppAddress(); + String requesterAddress = request.getTaskDescription().getRequester(); + + TeeEnclaveConfigurationValidator validator = mock(TeeEnclaveConfigurationValidator.class); + when(enclaveConfig.getValidator()).thenReturn(validator); + when(validator.isValid()).thenReturn(true); + addApplicationDeveloperSecret(appAddress); + addRequesterSecret(requesterAddress, REQUESTER_SECRET_KEY_1, REQUESTER_SECRET_VALUE_1); + addRequesterSecret(requesterAddress, REQUESTER_SECRET_KEY_2, REQUESTER_SECRET_VALUE_2); + + Map tokens = assertDoesNotThrow(() -> teeSecretsService.getAppTokens(request)); + + verify(teeTaskComputeSecretService).getSecret(OnChainObjectType.APPLICATION, appAddress, SecretOwnerRole.APPLICATION_DEVELOPER, "", APP_DEVELOPER_SECRET_INDEX); + verify(teeTaskComputeSecretService).getSecret(OnChainObjectType.APPLICATION, "", SecretOwnerRole.REQUESTER, requesterAddress, REQUESTER_SECRET_KEY_1); + verify(teeTaskComputeSecretService).getSecret(OnChainObjectType.APPLICATION, "", SecretOwnerRole.REQUESTER, requesterAddress, REQUESTER_SECRET_KEY_2); + + assertThat(tokens) + .containsExactlyInAnyOrderEntriesOf( + Map.of( + APP_MRENCLAVE, APP_FINGERPRINT, + INPUT_FILE_NAMES, + Map.of( + IexecEnvUtils.IEXEC_INPUT_FILE_NAME_PREFIX + "1", "file1", + IexecEnvUtils.IEXEC_INPUT_FILE_NAME_PREFIX + "2", "file2" + ), + IEXEC_APP_DEVELOPER_SECRET_1, APP_DEVELOPER_SECRET_VALUE, + REQUESTER_SECRETS, + Map.of( + IexecEnvUtils.IEXEC_REQUESTER_SECRET_PREFIX + "1", REQUESTER_SECRET_VALUE_1, + IexecEnvUtils.IEXEC_REQUESTER_SECRET_PREFIX + "2", REQUESTER_SECRET_VALUE_2 + ) + + ) + ); + } + + @Test + void shouldGetTokensWithEmptyAppComputeSecretWhenSecretsDoNotExist() { + final String appAddress = createEthereumAddress(); + final String requesterAddress = createEthereumAddress(); + final TaskDescription taskDescription = TaskDescription.builder() + .chainTaskId(TASK_ID) + .appUri(APP_URI) + .appAddress(appAddress) + .appEnclaveConfiguration(enclaveConfig) + .datasetAddress(DATASET_ADDRESS) + .datasetUri(DATASET_URL) + .datasetName(DATASET_NAME) + .datasetChecksum(DATASET_CHECKSUM) + .requester(requesterAddress) + .cmd(ARGS) + .inputFiles(List.of(INPUT_FILE_URL_1, INPUT_FILE_URL_2)) + .isResultEncryption(true) + .resultStorageProvider(STORAGE_PROVIDER) + .resultStorageProxy(STORAGE_PROXY) + .botSize(1) + .botFirstIndex(0) + .botIndex(0) + .build(); + TeeSecretsSessionRequest request = createSessionRequest(taskDescription); + TeeEnclaveConfigurationValidator validator = mock(TeeEnclaveConfigurationValidator.class); + when(enclaveConfig.getValidator()).thenReturn(validator); + when(validator.isValid()).thenReturn(true); + when(teeTaskComputeSecretService.getSecret( + OnChainObjectType.APPLICATION, + appAddress, + SecretOwnerRole.APPLICATION_DEVELOPER, + "", + APP_DEVELOPER_SECRET_INDEX)) + .thenReturn(Optional.empty()); + + Map tokens = assertDoesNotThrow(() -> teeSecretsService.getAppTokens(request)); + verify(teeTaskComputeSecretService).getSecret(eq(OnChainObjectType.APPLICATION), eq(appAddress), eq(SecretOwnerRole.APPLICATION_DEVELOPER), eq(""), any()); + verify(teeTaskComputeSecretService, never()).getSecret(eq(OnChainObjectType.APPLICATION), eq(""), eq(SecretOwnerRole.REQUESTER), any(), any()); + + assertThat(tokens) + .containsExactlyInAnyOrderEntriesOf( + Map.of( + APP_MRENCLAVE, APP_FINGERPRINT, + INPUT_FILE_NAMES, + Map.of( + IexecEnvUtils.IEXEC_INPUT_FILE_NAME_PREFIX + "1", "file1", + IexecEnvUtils.IEXEC_INPUT_FILE_NAME_PREFIX + "2", "file2" + ), + IEXEC_APP_DEVELOPER_SECRET_1, "", + REQUESTER_SECRETS, Collections.emptyMap() + ) + ); + } + + @Test + void shouldFailToGetAppTokensSinceNoTaskDescription() { + TeeSecretsSessionRequest request = TeeSecretsSessionRequest.builder() + .build(); + TeeSessionGenerationException exception = assertThrows(TeeSessionGenerationException.class, + () -> teeSecretsService.getAppTokens(request)); + Assertions.assertEquals(TeeSessionGenerationError.NO_TASK_DESCRIPTION, exception.getError()); + Assertions.assertEquals("Task description must no be null", exception.getMessage()); + } + + @Test + void shouldFailToGetAppTokensSinceNoEnclaveConfig() { + TeeSecretsSessionRequest request = TeeSecretsSessionRequest.builder() + .sessionId(SESSION_ID) + .workerAddress(WORKER_ADDRESS) + .enclaveChallenge(ENCLAVE_CHALLENGE) + .taskDescription(TaskDescription.builder().build()) + .build(); + TeeSessionGenerationException exception = assertThrows(TeeSessionGenerationException.class, + () -> teeSecretsService.getAppTokens(request)); + Assertions.assertEquals(TeeSessionGenerationError.APP_COMPUTE_NO_ENCLAVE_CONFIG, exception.getError()); + Assertions.assertEquals("Enclave configuration must no be null", exception.getMessage()); + } + + @Test + void shouldFailToGetAppTokensInvalidEnclaveConfig() { + TeeSecretsSessionRequest request = createSessionRequest(createTaskDescription(enclaveConfig)); + TeeEnclaveConfigurationValidator validator = mock(TeeEnclaveConfigurationValidator.class); + when(enclaveConfig.getValidator()).thenReturn(validator); + String validationError = "validation error"; + when(validator.validate()).thenReturn(Collections.singletonList(validationError)); + TeeSessionGenerationException exception = assertThrows(TeeSessionGenerationException.class, + () -> teeSecretsService.getAppTokens(request)); + Assertions.assertEquals(TeeSessionGenerationError.APP_COMPUTE_INVALID_ENCLAVE_CONFIG, exception.getError()); + } + + @Test + void shouldAddMultipleRequesterSecrets() { + TeeSecretsSessionRequest request = createSessionRequest(createTaskDescription(enclaveConfig)); + String requesterAddress = request.getTaskDescription().getRequester(); + + TeeEnclaveConfigurationValidator validator = mock(TeeEnclaveConfigurationValidator.class); + when(enclaveConfig.getValidator()).thenReturn(validator); + when(validator.isValid()).thenReturn(true); + addRequesterSecret(requesterAddress, REQUESTER_SECRET_KEY_1, REQUESTER_SECRET_VALUE_1); + addRequesterSecret(requesterAddress, REQUESTER_SECRET_KEY_2, REQUESTER_SECRET_VALUE_2); + Map tokens = assertDoesNotThrow(() -> teeSecretsService.getAppTokens(request)); + verify(teeTaskComputeSecretService, times(2)) + .getSecret(eq(OnChainObjectType.APPLICATION), eq(""), eq(SecretOwnerRole.REQUESTER), any(), any()); + verify(teeTaskComputeSecretService).getSecret(OnChainObjectType.APPLICATION, "", SecretOwnerRole.REQUESTER, requesterAddress, REQUESTER_SECRET_KEY_1); + verify(teeTaskComputeSecretService).getSecret(OnChainObjectType.APPLICATION, "", SecretOwnerRole.REQUESTER, requesterAddress, REQUESTER_SECRET_KEY_2); + assertThat(tokens).containsEntry(REQUESTER_SECRETS, + Map.of( + IexecEnvUtils.IEXEC_REQUESTER_SECRET_PREFIX + "1", REQUESTER_SECRET_VALUE_1, + IexecEnvUtils.IEXEC_REQUESTER_SECRET_PREFIX + "2", REQUESTER_SECRET_VALUE_2 + )); + } + + @Test + void shouldFilterRequesterSecretIndexLowerThanZero() { + TeeSecretsSessionRequest request = createSessionRequest(createTaskDescription(enclaveConfig)); + String requesterAddress = request.getTaskDescription().getRequester(); + + request.getTaskDescription().setSecrets(Map.of("1", REQUESTER_SECRET_KEY_1, "-1", "out-of-bound-requester-secret")); + TeeEnclaveConfigurationValidator validator = mock(TeeEnclaveConfigurationValidator.class); + when(enclaveConfig.getValidator()).thenReturn(validator); + when(validator.isValid()).thenReturn(true); + addRequesterSecret(requesterAddress, REQUESTER_SECRET_KEY_1, REQUESTER_SECRET_VALUE_1); + Map tokens = assertDoesNotThrow(() -> teeSecretsService.getAppTokens(request)); + verify(teeTaskComputeSecretService).getSecret(eq(OnChainObjectType.APPLICATION), eq(""), eq(SecretOwnerRole.REQUESTER), any(), any()); + assertThat(tokens).containsEntry(REQUESTER_SECRETS, + Map.of(IexecEnvUtils.IEXEC_REQUESTER_SECRET_PREFIX + "1", REQUESTER_SECRET_VALUE_1)); + } + //endregion + + //region getPostComputeTokens + @Test + void shouldGetPostComputeTokens() throws Exception { + TeeSecretsSessionRequest request = createSessionRequest(createTaskDescription(enclaveConfig)); + String requesterAddress = request.getTaskDescription().getRequester(); + + Secret publicKeySecret = new Secret("address", ENCRYPTION_PUBLIC_KEY); + when(teeWorkflowConfig.getPostComputeFingerprint()) + .thenReturn(POST_COMPUTE_FINGERPRINT); + when(teeWorkflowConfig.getPostComputeEntrypoint()) + .thenReturn(POST_COMPUTE_ENTRYPOINT); + when(web2SecretsService.getSecret( + request.getTaskDescription().getBeneficiary(), + ReservedSecretKeyName.IEXEC_RESULT_ENCRYPTION_PUBLIC_KEY, + true)) + .thenReturn(Optional.of(publicKeySecret)); + Secret storageSecret = new Secret("address", STORAGE_TOKEN); + when(web2SecretsService.getSecret( + requesterAddress, + ReservedSecretKeyName.IEXEC_RESULT_IEXEC_IPFS_TOKEN, + true)) + .thenReturn(Optional.of(storageSecret)); + + TeeChallenge challenge = TeeChallenge.builder() + .credentials(EthereumCredentials.generate()) + .build(); + when(teeChallengeService.getOrCreate(TASK_ID, true)) + .thenReturn(Optional.of(challenge)); + + + Map tokens = + teeSecretsService.getPostComputeTokens(request); + + final Map expectedTokens = new HashMap<>(); + expectedTokens.put(POST_COMPUTE_MRENCLAVE, POST_COMPUTE_FINGERPRINT); + // encryption tokens + expectedTokens.put(ResultUtils.RESULT_ENCRYPTION, "yes"); + expectedTokens.put(ResultUtils.RESULT_ENCRYPTION_PUBLIC_KEY, ENCRYPTION_PUBLIC_KEY); + // storage tokens + expectedTokens.put(ResultUtils.RESULT_STORAGE_CALLBACK, "no"); + expectedTokens.put(ResultUtils.RESULT_STORAGE_PROVIDER, STORAGE_PROVIDER); + expectedTokens.put(ResultUtils.RESULT_STORAGE_PROXY, STORAGE_PROXY); + expectedTokens.put(ResultUtils.RESULT_STORAGE_TOKEN, STORAGE_TOKEN); + // sign tokens + expectedTokens.put(ResultUtils.RESULT_TASK_ID, TASK_ID); + expectedTokens.put(ResultUtils.RESULT_SIGN_WORKER_ADDRESS, WORKER_ADDRESS); + expectedTokens.put(ResultUtils.RESULT_SIGN_TEE_CHALLENGE_PRIVATE_KEY, challenge.getCredentials().getPrivateKey()); + + assertThat(tokens).containsExactlyEntriesOf(expectedTokens); + } + + @Test + void shouldNotGetPostComputeTokensSinceTaskDescriptionMissing() { + TeeSecretsSessionRequest request = TeeSecretsSessionRequest.builder().build(); + + final TeeSessionGenerationException exception = assertThrows( + TeeSessionGenerationException.class, + () -> teeSecretsService.getPostComputeTokens(request) + ); + assertEquals(NO_TASK_DESCRIPTION, exception.getError()); + assertEquals("Task description must not be null", exception.getMessage()); + } + //endregion + + //region getPostComputeEncryptionTokens + @Test + void shouldGetPostComputeStorageTokensWithCallback() { + final TeeSecretsSessionRequest sessionRequest = createSessionRequest(createTaskDescription(enclaveConfig)); + sessionRequest.getTaskDescription().setCallback("callback"); + + final Map tokens = assertDoesNotThrow( + () -> teeSecretsService.getPostComputeStorageTokens(sessionRequest)); + + assertThat(tokens) + .containsExactlyInAnyOrderEntriesOf( + Map.of( + RESULT_STORAGE_CALLBACK, "yes", + RESULT_STORAGE_PROVIDER, EMPTY_YML_VALUE, + RESULT_STORAGE_PROXY, EMPTY_YML_VALUE, + RESULT_STORAGE_TOKEN, EMPTY_YML_VALUE + ) + ); + } + + @Test + void shouldGetPostComputeStorageTokensOnIpfs() { + final TeeSecretsSessionRequest sessionRequest = createSessionRequest(createTaskDescription(enclaveConfig)); + final TaskDescription taskDescription = sessionRequest.getTaskDescription(); + + final String secretValue = "Secret value"; + when(web2SecretsService.getSecret(taskDescription.getRequester(), ReservedSecretKeyName.IEXEC_RESULT_IEXEC_IPFS_TOKEN, true)) + .thenReturn(Optional.of(new Secret(null, secretValue))); + + final Map tokens = assertDoesNotThrow( + () -> teeSecretsService.getPostComputeStorageTokens(sessionRequest)); + + assertThat(tokens) + .containsExactlyInAnyOrderEntriesOf( + Map.of( + RESULT_STORAGE_CALLBACK, "no", + RESULT_STORAGE_PROVIDER, STORAGE_PROVIDER, + RESULT_STORAGE_PROXY, STORAGE_PROXY, + RESULT_STORAGE_TOKEN, secretValue + ) + ); + } + + @Test + void shouldGetPostComputeStorageTokensOnDropbox() { + final TeeSecretsSessionRequest sessionRequest = createSessionRequest(createTaskDescription(enclaveConfig)); + final TaskDescription taskDescription = sessionRequest.getTaskDescription(); + taskDescription.setResultStorageProvider(DROPBOX_RESULT_STORAGE_PROVIDER); + + final String secretValue = "Secret value"; + when(web2SecretsService.getSecret(taskDescription.getRequester(), IEXEC_RESULT_DROPBOX_TOKEN, true)) + .thenReturn(Optional.of(new Secret(null, secretValue))); + + final Map tokens = assertDoesNotThrow( + () -> teeSecretsService.getPostComputeStorageTokens(sessionRequest)); + + assertThat(tokens) + .containsExactlyInAnyOrderEntriesOf( + Map.of( + RESULT_STORAGE_CALLBACK, "no", + RESULT_STORAGE_PROVIDER, DROPBOX_RESULT_STORAGE_PROVIDER, + RESULT_STORAGE_PROXY, STORAGE_PROXY, + RESULT_STORAGE_TOKEN, secretValue + ) + ); + } + + @Test + void shouldNotGetPostComputeStorageTokensSinceNoSecret() { + final TeeSecretsSessionRequest sessionRequest = createSessionRequest(createTaskDescription(enclaveConfig)); + final TaskDescription taskDescription = sessionRequest.getTaskDescription(); + + when(web2SecretsService.getSecret(taskDescription.getRequester(), ReservedSecretKeyName.IEXEC_RESULT_IEXEC_IPFS_TOKEN, true)) + .thenReturn(Optional.empty()); + + final TeeSessionGenerationException exception = assertThrows( + TeeSessionGenerationException.class, + () -> teeSecretsService.getPostComputeStorageTokens(sessionRequest)); + + assertThat(exception.getError()).isEqualTo(POST_COMPUTE_GET_STORAGE_TOKENS_FAILED); + assertThat(exception.getMessage()).isEqualTo("Empty requester storage token - taskId: " + taskDescription.getChainTaskId()); + } + + @Test + void shouldGetPostComputeSignTokens() throws GeneralSecurityException { + final TeeSecretsSessionRequest sessionRequest = createSessionRequest(createTaskDescription(enclaveConfig)); + final TaskDescription taskDescription = sessionRequest.getTaskDescription(); + final String taskId = taskDescription.getChainTaskId(); + final EthereumCredentials credentials = EthereumCredentials.generate(); + + when(teeChallengeService.getOrCreate(taskId, true)) + .thenReturn(Optional.of(TeeChallenge.builder().credentials(credentials).build())); + + final Map tokens = assertDoesNotThrow(() -> teeSecretsService.getPostComputeSignTokens(sessionRequest)); + + assertThat(tokens) + .containsExactlyInAnyOrderEntriesOf( + Map.of( + RESULT_TASK_ID, taskId, + RESULT_SIGN_WORKER_ADDRESS, sessionRequest.getWorkerAddress(), + RESULT_SIGN_TEE_CHALLENGE_PRIVATE_KEY, credentials.getPrivateKey() + ) + ); + } + + @ParameterizedTest + @NullSource + @ValueSource(strings = {""}) + void shouldNotGetPostComputeSignTokensSinceNoWorkerAddress(String emptyWorkerAddress) { + final TeeSecretsSessionRequest sessionRequest = createSessionRequest(createTaskDescription(enclaveConfig)); + final String taskId = sessionRequest.getTaskDescription().getChainTaskId(); + sessionRequest.setWorkerAddress(emptyWorkerAddress); + + final TeeSessionGenerationException exception = assertThrows( + TeeSessionGenerationException.class, + () -> teeSecretsService.getPostComputeSignTokens(sessionRequest) + ); + + assertThat(exception.getError()).isEqualTo(POST_COMPUTE_GET_SIGNATURE_TOKENS_FAILED_EMPTY_WORKER_ADDRESS); + assertThat(exception.getMessage()).isEqualTo("Empty worker address - taskId: " + taskId); + } + + @ParameterizedTest + @NullSource + @ValueSource(strings = {""}) + void shouldNotGetPostComputeSignTokensSinceNoEnclaveChallenge(String emptyEnclaveChallenge) { + final TeeSecretsSessionRequest sessionRequest = createSessionRequest(createTaskDescription(enclaveConfig)); + final String taskId = sessionRequest.getTaskDescription().getChainTaskId(); + sessionRequest.setEnclaveChallenge(emptyEnclaveChallenge); + + final TeeSessionGenerationException exception = assertThrows( + TeeSessionGenerationException.class, + () -> teeSecretsService.getPostComputeSignTokens(sessionRequest) + ); + + assertThat(exception.getError()).isEqualTo(POST_COMPUTE_GET_SIGNATURE_TOKENS_FAILED_EMPTY_PUBLIC_ENCLAVE_CHALLENGE); + assertThat(exception.getMessage()).isEqualTo("Empty public enclave challenge - taskId: " + taskId); + } + + @Test + void shouldNotGetPostComputeSignTokensSinceNoTeeChallenge() { + final TeeSecretsSessionRequest sessionRequest = createSessionRequest(createTaskDescription(enclaveConfig)); + final String taskId = sessionRequest.getTaskDescription().getChainTaskId(); + + when(teeChallengeService.getOrCreate(taskId, true)) + .thenReturn(Optional.empty()); + + final TeeSessionGenerationException exception = assertThrows( + TeeSessionGenerationException.class, + () -> teeSecretsService.getPostComputeSignTokens(sessionRequest) + ); + + assertThat(exception.getError()).isEqualTo(POST_COMPUTE_GET_SIGNATURE_TOKENS_FAILED_EMPTY_TEE_CHALLENGE); + assertThat(exception.getMessage()).isEqualTo("Empty TEE challenge - taskId: " + taskId); + } + + @Test + void shouldNotGetPostComputeSignTokensSinceNoEnclaveCredentials() { + final TeeSecretsSessionRequest sessionRequest = createSessionRequest(createTaskDescription(enclaveConfig)); + final String taskId = sessionRequest.getTaskDescription().getChainTaskId(); + + when(teeChallengeService.getOrCreate(taskId, true)) + .thenReturn(Optional.of(TeeChallenge.builder().credentials(null).build())); + + final TeeSessionGenerationException exception = assertThrows( + TeeSessionGenerationException.class, + () -> teeSecretsService.getPostComputeSignTokens(sessionRequest) + ); + + assertThat(exception.getError()).isEqualTo(POST_COMPUTE_GET_SIGNATURE_TOKENS_FAILED_EMPTY_TEE_CREDENTIALS); + assertThat(exception.getMessage()).isEqualTo("Empty TEE challenge credentials - taskId: " + taskId); + } + + @Test + void shouldNotGetPostComputeSignTokensSinceNoEnclaveCredentialsPrivateKey() { + final TeeSecretsSessionRequest sessionRequest = createSessionRequest(createTaskDescription(enclaveConfig)); + final String taskId = sessionRequest.getTaskDescription().getChainTaskId(); + + when(teeChallengeService.getOrCreate(taskId, true)) + .thenReturn(Optional.of(TeeChallenge.builder().credentials(new EthereumCredentials("", "", false, "")).build())); + + final TeeSessionGenerationException exception = assertThrows( + TeeSessionGenerationException.class, + () -> teeSecretsService.getPostComputeSignTokens(sessionRequest) + ); + + assertThat(exception.getError()).isEqualTo(POST_COMPUTE_GET_SIGNATURE_TOKENS_FAILED_EMPTY_TEE_CREDENTIALS); + assertThat(exception.getMessage()).isEqualTo("Empty TEE challenge credentials - taskId: " + taskId); + } + + @Test + void shouldGetPostComputeEncryptionTokensWithEncryption() { + TeeSecretsSessionRequest request = createSessionRequest(createTaskDescription(enclaveConfig)); + + Secret publicKeySecret = new Secret("address", ENCRYPTION_PUBLIC_KEY); + when(web2SecretsService.getSecret( + request.getTaskDescription().getBeneficiary(), + IEXEC_RESULT_ENCRYPTION_PUBLIC_KEY, + true)) + .thenReturn(Optional.of(publicKeySecret)); + + final Map encryptionTokens = assertDoesNotThrow(() -> teeSecretsService.getPostComputeEncryptionTokens(request)); + assertThat(encryptionTokens) + .containsExactlyInAnyOrderEntriesOf( + Map.of( + RESULT_ENCRYPTION, "yes", + RESULT_ENCRYPTION_PUBLIC_KEY, ENCRYPTION_PUBLIC_KEY + ) + ); + } + + @Test + void shouldGetPostComputeEncryptionTokensWithoutEncryption() { + TeeSecretsSessionRequest request = createSessionRequest(createTaskDescription(enclaveConfig)); + request.getTaskDescription().setResultEncryption(false); + + final Map encryptionTokens = assertDoesNotThrow(() -> teeSecretsService.getPostComputeEncryptionTokens(request)); + assertThat(encryptionTokens) + .containsExactlyInAnyOrderEntriesOf( + Map.of( + RESULT_ENCRYPTION, "no", + RESULT_ENCRYPTION_PUBLIC_KEY, "" + ) + ); + } + + @Test + void shouldNotGetPostComputeEncryptionTokensSinceEmptyBeneficiaryKey() { + TeeSecretsSessionRequest request = createSessionRequest(createTaskDescription(enclaveConfig)); + + when(web2SecretsService.getSecret( + request.getTaskDescription().getBeneficiary(), + IEXEC_RESULT_ENCRYPTION_PUBLIC_KEY, + true)) + .thenReturn(Optional.empty()); + + final TeeSessionGenerationException exception = assertThrows( + TeeSessionGenerationException.class, + () -> teeSecretsService.getPostComputeEncryptionTokens(request) + ); + assertEquals(POST_COMPUTE_GET_ENCRYPTION_TOKENS_FAILED_EMPTY_BENEFICIARY_KEY, exception.getError()); + assertEquals("Empty beneficiary encryption key - taskId: taskId", exception.getMessage()); + } + + //endregion + + //region utils + private void addApplicationDeveloperSecret(String appAddress) { + TeeTaskComputeSecret applicationDeveloperSecret = getApplicationDeveloperSecret(appAddress); + when(teeTaskComputeSecretService.getSecret(OnChainObjectType.APPLICATION, appAddress, SecretOwnerRole.APPLICATION_DEVELOPER, "", APP_DEVELOPER_SECRET_INDEX)) + .thenReturn(Optional.of(applicationDeveloperSecret)); + } + + private void addRequesterSecret(String requesterAddress, String secretKey, String secretValue) { + TeeTaskComputeSecret requesterSecret = getRequesterSecret(requesterAddress, secretKey, secretValue); + when(teeTaskComputeSecretService.getSecret(OnChainObjectType.APPLICATION, "", SecretOwnerRole.REQUESTER, requesterAddress, secretKey)) + .thenReturn(Optional.of(requesterSecret)); + } + //endregion +} \ No newline at end of file diff --git a/src/test/java/com/iexec/sms/tee/session/TeeSessionTestUtils.java b/src/test/java/com/iexec/sms/tee/session/TeeSessionTestUtils.java new file mode 100644 index 00000000..ec45f6d2 --- /dev/null +++ b/src/test/java/com/iexec/sms/tee/session/TeeSessionTestUtils.java @@ -0,0 +1,196 @@ +/* + * Copyright 2022 IEXEC BLOCKCHAIN TECH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.iexec.sms.tee.session; + +import com.iexec.common.precompute.PreComputeUtils; +import com.iexec.common.task.TaskDescription; +import com.iexec.common.tee.TeeEnclaveConfiguration; +import com.iexec.common.utils.IexecEnvUtils; +import com.iexec.sms.secret.compute.OnChainObjectType; +import com.iexec.sms.secret.compute.SecretOwnerRole; +import com.iexec.sms.secret.compute.TeeTaskComputeSecret; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.ClassUtils; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static com.iexec.common.worker.result.ResultUtils.*; +import static com.iexec.sms.Web3jUtils.createEthereumAddress; +import static com.iexec.sms.tee.session.TeeSecretsService.*; +import static org.assertj.core.api.Assertions.assertThat; + +@Slf4j +public class TeeSessionTestUtils { + public static final String TASK_ID = "taskId"; + public static final String SESSION_ID = "sessionId"; + public static final String WORKER_ADDRESS = "workerAddress"; + public static final String ENCLAVE_CHALLENGE = "enclaveChallenge"; + // pre-compute + public static final String PRE_COMPUTE_FINGERPRINT = "mrEnclave1"; + public static final String PRE_COMPUTE_ENTRYPOINT = "entrypoint1"; + public static final String DATASET_ADDRESS = "0xDatasetAddress"; + public static final String DATASET_NAME = "datasetName"; + public static final String DATASET_CHECKSUM = "datasetChecksum"; + public static final String DATASET_URL = "http://datasetUrl"; // 0x687474703a2f2f646174617365742d75726c in hex + // keys with leading/trailing \n should not break the workflow + public static final String DATASET_KEY = "\ndatasetKey\n"; + // app + public static final String APP_DEVELOPER_SECRET_INDEX = "1"; + public static final String APP_DEVELOPER_SECRET_VALUE = "appDeveloperSecretValue"; + public static final String REQUESTER_SECRET_KEY_1 = "requesterSecretKey1"; + public static final String REQUESTER_SECRET_VALUE_1 = "requesterSecretValue1"; + public static final String REQUESTER_SECRET_KEY_2 = "requesterSecretKey2"; + public static final String REQUESTER_SECRET_VALUE_2 = "requesterSecretValue2"; + public static final String APP_URI = "appUri"; + public static final String APP_FINGERPRINT = "01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b"; + public static final String APP_ENTRYPOINT = "appEntrypoint"; + public static final String ARGS = "args"; + public static final String IEXEC_APP_DEVELOPER_SECRET_1 = "IEXEC_APP_DEVELOPER_SECRET_1"; + // post-compute + public static final String POST_COMPUTE_FINGERPRINT = "mrEnclave3"; + public static final String POST_COMPUTE_ENTRYPOINT = "entrypoint3"; + public static final String STORAGE_PROVIDER = "ipfs"; + public static final String STORAGE_PROXY = "storageProxy"; + public static final String STORAGE_TOKEN = "storageToken"; + public static final String ENCRYPTION_PUBLIC_KEY = "encryptionPublicKey"; + public static final String TEE_CHALLENGE_PRIVATE_KEY = "teeChallengePrivateKey"; + // input files + public static final String INPUT_FILE_URL_1 = "http://host/file1"; + public static final String INPUT_FILE_NAME_1 = "file1"; + public static final String INPUT_FILE_URL_2 = "http://host/file2"; + public static final String INPUT_FILE_NAME_2 = "file2"; + + //region utils + public static TeeTaskComputeSecret getApplicationDeveloperSecret(String appAddress) { + return TeeTaskComputeSecret.builder() + .onChainObjectType(OnChainObjectType.APPLICATION) + .onChainObjectAddress(appAddress) + .secretOwnerRole(SecretOwnerRole.APPLICATION_DEVELOPER) + .key(APP_DEVELOPER_SECRET_INDEX) + .value(APP_DEVELOPER_SECRET_VALUE) + .build(); + } + + public static TeeTaskComputeSecret getRequesterSecret(String requesterAddress, String secretKey, String secretValue) { + return TeeTaskComputeSecret.builder() + .onChainObjectType(OnChainObjectType.APPLICATION) + .onChainObjectAddress("") + .secretOwnerRole(SecretOwnerRole.REQUESTER) + .fixedSecretOwner(requesterAddress) + .key(secretKey) + .value(secretValue) + .build(); + } + + public static TeeSecretsSessionRequest createSessionRequest(TaskDescription taskDescription) { + return TeeSecretsSessionRequest.builder() + .sessionId(SESSION_ID) + .workerAddress(WORKER_ADDRESS) + .enclaveChallenge(ENCLAVE_CHALLENGE) + .taskDescription(taskDescription) + .build(); + } + + public static TaskDescription createTaskDescription(TeeEnclaveConfiguration enclaveConfig) { + String appAddress = createEthereumAddress(); + String requesterAddress = createEthereumAddress(); + return TaskDescription.builder() + .chainTaskId(TASK_ID) + .appUri(APP_URI) + .appAddress(appAddress) + .appEnclaveConfiguration(enclaveConfig) + .datasetAddress(DATASET_ADDRESS) + .datasetUri(DATASET_URL) + .datasetName(DATASET_NAME) + .datasetChecksum(DATASET_CHECKSUM) + .requester(requesterAddress) + .cmd(ARGS) + .inputFiles(List.of(INPUT_FILE_URL_1, INPUT_FILE_URL_2)) + .isResultEncryption(true) + .resultStorageProvider(STORAGE_PROVIDER) + .resultStorageProxy(STORAGE_PROXY) + .secrets(Map.of("1", REQUESTER_SECRET_KEY_1, "2", REQUESTER_SECRET_KEY_2)) + .botSize(1) + .botFirstIndex(0) + .botIndex(0) + .build(); + } + + public static Map getPreComputeTokens() { + return Map.of( + PRE_COMPUTE_MRENCLAVE, PRE_COMPUTE_FINGERPRINT, + PreComputeUtils.IS_DATASET_REQUIRED, true, + PreComputeUtils.IEXEC_DATASET_KEY, DATASET_KEY.trim(), + INPUT_FILE_URLS, Map.of( + IexecEnvUtils.IEXEC_INPUT_FILE_URL_PREFIX + "1", INPUT_FILE_URL_1, + IexecEnvUtils.IEXEC_INPUT_FILE_URL_PREFIX + "2", INPUT_FILE_URL_2)); + } + + public static Map getAppTokens() { + return Map.of( + APP_MRENCLAVE, APP_FINGERPRINT, + INPUT_FILE_NAMES, Map.of( + IexecEnvUtils.IEXEC_INPUT_FILE_NAME_PREFIX + "1", INPUT_FILE_NAME_1, + IexecEnvUtils.IEXEC_INPUT_FILE_NAME_PREFIX + "2", INPUT_FILE_NAME_2)); + } + + public static Map getPostComputeTokens() { + Map map = new HashMap<>(); + map.put(POST_COMPUTE_MRENCLAVE, POST_COMPUTE_FINGERPRINT); + map.put(RESULT_TASK_ID, TASK_ID); + map.put(RESULT_ENCRYPTION, "yes"); + map.put(RESULT_ENCRYPTION_PUBLIC_KEY, ENCRYPTION_PUBLIC_KEY); + map.put(RESULT_STORAGE_PROVIDER, STORAGE_PROVIDER); + map.put(RESULT_STORAGE_PROXY, STORAGE_PROXY); + map.put(RESULT_STORAGE_TOKEN, STORAGE_TOKEN); + map.put(RESULT_STORAGE_CALLBACK, "no"); + map.put(RESULT_SIGN_WORKER_ADDRESS, WORKER_ADDRESS); + map.put(RESULT_SIGN_TEE_CHALLENGE_PRIVATE_KEY, TEE_CHALLENGE_PRIVATE_KEY); + return map; + } + + public static void assertRecursively(Object expected, Object actual) { + if (expected == null || + expected instanceof String || + ClassUtils.isPrimitiveOrWrapper(expected.getClass())) { + log.info("Comparing [actual:{}, expected:{}]", expected, actual); + assertThat(expected).isEqualTo(actual); + return; + } + if (expected instanceof List) { + List actualList = (List) expected; + List expectedList = (List) actual; + for (int i = 0; i < actualList.size(); i++) { + assertRecursively(actualList.get(i), expectedList.get(i)); + } + return; + } + if (expected instanceof Map) { + Map actualMap = (Map) expected; + Map expectedMap = (Map) actual; + actualMap.keySet().forEach((key) -> { + final Object expectedObject = expectedMap.get(key); + final Object actualObject = actualMap.get(key); + log.info("Checking expected map contains valid '{}' key [expected value:{}, actual value:{}]", key, expectedObject, actualObject); + assertRecursively(expectedObject, actualObject); + }); + } + } + //endregion +} diff --git a/src/test/java/com/iexec/sms/tee/session/scone/palaemon/PalaemonSessionServiceTests.java b/src/test/java/com/iexec/sms/tee/session/scone/palaemon/PalaemonSessionServiceTests.java index efceabff..b6b7807f 100644 --- a/src/test/java/com/iexec/sms/tee/session/scone/palaemon/PalaemonSessionServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/scone/palaemon/PalaemonSessionServiceTests.java @@ -35,10 +35,10 @@ import com.iexec.sms.secret.web3.Web3SecretService; import com.iexec.sms.tee.challenge.TeeChallenge; import com.iexec.sms.tee.challenge.TeeChallengeService; +import com.iexec.sms.tee.session.TeeSecretsService; +import com.iexec.sms.tee.session.TeeSecretsSessionRequest; import com.iexec.sms.tee.session.TeeSessionGenerationException; import com.iexec.sms.tee.session.scone.attestation.AttestationSecurityConfig; -import com.iexec.sms.tee.session.scone.palaemon.PalaemonSessionRequest; -import com.iexec.sms.tee.session.scone.palaemon.PalaemonSessionService; import com.iexec.sms.tee.workflow.TeeWorkflowConfiguration; import com.iexec.sms.utils.EthereumCredentials; import lombok.extern.slf4j.Slf4j; @@ -49,8 +49,10 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.NullSource; import org.junit.jupiter.params.provider.ValueSource; +import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.mockito.Spy; import org.springframework.test.util.ReflectionTestUtils; import org.yaml.snakeyaml.Yaml; @@ -63,6 +65,8 @@ import static com.iexec.common.worker.result.ResultUtils.*; import static com.iexec.sms.Web3jUtils.createEthereumAddress; import static com.iexec.sms.api.TeeSessionGenerationError.*; +import static com.iexec.sms.tee.session.TeeSessionTestUtils.*; +import static com.iexec.sms.tee.session.TeeSessionTestUtils.APP_ENTRYPOINT; import static com.iexec.sms.tee.session.scone.palaemon.PalaemonSessionService.*; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.*; @@ -73,93 +77,55 @@ class PalaemonSessionServiceTests { private static final String TEMPLATE_SESSION_FILE = "src/main/resources/palaemonTemplate.vm"; private static final String EXPECTED_SESSION_FILE = "src/test/resources/tee-session.yml"; - - private static final String TASK_ID = "taskId"; - private static final String SESSION_ID = "sessionId"; - private static final String WORKER_ADDRESS = "workerAddress"; - private static final String ENCLAVE_CHALLENGE = "enclaveChallenge"; - // pre-compute - private static final String PRE_COMPUTE_FINGERPRINT = "mrEnclave1"; private static final String PRE_COMPUTE_ENTRYPOINT = "entrypoint1"; - private static final String DATASET_ADDRESS = "0xDatasetAddress"; - private static final String DATASET_NAME = "datasetName"; - private static final String DATASET_CHECKSUM = "datasetChecksum"; - private static final String DATASET_URL = "http://datasetUrl"; // 0x687474703a2f2f646174617365742d75726c in hex - // keys with leading/trailing \n should not break the workflow - private static final String DATASET_KEY = "\ndatasetKey\n"; - // app - private static final String APP_DEVELOPER_SECRET_INDEX = "1"; - private static final String APP_DEVELOPER_SECRET_VALUE = "appDeveloperSecretValue"; - private static final String REQUESTER_SECRET_KEY_1 = "requesterSecretKey1"; - private static final String REQUESTER_SECRET_VALUE_1 = "requesterSecretValue1"; - private static final String REQUESTER_SECRET_KEY_2 = "requesterSecretKey2"; - private static final String REQUESTER_SECRET_VALUE_2 = "requesterSecretValue2"; - private static final String APP_URI = "appUri"; private static final String APP_FINGERPRINT = "01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b"; private static final String APP_ENTRYPOINT = "appEntrypoint"; private static final TeeEnclaveConfiguration enclaveConfig = mock(TeeEnclaveConfiguration.class); - private static final String ARGS = "args"; - private static final String IEXEC_APP_DEVELOPER_SECRET_1 = "IEXEC_APP_DEVELOPER_SECRET_1"; - // post-compute - private static final String POST_COMPUTE_FINGERPRINT = "mrEnclave3"; private static final String POST_COMPUTE_ENTRYPOINT = "entrypoint3"; - private static final String STORAGE_PROVIDER = "ipfs"; - private static final String STORAGE_PROXY = "storageProxy"; - private static final String STORAGE_TOKEN = "storageToken"; - private static final String ENCRYPTION_PUBLIC_KEY = "encryptionPublicKey"; - private static final String TEE_CHALLENGE_PRIVATE_KEY = "teeChallengePrivateKey"; - // input files - private static final String INPUT_FILE_URL_1 = "http://host/file1"; - private static final String INPUT_FILE_NAME_1 = "file1"; - private static final String INPUT_FILE_URL_2 = "http://host/file2"; - private static final String INPUT_FILE_NAME_2 = "file2"; - - private String appAddress; - private String requesterAddress; - @Mock - private Web3SecretService web3SecretService; - @Mock - private Web2SecretsService web2SecretsService; - @Mock - private TeeChallengeService teeChallengeService; @Mock private TeeWorkflowConfiguration teeWorkflowConfig; + + @Spy + @InjectMocks + private TeeSecretsService teeSecretsService; @Mock private AttestationSecurityConfig attestationSecurityConfig; - @Mock private TeeTaskComputeSecretService teeTaskComputeSecretService; private PalaemonSessionService palaemonSessionService; @BeforeEach void beforeEach() { MockitoAnnotations.openMocks(this); - // spy is needed to mock some internal calls of the tested - // class when relevant - palaemonSessionService = spy(new PalaemonSessionService( - web3SecretService, - web2SecretsService, - teeChallengeService, - teeWorkflowConfig, - attestationSecurityConfig, - teeTaskComputeSecretService - )); + palaemonSessionService = spy(new PalaemonSessionService(teeSecretsService, teeWorkflowConfig, attestationSecurityConfig)); ReflectionTestUtils.setField(palaemonSessionService, "palaemonTemplateFilePath", TEMPLATE_SESSION_FILE); + when(enclaveConfig.getFingerprint()).thenReturn(APP_FINGERPRINT); when(enclaveConfig.getEntrypoint()).thenReturn(APP_ENTRYPOINT); } //region getSessionYml + /** + * FIXME + * This is currently not a unit test. + * It relies on {@link TeeSecretsService} implementation to work. + * This should be fixed. + */ @Test void shouldGetSessionYml() throws Exception { - PalaemonSessionRequest request = createSessionRequest(createTaskDescription()); - doReturn(getPreComputeTokens()).when(palaemonSessionService) - .getPreComputePalaemonTokens(request); - doReturn(getAppTokens()).when(palaemonSessionService) - .getAppPalaemonTokens(request); - doReturn(getPostComputeTokens()).when(palaemonSessionService) - .getPostComputePalaemonTokens(request); + TeeSecretsSessionRequest request = createSessionRequest(createTaskDescription(enclaveConfig)); + + doReturn(getPreComputeTokens()).when(teeSecretsService) + .getPreComputeTokens(request); + doReturn(getAppTokens()).when(teeSecretsService) + .getAppTokens(request); + doReturn(getPostComputeTokens()).when(teeSecretsService) + .getPostComputeTokens(request); + + when(teeWorkflowConfig.getPreComputeEntrypoint()).thenReturn(PRE_COMPUTE_ENTRYPOINT); + when(teeWorkflowConfig.getPostComputeEntrypoint()).thenReturn(POST_COMPUTE_ENTRYPOINT); + when(attestationSecurityConfig.getToleratedInsecureOptions()) .thenReturn(List.of("hyperthreading", "debug-mode")); when(attestationSecurityConfig.getIgnoredSgxAdvisories()) @@ -171,690 +137,5 @@ void shouldGetSessionYml() throws Exception { Map expectedYmlMap = new Yaml().load(expectedYamlString); assertRecursively(expectedYmlMap, actualYmlMap); } - - @Test - void shouldNotGetSessionYmlSinceRequestIsNull() { - final TeeSessionGenerationException exception = assertThrows( - TeeSessionGenerationException.class, - () -> palaemonSessionService.getSessionYml(null) - ); - assertEquals(NO_SESSION_REQUEST, exception.getError()); - assertEquals("Session request must not be null", exception.getMessage()); - } - - @Test - void shouldNotGetSessionYmlSinceTaskDescriptionIsMissing() { - PalaemonSessionRequest request = PalaemonSessionRequest.builder().build(); - - final TeeSessionGenerationException exception = assertThrows( - TeeSessionGenerationException.class, - () -> palaemonSessionService.getSessionYml(request) - ); - assertEquals(NO_TASK_DESCRIPTION, exception.getError()); - assertEquals("Task description must not be null", exception.getMessage()); - } - //endregion - - //region getPreComputePalaemonTokens - @Test - void shouldGetPreComputePalaemonTokens() throws Exception { - PalaemonSessionRequest request = createSessionRequest(createTaskDescription()); - when(teeWorkflowConfig.getPreComputeFingerprint()) - .thenReturn(PRE_COMPUTE_FINGERPRINT); - when(teeWorkflowConfig.getPreComputeEntrypoint()) - .thenReturn(PRE_COMPUTE_ENTRYPOINT); - Web3Secret secret = new Web3Secret(DATASET_ADDRESS, DATASET_KEY); - when(web3SecretService.getSecret(DATASET_ADDRESS, true)) - .thenReturn(Optional.of(secret)); - - Map tokens = - palaemonSessionService.getPreComputePalaemonTokens(request); - assertThat(tokens) - .containsExactlyInAnyOrderEntriesOf( - Map.of( - PalaemonSessionService.PRE_COMPUTE_MRENCLAVE, PRE_COMPUTE_FINGERPRINT, - PalaemonSessionService.PRE_COMPUTE_ENTRYPOINT, PRE_COMPUTE_ENTRYPOINT, - PreComputeUtils.IEXEC_DATASET_KEY, secret.getTrimmedValue(), - PreComputeUtils.IS_DATASET_REQUIRED, true, - PalaemonSessionService.INPUT_FILE_URLS, - Map.of( - IexecEnvUtils.IEXEC_INPUT_FILE_URL_PREFIX + "1", INPUT_FILE_URL_1, - IexecEnvUtils.IEXEC_INPUT_FILE_URL_PREFIX + "2", INPUT_FILE_URL_2) - - ) - ); - } - - @Test - void shouldGetPreComputePalaemonTokensWithoutDataset() throws Exception { - PalaemonSessionRequest request = PalaemonSessionRequest.builder() - .sessionId(SESSION_ID) - .workerAddress(WORKER_ADDRESS) - .enclaveChallenge(ENCLAVE_CHALLENGE) - .taskDescription(TaskDescription.builder() - .chainTaskId(TASK_ID) - .inputFiles(List.of(INPUT_FILE_URL_1, INPUT_FILE_URL_2)) - .build()) - .build(); - when(teeWorkflowConfig.getPreComputeFingerprint()) - .thenReturn(PRE_COMPUTE_FINGERPRINT); - when(teeWorkflowConfig.getPreComputeEntrypoint()) - .thenReturn(PRE_COMPUTE_ENTRYPOINT); - - Map tokens = - palaemonSessionService.getPreComputePalaemonTokens(request); - assertThat(tokens).isNotEmpty() - .containsExactlyInAnyOrderEntriesOf( - Map.of( - PalaemonSessionService.PRE_COMPUTE_MRENCLAVE, PRE_COMPUTE_FINGERPRINT, - PalaemonSessionService.PRE_COMPUTE_ENTRYPOINT, PRE_COMPUTE_ENTRYPOINT, - PreComputeUtils.IEXEC_DATASET_KEY, "", - PreComputeUtils.IS_DATASET_REQUIRED, false, - PalaemonSessionService.INPUT_FILE_URLS, - Map.of( - IexecEnvUtils.IEXEC_INPUT_FILE_URL_PREFIX + "1", INPUT_FILE_URL_1, - IexecEnvUtils.IEXEC_INPUT_FILE_URL_PREFIX + "2", INPUT_FILE_URL_2) - - ) - ); - } - //endregion - - //region getAppPalaemonTokens - @Test - void shouldGetAppPalaemonTokensForAdvancedTaskDescription() { - PalaemonSessionRequest request = createSessionRequest(createTaskDescription()); - TeeEnclaveConfigurationValidator validator = mock(TeeEnclaveConfigurationValidator.class); - when(enclaveConfig.getValidator()).thenReturn(validator); - when(validator.isValid()).thenReturn(true); - addApplicationDeveloperSecret(); - addRequesterSecret(REQUESTER_SECRET_KEY_1, REQUESTER_SECRET_VALUE_1); - addRequesterSecret(REQUESTER_SECRET_KEY_2, REQUESTER_SECRET_VALUE_2); - - Map tokens = assertDoesNotThrow(() -> palaemonSessionService.getAppPalaemonTokens(request)); - - verify(teeTaskComputeSecretService).getSecret(OnChainObjectType.APPLICATION, appAddress, SecretOwnerRole.APPLICATION_DEVELOPER, "", APP_DEVELOPER_SECRET_INDEX); - verify(teeTaskComputeSecretService).getSecret(OnChainObjectType.APPLICATION, "", SecretOwnerRole.REQUESTER, requesterAddress, REQUESTER_SECRET_KEY_1); - verify(teeTaskComputeSecretService).getSecret(OnChainObjectType.APPLICATION, "", SecretOwnerRole.REQUESTER, requesterAddress, REQUESTER_SECRET_KEY_2); - - assertThat(tokens) - .containsExactlyInAnyOrderEntriesOf( - Map.of( - PalaemonSessionService.APP_MRENCLAVE, APP_FINGERPRINT, - PalaemonSessionService.APP_ARGS, APP_ENTRYPOINT + " " + ARGS, - PalaemonSessionService.INPUT_FILE_NAMES, - Map.of( - IexecEnvUtils.IEXEC_INPUT_FILE_NAME_PREFIX + "1", "file1", - IexecEnvUtils.IEXEC_INPUT_FILE_NAME_PREFIX + "2", "file2" - ), - IEXEC_APP_DEVELOPER_SECRET_1, APP_DEVELOPER_SECRET_VALUE, - REQUESTER_SECRETS, - Map.of( - IexecEnvUtils.IEXEC_REQUESTER_SECRET_PREFIX + "1", REQUESTER_SECRET_VALUE_1, - IexecEnvUtils.IEXEC_REQUESTER_SECRET_PREFIX + "2", REQUESTER_SECRET_VALUE_2 - ) - - ) - ); - } - - @Test - void shouldGetPalaemonTokensWithEmptyAppComputeSecretWhenSecretsDoNotExist() { - final String appAddress = createEthereumAddress(); - final String requesterAddress = createEthereumAddress(); - final TaskDescription taskDescription = TaskDescription.builder() - .chainTaskId(TASK_ID) - .appUri(APP_URI) - .appAddress(appAddress) - .appEnclaveConfiguration(enclaveConfig) - .datasetAddress(DATASET_ADDRESS) - .datasetUri(DATASET_URL) - .datasetName(DATASET_NAME) - .datasetChecksum(DATASET_CHECKSUM) - .requester(requesterAddress) - .cmd(ARGS) - .inputFiles(List.of(INPUT_FILE_URL_1, INPUT_FILE_URL_2)) - .isResultEncryption(true) - .resultStorageProvider(STORAGE_PROVIDER) - .resultStorageProxy(STORAGE_PROXY) - .botSize(1) - .botFirstIndex(0) - .botIndex(0) - .build(); - PalaemonSessionRequest request = createSessionRequest(taskDescription); - TeeEnclaveConfigurationValidator validator = mock(TeeEnclaveConfigurationValidator.class); - when(enclaveConfig.getValidator()).thenReturn(validator); - when(validator.isValid()).thenReturn(true); - when(teeTaskComputeSecretService.getSecret( - OnChainObjectType.APPLICATION, - appAddress, - SecretOwnerRole.APPLICATION_DEVELOPER, - "", - APP_DEVELOPER_SECRET_INDEX)) - .thenReturn(Optional.empty()); - - Map tokens = assertDoesNotThrow(() -> palaemonSessionService.getAppPalaemonTokens(request)); - verify(teeTaskComputeSecretService).getSecret(eq(OnChainObjectType.APPLICATION), eq(appAddress), eq(SecretOwnerRole.APPLICATION_DEVELOPER), eq(""), any()); - verify(teeTaskComputeSecretService, never()).getSecret(eq(OnChainObjectType.APPLICATION), eq(""), eq(SecretOwnerRole.REQUESTER), any(), any()); - - assertThat(tokens) - .containsExactlyInAnyOrderEntriesOf( - Map.of( - PalaemonSessionService.APP_MRENCLAVE, APP_FINGERPRINT, - PalaemonSessionService.APP_ARGS, APP_ENTRYPOINT + " " + ARGS, - PalaemonSessionService.INPUT_FILE_NAMES, - Map.of( - IexecEnvUtils.IEXEC_INPUT_FILE_NAME_PREFIX + "1", "file1", - IexecEnvUtils.IEXEC_INPUT_FILE_NAME_PREFIX + "2", "file2" - ), - IEXEC_APP_DEVELOPER_SECRET_1, "", - REQUESTER_SECRETS, Collections.emptyMap() - ) - ); - } - - @Test - void shouldFailToGetAppPalaemonTokensSinceNoTaskDescription() { - PalaemonSessionRequest request = PalaemonSessionRequest.builder() - .build(); - TeeSessionGenerationException exception = assertThrows(TeeSessionGenerationException.class, - () -> palaemonSessionService.getAppPalaemonTokens(request)); - Assertions.assertEquals(TeeSessionGenerationError.NO_TASK_DESCRIPTION, exception.getError()); - Assertions.assertEquals("Task description must no be null", exception.getMessage()); - } - - @Test - void shouldFailToGetAppPalaemonTokensSinceNoEnclaveConfig() { - PalaemonSessionRequest request = PalaemonSessionRequest.builder() - .sessionId(SESSION_ID) - .workerAddress(WORKER_ADDRESS) - .enclaveChallenge(ENCLAVE_CHALLENGE) - .taskDescription(TaskDescription.builder().build()) - .build(); - TeeSessionGenerationException exception = assertThrows(TeeSessionGenerationException.class, - () -> palaemonSessionService.getAppPalaemonTokens(request)); - Assertions.assertEquals(TeeSessionGenerationError.APP_COMPUTE_NO_ENCLAVE_CONFIG, exception.getError()); - Assertions.assertEquals("Enclave configuration must no be null", exception.getMessage()); - } - - @Test - void shouldFailToGetAppPalaemonTokensInvalidEnclaveConfig() { - PalaemonSessionRequest request = createSessionRequest(createTaskDescription()); - TeeEnclaveConfigurationValidator validator = mock(TeeEnclaveConfigurationValidator.class); - when(enclaveConfig.getValidator()).thenReturn(validator); - String validationError = "validation error"; - when(validator.validate()).thenReturn(Collections.singletonList(validationError)); - TeeSessionGenerationException exception = assertThrows(TeeSessionGenerationException.class, - () -> palaemonSessionService.getAppPalaemonTokens(request)); - Assertions.assertEquals(TeeSessionGenerationError.APP_COMPUTE_INVALID_ENCLAVE_CONFIG, exception.getError()); - } - - @Test - void shouldAddMultipleRequesterSecrets() { - PalaemonSessionRequest request = createSessionRequest(createTaskDescription()); - TeeEnclaveConfigurationValidator validator = mock(TeeEnclaveConfigurationValidator.class); - when(enclaveConfig.getValidator()).thenReturn(validator); - when(validator.isValid()).thenReturn(true); - addRequesterSecret(REQUESTER_SECRET_KEY_1, REQUESTER_SECRET_VALUE_1); - addRequesterSecret(REQUESTER_SECRET_KEY_2, REQUESTER_SECRET_VALUE_2); - Map tokens = assertDoesNotThrow(() -> palaemonSessionService.getAppPalaemonTokens(request)); - verify(teeTaskComputeSecretService, times(2)) - .getSecret(eq(OnChainObjectType.APPLICATION), eq(""), eq(SecretOwnerRole.REQUESTER), any(), any()); - verify(teeTaskComputeSecretService).getSecret(OnChainObjectType.APPLICATION, "", SecretOwnerRole.REQUESTER, requesterAddress, REQUESTER_SECRET_KEY_1); - verify(teeTaskComputeSecretService).getSecret(OnChainObjectType.APPLICATION, "", SecretOwnerRole.REQUESTER, requesterAddress, REQUESTER_SECRET_KEY_2); - assertThat(tokens).containsEntry(REQUESTER_SECRETS, - Map.of( - IexecEnvUtils.IEXEC_REQUESTER_SECRET_PREFIX + "1", REQUESTER_SECRET_VALUE_1, - IexecEnvUtils.IEXEC_REQUESTER_SECRET_PREFIX + "2", REQUESTER_SECRET_VALUE_2 - )); - } - - @Test - void shouldFilterRequesterSecretIndexLowerThanZero() { - PalaemonSessionRequest request = createSessionRequest(createTaskDescription()); - request.getTaskDescription().setSecrets(Map.of("1", REQUESTER_SECRET_KEY_1, "-1", "out-of-bound-requester-secret")); - TeeEnclaveConfigurationValidator validator = mock(TeeEnclaveConfigurationValidator.class); - when(enclaveConfig.getValidator()).thenReturn(validator); - when(validator.isValid()).thenReturn(true); - addRequesterSecret(REQUESTER_SECRET_KEY_1, REQUESTER_SECRET_VALUE_1); - Map tokens = assertDoesNotThrow(() -> palaemonSessionService.getAppPalaemonTokens(request)); - verify(teeTaskComputeSecretService).getSecret(eq(OnChainObjectType.APPLICATION), eq(""), eq(SecretOwnerRole.REQUESTER), any(), any()); - assertThat(tokens).containsEntry(REQUESTER_SECRETS, - Map.of(IexecEnvUtils.IEXEC_REQUESTER_SECRET_PREFIX + "1", REQUESTER_SECRET_VALUE_1)); - } - //endregion - - //region getPostComputePalaemonTokens - @Test - void shouldGetPostComputePalaemonTokens() throws Exception { - PalaemonSessionRequest request = createSessionRequest(createTaskDescription()); - Secret publicKeySecret = new Secret("address", ENCRYPTION_PUBLIC_KEY); - when(teeWorkflowConfig.getPostComputeFingerprint()) - .thenReturn(POST_COMPUTE_FINGERPRINT); - when(teeWorkflowConfig.getPostComputeEntrypoint()) - .thenReturn(POST_COMPUTE_ENTRYPOINT); - when(web2SecretsService.getSecret( - request.getTaskDescription().getBeneficiary(), - ReservedSecretKeyName.IEXEC_RESULT_ENCRYPTION_PUBLIC_KEY, - true)) - .thenReturn(Optional.of(publicKeySecret)); - Secret storageSecret = new Secret("address", STORAGE_TOKEN); - when(web2SecretsService.getSecret( - requesterAddress, - ReservedSecretKeyName.IEXEC_RESULT_IEXEC_IPFS_TOKEN, - true)) - .thenReturn(Optional.of(storageSecret)); - - TeeChallenge challenge = TeeChallenge.builder() - .credentials(EthereumCredentials.generate()) - .build(); - when(teeChallengeService.getOrCreate(TASK_ID, true)) - .thenReturn(Optional.of(challenge)); - - - Map tokens = - palaemonSessionService.getPostComputePalaemonTokens(request); - - final Map expectedTokens = new HashMap<>(); - expectedTokens.put(PalaemonSessionService.POST_COMPUTE_MRENCLAVE, POST_COMPUTE_FINGERPRINT); - expectedTokens.put(PalaemonSessionService.POST_COMPUTE_ENTRYPOINT, POST_COMPUTE_ENTRYPOINT); - // encryption tokens - expectedTokens.put(ResultUtils.RESULT_ENCRYPTION, "yes"); - expectedTokens.put(ResultUtils.RESULT_ENCRYPTION_PUBLIC_KEY, ENCRYPTION_PUBLIC_KEY); - // storage tokens - expectedTokens.put(ResultUtils.RESULT_STORAGE_CALLBACK, "no"); - expectedTokens.put(ResultUtils.RESULT_STORAGE_PROVIDER, STORAGE_PROVIDER); - expectedTokens.put(ResultUtils.RESULT_STORAGE_PROXY, STORAGE_PROXY); - expectedTokens.put(ResultUtils.RESULT_STORAGE_TOKEN, STORAGE_TOKEN); - // sign tokens - expectedTokens.put(ResultUtils.RESULT_TASK_ID, TASK_ID); - expectedTokens.put(ResultUtils.RESULT_SIGN_WORKER_ADDRESS, WORKER_ADDRESS); - expectedTokens.put(ResultUtils.RESULT_SIGN_TEE_CHALLENGE_PRIVATE_KEY, challenge.getCredentials().getPrivateKey()); - - assertThat(tokens).containsExactlyEntriesOf(expectedTokens); - } - - @Test - void shouldNotGetPostComputePalaemonTokensSinceTaskDescriptionMissing() { - PalaemonSessionRequest request = PalaemonSessionRequest.builder().build(); - - final TeeSessionGenerationException exception = assertThrows( - TeeSessionGenerationException.class, - () -> palaemonSessionService.getPostComputePalaemonTokens(request) - ); - assertEquals(NO_TASK_DESCRIPTION, exception.getError()); - assertEquals("Task description must not be null", exception.getMessage()); - } - //endregion - - //region getPostComputeEncryptionTokens - @Test - void shouldGetPostComputeStorageTokensWithCallback() { - final PalaemonSessionRequest sessionRequest = createSessionRequest(createTaskDescription()); - sessionRequest.getTaskDescription().setCallback("callback"); - - final Map tokens = assertDoesNotThrow( - () -> palaemonSessionService.getPostComputeStorageTokens(sessionRequest)); - - assertThat(tokens) - .containsExactlyInAnyOrderEntriesOf( - Map.of( - RESULT_STORAGE_CALLBACK, "yes", - RESULT_STORAGE_PROVIDER, EMPTY_YML_VALUE, - RESULT_STORAGE_PROXY, EMPTY_YML_VALUE, - RESULT_STORAGE_TOKEN, EMPTY_YML_VALUE - ) - ); - } - - @Test - void shouldGetPostComputeStorageTokensOnIpfs() { - final PalaemonSessionRequest sessionRequest = createSessionRequest(createTaskDescription()); - final TaskDescription taskDescription = sessionRequest.getTaskDescription(); - - final String secretValue = "Secret value"; - when(web2SecretsService.getSecret(taskDescription.getRequester(), ReservedSecretKeyName.IEXEC_RESULT_IEXEC_IPFS_TOKEN, true)) - .thenReturn(Optional.of(new Secret(null, secretValue))); - - final Map tokens = assertDoesNotThrow( - () -> palaemonSessionService.getPostComputeStorageTokens(sessionRequest)); - - assertThat(tokens) - .containsExactlyInAnyOrderEntriesOf( - Map.of( - RESULT_STORAGE_CALLBACK, "no", - RESULT_STORAGE_PROVIDER, STORAGE_PROVIDER, - RESULT_STORAGE_PROXY, STORAGE_PROXY, - RESULT_STORAGE_TOKEN, secretValue - ) - ); - } - - @Test - void shouldGetPostComputeStorageTokensOnDropbox() { - final PalaemonSessionRequest sessionRequest = createSessionRequest(createTaskDescription()); - final TaskDescription taskDescription = sessionRequest.getTaskDescription(); - taskDescription.setResultStorageProvider(DROPBOX_RESULT_STORAGE_PROVIDER); - - final String secretValue = "Secret value"; - when(web2SecretsService.getSecret(taskDescription.getRequester(), IEXEC_RESULT_DROPBOX_TOKEN, true)) - .thenReturn(Optional.of(new Secret(null, secretValue))); - - final Map tokens = assertDoesNotThrow( - () -> palaemonSessionService.getPostComputeStorageTokens(sessionRequest)); - - assertThat(tokens) - .containsExactlyInAnyOrderEntriesOf( - Map.of( - RESULT_STORAGE_CALLBACK, "no", - RESULT_STORAGE_PROVIDER, DROPBOX_RESULT_STORAGE_PROVIDER, - RESULT_STORAGE_PROXY, STORAGE_PROXY, - RESULT_STORAGE_TOKEN, secretValue - ) - ); - } - - @Test - void shouldNotGetPostComputeStorageTokensSinceNoSecret() { - final PalaemonSessionRequest sessionRequest = createSessionRequest(createTaskDescription()); - final TaskDescription taskDescription = sessionRequest.getTaskDescription(); - - when(web2SecretsService.getSecret(taskDescription.getRequester(), ReservedSecretKeyName.IEXEC_RESULT_IEXEC_IPFS_TOKEN, true)) - .thenReturn(Optional.empty()); - - final TeeSessionGenerationException exception = assertThrows( - TeeSessionGenerationException.class, - () -> palaemonSessionService.getPostComputeStorageTokens(sessionRequest)); - - assertThat(exception.getError()).isEqualTo(POST_COMPUTE_GET_STORAGE_TOKENS_FAILED); - assertThat(exception.getMessage()).isEqualTo("Empty requester storage token - taskId: " + taskDescription.getChainTaskId()); - } - - @Test - void shouldGetPostComputeSignTokens() throws GeneralSecurityException { - final PalaemonSessionRequest sessionRequest = createSessionRequest(createTaskDescription()); - final TaskDescription taskDescription = sessionRequest.getTaskDescription(); - final String taskId = taskDescription.getChainTaskId(); - final EthereumCredentials credentials = EthereumCredentials.generate(); - - when(teeChallengeService.getOrCreate(taskId, true)) - .thenReturn(Optional.of(TeeChallenge.builder().credentials(credentials).build())); - - final Map tokens = assertDoesNotThrow(() -> palaemonSessionService.getPostComputeSignTokens(sessionRequest)); - - assertThat(tokens) - .containsExactlyInAnyOrderEntriesOf( - Map.of( - RESULT_TASK_ID, taskId, - RESULT_SIGN_WORKER_ADDRESS, sessionRequest.getWorkerAddress(), - RESULT_SIGN_TEE_CHALLENGE_PRIVATE_KEY, credentials.getPrivateKey() - ) - ); - } - - @ParameterizedTest - @NullSource - @ValueSource(strings = {""}) - void shouldNotGetPostComputeSignTokensSinceNoWorkerAddress(String emptyWorkerAddress) { - final PalaemonSessionRequest sessionRequest = createSessionRequest(createTaskDescription()); - final String taskId = sessionRequest.getTaskDescription().getChainTaskId(); - sessionRequest.setWorkerAddress(emptyWorkerAddress); - - final TeeSessionGenerationException exception = assertThrows( - TeeSessionGenerationException.class, - () -> palaemonSessionService.getPostComputeSignTokens(sessionRequest) - ); - - assertThat(exception.getError()).isEqualTo(POST_COMPUTE_GET_SIGNATURE_TOKENS_FAILED_EMPTY_WORKER_ADDRESS); - assertThat(exception.getMessage()).isEqualTo("Empty worker address - taskId: " + taskId); - } - - @ParameterizedTest - @NullSource - @ValueSource(strings = {""}) - void shouldNotGetPostComputeSignTokensSinceNoEnclaveChallenge(String emptyEnclaveChallenge) { - final PalaemonSessionRequest sessionRequest = createSessionRequest(createTaskDescription()); - final String taskId = sessionRequest.getTaskDescription().getChainTaskId(); - sessionRequest.setEnclaveChallenge(emptyEnclaveChallenge); - - final TeeSessionGenerationException exception = assertThrows( - TeeSessionGenerationException.class, - () -> palaemonSessionService.getPostComputeSignTokens(sessionRequest) - ); - - assertThat(exception.getError()).isEqualTo(POST_COMPUTE_GET_SIGNATURE_TOKENS_FAILED_EMPTY_PUBLIC_ENCLAVE_CHALLENGE); - assertThat(exception.getMessage()).isEqualTo("Empty public enclave challenge - taskId: " + taskId); - } - - @Test - void shouldNotGetPostComputeSignTokensSinceNoTeeChallenge() { - final PalaemonSessionRequest sessionRequest = createSessionRequest(createTaskDescription()); - final String taskId = sessionRequest.getTaskDescription().getChainTaskId(); - - when(teeChallengeService.getOrCreate(taskId, true)) - .thenReturn(Optional.empty()); - - final TeeSessionGenerationException exception = assertThrows( - TeeSessionGenerationException.class, - () -> palaemonSessionService.getPostComputeSignTokens(sessionRequest) - ); - - assertThat(exception.getError()).isEqualTo(POST_COMPUTE_GET_SIGNATURE_TOKENS_FAILED_EMPTY_TEE_CHALLENGE); - assertThat(exception.getMessage()).isEqualTo("Empty TEE challenge - taskId: " + taskId); - } - - @Test - void shouldNotGetPostComputeSignTokensSinceNoEnclaveCredentials() { - final PalaemonSessionRequest sessionRequest = createSessionRequest(createTaskDescription()); - final String taskId = sessionRequest.getTaskDescription().getChainTaskId(); - - when(teeChallengeService.getOrCreate(taskId, true)) - .thenReturn(Optional.of(TeeChallenge.builder().credentials(null).build())); - - final TeeSessionGenerationException exception = assertThrows( - TeeSessionGenerationException.class, - () -> palaemonSessionService.getPostComputeSignTokens(sessionRequest) - ); - - assertThat(exception.getError()).isEqualTo(POST_COMPUTE_GET_SIGNATURE_TOKENS_FAILED_EMPTY_TEE_CREDENTIALS); - assertThat(exception.getMessage()).isEqualTo("Empty TEE challenge credentials - taskId: " + taskId); - } - - @Test - void shouldNotGetPostComputeSignTokensSinceNoEnclaveCredentialsPrivateKey() { - final PalaemonSessionRequest sessionRequest = createSessionRequest(createTaskDescription()); - final String taskId = sessionRequest.getTaskDescription().getChainTaskId(); - - when(teeChallengeService.getOrCreate(taskId, true)) - .thenReturn(Optional.of(TeeChallenge.builder().credentials(new EthereumCredentials("", "", false, "")).build())); - - final TeeSessionGenerationException exception = assertThrows( - TeeSessionGenerationException.class, - () -> palaemonSessionService.getPostComputeSignTokens(sessionRequest) - ); - - assertThat(exception.getError()).isEqualTo(POST_COMPUTE_GET_SIGNATURE_TOKENS_FAILED_EMPTY_TEE_CREDENTIALS); - assertThat(exception.getMessage()).isEqualTo("Empty TEE challenge credentials - taskId: " + taskId); - } - - // endregion - - @Test - void shouldGetPostComputeEncryptionTokensWithEncryption() { - PalaemonSessionRequest request = createSessionRequest(createTaskDescription()); - - Secret publicKeySecret = new Secret("address", ENCRYPTION_PUBLIC_KEY); - when(web2SecretsService.getSecret( - request.getTaskDescription().getBeneficiary(), - IEXEC_RESULT_ENCRYPTION_PUBLIC_KEY, - true)) - .thenReturn(Optional.of(publicKeySecret)); - - final Map encryptionTokens = assertDoesNotThrow(() -> palaemonSessionService.getPostComputeEncryptionTokens(request)); - assertThat(encryptionTokens) - .containsExactlyInAnyOrderEntriesOf( - Map.of( - RESULT_ENCRYPTION, "yes", - RESULT_ENCRYPTION_PUBLIC_KEY, ENCRYPTION_PUBLIC_KEY - ) - ); - } - - @Test - void shouldGetPostComputeEncryptionTokensWithoutEncryption() { - PalaemonSessionRequest request = createSessionRequest(createTaskDescription()); - request.getTaskDescription().setResultEncryption(false); - - final Map encryptionTokens = assertDoesNotThrow(() -> palaemonSessionService.getPostComputeEncryptionTokens(request)); - assertThat(encryptionTokens) - .containsExactlyInAnyOrderEntriesOf( - Map.of( - RESULT_ENCRYPTION, "no", - RESULT_ENCRYPTION_PUBLIC_KEY, "" - ) - ); - } - - @Test - void shouldNotGetPostComputeEncryptionTokensSinceEmptyBeneficiaryKey() { - PalaemonSessionRequest request = createSessionRequest(createTaskDescription()); - - when(web2SecretsService.getSecret( - request.getTaskDescription().getBeneficiary(), - IEXEC_RESULT_ENCRYPTION_PUBLIC_KEY, - true)) - .thenReturn(Optional.empty()); - - final TeeSessionGenerationException exception = assertThrows( - TeeSessionGenerationException.class, - () -> palaemonSessionService.getPostComputeEncryptionTokens(request) - ); - assertEquals(POST_COMPUTE_GET_ENCRYPTION_TOKENS_FAILED_EMPTY_BENEFICIARY_KEY, exception.getError()); - assertEquals("Empty beneficiary encryption key - taskId: taskId", exception.getMessage()); - } - - //endregion - - //region utils - private void addApplicationDeveloperSecret() { - TeeTaskComputeSecret applicationDeveloperSecret = TeeTaskComputeSecret.builder() - .onChainObjectType(OnChainObjectType.APPLICATION) - .onChainObjectAddress(appAddress) - .secretOwnerRole(SecretOwnerRole.APPLICATION_DEVELOPER) - .key(APP_DEVELOPER_SECRET_INDEX) - .value(APP_DEVELOPER_SECRET_VALUE) - .build(); - when(teeTaskComputeSecretService.getSecret(OnChainObjectType.APPLICATION, appAddress, SecretOwnerRole.APPLICATION_DEVELOPER, "", APP_DEVELOPER_SECRET_INDEX)) - .thenReturn(Optional.of(applicationDeveloperSecret)); - } - - private void addRequesterSecret(String secretKey, String secretValue) { - TeeTaskComputeSecret requesterSecret = TeeTaskComputeSecret.builder() - .onChainObjectType(OnChainObjectType.APPLICATION) - .onChainObjectAddress("") - .secretOwnerRole(SecretOwnerRole.REQUESTER) - .fixedSecretOwner(requesterAddress) - .key(secretKey) - .value(secretValue) - .build(); - when(teeTaskComputeSecretService.getSecret(OnChainObjectType.APPLICATION, "", SecretOwnerRole.REQUESTER, requesterAddress, secretKey)) - .thenReturn(Optional.of(requesterSecret)); - } - - private PalaemonSessionRequest createSessionRequest(TaskDescription taskDescription) { - return PalaemonSessionRequest.builder() - .sessionId(SESSION_ID) - .workerAddress(WORKER_ADDRESS) - .enclaveChallenge(ENCLAVE_CHALLENGE) - .taskDescription(taskDescription) - .build(); - } - - private TaskDescription createTaskDescription() { - appAddress = createEthereumAddress(); - requesterAddress = createEthereumAddress(); - return TaskDescription.builder() - .chainTaskId(TASK_ID) - .appUri(APP_URI) - .appAddress(appAddress) - .appEnclaveConfiguration(enclaveConfig) - .datasetAddress(DATASET_ADDRESS) - .datasetUri(DATASET_URL) - .datasetName(DATASET_NAME) - .datasetChecksum(DATASET_CHECKSUM) - .requester(requesterAddress) - .cmd(ARGS) - .inputFiles(List.of(INPUT_FILE_URL_1, INPUT_FILE_URL_2)) - .isResultEncryption(true) - .resultStorageProvider(STORAGE_PROVIDER) - .resultStorageProxy(STORAGE_PROXY) - .secrets(Map.of("1", REQUESTER_SECRET_KEY_1, "2", REQUESTER_SECRET_KEY_2)) - .botSize(1) - .botFirstIndex(0) - .botIndex(0) - .build(); - } - - private Map getPreComputeTokens() { - return Map.of( - PRE_COMPUTE_MRENCLAVE, PRE_COMPUTE_FINGERPRINT, - PalaemonSessionService.PRE_COMPUTE_ENTRYPOINT, PRE_COMPUTE_ENTRYPOINT, - PreComputeUtils.IS_DATASET_REQUIRED, true, - PreComputeUtils.IEXEC_DATASET_KEY, DATASET_KEY.trim(), - INPUT_FILE_URLS, Map.of( - IexecEnvUtils.IEXEC_INPUT_FILE_URL_PREFIX + "1", INPUT_FILE_URL_1, - IexecEnvUtils.IEXEC_INPUT_FILE_URL_PREFIX + "2", INPUT_FILE_URL_2)); - } - - private Map getAppTokens() { - return Map.of( - APP_MRENCLAVE, APP_FINGERPRINT, - APP_ARGS, APP_ENTRYPOINT + " " + ARGS, - INPUT_FILE_NAMES, Map.of( - IexecEnvUtils.IEXEC_INPUT_FILE_NAME_PREFIX + "1", INPUT_FILE_NAME_1, - IexecEnvUtils.IEXEC_INPUT_FILE_NAME_PREFIX + "2", INPUT_FILE_NAME_2)); - } - - private Map getPostComputeTokens() { - Map map = new HashMap<>(); - map.put(POST_COMPUTE_MRENCLAVE, POST_COMPUTE_FINGERPRINT); - map.put(PalaemonSessionService.POST_COMPUTE_ENTRYPOINT, POST_COMPUTE_ENTRYPOINT); - map.put(RESULT_TASK_ID, TASK_ID); - map.put(RESULT_ENCRYPTION, "yes"); - map.put(RESULT_ENCRYPTION_PUBLIC_KEY, ENCRYPTION_PUBLIC_KEY); - map.put(RESULT_STORAGE_PROVIDER, STORAGE_PROVIDER); - map.put(RESULT_STORAGE_PROXY, STORAGE_PROXY); - map.put(RESULT_STORAGE_TOKEN, STORAGE_TOKEN); - map.put(RESULT_STORAGE_CALLBACK, "no"); - map.put(RESULT_SIGN_WORKER_ADDRESS, WORKER_ADDRESS); - map.put(RESULT_SIGN_TEE_CHALLENGE_PRIVATE_KEY, TEE_CHALLENGE_PRIVATE_KEY); - return map; - } - - private void assertRecursively(Object expected, Object actual) { - if (expected == null || - expected instanceof String || - ClassUtils.isPrimitiveOrWrapper(expected.getClass())) { - log.info("Comparing [actual:{}, expected:{}]", expected, actual); - assertThat(expected).isEqualTo(actual); - return; - } - if (expected instanceof List) { - List actualList = (List) expected; - List expectedList = (List) actual; - for (int i = 0; i < actualList.size(); i++) { - assertRecursively(actualList.get(i), expectedList.get(i)); - } - return; - } - if (expected instanceof Map) { - Map actualMap = (Map) expected; - Map expectedMap = (Map) actual; - actualMap.keySet().forEach((key) -> { - log.info("Checking '{}'", key); - assertRecursively(actualMap.get(key), expectedMap.get(key)); - }); - } - } //endregion } From a7d930fb8e1061078026c65f8337ad6b90a7f34d Mon Sep 17 00:00:00 2001 From: maxence Date: Mon, 11 Jul 2022 17:21:19 +0200 Subject: [PATCH 005/293] Add `GramineSessionService` --- gramine.md | 6 +- .../gramine/GramineSessionService.java | 80 +++++++++++++++++++ src/main/resources/application.yml | 4 + .../resources/gramineSessionTemplate.json.vm | 57 +++++++++++++ .../gramine/GramineSessionServiceTests.java | 78 ++++++++++++++++++ .../palaemon/PalaemonSessionServiceTests.java | 2 +- src/test/resources/gramine-tee-session.json | 50 ++++++++++++ ...e-session.yml => palaemon-tee-session.yml} | 0 8 files changed, 274 insertions(+), 3 deletions(-) create mode 100644 src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionService.java create mode 100644 src/main/resources/gramineSessionTemplate.json.vm create mode 100644 src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionServiceTests.java create mode 100644 src/test/resources/gramine-tee-session.json rename src/test/resources/{tee-session.yml => palaemon-tee-session.yml} (100%) diff --git a/gramine.md b/gramine.md index 6114cca5..cc910e20 100644 --- a/gramine.md +++ b/gramine.md @@ -2,7 +2,9 @@ ## Architecture -- Move `com.iexec.sms.tee.session.[attestation|cas|palaemon]` package to `com.iexec.sms.tee.session.scone`. +- ✅ Move `com.iexec.sms.tee.session.[attestation|cas|palaemon]` package to `com.iexec.sms.tee.session.scone`. +- ✅ Add a `gramineSessionTemplate.json.vm` file +- ✅ Rename `PalaemonSessionRequest` into `TeeSecretsSessionRequest` ## Code ### `TeeController` class @@ -19,7 +21,7 @@ ### `PalaemonSessionService` class -- Should be generified to provide a single secret filler service +- ✅ Should be generified to provide a single secret filler service ### `TeeWorkflowConfiguration` class diff --git a/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionService.java b/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionService.java new file mode 100644 index 00000000..2c770039 --- /dev/null +++ b/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionService.java @@ -0,0 +1,80 @@ +/* + * Copyright 2022 IEXEC BLOCKCHAIN TECH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.iexec.sms.tee.session.gramine; + +import com.iexec.common.utils.FileHelper; +import com.iexec.sms.tee.session.TeeSecretsService; +import com.iexec.sms.tee.session.TeeSecretsSessionRequest; +import com.iexec.sms.tee.session.TeeSessionGenerationException; +import org.apache.commons.lang3.StringUtils; +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.VelocityEngine; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import javax.annotation.PostConstruct; +import java.io.FileNotFoundException; +import java.io.StringWriter; +import java.util.Map; + +@Service +public class GramineSessionService { + + private final TeeSecretsService teeSecretsService; + + @Value("${gramine.session.templateFile}") + private String gramineTemplateFilePath; + + public GramineSessionService(TeeSecretsService teeSecretsService) { + this.teeSecretsService = teeSecretsService; + } + + @PostConstruct + void postConstruct() throws FileNotFoundException { + if (StringUtils.isEmpty(gramineTemplateFilePath)) { + throw new IllegalArgumentException("Missing gramine template filepath"); + } + if (!FileHelper.exists(gramineTemplateFilePath)) { + throw new FileNotFoundException("Missing gramine template file"); + } + } + + /** + * Collect tokens required for different compute stages (pre, in, post) + * and build the JSON config of the TEE session. + * + * @param request session request details + * @return session config in json string format + */ + public String getSessionJson(TeeSecretsSessionRequest request) throws TeeSessionGenerationException { + Map tokens = teeSecretsService.getSecretsTokens(request); + // Merge template with tokens and return the result + return getFilledGramineTemplate(this.gramineTemplateFilePath, tokens); + } + + private String getFilledGramineTemplate(String templatePath, Map tokens) { + VelocityEngine ve = new VelocityEngine(); + ve.init(); + Template template = ve.getTemplate(templatePath); + VelocityContext context = new VelocityContext(); + tokens.forEach(context::put); // copy all data from the tokens into context + StringWriter writer = new StringWriter(); + template.merge(context, writer); + return writer.toString(); + } +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 610ac599..cc35ddcd 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -60,6 +60,10 @@ scone: tolerated-insecure-options: ${IEXEC_SCONE_TOLERATED_INSECURE_OPTIONS:} # e.g.: hyperthreading,software-hardening-needed,insecure-igpu,outdated-tcb,debug-mode ignored-sgx-advisories: ${IEXEC_IGNORED_SGX_ADVISORIES:} # e.g.: INTEL-SA-00220,INTEL-SA-00270 +gramine: + session: + templateFile: ${IEXEC_GRAMINE_TEMPLATE:./src/main/resources/gramineSessionTemplate.json.vm} + # TODO /!\ remove the option of env variable for releases. tee.workflow: las-image: ${IEXEC_SMS_IMAGE_LAS_IMAGE:} # e.g.: registry.scontain.com:5050/scone-production/iexec-las:x.y.z diff --git a/src/main/resources/gramineSessionTemplate.json.vm b/src/main/resources/gramineSessionTemplate.json.vm new file mode 100644 index 00000000..9910c2fa --- /dev/null +++ b/src/main/resources/gramineSessionTemplate.json.vm @@ -0,0 +1,57 @@ +{ + "session": "$SESSION_ID", + "enclaves": [ + { + "name": "app", + "mrenclave": "$APP_MRENCLAVE", + "command": "/apploader.sh", + "environment": { + "IEXEC_TASK_ID": "$env.get('IEXEC_TASK_ID')", + "IEXEC_IN": "$env.get('IEXEC_IN')", + "IEXEC_OUT": "$env.get('IEXEC_OUT')", + + "IEXEC_DATASET_ADDRESS": "$env.get('IEXEC_DATASET_ADDRESS')", + "IEXEC_DATASET_FILENAME": "$env.get('IEXEC_DATASET_FILENAME')", + + "IEXEC_BOT_SIZE": "$env.get('IEXEC_BOT_SIZE')", + "IEXEC_BOT_FIRST_INDEX": "$env.get('IEXEC_BOT_FIRST_INDEX')", + "IEXEC_BOT_TASK_INDEX": "$env.get('IEXEC_BOT_TASK_INDEX')", + + "IEXEC_INPUT_FILES_FOLDER": "$env.get('IEXEC_INPUT_FILES_FOLDER')", + "IEXEC_INPUT_FILES_NUMBER": "$env.get('IEXEC_INPUT_FILES_NUMBER')", + #foreach($key in $INPUT_FILE_NAMES.keySet()) + "$key": "$INPUT_FILE_NAMES.get($key)", + #end + + "IEXEC_APP_DEVELOPER_SECRET": "$IEXEC_APP_DEVELOPER_SECRET_1", + "IEXEC_APP_DEVELOPER_SECRET_1": "$IEXEC_APP_DEVELOPER_SECRET_1", + #foreach($key in $REQUESTER_SECRETS.keySet()) + "$key": "$REQUESTER_SECRETS.get($key)", + #end + }, + "volumes": [ + "$env.get('IEXEC_IN')", + "$env.get('IEXEC_OUT')" + ] + }, + { + "name": "Post Compute", + "mrenclave": "$POST_COMPUTE_MRENCLAVE", + "command": "/apploader.sh", + "environment": { + "RESULT_TASK_ID": "$RESULT_TASK_ID", + "RESULT_ENCRYPTION": "$RESULT_ENCRYPTION", + "RESULT_ENCRYPTION_PUBLIC_KEY": "$RESULT_ENCRYPTION_PUBLIC_KEY", + "RESULT_STORAGE_PROVIDER": "$RESULT_STORAGE_PROVIDER", + "RESULT_STORAGE_PROXY": "$RESULT_STORAGE_PROXY", + "RESULT_STORAGE_TOKEN": "$RESULT_STORAGE_TOKEN", + "RESULT_STORAGE_CALLBACK": "$RESULT_STORAGE_CALLBACK", + "RESULT_SIGN_WORKER_ADDRESS": "$RESULT_SIGN_WORKER_ADDRESS", + "RESULT_SIGN_TEE_CHALLENGE_PRIVATE_KEY": "$RESULT_SIGN_TEE_CHALLENGE_PRIVATE_KEY" + }, + "volumes": [ + "$env.get('IEXEC_OUT')" + ] + } + ] +} \ No newline at end of file diff --git a/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionServiceTests.java b/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionServiceTests.java new file mode 100644 index 00000000..72a58e2f --- /dev/null +++ b/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionServiceTests.java @@ -0,0 +1,78 @@ +package com.iexec.sms.tee.session.gramine; + +import com.iexec.common.tee.TeeEnclaveConfiguration; +import com.iexec.common.utils.FileHelper; +import com.iexec.sms.tee.session.TeeSecretsService; +import com.iexec.sms.tee.session.TeeSecretsSessionRequest; +import com.iexec.sms.tee.workflow.TeeWorkflowConfiguration; +import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.Spy; +import org.springframework.test.util.ReflectionTestUtils; +import org.yaml.snakeyaml.Yaml; + +import java.util.Map; + +import static com.iexec.sms.tee.session.TeeSessionTestUtils.*; +import static org.mockito.Mockito.*; + +@Slf4j +class GramineSessionServiceTests { + private static final String TEMPLATE_SESSION_FILE = "src/main/resources/gramineSessionTemplate.json.vm"; + private static final String EXPECTED_SESSION_FILE = "src/test/resources/gramine-tee-session.json"; + + private static final TeeEnclaveConfiguration enclaveConfig = + mock(TeeEnclaveConfiguration.class); + + @Mock + private TeeWorkflowConfiguration teeWorkflowConfig; + + @Spy + @InjectMocks + private TeeSecretsService teeSecretsService; + + private GramineSessionService gramineSessionService; + + @BeforeEach + void beforeEach() { + MockitoAnnotations.openMocks(this); + + gramineSessionService = spy(new GramineSessionService(teeSecretsService)); + ReflectionTestUtils.setField(gramineSessionService, "gramineTemplateFilePath", TEMPLATE_SESSION_FILE); + } + + //region getSessionYml + /** + * FIXME + * This is currently not a unit test. + * It relies on {@link TeeSecretsService} implementation to work. + * This should be fixed. + */ + @Test + void shouldGetSessionJson() throws Exception { + TeeSecretsSessionRequest request = createSessionRequest(createTaskDescription(enclaveConfig)); + + doReturn(getPreComputeTokens()).when(teeSecretsService) + .getPreComputeTokens(request); + doReturn(getAppTokens()).when(teeSecretsService) + .getAppTokens(request); + doReturn(getPostComputeTokens()).when(teeSecretsService) + .getPostComputeTokens(request); + + when(teeWorkflowConfig.getPreComputeEntrypoint()).thenReturn(PRE_COMPUTE_ENTRYPOINT); + when(teeWorkflowConfig.getPostComputeEntrypoint()).thenReturn(POST_COMPUTE_ENTRYPOINT); + + String actualJsonString = gramineSessionService.getSessionJson(request); + log.info(actualJsonString); + + Map actualJsonMap = new Yaml().load(actualJsonString); + String expectedJsonString = FileHelper.readFile(EXPECTED_SESSION_FILE); + Map expectedYmlMap = new Yaml().load(expectedJsonString); + assertRecursively(expectedYmlMap, actualJsonMap); + } + //endregion +} \ No newline at end of file diff --git a/src/test/java/com/iexec/sms/tee/session/scone/palaemon/PalaemonSessionServiceTests.java b/src/test/java/com/iexec/sms/tee/session/scone/palaemon/PalaemonSessionServiceTests.java index b6b7807f..96e49c0e 100644 --- a/src/test/java/com/iexec/sms/tee/session/scone/palaemon/PalaemonSessionServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/scone/palaemon/PalaemonSessionServiceTests.java @@ -76,7 +76,7 @@ class PalaemonSessionServiceTests { private static final String TEMPLATE_SESSION_FILE = "src/main/resources/palaemonTemplate.vm"; - private static final String EXPECTED_SESSION_FILE = "src/test/resources/tee-session.yml"; + private static final String EXPECTED_SESSION_FILE = "src/test/resources/palaemon-tee-session.yml"; private static final String PRE_COMPUTE_ENTRYPOINT = "entrypoint1"; private static final String APP_FINGERPRINT = "01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b"; private static final String APP_ENTRYPOINT = "appEntrypoint"; diff --git a/src/test/resources/gramine-tee-session.json b/src/test/resources/gramine-tee-session.json new file mode 100644 index 00000000..7b39ec98 --- /dev/null +++ b/src/test/resources/gramine-tee-session.json @@ -0,0 +1,50 @@ +{ + "session": "sessionId", + "enclaves": [ + { + "name": "app", + "mrenclave": "01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b", + "command": "/apploader.sh", + "environment": { + "IEXEC_TASK_ID": "taskId", + "IEXEC_IN": "/iexec_in", + "IEXEC_OUT": "/iexec_out", + + "IEXEC_DATASET_ADDRESS": "0xDatasetAddress", + "IEXEC_DATASET_FILENAME": "datasetName", + + "IEXEC_BOT_SIZE": "1", + "IEXEC_BOT_FIRST_INDEX": "0", + "IEXEC_BOT_TASK_INDEX": "0", + + "IEXEC_INPUT_FILES_FOLDER": "/iexec_in", + "IEXEC_INPUT_FILES_NUMBER": "2", + "IEXEC_INPUT_FILE_NAME_1": "file1", + "IEXEC_INPUT_FILE_NAME_2": "file2" + }, + "volumes": [ + "/iexec_in", + "/iexec_out" + ] + }, + { + "name": "Post Compute", + "mrenclave": "mrEnclave3", + "command": "/apploader.sh", + "environment": { + "RESULT_TASK_ID": "taskId", + "RESULT_ENCRYPTION": "yes", + "RESULT_ENCRYPTION_PUBLIC_KEY": "encryptionPublicKey", + "RESULT_STORAGE_PROVIDER": "ipfs", + "RESULT_STORAGE_PROXY": "storageProxy", + "RESULT_STORAGE_TOKEN": "storageToken", + "RESULT_STORAGE_CALLBACK": "no", + "RESULT_SIGN_WORKER_ADDRESS": "workerAddress", + "RESULT_SIGN_TEE_CHALLENGE_PRIVATE_KEY": "teeChallengePrivateKey" + }, + "volumes": [ + "/iexec_out" + ] + } + ] +} \ No newline at end of file diff --git a/src/test/resources/tee-session.yml b/src/test/resources/palaemon-tee-session.yml similarity index 100% rename from src/test/resources/tee-session.yml rename to src/test/resources/palaemon-tee-session.yml From b898c1faa8274203b2f855d965b7a6598445707e Mon Sep 17 00:00:00 2001 From: maxence Date: Mon, 11 Jul 2022 17:37:07 +0200 Subject: [PATCH 006/293] Add SPS configuration --- .../java/com/iexec/sms/api/SmsClient.java | 3 ++ .../tee/session/gramine/sps/SpsClient.java | 40 ++++++++++++++++++ .../session/gramine/sps/SpsConfiguration.java | 35 ++++++++++++++++ .../sps/SpsConfigurationController.java | 42 +++++++++++++++++++ src/main/resources/application.yml | 2 + 5 files changed, 122 insertions(+) create mode 100644 src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsClient.java create mode 100644 src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsConfiguration.java create mode 100644 src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsConfigurationController.java diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java index d4c8f147..87672e3a 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java @@ -52,6 +52,9 @@ ApiResponseBody> isAppDeveloperAppComputeSecretPresent( @RequestLine("GET /cas/url") String getSconeCasUrl(); + @RequestLine("GET /sps/url") + String getGramineSpsUrl(); + @RequestLine("POST /requesters/{requesterAddress}/secrets/{secretKey}") @Headers("Authorization: {authorization}") ApiResponseBody> addRequesterAppComputeSecret( diff --git a/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsClient.java b/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsClient.java new file mode 100644 index 00000000..be932ef6 --- /dev/null +++ b/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsClient.java @@ -0,0 +1,40 @@ +/* + * Copyright 2020 IEXEC BLOCKCHAIN TECH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.iexec.sms.tee.session.gramine.sps; + +import org.springframework.http.HttpEntity; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +@Service +public class SpsClient { + + private final SpsConfiguration spsConfiguration; + + public SpsClient(SpsConfiguration spsConfiguration) { + this.spsConfiguration = spsConfiguration; + } + + public ResponseEntity generateSecureSession(byte[] sessionFile) { + String url = spsConfiguration.getUrl() + "/api/session"; + HttpEntity request = new HttpEntity<>(sessionFile); + return new RestTemplate() + .postForEntity(url, request, String.class); + } + +} \ No newline at end of file diff --git a/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsConfiguration.java b/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsConfiguration.java new file mode 100644 index 00000000..62effda1 --- /dev/null +++ b/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsConfiguration.java @@ -0,0 +1,35 @@ +/* + * Copyright 2022 IEXEC BLOCKCHAIN TECH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.iexec.sms.tee.session.gramine.sps; + +import lombok.Getter; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; + +@Configuration +@Getter +public class SpsConfiguration { + @Value("${gramine.session.host}") + private String host; + + @Value("${gramine.session.port}") + private String port; + + public String getUrl() { + return "https://" + host + ":" + port; + } +} diff --git a/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsConfigurationController.java b/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsConfigurationController.java new file mode 100644 index 00000000..5ecc78aa --- /dev/null +++ b/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsConfigurationController.java @@ -0,0 +1,42 @@ +/* + * Copyright 2021 IEXEC BLOCKCHAIN TECH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.iexec.sms.tee.session.gramine.sps; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/sps") +public class SpsConfigurationController { + + private final SpsConfiguration spsConfiguration; + + public SpsConfigurationController(SpsConfiguration spsConfiguration) { + this.spsConfiguration = spsConfiguration; + } + + /** + * Get SPS public url intended for enclaves. + * + * @return SPS url + */ + @GetMapping("/url") + public String getGramineSpsUrl() { + return spsConfiguration.getUrl(); + } +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index cc35ddcd..9563c3cb 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -62,6 +62,8 @@ scone: gramine: session: + host: ${IEXEC_GRAMINE_SPS_HOST:localhost} + port: ${IEXEC_GRAMINE_SPS_PORT:8082} templateFile: ${IEXEC_GRAMINE_TEMPLATE:./src/main/resources/gramineSessionTemplate.json.vm} # TODO /!\ remove the option of env variable for releases. From 44aaf2f2b817e14bbb3dd09c6de774f61fad8bac Mon Sep 17 00:00:00 2001 From: maxence Date: Fri, 15 Jul 2022 14:43:47 +0200 Subject: [PATCH 007/293] Post Gramine session to SPS --- gradle.properties | 4 +- gramine.md | 30 ----- .../sms/api/TeeSessionGenerationError.java | 6 +- .../sms/tee/session/TeeSessionService.java | 65 +++++++---- .../{ => generic}/TeeSecretsService.java | 21 ++-- .../generic/TeeSessionProviderService.java | 24 ++++ .../tee/session/generic/TeeSessionStack.java | 46 ++++++++ .../generic/TeeSessionStorageClient.java | 23 ++++ .../gramine/GramineSessionService.java | 10 +- .../sms/tee/session/gramine/GramineStack.java | 29 +++++ .../tee/session/gramine/sps/SpsClient.java | 19 ++- .../session/gramine/sps/SpsConfiguration.java | 28 ++++- .../sps/SpsConfigurationController.java | 5 +- .../sms/tee/session/scone/SconeStack.java | 30 +++++ .../sms/tee/session/scone/cas/CasClient.java | 5 +- .../palaemon/PalaemonSessionService.java | 8 +- src/main/resources/application.yml | 12 +- .../tee/session/TeeSessionServiceTests.java | 109 +++++++++++++----- .../sms/tee/session/TeeSessionTestUtils.java | 2 +- .../{ => generic}/TeeSecretsServiceTests.java | 9 +- .../session/generic/TeeSessionStackTests.java | 76 ++++++++++++ .../gramine/GramineSessionServiceTests.java | 4 +- .../session/gramine/GramineStackTests.java | 18 +++ .../tee/session/scone/SconeStackTests.java | 18 +++ .../palaemon/PalaemonSessionServiceTests.java | 42 +------ 25 files changed, 484 insertions(+), 159 deletions(-) delete mode 100644 gramine.md rename src/main/java/com/iexec/sms/tee/session/{ => generic}/TeeSecretsService.java (96%) create mode 100644 src/main/java/com/iexec/sms/tee/session/generic/TeeSessionProviderService.java create mode 100644 src/main/java/com/iexec/sms/tee/session/generic/TeeSessionStack.java create mode 100644 src/main/java/com/iexec/sms/tee/session/generic/TeeSessionStorageClient.java create mode 100644 src/main/java/com/iexec/sms/tee/session/gramine/GramineStack.java create mode 100644 src/main/java/com/iexec/sms/tee/session/scone/SconeStack.java rename src/test/java/com/iexec/sms/tee/session/{ => generic}/TeeSecretsServiceTests.java (98%) create mode 100644 src/test/java/com/iexec/sms/tee/session/generic/TeeSessionStackTests.java create mode 100644 src/test/java/com/iexec/sms/tee/session/gramine/GramineStackTests.java create mode 100644 src/test/java/com/iexec/sms/tee/session/scone/SconeStackTests.java diff --git a/gradle.properties b/gradle.properties index 21154a17..524a96c0 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -version=7.0.0 -iexecCommonVersion=7.0.0-NEXT-SNAPSHOT +version=7.0.0-gramine +iexecCommonVersion=7.0.0-gramine-NEXT-SNAPSHOT nexusUser= nexusPassword= diff --git a/gramine.md b/gramine.md deleted file mode 100644 index cc910e20..00000000 --- a/gramine.md +++ /dev/null @@ -1,30 +0,0 @@ -# What should change in SMS to add Gramine feature? - -## Architecture - -- ✅ Move `com.iexec.sms.tee.session.[attestation|cas|palaemon]` package to `com.iexec.sms.tee.session.scone`. -- ✅ Add a `gramineSessionTemplate.json.vm` file -- ✅ Rename `PalaemonSessionRequest` into `TeeSecretsSessionRequest` - -## Code -### `TeeController` class - -#### `generateTeeSession` method - -- Signature should get a new `OrderTag` parameter (in `WorkerpoolAuthorization`?) - -### `TeeSessionService` class - -#### `generateTeeSession` method - -- Signature should get a new `OrderTag` parameter - -### `PalaemonSessionService` class - -- ✅ Should be generified to provide a single secret filler service - -### `TeeWorkflowConfiguration` class - -- Rename all `preCompute[...]` and `postCompute[...]` fields to `sconePreCompute[...]` and `sconePostCompute[...]`. -- Add `graminePreCompute[...]` and `graminePostCompute[...]` fields. -- These changes should be made in `application.yml` too. \ No newline at end of file diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/TeeSessionGenerationError.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/TeeSessionGenerationError.java index 77f001c1..61c6a57e 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/TeeSessionGenerationError.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/TeeSessionGenerationError.java @@ -47,15 +47,17 @@ public enum TeeSessionGenerationError { // endregion // region Secure session generation - SECURE_SESSION_CAS_CALL_FAILED, + SECURE_SESSION_STORAGE_CALL_FAILED, SECURE_SESSION_GENERATION_FAILED, + SECURE_SESSION_NO_TEE_PROVIDER, + SECURE_SESSION_UNKNOWN_TEE_PROVIDER, // endregion // region Miscellaneous GET_TASK_DESCRIPTION_FAILED, NO_SESSION_REQUEST, NO_TASK_DESCRIPTION, - GET_SESSION_YML_FAILED, + GET_SESSION_FAILED, UNKNOWN_ISSUE // endregion diff --git a/src/main/java/com/iexec/sms/tee/session/TeeSessionService.java b/src/main/java/com/iexec/sms/tee/session/TeeSessionService.java index f985127d..6e4d7f12 100644 --- a/src/main/java/com/iexec/sms/tee/session/TeeSessionService.java +++ b/src/main/java/com/iexec/sms/tee/session/TeeSessionService.java @@ -17,35 +17,42 @@ package com.iexec.sms.tee.session; import com.iexec.common.task.TaskDescription; +import com.iexec.common.tee.TeeEnclaveProvider; import com.iexec.sms.blockchain.IexecHubService; -import com.iexec.sms.tee.session.scone.cas.CasClient; -import com.iexec.sms.tee.session.scone.palaemon.PalaemonSessionService; +import com.iexec.sms.tee.session.generic.TeeSessionStack; +import com.iexec.sms.tee.session.gramine.GramineStack; +import com.iexec.sms.tee.session.scone.SconeStack; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.RandomStringUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; +import java.util.Map; + import static com.iexec.sms.api.TeeSessionGenerationError.*; @Slf4j @Service public class TeeSessionService { + private final IexecHubService iexecHubService; - private final CasClient casClient; - private final PalaemonSessionService palaemonSessionService; private final boolean shouldDisplayDebugSession; + private final Map teeSessionConfigurations; + public TeeSessionService( IexecHubService iexecService, - PalaemonSessionService palaemonSessionService, - CasClient casClient, - @Value("${logging.tee.display-debug-session}") - boolean shouldDisplayDebugSession) { + SconeStack sconeStack, + GramineStack gramineStack, + @Value("${logging.tee.display-debug-session}") boolean shouldDisplayDebugSession) { this.iexecHubService = iexecService; - this.palaemonSessionService = palaemonSessionService; - this.casClient = casClient; this.shouldDisplayDebugSession = shouldDisplayDebugSession; + + this.teeSessionConfigurations = Map.of( + TeeEnclaveProvider.SCONE, sconeStack, + TeeEnclaveProvider.GRAMINE, gramineStack + ); } public String generateTeeSession( @@ -67,25 +74,43 @@ public String generateTeeSession( .workerAddress(workerAddress) .enclaveChallenge(teeChallenge) .build(); - String sessionYmlAsString = palaemonSessionService.getSessionYml(request); - if (sessionYmlAsString.isEmpty()) { + + final TeeEnclaveProvider teeEnclaveProvider = taskDescription.getTeeEnclaveProvider(); + if (teeEnclaveProvider == null) { + throw new TeeSessionGenerationException( + SECURE_SESSION_NO_TEE_PROVIDER, + String.format("TEE provider can't be null [taskId:%s]", taskId)); + } + + final TeeSessionStack teeSessionStack = + teeSessionConfigurations.get(teeEnclaveProvider); + if (teeSessionStack == null) { + throw new TeeSessionGenerationException( + SECURE_SESSION_UNKNOWN_TEE_PROVIDER, + String.format("Unknown TEE provider [taskId:%s, teeProvider:%s]", taskId, teeEnclaveProvider)); + } + + String sessionAsString = teeSessionStack.generateSession(request); + if (sessionAsString.isEmpty()) { throw new TeeSessionGenerationException( - GET_SESSION_YML_FAILED, - String.format("Failed to get session yml [taskId:%s, workerAddress:%s]", taskId, workerAddress)); + GET_SESSION_FAILED, + String.format("Failed to get session [taskId:%s, workerAddress:%s, enclaveProvider:%s]", + taskId, workerAddress, teeEnclaveProvider)); } - log.info("Session yml is ready [taskId:{}]", taskId); + log.info("Session is ready [taskId:{}]", taskId); if (shouldDisplayDebugSession){ - log.info("Session yml content [taskId:{}]\n{}", taskId, sessionYmlAsString); + log.info("Session content [taskId:{}]\n{}", taskId, sessionAsString); } // /!\ TODO clean expired tasks sessions - boolean isSessionGenerated = casClient - .generateSecureSession(sessionYmlAsString.getBytes()) + boolean isSessionGenerated = teeSessionStack + .postSession(sessionAsString.getBytes()) .getStatusCode() .is2xxSuccessful(); if (!isSessionGenerated) { throw new TeeSessionGenerationException( - SECURE_SESSION_CAS_CALL_FAILED, - String.format("Failed to generate secure session [taskId:%s, workerAddress:%s]", taskId, workerAddress) + SECURE_SESSION_STORAGE_CALL_FAILED, + String.format("Failed to generate secure session [taskId:%s, workerAddress:%s, enclaveProvider:%s]", + taskId, workerAddress, teeEnclaveProvider) ); } return sessionId; diff --git a/src/main/java/com/iexec/sms/tee/session/TeeSecretsService.java b/src/main/java/com/iexec/sms/tee/session/generic/TeeSecretsService.java similarity index 96% rename from src/main/java/com/iexec/sms/tee/session/TeeSecretsService.java rename to src/main/java/com/iexec/sms/tee/session/generic/TeeSecretsService.java index 4de5dbb2..20c46f79 100644 --- a/src/main/java/com/iexec/sms/tee/session/TeeSecretsService.java +++ b/src/main/java/com/iexec/sms/tee/session/generic/TeeSecretsService.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.iexec.sms.tee.session; +package com.iexec.sms.tee.session.generic; import com.iexec.common.sms.secret.ReservedSecretKeyName; import com.iexec.common.task.TaskDescription; @@ -29,9 +29,10 @@ import com.iexec.sms.secret.web3.Web3SecretService; import com.iexec.sms.tee.challenge.TeeChallenge; import com.iexec.sms.tee.challenge.TeeChallengeService; +import com.iexec.sms.tee.session.TeeSecretsSessionRequest; +import com.iexec.sms.tee.session.TeeSessionGenerationException; import com.iexec.sms.tee.workflow.TeeWorkflowConfiguration; import com.iexec.sms.utils.EthereumCredentials; -import lombok.NoArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; @@ -57,18 +58,18 @@ public class TeeSecretsService { public static final String EMPTY_YML_VALUE = ""; // Generic - static final String SESSION_ID = "SESSION_ID"; - static final String INPUT_FILE_URLS = "INPUT_FILE_URLS"; - static final String INPUT_FILE_NAMES = "INPUT_FILE_NAMES"; + public static final String SESSION_ID = "SESSION_ID"; + public static final String INPUT_FILE_URLS = "INPUT_FILE_URLS"; + public static final String INPUT_FILE_NAMES = "INPUT_FILE_NAMES"; // PreCompute - static final String IS_PRE_COMPUTE_REQUIRED = "IS_PRE_COMPUTE_REQUIRED"; - static final String PRE_COMPUTE_MRENCLAVE = "PRE_COMPUTE_MRENCLAVE"; + public static final String IS_PRE_COMPUTE_REQUIRED = "IS_PRE_COMPUTE_REQUIRED"; + public static final String PRE_COMPUTE_MRENCLAVE = "PRE_COMPUTE_MRENCLAVE"; // Compute - static final String APP_MRENCLAVE = "APP_MRENCLAVE"; + public static final String APP_MRENCLAVE = "APP_MRENCLAVE"; // PostCompute - static final String POST_COMPUTE_MRENCLAVE = "POST_COMPUTE_MRENCLAVE"; + public static final String POST_COMPUTE_MRENCLAVE = "POST_COMPUTE_MRENCLAVE"; // Secrets - static final String REQUESTER_SECRETS = "REQUESTER_SECRETS"; + public static final String REQUESTER_SECRETS = "REQUESTER_SECRETS"; // Env private static final String ENV_PROPERTY = "env"; diff --git a/src/main/java/com/iexec/sms/tee/session/generic/TeeSessionProviderService.java b/src/main/java/com/iexec/sms/tee/session/generic/TeeSessionProviderService.java new file mode 100644 index 00000000..6d2e954d --- /dev/null +++ b/src/main/java/com/iexec/sms/tee/session/generic/TeeSessionProviderService.java @@ -0,0 +1,24 @@ +/* + * Copyright 2022 IEXEC BLOCKCHAIN TECH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.iexec.sms.tee.session.generic; + +import com.iexec.sms.tee.session.TeeSecretsSessionRequest; +import com.iexec.sms.tee.session.TeeSessionGenerationException; + +public interface TeeSessionProviderService { + String generateSession(TeeSecretsSessionRequest request) throws TeeSessionGenerationException; +} diff --git a/src/main/java/com/iexec/sms/tee/session/generic/TeeSessionStack.java b/src/main/java/com/iexec/sms/tee/session/generic/TeeSessionStack.java new file mode 100644 index 00000000..35ed6cbf --- /dev/null +++ b/src/main/java/com/iexec/sms/tee/session/generic/TeeSessionStack.java @@ -0,0 +1,46 @@ +/* + * Copyright 2022 IEXEC BLOCKCHAIN TECH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.iexec.sms.tee.session.generic; + +import com.iexec.common.tee.TeeEnclaveProvider; +import com.iexec.sms.tee.session.TeeSecretsSessionRequest; +import com.iexec.sms.tee.session.TeeSessionGenerationException; +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.springframework.http.ResponseEntity; + +/** + * Simple class grouping services & clients + * related to a single TEE enclave provider. + * Some methods from these services & clients + * are transparently called from this class' methods. + */ +@AllArgsConstructor +@Getter +public abstract class TeeSessionStack { + private final TeeEnclaveProvider teeEnclaveProvider; + private final TeeSessionProviderService sessionService; + private final TeeSessionStorageClient client; + + public String generateSession(TeeSecretsSessionRequest request) throws TeeSessionGenerationException { + return sessionService.generateSession(request); + } + + public ResponseEntity postSession(byte[] sessionFile) { + return client.postSession(sessionFile); + } +} diff --git a/src/main/java/com/iexec/sms/tee/session/generic/TeeSessionStorageClient.java b/src/main/java/com/iexec/sms/tee/session/generic/TeeSessionStorageClient.java new file mode 100644 index 00000000..88465db1 --- /dev/null +++ b/src/main/java/com/iexec/sms/tee/session/generic/TeeSessionStorageClient.java @@ -0,0 +1,23 @@ +/* + * Copyright 2022 IEXEC BLOCKCHAIN TECH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.iexec.sms.tee.session.generic; + +import org.springframework.http.ResponseEntity; + +public interface TeeSessionStorageClient { + ResponseEntity postSession(byte[] sessionFile); +} diff --git a/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionService.java b/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionService.java index 2c770039..576a6ae0 100644 --- a/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionService.java +++ b/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionService.java @@ -17,9 +17,10 @@ package com.iexec.sms.tee.session.gramine; import com.iexec.common.utils.FileHelper; -import com.iexec.sms.tee.session.TeeSecretsService; +import com.iexec.sms.tee.session.generic.TeeSecretsService; import com.iexec.sms.tee.session.TeeSecretsSessionRequest; import com.iexec.sms.tee.session.TeeSessionGenerationException; +import com.iexec.sms.tee.session.generic.TeeSessionProviderService; import org.apache.commons.lang3.StringUtils; import org.apache.velocity.Template; import org.apache.velocity.VelocityContext; @@ -33,11 +34,11 @@ import java.util.Map; @Service -public class GramineSessionService { +public class GramineSessionService implements TeeSessionProviderService { private final TeeSecretsService teeSecretsService; - @Value("${gramine.session.templateFile}") + @Value("${gramine.sps.templateFile}") private String gramineTemplateFilePath; public GramineSessionService(TeeSecretsService teeSecretsService) { @@ -61,7 +62,8 @@ void postConstruct() throws FileNotFoundException { * @param request session request details * @return session config in json string format */ - public String getSessionJson(TeeSecretsSessionRequest request) throws TeeSessionGenerationException { + @Override + public String generateSession(TeeSecretsSessionRequest request) throws TeeSessionGenerationException { Map tokens = teeSecretsService.getSecretsTokens(request); // Merge template with tokens and return the result return getFilledGramineTemplate(this.gramineTemplateFilePath, tokens); diff --git a/src/main/java/com/iexec/sms/tee/session/gramine/GramineStack.java b/src/main/java/com/iexec/sms/tee/session/gramine/GramineStack.java new file mode 100644 index 00000000..982949ba --- /dev/null +++ b/src/main/java/com/iexec/sms/tee/session/gramine/GramineStack.java @@ -0,0 +1,29 @@ +/* + * Copyright 2022 IEXEC BLOCKCHAIN TECH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.iexec.sms.tee.session.gramine; + +import com.iexec.common.tee.TeeEnclaveProvider; +import com.iexec.sms.tee.session.generic.TeeSessionStack; +import com.iexec.sms.tee.session.gramine.sps.SpsClient; +import org.springframework.stereotype.Component; + +@Component +public class GramineStack extends TeeSessionStack { + public GramineStack(GramineSessionService sessionService, SpsClient client) { + super(TeeEnclaveProvider.GRAMINE, sessionService, client); + } +} diff --git a/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsClient.java b/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsClient.java index be932ef6..8bf7feb0 100644 --- a/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsClient.java +++ b/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsClient.java @@ -16,13 +16,17 @@ package com.iexec.sms.tee.session.gramine.sps; +import com.iexec.sms.tee.session.generic.TeeSessionStorageClient; import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; +import java.nio.charset.Charset; + @Service -public class SpsClient { +public class SpsClient implements TeeSessionStorageClient { private final SpsConfiguration spsConfiguration; @@ -30,9 +34,16 @@ public SpsClient(SpsConfiguration spsConfiguration) { this.spsConfiguration = spsConfiguration; } - public ResponseEntity generateSecureSession(byte[] sessionFile) { - String url = spsConfiguration.getUrl() + "/api/session"; - HttpEntity request = new HttpEntity<>(sessionFile); + public ResponseEntity postSession(byte[] sessionFile) { + String url = spsConfiguration.getWebUrl() + "/api/session"; + HttpHeaders httpHeaders = new HttpHeaders(); + + httpHeaders.add(HttpHeaders.AUTHORIZATION, HttpHeaders.encodeBasicAuth( + spsConfiguration.getWebLogin(), + spsConfiguration.getWebPassword(), + Charset.defaultCharset())); + + HttpEntity request = new HttpEntity<>(sessionFile, httpHeaders); return new RestTemplate() .postForEntity(url, request, String.class); } diff --git a/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsConfiguration.java b/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsConfiguration.java index 62effda1..e04f23b0 100644 --- a/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsConfiguration.java +++ b/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsConfiguration.java @@ -23,13 +23,29 @@ @Configuration @Getter public class SpsConfiguration { - @Value("${gramine.session.host}") - private String host; + @Value("${gramine.sps.web.host}") + private String webHost; - @Value("${gramine.session.port}") - private String port; + @Value("${gramine.sps.web.port}") + private String webPort; - public String getUrl() { - return "https://" + host + ":" + port; + @Value("${gramine.sps.web.login}") + private String webLogin; + + @Value("${gramine.sps.web.password}") + private String webPassword; + + @Value("${gramine.sps.enclave.host}") + private String enclaveHost; + + @Value("${gramine.sps.enclave.port}") + private String enclavePort; + + public String getWebUrl() { + return "https://" + webHost + ":" + webPort; + } + + public String getEnclaveUrl() { + return "https://" + enclaveHost + ":" + enclavePort; } } diff --git a/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsConfigurationController.java b/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsConfigurationController.java index 5ecc78aa..d3ba1b90 100644 --- a/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsConfigurationController.java +++ b/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsConfigurationController.java @@ -36,7 +36,8 @@ public SpsConfigurationController(SpsConfiguration spsConfiguration) { * @return SPS url */ @GetMapping("/url") - public String getGramineSpsUrl() { - return spsConfiguration.getUrl(); + public String getGramineSpsEnclaveUrl() { + return spsConfiguration.getEnclaveUrl(); } + } diff --git a/src/main/java/com/iexec/sms/tee/session/scone/SconeStack.java b/src/main/java/com/iexec/sms/tee/session/scone/SconeStack.java new file mode 100644 index 00000000..9daacf7b --- /dev/null +++ b/src/main/java/com/iexec/sms/tee/session/scone/SconeStack.java @@ -0,0 +1,30 @@ +/* + * Copyright 2022 IEXEC BLOCKCHAIN TECH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.iexec.sms.tee.session.scone; + +import com.iexec.common.tee.TeeEnclaveProvider; +import com.iexec.sms.tee.session.generic.TeeSessionStack; +import com.iexec.sms.tee.session.scone.cas.CasClient; +import com.iexec.sms.tee.session.scone.palaemon.PalaemonSessionService; +import org.springframework.stereotype.Component; + +@Component +public class SconeStack extends TeeSessionStack { + public SconeStack(PalaemonSessionService sessionService, CasClient client) { + super(TeeEnclaveProvider.SCONE, sessionService, client); + } +} diff --git a/src/main/java/com/iexec/sms/tee/session/scone/cas/CasClient.java b/src/main/java/com/iexec/sms/tee/session/scone/cas/CasClient.java index 08ad6d28..ae5bfc05 100644 --- a/src/main/java/com/iexec/sms/tee/session/scone/cas/CasClient.java +++ b/src/main/java/com/iexec/sms/tee/session/scone/cas/CasClient.java @@ -17,12 +17,13 @@ package com.iexec.sms.tee.session.scone.cas; import com.iexec.sms.ssl.TwoWaySslClient; +import com.iexec.sms.tee.session.generic.TeeSessionStorageClient; import org.springframework.http.HttpEntity; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; @Service -public class CasClient { +public class CasClient implements TeeSessionStorageClient { private final CasConfiguration casConfiguration; private final TwoWaySslClient twoWaySslClient; @@ -36,7 +37,7 @@ public CasClient(CasConfiguration teeCasConfiguration, /* * POST /session of CAS requires 2-way SSL authentication * */ - public ResponseEntity generateSecureSession(byte[] palaemonFile) { + public ResponseEntity postSession(byte[] palaemonFile) { String url = casConfiguration.getUrl() + "/session"; HttpEntity request = new HttpEntity<>(palaemonFile); return twoWaySslClient diff --git a/src/main/java/com/iexec/sms/tee/session/scone/palaemon/PalaemonSessionService.java b/src/main/java/com/iexec/sms/tee/session/scone/palaemon/PalaemonSessionService.java index 60c8b521..17ede7dd 100644 --- a/src/main/java/com/iexec/sms/tee/session/scone/palaemon/PalaemonSessionService.java +++ b/src/main/java/com/iexec/sms/tee/session/scone/palaemon/PalaemonSessionService.java @@ -19,9 +19,10 @@ import com.iexec.common.task.TaskDescription; import com.iexec.common.tee.TeeEnclaveConfiguration; import com.iexec.common.utils.FileHelper; -import com.iexec.sms.tee.session.TeeSecretsService; +import com.iexec.sms.tee.session.generic.TeeSecretsService; import com.iexec.sms.tee.session.TeeSecretsSessionRequest; import com.iexec.sms.tee.session.TeeSessionGenerationException; +import com.iexec.sms.tee.session.generic.TeeSessionProviderService; import com.iexec.sms.tee.session.scone.attestation.AttestationSecurityConfig; import com.iexec.sms.tee.workflow.TeeWorkflowConfiguration; import lombok.extern.slf4j.Slf4j; @@ -40,7 +41,7 @@ @Slf4j @Service -public class PalaemonSessionService { +public class PalaemonSessionService implements TeeSessionProviderService { // Internal values required for setting up a palaemon session // Generic @@ -90,7 +91,8 @@ void postConstruct() throws FileNotFoundException { * @param request session request details * @return session config in yaml string format */ - public String getSessionYml(TeeSecretsSessionRequest request) throws TeeSessionGenerationException { + @Override + public String generateSession(TeeSecretsSessionRequest request) throws TeeSessionGenerationException { Map tokens = teeSecretsService.getSecretsTokens(request); tokens.putAll(getSpecificPalaemonTokens(request)); // Merge template with tokens and return the result diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 9563c3cb..af3befc9 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -61,9 +61,15 @@ scone: ignored-sgx-advisories: ${IEXEC_IGNORED_SGX_ADVISORIES:} # e.g.: INTEL-SA-00220,INTEL-SA-00270 gramine: - session: - host: ${IEXEC_GRAMINE_SPS_HOST:localhost} - port: ${IEXEC_GRAMINE_SPS_PORT:8082} + sps: + web: + host: ${IEXEC_GRAPHENE_SPS_WEB_HOST:localhost} + port: ${IEXEC_GRAPHENE_SPS_WEB_POST:8080} + login: ${IEXEC_GRAPHENE_SPS_WEB_LOGIN:admin} + password: ${IEXEC_GRAPHENE_SPS_WEB_PASSWORD:admin} + enclave: + host: ${IEXEC_GRAPHENE_SPS_ENCLAVE_HOST:localhost} + port: ${IEXEC_GRAPHENE_SPS_ENCLAVE_PORT:4443} templateFile: ${IEXEC_GRAMINE_TEMPLATE:./src/main/resources/gramineSessionTemplate.json.vm} # TODO /!\ remove the option of env variable for releases. diff --git a/src/test/java/com/iexec/sms/tee/session/TeeSessionServiceTests.java b/src/test/java/com/iexec/sms/tee/session/TeeSessionServiceTests.java index 17dff49e..3649a006 100644 --- a/src/test/java/com/iexec/sms/tee/session/TeeSessionServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/TeeSessionServiceTests.java @@ -1,50 +1,76 @@ package com.iexec.sms.tee.session; import com.iexec.common.task.TaskDescription; +import com.iexec.common.tee.TeeEnclaveProvider; import com.iexec.sms.blockchain.IexecHubService; -import com.iexec.sms.tee.session.scone.cas.CasClient; -import com.iexec.sms.tee.session.scone.palaemon.PalaemonSessionService; +import com.iexec.sms.tee.session.generic.TeeSessionStack; +import com.iexec.sms.tee.session.gramine.GramineStack; +import com.iexec.sms.tee.session.scone.SconeStack; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.springframework.http.ResponseEntity; +import java.util.stream.Stream; + import static com.iexec.sms.api.TeeSessionGenerationError.*; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; class TeeSessionServiceTests { private final static String TASK_ID = "0x0"; private final static String WORKER_ADDRESS = "0x1"; private final static String TEE_CHALLENGE = "0x2"; + private static SconeStack sconeStack; + private static GramineStack gramineStack; @Mock IexecHubService iexecHubService; - @Mock - CasClient casClient; + TeeSessionService teeSessionService; - @Mock - PalaemonSessionService palaemonSessionService; + @BeforeAll + static void setUpStacks() { + sconeStack = mock(SconeStack.class); + when(sconeStack.getTeeEnclaveProvider()).thenReturn(TeeEnclaveProvider.SCONE); - TeeSessionService teeSessionService; + gramineStack = mock(GramineStack.class); + when(gramineStack.getTeeEnclaveProvider()).thenReturn(TeeEnclaveProvider.GRAMINE); + } @BeforeEach void setUp() { MockitoAnnotations.openMocks(this); - teeSessionService = new TeeSessionService(iexecHubService, palaemonSessionService, casClient, false); + teeSessionService = new TeeSessionService(iexecHubService, sconeStack, gramineStack, false); + } + + static Stream teeStacks() { + return Stream.of( + Arguments.of(sconeStack), + Arguments.of(gramineStack) + ); } - @Test - void shouldGenerateTeeSession() throws TeeSessionGenerationException { - final TaskDescription taskDescription = TaskDescription.builder().chainTaskId(TASK_ID).build(); - final String sessionYmlAsString = "YML session"; + + @ParameterizedTest + @MethodSource("teeStacks") + void shouldGenerateTeeSession(TeeSessionStack teeSessionStack) throws TeeSessionGenerationException { + final TaskDescription taskDescription = TaskDescription.builder() + .chainTaskId(TASK_ID) + .teeEnclaveProvider(teeSessionStack.getTeeEnclaveProvider()) + .build(); + final String sessionAsString = "session"; when(iexecHubService.getTaskDescription(TASK_ID)).thenReturn(taskDescription); - when(palaemonSessionService.getSessionYml(any())).thenReturn(sessionYmlAsString); - when(casClient.generateSecureSession(sessionYmlAsString.getBytes())).thenReturn(ResponseEntity.ok(null)); + when(teeSessionStack.generateSession(any())).thenReturn(sessionAsString); + when(teeSessionStack.postSession(sessionAsString.getBytes())).thenReturn(ResponseEntity.ok(null)); final String teeSession = assertDoesNotThrow(() -> teeSessionService.generateTeeSession(TASK_ID, WORKER_ADDRESS, TEE_CHALLENGE)); assertNotNull(teeSession); @@ -60,28 +86,57 @@ void shouldNotGenerateTeeSessionSinceCantGetTaskDescription() { } @Test - void shouldNotGenerateTeeSessionSinceCantGetSessionYml() throws TeeSessionGenerationException { - final TaskDescription taskDescription = TaskDescription.builder().chainTaskId(TASK_ID).build(); + void shouldNotGenerateTeeSessionSinceNoTeeEnclaveProvider() { + final TaskDescription taskDescription = TaskDescription.builder() + .chainTaskId(TASK_ID) + .teeEnclaveProvider(null) + .build(); when(iexecHubService.getTaskDescription(TASK_ID)).thenReturn(taskDescription); - when(palaemonSessionService.getSessionYml(any())).thenReturn(""); final TeeSessionGenerationException teeSessionGenerationException = assertThrows(TeeSessionGenerationException.class, () -> teeSessionService.generateTeeSession(TASK_ID, WORKER_ADDRESS, TEE_CHALLENGE)); - assertEquals(GET_SESSION_YML_FAILED, teeSessionGenerationException.getError()); - assertEquals(String.format("Failed to get session yml [taskId:%s, workerAddress:%s]", TASK_ID, WORKER_ADDRESS), teeSessionGenerationException.getMessage()); + assertEquals(SECURE_SESSION_NO_TEE_PROVIDER, teeSessionGenerationException.getError()); + assertEquals(String.format("TEE provider can't be null [taskId:%s]", + TASK_ID), + teeSessionGenerationException.getMessage()); } - @Test - void shouldNotGenerateTeeSessionSinceCantGenerateSecureSession() throws TeeSessionGenerationException { - final TaskDescription taskDescription = TaskDescription.builder().chainTaskId(TASK_ID).build(); - final String sessionYmlAsString = "YML session"; + + @ParameterizedTest + @MethodSource("teeStacks") + void shouldNotGenerateTeeSessionSinceCantGetSession(TeeSessionStack teeSessionStack) throws TeeSessionGenerationException { + final TaskDescription taskDescription = TaskDescription.builder() + .chainTaskId(TASK_ID) + .teeEnclaveProvider(teeSessionStack.getTeeEnclaveProvider()) + .build(); + + when(iexecHubService.getTaskDescription(TASK_ID)).thenReturn(taskDescription); + when(teeSessionStack.generateSession(any())).thenReturn(""); + + final TeeSessionGenerationException teeSessionGenerationException = assertThrows(TeeSessionGenerationException.class, () -> teeSessionService.generateTeeSession(TASK_ID, WORKER_ADDRESS, TEE_CHALLENGE)); + assertEquals(GET_SESSION_FAILED, teeSessionGenerationException.getError()); + assertEquals(String.format("Failed to get session [taskId:%s, workerAddress:%s, enclaveProvider:%s]", + TASK_ID, WORKER_ADDRESS, teeSessionStack.getTeeEnclaveProvider()), + teeSessionGenerationException.getMessage()); + } + + @ParameterizedTest + @MethodSource("teeStacks") + void shouldNotGenerateTeeSessionSinceCantGenerateSecureSession(TeeSessionStack teeSessionStack) throws TeeSessionGenerationException { + final TaskDescription taskDescription = TaskDescription.builder() + .chainTaskId(TASK_ID) + .teeEnclaveProvider(teeSessionStack.getTeeEnclaveProvider()) + .build(); + final String sessionAsString = "session"; when(iexecHubService.getTaskDescription(TASK_ID)).thenReturn(taskDescription); - when(palaemonSessionService.getSessionYml(any())).thenReturn(sessionYmlAsString); - when(casClient.generateSecureSession(sessionYmlAsString.getBytes())).thenReturn(ResponseEntity.notFound().build()); + when(teeSessionStack.generateSession(any())).thenReturn(sessionAsString); + when(teeSessionStack.postSession(sessionAsString.getBytes())).thenReturn(ResponseEntity.notFound().build()); final TeeSessionGenerationException teeSessionGenerationException = assertThrows(TeeSessionGenerationException.class, () -> teeSessionService.generateTeeSession(TASK_ID, WORKER_ADDRESS, TEE_CHALLENGE)); - assertEquals(SECURE_SESSION_CAS_CALL_FAILED, teeSessionGenerationException.getError()); - assertEquals(String.format("Failed to generate secure session [taskId:%s, workerAddress:%s]", TASK_ID, WORKER_ADDRESS), teeSessionGenerationException.getMessage()); + assertEquals(SECURE_SESSION_STORAGE_CALL_FAILED, teeSessionGenerationException.getError()); + assertEquals(String.format("Failed to generate secure session [taskId:%s, workerAddress:%s, enclaveProvider:%s]", + TASK_ID, WORKER_ADDRESS, teeSessionStack.getTeeEnclaveProvider()), + teeSessionGenerationException.getMessage()); } } \ No newline at end of file diff --git a/src/test/java/com/iexec/sms/tee/session/TeeSessionTestUtils.java b/src/test/java/com/iexec/sms/tee/session/TeeSessionTestUtils.java index ec45f6d2..98ca9050 100644 --- a/src/test/java/com/iexec/sms/tee/session/TeeSessionTestUtils.java +++ b/src/test/java/com/iexec/sms/tee/session/TeeSessionTestUtils.java @@ -32,7 +32,7 @@ import static com.iexec.common.worker.result.ResultUtils.*; import static com.iexec.sms.Web3jUtils.createEthereumAddress; -import static com.iexec.sms.tee.session.TeeSecretsService.*; +import static com.iexec.sms.tee.session.generic.TeeSecretsService.*; import static org.assertj.core.api.Assertions.assertThat; @Slf4j diff --git a/src/test/java/com/iexec/sms/tee/session/TeeSecretsServiceTests.java b/src/test/java/com/iexec/sms/tee/session/generic/TeeSecretsServiceTests.java similarity index 98% rename from src/test/java/com/iexec/sms/tee/session/TeeSecretsServiceTests.java rename to src/test/java/com/iexec/sms/tee/session/generic/TeeSecretsServiceTests.java index 20677951..ff554f33 100644 --- a/src/test/java/com/iexec/sms/tee/session/TeeSecretsServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/generic/TeeSecretsServiceTests.java @@ -1,4 +1,4 @@ -package com.iexec.sms.tee.session; +package com.iexec.sms.tee.session.generic; import com.iexec.common.precompute.PreComputeUtils; import com.iexec.common.sms.secret.ReservedSecretKeyName; @@ -18,6 +18,9 @@ import com.iexec.sms.secret.web3.Web3SecretService; import com.iexec.sms.tee.challenge.TeeChallenge; import com.iexec.sms.tee.challenge.TeeChallengeService; +import com.iexec.sms.tee.session.TeeSecretsSessionRequest; +import com.iexec.sms.tee.session.TeeSessionGenerationException; +import com.iexec.sms.tee.session.generic.TeeSecretsService; import com.iexec.sms.tee.workflow.TeeWorkflowConfiguration; import com.iexec.sms.utils.EthereumCredentials; import org.junit.jupiter.api.Assertions; @@ -43,8 +46,8 @@ import static com.iexec.common.worker.result.ResultUtils.*; import static com.iexec.sms.Web3jUtils.createEthereumAddress; import static com.iexec.sms.api.TeeSessionGenerationError.*; -import static com.iexec.sms.tee.session.TeeSecretsService.SESSION_ID; -import static com.iexec.sms.tee.session.TeeSecretsService.*; +import static com.iexec.sms.tee.session.generic.TeeSecretsService.SESSION_ID; +import static com.iexec.sms.tee.session.generic.TeeSecretsService.*; import static com.iexec.sms.tee.session.TeeSessionTestUtils.*; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.*; diff --git a/src/test/java/com/iexec/sms/tee/session/generic/TeeSessionStackTests.java b/src/test/java/com/iexec/sms/tee/session/generic/TeeSessionStackTests.java new file mode 100644 index 00000000..301bb3ac --- /dev/null +++ b/src/test/java/com/iexec/sms/tee/session/generic/TeeSessionStackTests.java @@ -0,0 +1,76 @@ +package com.iexec.sms.tee.session.generic; + +import com.iexec.common.tee.TeeEnclaveProvider; +import com.iexec.sms.api.TeeSessionGenerationError; +import com.iexec.sms.tee.session.TeeSecretsSessionRequest; +import com.iexec.sms.tee.session.TeeSessionGenerationException; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +class TeeSessionStackTests { + private final TeeEnclaveProvider teeEnclaveProvider = TeeEnclaveProvider.GRAMINE; + @Mock + private TeeSessionProviderService sessionService; + @Mock + private TeeSessionStorageClient client; + + private TeeSessionStack teeSessionStack; + + @BeforeEach + void setUp() { + MockitoAnnotations.openMocks(this); + teeSessionStack = new TeeSessionStack(teeEnclaveProvider, sessionService, client) {}; + } + + // region generateSession + @Test + void shouldGenerateSession() throws TeeSessionGenerationException { + TeeSecretsSessionRequest request = mock(TeeSecretsSessionRequest.class); + assertDoesNotThrow(() -> teeSessionStack.generateSession(request)); + verify(sessionService, times(1)).generateSession(request); + verify(client, times(0)).postSession(any()); + } + + @Test + void shouldNotGenerateSessionSinceExceptionThrown() throws TeeSessionGenerationException { + TeeSecretsSessionRequest request = mock(TeeSecretsSessionRequest.class); + final TeeSessionGenerationException expectedException = + new TeeSessionGenerationException(TeeSessionGenerationError.APP_COMPUTE_INVALID_ENCLAVE_CONFIG, ""); + when(sessionService.generateSession(request)).thenThrow(expectedException); + + final TeeSessionGenerationException exception = + assertThrows(TeeSessionGenerationException.class, () -> teeSessionStack.generateSession(request)); + assertEquals(expectedException, exception); + verify(sessionService, times(1)).generateSession(request); + verify(client, times(0)).postSession(any()); + } + // endregion + + // region postSession + @Test + void shouldPostSession() throws TeeSessionGenerationException { + byte[] sessionFile = new byte[10]; + assertDoesNotThrow(() -> teeSessionStack.postSession(sessionFile)); + verify(sessionService, times(0)).generateSession(any()); + verify(client, times(1)).postSession(sessionFile); + } + + @Test + void shouldNotPostSessionSinceExceptionThrown() throws TeeSessionGenerationException { + byte[] sessionFile = new byte[10]; + final RuntimeException expectedException = new RuntimeException(); + when(client.postSession(sessionFile)).thenThrow(expectedException); + + final RuntimeException exception = + assertThrows(RuntimeException.class, () -> teeSessionStack.postSession(sessionFile)); + assertEquals(expectedException, exception); + verify(sessionService, times(0)).generateSession(any()); + verify(client, times(1)).postSession(sessionFile); + } + // endregion +} \ No newline at end of file diff --git a/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionServiceTests.java b/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionServiceTests.java index 72a58e2f..82cb4acb 100644 --- a/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionServiceTests.java @@ -2,7 +2,7 @@ import com.iexec.common.tee.TeeEnclaveConfiguration; import com.iexec.common.utils.FileHelper; -import com.iexec.sms.tee.session.TeeSecretsService; +import com.iexec.sms.tee.session.generic.TeeSecretsService; import com.iexec.sms.tee.session.TeeSecretsSessionRequest; import com.iexec.sms.tee.workflow.TeeWorkflowConfiguration; import lombok.extern.slf4j.Slf4j; @@ -66,7 +66,7 @@ void shouldGetSessionJson() throws Exception { when(teeWorkflowConfig.getPreComputeEntrypoint()).thenReturn(PRE_COMPUTE_ENTRYPOINT); when(teeWorkflowConfig.getPostComputeEntrypoint()).thenReturn(POST_COMPUTE_ENTRYPOINT); - String actualJsonString = gramineSessionService.getSessionJson(request); + String actualJsonString = gramineSessionService.generateSession(request); log.info(actualJsonString); Map actualJsonMap = new Yaml().load(actualJsonString); diff --git a/src/test/java/com/iexec/sms/tee/session/gramine/GramineStackTests.java b/src/test/java/com/iexec/sms/tee/session/gramine/GramineStackTests.java new file mode 100644 index 00000000..53df352a --- /dev/null +++ b/src/test/java/com/iexec/sms/tee/session/gramine/GramineStackTests.java @@ -0,0 +1,18 @@ +package com.iexec.sms.tee.session.gramine; + +import com.iexec.common.tee.TeeEnclaveProvider; +import com.iexec.sms.tee.session.gramine.sps.SpsClient; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.mock; + +class GramineStackTests { + @Test + void shouldCreateGramineStack() { + final GramineStack stack = + new GramineStack(mock(GramineSessionService.class), mock(SpsClient.class)); + assertEquals(TeeEnclaveProvider.GRAMINE, stack.getTeeEnclaveProvider()); + } + +} \ No newline at end of file diff --git a/src/test/java/com/iexec/sms/tee/session/scone/SconeStackTests.java b/src/test/java/com/iexec/sms/tee/session/scone/SconeStackTests.java new file mode 100644 index 00000000..84232fec --- /dev/null +++ b/src/test/java/com/iexec/sms/tee/session/scone/SconeStackTests.java @@ -0,0 +1,18 @@ +package com.iexec.sms.tee.session.scone; + +import com.iexec.common.tee.TeeEnclaveProvider; +import com.iexec.sms.tee.session.scone.cas.CasClient; +import com.iexec.sms.tee.session.scone.palaemon.PalaemonSessionService; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.mock; + +class SconeStackTests { + @Test + void shouldCreateSconeStack() { + final SconeStack stack = + new SconeStack(mock(PalaemonSessionService.class), mock(CasClient.class)); + assertEquals(TeeEnclaveProvider.SCONE, stack.getTeeEnclaveProvider()); + } +} \ No newline at end of file diff --git a/src/test/java/com/iexec/sms/tee/session/scone/palaemon/PalaemonSessionServiceTests.java b/src/test/java/com/iexec/sms/tee/session/scone/palaemon/PalaemonSessionServiceTests.java index 96e49c0e..c55f96b0 100644 --- a/src/test/java/com/iexec/sms/tee/session/scone/palaemon/PalaemonSessionServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/scone/palaemon/PalaemonSessionServiceTests.java @@ -16,39 +16,15 @@ package com.iexec.sms.tee.session.scone.palaemon; -import com.iexec.common.precompute.PreComputeUtils; -import com.iexec.common.sms.secret.ReservedSecretKeyName; -import com.iexec.common.task.TaskDescription; import com.iexec.common.tee.TeeEnclaveConfiguration; -import com.iexec.common.tee.TeeEnclaveConfigurationValidator; import com.iexec.common.utils.FileHelper; -import com.iexec.common.utils.IexecEnvUtils; -import com.iexec.common.worker.result.ResultUtils; -import com.iexec.sms.api.TeeSessionGenerationError; -import com.iexec.sms.secret.Secret; -import com.iexec.sms.secret.compute.OnChainObjectType; -import com.iexec.sms.secret.compute.SecretOwnerRole; -import com.iexec.sms.secret.compute.TeeTaskComputeSecret; -import com.iexec.sms.secret.compute.TeeTaskComputeSecretService; -import com.iexec.sms.secret.web2.Web2SecretsService; -import com.iexec.sms.secret.web3.Web3Secret; -import com.iexec.sms.secret.web3.Web3SecretService; -import com.iexec.sms.tee.challenge.TeeChallenge; -import com.iexec.sms.tee.challenge.TeeChallengeService; -import com.iexec.sms.tee.session.TeeSecretsService; import com.iexec.sms.tee.session.TeeSecretsSessionRequest; -import com.iexec.sms.tee.session.TeeSessionGenerationException; +import com.iexec.sms.tee.session.generic.TeeSecretsService; import com.iexec.sms.tee.session.scone.attestation.AttestationSecurityConfig; import com.iexec.sms.tee.workflow.TeeWorkflowConfiguration; -import com.iexec.sms.utils.EthereumCredentials; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.ClassUtils; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.NullSource; -import org.junit.jupiter.params.provider.ValueSource; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -56,20 +32,10 @@ import org.springframework.test.util.ReflectionTestUtils; import org.yaml.snakeyaml.Yaml; -import java.security.GeneralSecurityException; -import java.util.*; +import java.util.List; +import java.util.Map; -import static com.iexec.common.chain.DealParams.DROPBOX_RESULT_STORAGE_PROVIDER; -import static com.iexec.common.sms.secret.ReservedSecretKeyName.IEXEC_RESULT_DROPBOX_TOKEN; -import static com.iexec.common.sms.secret.ReservedSecretKeyName.IEXEC_RESULT_ENCRYPTION_PUBLIC_KEY; -import static com.iexec.common.worker.result.ResultUtils.*; -import static com.iexec.sms.Web3jUtils.createEthereumAddress; -import static com.iexec.sms.api.TeeSessionGenerationError.*; import static com.iexec.sms.tee.session.TeeSessionTestUtils.*; -import static com.iexec.sms.tee.session.TeeSessionTestUtils.APP_ENTRYPOINT; -import static com.iexec.sms.tee.session.scone.palaemon.PalaemonSessionService.*; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; @Slf4j @@ -131,7 +97,7 @@ void shouldGetSessionYml() throws Exception { when(attestationSecurityConfig.getIgnoredSgxAdvisories()) .thenReturn(List.of("INTEL-SA-00161", "INTEL-SA-00289")); - String actualYmlString = palaemonSessionService.getSessionYml(request); + String actualYmlString = palaemonSessionService.generateSession(request); Map actualYmlMap = new Yaml().load(actualYmlString); String expectedYamlString = FileHelper.readFile(EXPECTED_SESSION_FILE); Map expectedYmlMap = new Yaml().load(expectedYamlString); From d880d634f629ab1d7539ddc33919a75a7a3bc41f Mon Sep 17 00:00:00 2001 From: maxence Date: Fri, 15 Jul 2022 15:13:04 +0200 Subject: [PATCH 008/293] Fix call to SPS & add test --- .../tee/session/gramine/sps/SpsClient.java | 14 +++-- .../session/gramine/sps/SpsClientTests.java | 58 +++++++++++++++++++ 2 files changed, 67 insertions(+), 5 deletions(-) create mode 100644 src/test/java/com/iexec/sms/tee/session/gramine/sps/SpsClientTests.java diff --git a/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsClient.java b/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsClient.java index 8bf7feb0..08597dc4 100644 --- a/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsClient.java +++ b/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsClient.java @@ -38,14 +38,18 @@ public ResponseEntity postSession(byte[] sessionFile) { String url = spsConfiguration.getWebUrl() + "/api/session"; HttpHeaders httpHeaders = new HttpHeaders(); - httpHeaders.add(HttpHeaders.AUTHORIZATION, HttpHeaders.encodeBasicAuth( - spsConfiguration.getWebLogin(), - spsConfiguration.getWebPassword(), - Charset.defaultCharset())); + httpHeaders.add(HttpHeaders.AUTHORIZATION, "Basic " + + HttpHeaders.encodeBasicAuth( + spsConfiguration.getWebLogin(), + spsConfiguration.getWebPassword(), + Charset.defaultCharset())); HttpEntity request = new HttpEntity<>(sessionFile, httpHeaders); - return new RestTemplate() + return createRestTemplate() .postForEntity(url, request, String.class); } + RestTemplate createRestTemplate() { + return new RestTemplate(); + } } \ No newline at end of file diff --git a/src/test/java/com/iexec/sms/tee/session/gramine/sps/SpsClientTests.java b/src/test/java/com/iexec/sms/tee/session/gramine/sps/SpsClientTests.java new file mode 100644 index 00000000..d7bec7b3 --- /dev/null +++ b/src/test/java/com/iexec/sms/tee/session/gramine/sps/SpsClientTests.java @@ -0,0 +1,58 @@ +package com.iexec.sms.tee.session.gramine.sps; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.*; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.ResponseEntity; +import org.springframework.web.client.RestTemplate; + +import static org.mockito.Mockito.*; + +class SpsClientTests { + private static final String SPS_URL = "localhost:8080"; + private static final String SPS_LOGIN = "admin"; + private static final String SPS_PASSWORD = "admin"; + + @Captor + ArgumentCaptor sessionPostUrlCaptor; + @Captor + ArgumentCaptor> sessionPostRequestCaptor; + + @Mock + private SpsConfiguration spsConfiguration; + + @InjectMocks + @Spy + private SpsClient spsClient; + + @BeforeEach + void setUp() { + MockitoAnnotations.openMocks(this); + } + + @Test + void shouldPostSession() { + byte[] session = new byte[10]; + + final RestTemplate restTemplate = mock(RestTemplate.class); + when(spsClient.createRestTemplate()).thenReturn(restTemplate); + when(restTemplate.postForEntity(any(), any(), eq(String.class))).thenReturn(ResponseEntity.ok("OK")); + + when(spsConfiguration.getWebUrl()).thenReturn(SPS_URL); + when(spsConfiguration.getWebLogin()).thenReturn(SPS_LOGIN); + when(spsConfiguration.getWebPassword()).thenReturn(SPS_PASSWORD); + + spsClient.postSession(session); + + verify(restTemplate).postForEntity(sessionPostUrlCaptor.capture(), sessionPostRequestCaptor.capture(), eq(String.class)); + + Assertions.assertEquals(SPS_URL + "/api/session", sessionPostUrlCaptor.getValue()); + Assertions.assertEquals("Basic YWRtaW46YWRtaW4=", sessionPostRequestCaptor.getValue() + .getHeaders() + .get(HttpHeaders.AUTHORIZATION) + .get(0)); + } +} \ No newline at end of file From 77a7421bbfd4c750e3a676754c4d0f4f4bd0de89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20James=20Toussaint?= Date: Fri, 22 Jul 2022 12:40:41 +0200 Subject: [PATCH 009/293] Post on SPS API, refactoring and tests --- build.gradle | 5 + gradle.properties | 4 +- .../com/iexec/sms/api/SmsClientTest.class | Bin 0 -> 823 bytes ...k.java => TeeSessionLogConfiguration.java} | 17 +-- .../sms/tee/session/TeeSessionService.java | 56 ++------ .../session/generic/TeeSecretsService.java | 16 +-- ...derService.java => TeeSessionHandler.java} | 8 +- .../tee/session/generic/TeeSessionStack.java | 46 ------ .../gramine/GramineSessionHandlerService.java | 63 +++++++++ ...e.java => GramineSessionMakerService.java} | 27 ++-- .../sps/SpsApiClient.java} | 11 +- .../tee/session/gramine/sps/SpsClient.java | 55 -------- .../session/gramine/sps/SpsConfiguration.java | 10 +- .../tee/session/gramine/sps/SpsSession.java | 50 +++++++ .../sps/SpsSessionEnclave.java} | 35 +++-- .../scone/SconeSessionHandlerService.java | 61 ++++++++ .../sms/tee/session/scone/cas/CasClient.java | 13 +- .../palaemon/PalaemonSessionService.java | 8 +- .../com/iexec/sms/untee/UnTeeController.java | 14 +- src/main/resources/Dockerfile.untrusted | 4 +- .../resources/gramineSessionTemplate.json.vm | 8 +- src/main/resources/logback-spring.xml | 29 ++++ .../tee/session/TeeSessionServiceTests.java | 133 ++++++++---------- .../sms/tee/session/TeeSessionTestUtils.java | 13 +- .../generic/TeeSecretsServiceTests.java | 21 +-- .../session/generic/TeeSessionStackTests.java | 117 +++++++-------- .../gramine/GramineSessionServiceTests.java | 23 ++- .../session/gramine/GramineStackTests.java | 18 --- .../session/gramine/sps/SpsClientTests.java | 58 -------- .../tee/session/scone/SconeStackTests.java | 18 --- .../palaemon/PalaemonSessionServiceTests.java | 5 +- 31 files changed, 454 insertions(+), 492 deletions(-) create mode 100644 iexec-sms-library/bin/test/com/iexec/sms/api/SmsClientTest.class rename src/main/java/com/iexec/sms/tee/session/{gramine/GramineStack.java => TeeSessionLogConfiguration.java} (61%) rename src/main/java/com/iexec/sms/tee/session/generic/{TeeSessionProviderService.java => TeeSessionHandler.java} (78%) delete mode 100644 src/main/java/com/iexec/sms/tee/session/generic/TeeSessionStack.java create mode 100644 src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerService.java rename src/main/java/com/iexec/sms/tee/session/gramine/{GramineSessionService.java => GramineSessionMakerService.java} (74%) rename src/main/java/com/iexec/sms/tee/session/{generic/TeeSessionStorageClient.java => gramine/sps/SpsApiClient.java} (75%) delete mode 100644 src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsClient.java create mode 100644 src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsSession.java rename src/main/java/com/iexec/sms/tee/session/{scone/SconeStack.java => gramine/sps/SpsSessionEnclave.java} (51%) create mode 100644 src/main/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerService.java create mode 100644 src/main/resources/logback-spring.xml delete mode 100644 src/test/java/com/iexec/sms/tee/session/gramine/GramineStackTests.java delete mode 100644 src/test/java/com/iexec/sms/tee/session/gramine/sps/SpsClientTests.java delete mode 100644 src/test/java/com/iexec/sms/tee/session/scone/SconeStackTests.java diff --git a/build.gradle b/build.gradle index be62b520..4b9af563 100644 --- a/build.gradle +++ b/build.gradle @@ -90,6 +90,11 @@ dependencies { testImplementation 'org.testcontainers:junit-jupiter:1.16.0' testImplementation 'org.testcontainers:testcontainers:1.16.0' testImplementation 'org.testcontainers:mongodb:1.16.0' + + // feign + implementation "io.github.openfeign:feign-core:$openFeignVersion" + implementation "io.github.openfeign:feign-jackson:$openFeignVersion" + implementation "io.github.openfeign:feign-slf4j:$openFeignVersion" } sourceSets { diff --git a/gradle.properties b/gradle.properties index 524a96c0..27c57297 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -version=7.0.0-gramine -iexecCommonVersion=7.0.0-gramine-NEXT-SNAPSHOT +version=gramine +iexecCommonVersion=gramine-NEXT-SNAPSHOT nexusUser= nexusPassword= diff --git a/iexec-sms-library/bin/test/com/iexec/sms/api/SmsClientTest.class b/iexec-sms-library/bin/test/com/iexec/sms/api/SmsClientTest.class new file mode 100644 index 0000000000000000000000000000000000000000..27595b02c162ad2f539077153386457148b786de GIT binary patch literal 823 zcmah{QBM;=5dOBb96b(!0%D~KMbs7(@6p6FMr=7dY_qpVcJ~N>OJ5{D z_yhb=#@T~}8VSD4?94a&?aa6H>-UeJ0AAsRhZ@6nTI8YN7d#D3Zo=eDgrnRHq~OXP zb7MW!8CIsrc@oM*W#Pxkl&6+q{*6$=zGax}^~VhLL2<%;%%K^efq91ISSUU$^9k3- z$wYF7R$Qcs94A`1_&Qm)r@}CF@h4QRc2V&VJRiUMsMcLtIv+y2m7O<)G0p{ z)mQ$tA}?K&48f67To0rpG#>htnH7$qQHhH#XlZBzff}7?S;%@6h2$Ce#{PFKe63)g ztb>6~ERqeb3dk=}1l%LEhGjarsul8%=ygR*)!(q%+Pp;j65BU?KB2%C@pWc6gKN$j Uo)TKaGdw5n6Ke}S?7wUO0X}xgs{jB1 literal 0 HcmV?d00001 diff --git a/src/main/java/com/iexec/sms/tee/session/gramine/GramineStack.java b/src/main/java/com/iexec/sms/tee/session/TeeSessionLogConfiguration.java similarity index 61% rename from src/main/java/com/iexec/sms/tee/session/gramine/GramineStack.java rename to src/main/java/com/iexec/sms/tee/session/TeeSessionLogConfiguration.java index 982949ba..535390c2 100644 --- a/src/main/java/com/iexec/sms/tee/session/gramine/GramineStack.java +++ b/src/main/java/com/iexec/sms/tee/session/TeeSessionLogConfiguration.java @@ -14,16 +14,17 @@ * limitations under the License. */ -package com.iexec.sms.tee.session.gramine; +package com.iexec.sms.tee.session; -import com.iexec.common.tee.TeeEnclaveProvider; -import com.iexec.sms.tee.session.generic.TeeSessionStack; -import com.iexec.sms.tee.session.gramine.sps.SpsClient; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; +import lombok.Getter; + +@Getter @Component -public class GramineStack extends TeeSessionStack { - public GramineStack(GramineSessionService sessionService, SpsClient client) { - super(TeeEnclaveProvider.GRAMINE, sessionService, client); - } +public class TeeSessionLogConfiguration { + + @Value("${logging.tee.display-debug-session}") + boolean displayDebugSessionEnabled; } diff --git a/src/main/java/com/iexec/sms/tee/session/TeeSessionService.java b/src/main/java/com/iexec/sms/tee/session/TeeSessionService.java index 6e4d7f12..ecb0c8eb 100644 --- a/src/main/java/com/iexec/sms/tee/session/TeeSessionService.java +++ b/src/main/java/com/iexec/sms/tee/session/TeeSessionService.java @@ -19,12 +19,11 @@ import com.iexec.common.task.TaskDescription; import com.iexec.common.tee.TeeEnclaveProvider; import com.iexec.sms.blockchain.IexecHubService; -import com.iexec.sms.tee.session.generic.TeeSessionStack; -import com.iexec.sms.tee.session.gramine.GramineStack; -import com.iexec.sms.tee.session.scone.SconeStack; +import com.iexec.sms.tee.session.generic.TeeSessionHandler; +import com.iexec.sms.tee.session.gramine.GramineSessionHandlerService; +import com.iexec.sms.tee.session.scone.SconeSessionHandlerService; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.RandomStringUtils; -import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import java.util.Map; @@ -35,38 +34,30 @@ @Service public class TeeSessionService { - private final IexecHubService iexecHubService; - private final boolean shouldDisplayDebugSession; - private final Map teeSessionConfigurations; + private final Map teeSessionConfigurations; public TeeSessionService( IexecHubService iexecService, - SconeStack sconeStack, - GramineStack gramineStack, - @Value("${logging.tee.display-debug-session}") boolean shouldDisplayDebugSession) { + SconeSessionHandlerService sconeService, + GramineSessionHandlerService gramineService) { this.iexecHubService = iexecService; - this.shouldDisplayDebugSession = shouldDisplayDebugSession; - this.teeSessionConfigurations = Map.of( - TeeEnclaveProvider.SCONE, sconeStack, - TeeEnclaveProvider.GRAMINE, gramineStack - ); + TeeEnclaveProvider.SCONE, sconeService, + TeeEnclaveProvider.GRAMINE, gramineService); } public String generateTeeSession( String taskId, String workerAddress, String teeChallenge) throws TeeSessionGenerationException { - String sessionId = createSessionId(taskId); TaskDescription taskDescription = iexecHubService.getTaskDescription(taskId); if (taskDescription == null) { throw new TeeSessionGenerationException( GET_TASK_DESCRIPTION_FAILED, - String.format("Failed to get task description [taskId:%s]", taskId) - ); + String.format("Failed to get task description [taskId:%s]", taskId)); } TeeSecretsSessionRequest request = TeeSecretsSessionRequest.builder() .sessionId(sessionId) @@ -82,37 +73,15 @@ public String generateTeeSession( String.format("TEE provider can't be null [taskId:%s]", taskId)); } - final TeeSessionStack teeSessionStack = - teeSessionConfigurations.get(teeEnclaveProvider); - if (teeSessionStack == null) { + final TeeSessionHandler teeSessionHandler = teeSessionConfigurations.get(teeEnclaveProvider); + if (teeSessionHandler == null) { throw new TeeSessionGenerationException( SECURE_SESSION_UNKNOWN_TEE_PROVIDER, String.format("Unknown TEE provider [taskId:%s, teeProvider:%s]", taskId, teeEnclaveProvider)); } - String sessionAsString = teeSessionStack.generateSession(request); - if (sessionAsString.isEmpty()) { - throw new TeeSessionGenerationException( - GET_SESSION_FAILED, - String.format("Failed to get session [taskId:%s, workerAddress:%s, enclaveProvider:%s]", - taskId, workerAddress, teeEnclaveProvider)); - } - log.info("Session is ready [taskId:{}]", taskId); - if (shouldDisplayDebugSession){ - log.info("Session content [taskId:{}]\n{}", taskId, sessionAsString); - } // /!\ TODO clean expired tasks sessions - boolean isSessionGenerated = teeSessionStack - .postSession(sessionAsString.getBytes()) - .getStatusCode() - .is2xxSuccessful(); - if (!isSessionGenerated) { - throw new TeeSessionGenerationException( - SECURE_SESSION_STORAGE_CALL_FAILED, - String.format("Failed to generate secure session [taskId:%s, workerAddress:%s, enclaveProvider:%s]", - taskId, workerAddress, teeEnclaveProvider) - ); - } + teeSessionHandler.buildAndPostSession(request); return sessionId; } @@ -120,4 +89,5 @@ private String createSessionId(String taskId) { String randomString = RandomStringUtils.randomAlphanumeric(10); return String.format("%s0000%s", randomString, taskId); } + } diff --git a/src/main/java/com/iexec/sms/tee/session/generic/TeeSecretsService.java b/src/main/java/com/iexec/sms/tee/session/generic/TeeSecretsService.java index 20c46f79..69b64522 100644 --- a/src/main/java/com/iexec/sms/tee/session/generic/TeeSecretsService.java +++ b/src/main/java/com/iexec/sms/tee/session/generic/TeeSecretsService.java @@ -21,10 +21,7 @@ import com.iexec.common.tee.TeeEnclaveConfiguration; import com.iexec.common.utils.IexecEnvUtils; import com.iexec.sms.secret.Secret; -import com.iexec.sms.secret.compute.OnChainObjectType; -import com.iexec.sms.secret.compute.SecretOwnerRole; -import com.iexec.sms.secret.compute.TeeTaskComputeSecret; -import com.iexec.sms.secret.compute.TeeTaskComputeSecretService; +import com.iexec.sms.secret.compute.*; import com.iexec.sms.secret.web2.Web2SecretsService; import com.iexec.sms.secret.web3.Web3SecretService; import com.iexec.sms.tee.challenge.TeeChallenge; @@ -37,10 +34,7 @@ import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; +import java.util.*; import java.util.stream.Collectors; import static com.iexec.common.chain.DealParams.DROPBOX_RESULT_STORAGE_PROVIDER; @@ -304,7 +298,7 @@ public Map getPostComputeTokens(TeeSecretsSessionRequest request return tokens; } - Map getPostComputeEncryptionTokens(TeeSecretsSessionRequest request) + public Map getPostComputeEncryptionTokens(TeeSecretsSessionRequest request) throws TeeSessionGenerationException { TaskDescription taskDescription = request.getTaskDescription(); String taskId = taskDescription.getChainTaskId(); @@ -335,7 +329,7 @@ Map getPostComputeEncryptionTokens(TeeSecretsSessionRequest requ // to the beneficiary private storage space waiting for // that feature we only allow to push to the requester // private storage space - Map getPostComputeStorageTokens(TeeSecretsSessionRequest request) + public Map getPostComputeStorageTokens(TeeSecretsSessionRequest request) throws TeeSessionGenerationException { TaskDescription taskDescription = request.getTaskDescription(); String taskId = taskDescription.getChainTaskId(); @@ -369,7 +363,7 @@ Map getPostComputeStorageTokens(TeeSecretsSessionRequest request return tokens; } - Map getPostComputeSignTokens(TeeSecretsSessionRequest request) + public Map getPostComputeSignTokens(TeeSecretsSessionRequest request) throws TeeSessionGenerationException { String taskId = request.getTaskDescription().getChainTaskId(); String workerAddress = request.getWorkerAddress(); diff --git a/src/main/java/com/iexec/sms/tee/session/generic/TeeSessionProviderService.java b/src/main/java/com/iexec/sms/tee/session/generic/TeeSessionHandler.java similarity index 78% rename from src/main/java/com/iexec/sms/tee/session/generic/TeeSessionProviderService.java rename to src/main/java/com/iexec/sms/tee/session/generic/TeeSessionHandler.java index 6d2e954d..741929d3 100644 --- a/src/main/java/com/iexec/sms/tee/session/generic/TeeSessionProviderService.java +++ b/src/main/java/com/iexec/sms/tee/session/generic/TeeSessionHandler.java @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -19,6 +19,8 @@ import com.iexec.sms.tee.session.TeeSecretsSessionRequest; import com.iexec.sms.tee.session.TeeSessionGenerationException; -public interface TeeSessionProviderService { - String generateSession(TeeSecretsSessionRequest request) throws TeeSessionGenerationException; +public interface TeeSessionHandler { + + void buildAndPostSession(TeeSecretsSessionRequest request) throws TeeSessionGenerationException; + } diff --git a/src/main/java/com/iexec/sms/tee/session/generic/TeeSessionStack.java b/src/main/java/com/iexec/sms/tee/session/generic/TeeSessionStack.java deleted file mode 100644 index 35ed6cbf..00000000 --- a/src/main/java/com/iexec/sms/tee/session/generic/TeeSessionStack.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2022 IEXEC BLOCKCHAIN TECH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.iexec.sms.tee.session.generic; - -import com.iexec.common.tee.TeeEnclaveProvider; -import com.iexec.sms.tee.session.TeeSecretsSessionRequest; -import com.iexec.sms.tee.session.TeeSessionGenerationException; -import lombok.AllArgsConstructor; -import lombok.Getter; -import org.springframework.http.ResponseEntity; - -/** - * Simple class grouping services & clients - * related to a single TEE enclave provider. - * Some methods from these services & clients - * are transparently called from this class' methods. - */ -@AllArgsConstructor -@Getter -public abstract class TeeSessionStack { - private final TeeEnclaveProvider teeEnclaveProvider; - private final TeeSessionProviderService sessionService; - private final TeeSessionStorageClient client; - - public String generateSession(TeeSecretsSessionRequest request) throws TeeSessionGenerationException { - return sessionService.generateSession(request); - } - - public ResponseEntity postSession(byte[] sessionFile) { - return client.postSession(sessionFile); - } -} diff --git a/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerService.java b/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerService.java new file mode 100644 index 00000000..9a2fc481 --- /dev/null +++ b/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerService.java @@ -0,0 +1,63 @@ +/* + * This is the default license template. + * + * File: GramineSessionHandlerService.GHIJ +/* + * Copyright 2022 IEXEC BLOCKCHAIN TECH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.iexec.sms.tee.session.gramine; + +import com.iexec.sms.api.TeeSessionGenerationError; +import com.iexec.sms.tee.session.*; +import com.iexec.sms.tee.session.generic.TeeSessionHandler; +import com.iexec.sms.tee.session.gramine.sps.*; +import feign.Logger.Level; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +public class GramineSessionHandlerService implements TeeSessionHandler { + private GramineSessionMakerService sessionService; + private SpsApiClient spsClient; + private TeeSessionLogConfiguration teeSessionLogConfiguration; + + public GramineSessionHandlerService(GramineSessionMakerService sessionService, + SpsConfiguration spsConfiguration, + TeeSessionLogConfiguration teeSessionLogConfiguration) { + this.sessionService = sessionService; + this.teeSessionLogConfiguration = teeSessionLogConfiguration; + this.spsClient = spsConfiguration.getInstanceWithBasicAuth(Level.FULL); + } + + public void buildAndPostSession(TeeSecretsSessionRequest request) + throws TeeSessionGenerationException { + SpsSession session = sessionService.generateSession(request); + if (session != null + && teeSessionLogConfiguration.isDisplayDebugSessionEnabled()) { + log.info("Session content [taskId:{}]\n{}", + request.getTaskDescription().getChainTaskId(), session.toString()); + } + + try { + spsClient.postSession(session); + } catch (Exception e) { + throw new TeeSessionGenerationException( + TeeSessionGenerationError.SECURE_SESSION_STORAGE_CALL_FAILED, + "Failed to post session: " + e.getMessage()); + } + } +} diff --git a/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionService.java b/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerService.java similarity index 74% rename from src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionService.java rename to src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerService.java index 576a6ae0..30d34d5d 100644 --- a/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionService.java +++ b/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerService.java @@ -16,11 +16,13 @@ package com.iexec.sms.tee.session.gramine; +import com.fasterxml.jackson.databind.ObjectMapper; import com.iexec.common.utils.FileHelper; -import com.iexec.sms.tee.session.generic.TeeSecretsService; +import com.iexec.sms.api.TeeSessionGenerationError; import com.iexec.sms.tee.session.TeeSecretsSessionRequest; import com.iexec.sms.tee.session.TeeSessionGenerationException; -import com.iexec.sms.tee.session.generic.TeeSessionProviderService; +import com.iexec.sms.tee.session.generic.TeeSecretsService; +import com.iexec.sms.tee.session.gramine.sps.SpsSession; import org.apache.commons.lang3.StringUtils; import org.apache.velocity.Template; import org.apache.velocity.VelocityContext; @@ -29,19 +31,20 @@ import org.springframework.stereotype.Service; import javax.annotation.PostConstruct; + import java.io.FileNotFoundException; import java.io.StringWriter; import java.util.Map; @Service -public class GramineSessionService implements TeeSessionProviderService { +public class GramineSessionMakerService { private final TeeSecretsService teeSecretsService; @Value("${gramine.sps.templateFile}") private String gramineTemplateFilePath; - public GramineSessionService(TeeSecretsService teeSecretsService) { + public GramineSessionMakerService(TeeSecretsService teeSecretsService) { this.teeSecretsService = teeSecretsService; } @@ -60,13 +63,19 @@ void postConstruct() throws FileNotFoundException { * and build the JSON config of the TEE session. * * @param request session request details - * @return session config in json string format + * @return session config */ - @Override - public String generateSession(TeeSecretsSessionRequest request) throws TeeSessionGenerationException { + public SpsSession generateSession(TeeSecretsSessionRequest request) throws TeeSessionGenerationException { Map tokens = teeSecretsService.getSecretsTokens(request); - // Merge template with tokens and return the result - return getFilledGramineTemplate(this.gramineTemplateFilePath, tokens); + // Merge template with tokens + String sessionJsonAsString = getFilledGramineTemplate(this.gramineTemplateFilePath, tokens); + try { + return new ObjectMapper().readValue(sessionJsonAsString, SpsSession.class); + } catch (Exception e) { + throw new TeeSessionGenerationException( + TeeSessionGenerationError.SECURE_SESSION_GENERATION_FAILED, + "Failed to parse SPS session:" + e.getMessage()); + } } private String getFilledGramineTemplate(String templatePath, Map tokens) { diff --git a/src/main/java/com/iexec/sms/tee/session/generic/TeeSessionStorageClient.java b/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsApiClient.java similarity index 75% rename from src/main/java/com/iexec/sms/tee/session/generic/TeeSessionStorageClient.java rename to src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsApiClient.java index 88465db1..794b2aa2 100644 --- a/src/main/java/com/iexec/sms/tee/session/generic/TeeSessionStorageClient.java +++ b/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsApiClient.java @@ -14,10 +14,13 @@ * limitations under the License. */ -package com.iexec.sms.tee.session.generic; +package com.iexec.sms.tee.session.gramine.sps; -import org.springframework.http.ResponseEntity; +import feign.RequestLine; + +public interface SpsApiClient { + + @RequestLine("POST /api/session") + String postSession(SpsSession spsSession); -public interface TeeSessionStorageClient { - ResponseEntity postSession(byte[] sessionFile); } diff --git a/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsClient.java b/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsClient.java deleted file mode 100644 index 08597dc4..00000000 --- a/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsClient.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2020 IEXEC BLOCKCHAIN TECH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.iexec.sms.tee.session.gramine.sps; - -import com.iexec.sms.tee.session.generic.TeeSessionStorageClient; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.ResponseEntity; -import org.springframework.stereotype.Service; -import org.springframework.web.client.RestTemplate; - -import java.nio.charset.Charset; - -@Service -public class SpsClient implements TeeSessionStorageClient { - - private final SpsConfiguration spsConfiguration; - - public SpsClient(SpsConfiguration spsConfiguration) { - this.spsConfiguration = spsConfiguration; - } - - public ResponseEntity postSession(byte[] sessionFile) { - String url = spsConfiguration.getWebUrl() + "/api/session"; - HttpHeaders httpHeaders = new HttpHeaders(); - - httpHeaders.add(HttpHeaders.AUTHORIZATION, "Basic " + - HttpHeaders.encodeBasicAuth( - spsConfiguration.getWebLogin(), - spsConfiguration.getWebPassword(), - Charset.defaultCharset())); - - HttpEntity request = new HttpEntity<>(sessionFile, httpHeaders); - return createRestTemplate() - .postForEntity(url, request, String.class); - } - - RestTemplate createRestTemplate() { - return new RestTemplate(); - } -} \ No newline at end of file diff --git a/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsConfiguration.java b/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsConfiguration.java index e04f23b0..e7e11ddc 100644 --- a/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsConfiguration.java +++ b/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsConfiguration.java @@ -16,6 +16,8 @@ package com.iexec.sms.tee.session.gramine.sps; +import com.iexec.common.utils.FeignBuilder; +import feign.Logger; import lombok.Getter; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; @@ -42,10 +44,16 @@ public class SpsConfiguration { private String enclavePort; public String getWebUrl() { - return "https://" + webHost + ":" + webPort; + return "http://" + webHost + ":" + webPort; } public String getEnclaveUrl() { return "https://" + enclaveHost + ":" + enclavePort; } + + public SpsApiClient getInstanceWithBasicAuth(Logger.Level logLevel) { + return FeignBuilder.createBuilderWithBasicAuth(logLevel, webLogin, webPassword) + .target(SpsApiClient.class, getWebUrl()); + } + } diff --git a/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsSession.java b/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsSession.java new file mode 100644 index 00000000..7a718f7a --- /dev/null +++ b/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsSession.java @@ -0,0 +1,50 @@ +/* + * Copyright 2022 IEXEC BLOCKCHAIN TECH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.iexec.sms.tee.session.gramine.sps; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.*; +import lombok.extern.slf4j.Slf4j; + +import java.util.List; + +@Slf4j +@Builder +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class SpsSession { + + @JsonProperty("session") + private String session; + @JsonProperty("enclaves") + private List enclaves; + + @Override + public String toString() { + try { + return new ObjectMapper().writeValueAsString(this); + } catch (JsonProcessingException e) { + log.error("Failed to write SPS session as string [session:{}]", session, e); + return ""; + } + } + +} diff --git a/src/main/java/com/iexec/sms/tee/session/scone/SconeStack.java b/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsSessionEnclave.java similarity index 51% rename from src/main/java/com/iexec/sms/tee/session/scone/SconeStack.java rename to src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsSessionEnclave.java index 9daacf7b..588e4470 100644 --- a/src/main/java/com/iexec/sms/tee/session/scone/SconeStack.java +++ b/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsSessionEnclave.java @@ -14,17 +14,30 @@ * limitations under the License. */ -package com.iexec.sms.tee.session.scone; +package com.iexec.sms.tee.session.gramine.sps; -import com.iexec.common.tee.TeeEnclaveProvider; -import com.iexec.sms.tee.session.generic.TeeSessionStack; -import com.iexec.sms.tee.session.scone.cas.CasClient; -import com.iexec.sms.tee.session.scone.palaemon.PalaemonSessionService; -import org.springframework.stereotype.Component; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.*; + +import java.util.List; +import java.util.Map; + +@Builder +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class SpsSessionEnclave { + + @JsonProperty("name") + private String name; + @JsonProperty("mrenclave") + private String mrenclave; + @JsonProperty("command") + private String command; + @JsonProperty("environment") + private Map environment; + @JsonProperty("volumes") + private List volumes; -@Component -public class SconeStack extends TeeSessionStack { - public SconeStack(PalaemonSessionService sessionService, CasClient client) { - super(TeeEnclaveProvider.SCONE, sessionService, client); - } } diff --git a/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerService.java b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerService.java new file mode 100644 index 00000000..749ed191 --- /dev/null +++ b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerService.java @@ -0,0 +1,61 @@ +/* + * Copyright 2022 IEXEC BLOCKCHAIN TECH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.iexec.sms.tee.session.scone; + +import com.iexec.sms.api.TeeSessionGenerationError; +import com.iexec.sms.tee.session.*; +import com.iexec.sms.tee.session.generic.TeeSessionHandler; +import com.iexec.sms.tee.session.scone.cas.CasClient; +import com.iexec.sms.tee.session.scone.palaemon.PalaemonSessionService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +public class SconeSessionHandlerService implements TeeSessionHandler { + private PalaemonSessionService sessionService; + private CasClient client; + private TeeSessionLogConfiguration teeSessionLogConfiguration; + + public SconeSessionHandlerService(PalaemonSessionService sessionService, + CasClient client, + TeeSessionLogConfiguration teeSessionLogConfiguration) { + this.sessionService = sessionService; + this.client = client; + this.teeSessionLogConfiguration = teeSessionLogConfiguration; + } + + @Override + public void buildAndPostSession(TeeSecretsSessionRequest request) + throws TeeSessionGenerationException { + String session = sessionService.generateSession(request); + if (session != null + && teeSessionLogConfiguration.isDisplayDebugSessionEnabled()) { + log.info("Session content [taskId:{}]\n{}", + request.getTaskDescription().getChainTaskId(), session); + } + ResponseEntity postSession = client.postSession(session); + int httpCode = postSession != null ? postSession.getStatusCodeValue() : null; + if (httpCode != 200) { + throw new TeeSessionGenerationException( + TeeSessionGenerationError.SECURE_SESSION_STORAGE_CALL_FAILED, + "Failed to post session: " + httpCode); + } + } + +} diff --git a/src/main/java/com/iexec/sms/tee/session/scone/cas/CasClient.java b/src/main/java/com/iexec/sms/tee/session/scone/cas/CasClient.java index ae5bfc05..ef5e85e6 100644 --- a/src/main/java/com/iexec/sms/tee/session/scone/cas/CasClient.java +++ b/src/main/java/com/iexec/sms/tee/session/scone/cas/CasClient.java @@ -17,29 +17,30 @@ package com.iexec.sms.tee.session.scone.cas; import com.iexec.sms.ssl.TwoWaySslClient; -import com.iexec.sms.tee.session.generic.TeeSessionStorageClient; import org.springframework.http.HttpEntity; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; +import java.nio.charset.StandardCharsets; + @Service -public class CasClient implements TeeSessionStorageClient { +public class CasClient { private final CasConfiguration casConfiguration; private final TwoWaySslClient twoWaySslClient; public CasClient(CasConfiguration teeCasConfiguration, - TwoWaySslClient twoWaySslClient) { + TwoWaySslClient twoWaySslClient) { this.casConfiguration = teeCasConfiguration; this.twoWaySslClient = twoWaySslClient; } /* * POST /session of CAS requires 2-way SSL authentication - * */ - public ResponseEntity postSession(byte[] palaemonFile) { + */ + public ResponseEntity postSession(String palaemonFile) { String url = casConfiguration.getUrl() + "/session"; - HttpEntity request = new HttpEntity<>(palaemonFile); + HttpEntity request = new HttpEntity<>(palaemonFile.getBytes(StandardCharsets.UTF_8)); return twoWaySslClient .getRestTemplate() .postForEntity(url, request, String.class); diff --git a/src/main/java/com/iexec/sms/tee/session/scone/palaemon/PalaemonSessionService.java b/src/main/java/com/iexec/sms/tee/session/scone/palaemon/PalaemonSessionService.java index 17ede7dd..50672e46 100644 --- a/src/main/java/com/iexec/sms/tee/session/scone/palaemon/PalaemonSessionService.java +++ b/src/main/java/com/iexec/sms/tee/session/scone/palaemon/PalaemonSessionService.java @@ -19,10 +19,9 @@ import com.iexec.common.task.TaskDescription; import com.iexec.common.tee.TeeEnclaveConfiguration; import com.iexec.common.utils.FileHelper; -import com.iexec.sms.tee.session.generic.TeeSecretsService; import com.iexec.sms.tee.session.TeeSecretsSessionRequest; import com.iexec.sms.tee.session.TeeSessionGenerationException; -import com.iexec.sms.tee.session.generic.TeeSessionProviderService; +import com.iexec.sms.tee.session.generic.TeeSecretsService; import com.iexec.sms.tee.session.scone.attestation.AttestationSecurityConfig; import com.iexec.sms.tee.workflow.TeeWorkflowConfiguration; import lombok.extern.slf4j.Slf4j; @@ -34,14 +33,16 @@ import org.springframework.stereotype.Service; import javax.annotation.PostConstruct; + import java.io.FileNotFoundException; import java.io.StringWriter; import java.util.HashMap; import java.util.Map; +//TODO Rename and move @Slf4j @Service -public class PalaemonSessionService implements TeeSessionProviderService { +public class PalaemonSessionService { // Internal values required for setting up a palaemon session // Generic @@ -91,7 +92,6 @@ void postConstruct() throws FileNotFoundException { * @param request session request details * @return session config in yaml string format */ - @Override public String generateSession(TeeSecretsSessionRequest request) throws TeeSessionGenerationException { Map tokens = teeSecretsService.getSecretsTokens(request); tokens.putAll(getSpecificPalaemonTokens(request)); diff --git a/src/main/java/com/iexec/sms/untee/UnTeeController.java b/src/main/java/com/iexec/sms/untee/UnTeeController.java index 3f5161f9..9b7c2543 100644 --- a/src/main/java/com/iexec/sms/untee/UnTeeController.java +++ b/src/main/java/com/iexec/sms/untee/UnTeeController.java @@ -17,21 +17,15 @@ package com.iexec.sms.untee; -import java.util.Optional; - import com.iexec.common.chain.WorkerpoolAuthorization; -import com.iexec.common.sms.secret.SmsSecretResponse; -import com.iexec.common.sms.secret.SmsSecretResponseData; -import com.iexec.common.sms.secret.TaskSecrets; +import com.iexec.common.sms.secret.*; import com.iexec.sms.authorization.AuthorizationService; import com.iexec.sms.untee.secret.UnTeeSecretService; - import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestHeader; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; + +import java.util.Optional; @RestController public class UnTeeController { diff --git a/src/main/resources/Dockerfile.untrusted b/src/main/resources/Dockerfile.untrusted index 76063921..9aa093e4 100644 --- a/src/main/resources/Dockerfile.untrusted +++ b/src/main/resources/Dockerfile.untrusted @@ -5,10 +5,12 @@ ARG jar RUN test -n "$jar" COPY $jar /app/iexec-sms.jar -COPY build/resources/main/palaemonTemplate.vm /app/palaemonTemplate.vm +COPY build/resources/main/*.vm /app/ COPY src/main/resources/ssl-keystore-dev.p12 /app/ssl-keystore-dev.p12 ENV IEXEC_PALAEMON_TEMPLATE=/app/palaemonTemplate.vm +ENV IEXEC_GRAMINE_TEMPLATE=/app/gramineSessionTemplate.json.vm +ENV IEXEC_SMS_SSL_KEYSTORE=/app/ssl-keystore-dev.p12 ENV IEXEC_SMS_SSL_KEYSTORE=/app/ssl-keystore-dev.p12 ENV IEXEC_SMS_STORAGE_ENCRYPTION_AES_KEY_PATH=/scone/iexec-sms-aes.key ENV IEXEC_SMS_BLOCKCHAIN_NODE_ADDRESS=http://chain:8545 diff --git a/src/main/resources/gramineSessionTemplate.json.vm b/src/main/resources/gramineSessionTemplate.json.vm index 9910c2fa..970ce651 100644 --- a/src/main/resources/gramineSessionTemplate.json.vm +++ b/src/main/resources/gramineSessionTemplate.json.vm @@ -9,25 +9,21 @@ "IEXEC_TASK_ID": "$env.get('IEXEC_TASK_ID')", "IEXEC_IN": "$env.get('IEXEC_IN')", "IEXEC_OUT": "$env.get('IEXEC_OUT')", - "IEXEC_DATASET_ADDRESS": "$env.get('IEXEC_DATASET_ADDRESS')", "IEXEC_DATASET_FILENAME": "$env.get('IEXEC_DATASET_FILENAME')", - "IEXEC_BOT_SIZE": "$env.get('IEXEC_BOT_SIZE')", "IEXEC_BOT_FIRST_INDEX": "$env.get('IEXEC_BOT_FIRST_INDEX')", "IEXEC_BOT_TASK_INDEX": "$env.get('IEXEC_BOT_TASK_INDEX')", - "IEXEC_INPUT_FILES_FOLDER": "$env.get('IEXEC_INPUT_FILES_FOLDER')", "IEXEC_INPUT_FILES_NUMBER": "$env.get('IEXEC_INPUT_FILES_NUMBER')", #foreach($key in $INPUT_FILE_NAMES.keySet()) "$key": "$INPUT_FILE_NAMES.get($key)", #end - - "IEXEC_APP_DEVELOPER_SECRET": "$IEXEC_APP_DEVELOPER_SECRET_1", - "IEXEC_APP_DEVELOPER_SECRET_1": "$IEXEC_APP_DEVELOPER_SECRET_1", #foreach($key in $REQUESTER_SECRETS.keySet()) "$key": "$REQUESTER_SECRETS.get($key)", #end + "IEXEC_APP_DEVELOPER_SECRET": "$IEXEC_APP_DEVELOPER_SECRET_1", + "IEXEC_APP_DEVELOPER_SECRET_1": "$IEXEC_APP_DEVELOPER_SECRET_1" }, "volumes": [ "$env.get('IEXEC_IN')", diff --git a/src/main/resources/logback-spring.xml b/src/main/resources/logback-spring.xml new file mode 100644 index 00000000..8748ead4 --- /dev/null +++ b/src/main/resources/logback-spring.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + --> + + \ No newline at end of file diff --git a/src/test/java/com/iexec/sms/tee/session/TeeSessionServiceTests.java b/src/test/java/com/iexec/sms/tee/session/TeeSessionServiceTests.java index 3649a006..e9f4c780 100644 --- a/src/test/java/com/iexec/sms/tee/session/TeeSessionServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/TeeSessionServiceTests.java @@ -2,77 +2,66 @@ import com.iexec.common.task.TaskDescription; import com.iexec.common.tee.TeeEnclaveProvider; +import com.iexec.sms.api.TeeSessionGenerationError; import com.iexec.sms.blockchain.IexecHubService; -import com.iexec.sms.tee.session.generic.TeeSessionStack; -import com.iexec.sms.tee.session.gramine.GramineStack; -import com.iexec.sms.tee.session.scone.SconeStack; -import org.junit.jupiter.api.BeforeAll; +import com.iexec.sms.tee.session.generic.TeeSessionHandler; +import com.iexec.sms.tee.session.gramine.GramineSessionHandlerService; +import com.iexec.sms.tee.session.scone.SconeSessionHandlerService; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.springframework.http.ResponseEntity; +import org.mockito.*; +import java.util.Map; import java.util.stream.Stream; -import static com.iexec.sms.api.TeeSessionGenerationError.*; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; +import static org.mockito.Mockito.*; class TeeSessionServiceTests { private final static String TASK_ID = "0x0"; private final static String WORKER_ADDRESS = "0x1"; private final static String TEE_CHALLENGE = "0x2"; - private static SconeStack sconeStack; - private static GramineStack gramineStack; - @Mock - IexecHubService iexecHubService; - - TeeSessionService teeSessionService; - - @BeforeAll - static void setUpStacks() { - sconeStack = mock(SconeStack.class); - when(sconeStack.getTeeEnclaveProvider()).thenReturn(TeeEnclaveProvider.SCONE); - - gramineStack = mock(GramineStack.class); - when(gramineStack.getTeeEnclaveProvider()).thenReturn(TeeEnclaveProvider.GRAMINE); - } + private SconeSessionHandlerService sconeService; + @Mock + private GramineSessionHandlerService gramineService; + @Mock + private IexecHubService iexecHubService; + @InjectMocks + private TeeSessionService teeSessionService; + private Map providerToSessionService; @BeforeEach void setUp() { MockitoAnnotations.openMocks(this); - teeSessionService = new TeeSessionService(iexecHubService, sconeStack, gramineStack, false); + providerToSessionService = Map.of( + TeeEnclaveProvider.SCONE, sconeService, + TeeEnclaveProvider.GRAMINE, gramineService); } - static Stream teeStacks() { + static Stream teeProviders() { return Stream.of( - Arguments.of(sconeStack), - Arguments.of(gramineStack) - ); + TeeEnclaveProvider.SCONE, + TeeEnclaveProvider.GRAMINE); } - @ParameterizedTest - @MethodSource("teeStacks") - void shouldGenerateTeeSession(TeeSessionStack teeSessionStack) throws TeeSessionGenerationException { + @MethodSource("teeProviders") + void shouldGenerateTeeSession(TeeEnclaveProvider teeEnclaveProvider) + throws TeeSessionGenerationException { final TaskDescription taskDescription = TaskDescription.builder() .chainTaskId(TASK_ID) - .teeEnclaveProvider(teeSessionStack.getTeeEnclaveProvider()) + .teeEnclaveProvider(teeEnclaveProvider) .build(); - final String sessionAsString = "session"; - when(iexecHubService.getTaskDescription(TASK_ID)).thenReturn(taskDescription); - when(teeSessionStack.generateSession(any())).thenReturn(sessionAsString); - when(teeSessionStack.postSession(sessionAsString.getBytes())).thenReturn(ResponseEntity.ok(null)); - final String teeSession = assertDoesNotThrow(() -> teeSessionService.generateTeeSession(TASK_ID, WORKER_ADDRESS, TEE_CHALLENGE)); + final String teeSession = assertDoesNotThrow( + () -> teeSessionService.generateTeeSession(TASK_ID, WORKER_ADDRESS, TEE_CHALLENGE)); + verify(getTeeSessionHandler(teeEnclaveProvider), times(1)) + .buildAndPostSession(any()); assertNotNull(teeSession); } @@ -80,9 +69,13 @@ void shouldGenerateTeeSession(TeeSessionStack teeSessionStack) throws TeeSession void shouldNotGenerateTeeSessionSinceCantGetTaskDescription() { when(iexecHubService.getTaskDescription(TASK_ID)).thenReturn(null); - final TeeSessionGenerationException teeSessionGenerationException = assertThrows(TeeSessionGenerationException.class, () -> teeSessionService.generateTeeSession(TASK_ID, WORKER_ADDRESS, TEE_CHALLENGE)); - assertEquals(GET_TASK_DESCRIPTION_FAILED, teeSessionGenerationException.getError()); - assertEquals(String.format("Failed to get task description [taskId:%s]", TASK_ID), teeSessionGenerationException.getMessage()); + final TeeSessionGenerationException teeSessionGenerationException = assertThrows( + TeeSessionGenerationException.class, + () -> teeSessionService.generateTeeSession(TASK_ID, WORKER_ADDRESS, TEE_CHALLENGE)); + assertEquals(TeeSessionGenerationError.GET_TASK_DESCRIPTION_FAILED, + teeSessionGenerationException.getError()); + assertEquals(String.format("Failed to get task description [taskId:%s]", TASK_ID), + teeSessionGenerationException.getMessage()); } @Test @@ -94,49 +87,39 @@ void shouldNotGenerateTeeSessionSinceNoTeeEnclaveProvider() { when(iexecHubService.getTaskDescription(TASK_ID)).thenReturn(taskDescription); - final TeeSessionGenerationException teeSessionGenerationException = assertThrows(TeeSessionGenerationException.class, () -> teeSessionService.generateTeeSession(TASK_ID, WORKER_ADDRESS, TEE_CHALLENGE)); - assertEquals(SECURE_SESSION_NO_TEE_PROVIDER, teeSessionGenerationException.getError()); + final TeeSessionGenerationException teeSessionGenerationException = assertThrows( + TeeSessionGenerationException.class, + () -> teeSessionService.generateTeeSession(TASK_ID, WORKER_ADDRESS, TEE_CHALLENGE)); + assertEquals(TeeSessionGenerationError.SECURE_SESSION_NO_TEE_PROVIDER, + teeSessionGenerationException.getError()); assertEquals(String.format("TEE provider can't be null [taskId:%s]", - TASK_ID), + TASK_ID), teeSessionGenerationException.getMessage()); } - @ParameterizedTest - @MethodSource("teeStacks") - void shouldNotGenerateTeeSessionSinceCantGetSession(TeeSessionStack teeSessionStack) throws TeeSessionGenerationException { + @MethodSource("teeProviders") + void shouldNotGenerateTeeSessionSinceCantBuildAndPostSession(TeeEnclaveProvider teeEnclaveProvider) + throws TeeSessionGenerationException { final TaskDescription taskDescription = TaskDescription.builder() .chainTaskId(TASK_ID) - .teeEnclaveProvider(teeSessionStack.getTeeEnclaveProvider()) + .teeEnclaveProvider(teeEnclaveProvider) .build(); - + TeeSessionGenerationError error = TeeSessionGenerationError.SECURE_SESSION_GENERATION_FAILED; + TeeSessionGenerationException exception = new TeeSessionGenerationException( + error, "some error"); when(iexecHubService.getTaskDescription(TASK_ID)).thenReturn(taskDescription); - when(teeSessionStack.generateSession(any())).thenReturn(""); + doThrow(exception) + .when(getTeeSessionHandler(teeEnclaveProvider)).buildAndPostSession(any()); - final TeeSessionGenerationException teeSessionGenerationException = assertThrows(TeeSessionGenerationException.class, () -> teeSessionService.generateTeeSession(TASK_ID, WORKER_ADDRESS, TEE_CHALLENGE)); - assertEquals(GET_SESSION_FAILED, teeSessionGenerationException.getError()); - assertEquals(String.format("Failed to get session [taskId:%s, workerAddress:%s, enclaveProvider:%s]", - TASK_ID, WORKER_ADDRESS, teeSessionStack.getTeeEnclaveProvider()), - teeSessionGenerationException.getMessage()); + final TeeSessionGenerationException teeSessionGenerationException = assertThrows( + exception.getClass(), + () -> teeSessionService.generateTeeSession(TASK_ID, WORKER_ADDRESS, TEE_CHALLENGE)); + assertEquals(error, teeSessionGenerationException.getError()); } - @ParameterizedTest - @MethodSource("teeStacks") - void shouldNotGenerateTeeSessionSinceCantGenerateSecureSession(TeeSessionStack teeSessionStack) throws TeeSessionGenerationException { - final TaskDescription taskDescription = TaskDescription.builder() - .chainTaskId(TASK_ID) - .teeEnclaveProvider(teeSessionStack.getTeeEnclaveProvider()) - .build(); - final String sessionAsString = "session"; - - when(iexecHubService.getTaskDescription(TASK_ID)).thenReturn(taskDescription); - when(teeSessionStack.generateSession(any())).thenReturn(sessionAsString); - when(teeSessionStack.postSession(sessionAsString.getBytes())).thenReturn(ResponseEntity.notFound().build()); - - final TeeSessionGenerationException teeSessionGenerationException = assertThrows(TeeSessionGenerationException.class, () -> teeSessionService.generateTeeSession(TASK_ID, WORKER_ADDRESS, TEE_CHALLENGE)); - assertEquals(SECURE_SESSION_STORAGE_CALL_FAILED, teeSessionGenerationException.getError()); - assertEquals(String.format("Failed to generate secure session [taskId:%s, workerAddress:%s, enclaveProvider:%s]", - TASK_ID, WORKER_ADDRESS, teeSessionStack.getTeeEnclaveProvider()), - teeSessionGenerationException.getMessage()); + private TeeSessionHandler getTeeSessionHandler(TeeEnclaveProvider teeEnclaveProvider) { + return providerToSessionService.get(teeEnclaveProvider); } + } \ No newline at end of file diff --git a/src/test/java/com/iexec/sms/tee/session/TeeSessionTestUtils.java b/src/test/java/com/iexec/sms/tee/session/TeeSessionTestUtils.java index 98ca9050..fcd4a824 100644 --- a/src/test/java/com/iexec/sms/tee/session/TeeSessionTestUtils.java +++ b/src/test/java/com/iexec/sms/tee/session/TeeSessionTestUtils.java @@ -20,15 +20,12 @@ import com.iexec.common.task.TaskDescription; import com.iexec.common.tee.TeeEnclaveConfiguration; import com.iexec.common.utils.IexecEnvUtils; -import com.iexec.sms.secret.compute.OnChainObjectType; -import com.iexec.sms.secret.compute.SecretOwnerRole; -import com.iexec.sms.secret.compute.TeeTaskComputeSecret; +import com.iexec.sms.secret.compute.*; +import com.iexec.sms.tee.session.generic.TeeSecretsService; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.ClassUtils; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import static com.iexec.common.worker.result.ResultUtils.*; import static com.iexec.sms.Web3jUtils.createEthereumAddress; @@ -144,8 +141,8 @@ public static Map getPreComputeTokens() { public static Map getAppTokens() { return Map.of( - APP_MRENCLAVE, APP_FINGERPRINT, - INPUT_FILE_NAMES, Map.of( + APP_MRENCLAVE, APP_FINGERPRINT, + TeeSecretsService.INPUT_FILE_NAMES, Map.of( IexecEnvUtils.IEXEC_INPUT_FILE_NAME_PREFIX + "1", INPUT_FILE_NAME_1, IexecEnvUtils.IEXEC_INPUT_FILE_NAME_PREFIX + "2", INPUT_FILE_NAME_2)); } diff --git a/src/test/java/com/iexec/sms/tee/session/generic/TeeSecretsServiceTests.java b/src/test/java/com/iexec/sms/tee/session/generic/TeeSecretsServiceTests.java index ff554f33..90b12c84 100644 --- a/src/test/java/com/iexec/sms/tee/session/generic/TeeSecretsServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/generic/TeeSecretsServiceTests.java @@ -9,10 +9,7 @@ import com.iexec.common.worker.result.ResultUtils; import com.iexec.sms.api.TeeSessionGenerationError; import com.iexec.sms.secret.Secret; -import com.iexec.sms.secret.compute.OnChainObjectType; -import com.iexec.sms.secret.compute.SecretOwnerRole; -import com.iexec.sms.secret.compute.TeeTaskComputeSecret; -import com.iexec.sms.secret.compute.TeeTaskComputeSecretService; +import com.iexec.sms.secret.compute.*; import com.iexec.sms.secret.web2.Web2SecretsService; import com.iexec.sms.secret.web3.Web3Secret; import com.iexec.sms.secret.web3.Web3SecretService; @@ -20,19 +17,13 @@ import com.iexec.sms.tee.challenge.TeeChallengeService; import com.iexec.sms.tee.session.TeeSecretsSessionRequest; import com.iexec.sms.tee.session.TeeSessionGenerationException; -import com.iexec.sms.tee.session.generic.TeeSecretsService; import com.iexec.sms.tee.workflow.TeeWorkflowConfiguration; import com.iexec.sms.utils.EthereumCredentials; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.*; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.NullSource; import org.junit.jupiter.params.provider.ValueSource; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.mockito.Spy; +import org.mockito.*; import java.security.GeneralSecurityException; import java.util.*; @@ -46,11 +37,13 @@ import static com.iexec.common.worker.result.ResultUtils.*; import static com.iexec.sms.Web3jUtils.createEthereumAddress; import static com.iexec.sms.api.TeeSessionGenerationError.*; -import static com.iexec.sms.tee.session.generic.TeeSecretsService.SESSION_ID; -import static com.iexec.sms.tee.session.generic.TeeSecretsService.*; import static com.iexec.sms.tee.session.TeeSessionTestUtils.*; +import static com.iexec.sms.tee.session.generic.TeeSecretsService.*; +import static com.iexec.sms.tee.session.generic.TeeSecretsService.SESSION_ID; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.*; class TeeSecretsServiceTests { diff --git a/src/test/java/com/iexec/sms/tee/session/generic/TeeSessionStackTests.java b/src/test/java/com/iexec/sms/tee/session/generic/TeeSessionStackTests.java index 301bb3ac..24dd5080 100644 --- a/src/test/java/com/iexec/sms/tee/session/generic/TeeSessionStackTests.java +++ b/src/test/java/com/iexec/sms/tee/session/generic/TeeSessionStackTests.java @@ -1,76 +1,67 @@ package com.iexec.sms.tee.session.generic; -import com.iexec.common.tee.TeeEnclaveProvider; -import com.iexec.sms.api.TeeSessionGenerationError; -import com.iexec.sms.tee.session.TeeSecretsSessionRequest; -import com.iexec.sms.tee.session.TeeSessionGenerationException; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; +class TeeSessionStackTests { -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.*; -class TeeSessionStackTests { - private final TeeEnclaveProvider teeEnclaveProvider = TeeEnclaveProvider.GRAMINE; - @Mock - private TeeSessionProviderService sessionService; - @Mock - private TeeSessionStorageClient client; + // private final TeeEnclaveProvider teeEnclaveProvider = TeeEnclaveProvider.GRAMINE; + // @Mock + // private TeeSessionMaker sessionService; + // @Mock + // private TeeSessionUploader client; + + // private TeeSessionHandler teeSessionStack; - private TeeSessionStack teeSessionStack; + // @BeforeEach + // void setUp() { + // MockitoAnnotations.openMocks(this); + // teeSessionStack = new TeeSessionHandler(teeEnclaveProvider, sessionService, client) {}; + // } - @BeforeEach - void setUp() { - MockitoAnnotations.openMocks(this); - teeSessionStack = new TeeSessionStack(teeEnclaveProvider, sessionService, client) {}; - } + // // region generateSession + // @Test + // void shouldGenerateSession() throws TeeSessionGenerationException { + // TeeSecretsSessionRequest request = mock(TeeSecretsSessionRequest.class); + // assertDoesNotThrow(() -> teeSessionStack.generateSession(request)); + // verify(sessionService, times(1)).generateSession(request); + // verify(client, times(0)).postSession(any()); + // } - // region generateSession - @Test - void shouldGenerateSession() throws TeeSessionGenerationException { - TeeSecretsSessionRequest request = mock(TeeSecretsSessionRequest.class); - assertDoesNotThrow(() -> teeSessionStack.generateSession(request)); - verify(sessionService, times(1)).generateSession(request); - verify(client, times(0)).postSession(any()); - } + // @Test + // void shouldNotGenerateSessionSinceExceptionThrown() throws TeeSessionGenerationException { + // TeeSecretsSessionRequest request = mock(TeeSecretsSessionRequest.class); + // final TeeSessionGenerationException expectedException = + // new TeeSessionGenerationException(TeeSessionGenerationError.APP_COMPUTE_INVALID_ENCLAVE_CONFIG, ""); + // when(sessionService.generateSession(request)).thenThrow(expectedException); - @Test - void shouldNotGenerateSessionSinceExceptionThrown() throws TeeSessionGenerationException { - TeeSecretsSessionRequest request = mock(TeeSecretsSessionRequest.class); - final TeeSessionGenerationException expectedException = - new TeeSessionGenerationException(TeeSessionGenerationError.APP_COMPUTE_INVALID_ENCLAVE_CONFIG, ""); - when(sessionService.generateSession(request)).thenThrow(expectedException); + // final TeeSessionGenerationException exception = + // assertThrows(TeeSessionGenerationException.class, () -> teeSessionStack.generateSession(request)); + // assertEquals(expectedException, exception); + // verify(sessionService, times(1)).generateSession(request); + // verify(client, times(0)).postSession(any()); + // } + // // endregion - final TeeSessionGenerationException exception = - assertThrows(TeeSessionGenerationException.class, () -> teeSessionStack.generateSession(request)); - assertEquals(expectedException, exception); - verify(sessionService, times(1)).generateSession(request); - verify(client, times(0)).postSession(any()); - } - // endregion + // // region postSession + // @Test + // void shouldPostSession() throws TeeSessionGenerationException { + // byte[] sessionFile = new byte[10]; + // assertDoesNotThrow(() -> teeSessionStack.postSession(sessionFile)); + // verify(sessionService, times(0)).generateSession(any()); + // verify(client, times(1)).postSession(sessionFile); + // } - // region postSession - @Test - void shouldPostSession() throws TeeSessionGenerationException { - byte[] sessionFile = new byte[10]; - assertDoesNotThrow(() -> teeSessionStack.postSession(sessionFile)); - verify(sessionService, times(0)).generateSession(any()); - verify(client, times(1)).postSession(sessionFile); - } + // @Test + // void shouldNotPostSessionSinceExceptionThrown() throws TeeSessionGenerationException { + // byte[] sessionFile = new byte[10]; + // final RuntimeException expectedException = new RuntimeException(); + // when(client.postSession(sessionFile)).thenThrow(expectedException); - @Test - void shouldNotPostSessionSinceExceptionThrown() throws TeeSessionGenerationException { - byte[] sessionFile = new byte[10]; - final RuntimeException expectedException = new RuntimeException(); - when(client.postSession(sessionFile)).thenThrow(expectedException); + // final RuntimeException exception = + // assertThrows(RuntimeException.class, () -> teeSessionStack.postSession(sessionFile)); + // assertEquals(expectedException, exception); + // verify(sessionService, times(0)).generateSession(any()); + // verify(client, times(1)).postSession(sessionFile); + // } + // // endregion - final RuntimeException exception = - assertThrows(RuntimeException.class, () -> teeSessionStack.postSession(sessionFile)); - assertEquals(expectedException, exception); - verify(sessionService, times(0)).generateSession(any()); - verify(client, times(1)).postSession(sessionFile); - } - // endregion } \ No newline at end of file diff --git a/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionServiceTests.java b/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionServiceTests.java index 82cb4acb..236e1b0c 100644 --- a/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionServiceTests.java @@ -1,21 +1,15 @@ package com.iexec.sms.tee.session.gramine; import com.iexec.common.tee.TeeEnclaveConfiguration; -import com.iexec.common.utils.FileHelper; -import com.iexec.sms.tee.session.generic.TeeSecretsService; import com.iexec.sms.tee.session.TeeSecretsSessionRequest; +import com.iexec.sms.tee.session.generic.TeeSecretsService; +import com.iexec.sms.tee.session.gramine.sps.SpsSession; import com.iexec.sms.tee.workflow.TeeWorkflowConfiguration; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.mockito.Spy; +import org.mockito.*; import org.springframework.test.util.ReflectionTestUtils; -import org.yaml.snakeyaml.Yaml; - -import java.util.Map; import static com.iexec.sms.tee.session.TeeSessionTestUtils.*; import static org.mockito.Mockito.*; @@ -35,13 +29,13 @@ class GramineSessionServiceTests { @InjectMocks private TeeSecretsService teeSecretsService; - private GramineSessionService gramineSessionService; + private GramineSessionMakerService gramineSessionService; @BeforeEach void beforeEach() { MockitoAnnotations.openMocks(this); - gramineSessionService = spy(new GramineSessionService(teeSecretsService)); + gramineSessionService = spy(new GramineSessionMakerService(teeSecretsService)); ReflectionTestUtils.setField(gramineSessionService, "gramineTemplateFilePath", TEMPLATE_SESSION_FILE); } @@ -66,13 +60,14 @@ void shouldGetSessionJson() throws Exception { when(teeWorkflowConfig.getPreComputeEntrypoint()).thenReturn(PRE_COMPUTE_ENTRYPOINT); when(teeWorkflowConfig.getPostComputeEntrypoint()).thenReturn(POST_COMPUTE_ENTRYPOINT); - String actualJsonString = gramineSessionService.generateSession(request); - log.info(actualJsonString); - + SpsSession actualJsonString = gramineSessionService.generateSession(request); + log.info(actualJsonString.toString()); +/* Map actualJsonMap = new Yaml().load(actualJsonString); String expectedJsonString = FileHelper.readFile(EXPECTED_SESSION_FILE); Map expectedYmlMap = new Yaml().load(expectedJsonString); assertRecursively(expectedYmlMap, actualJsonMap); + */ } //endregion } \ No newline at end of file diff --git a/src/test/java/com/iexec/sms/tee/session/gramine/GramineStackTests.java b/src/test/java/com/iexec/sms/tee/session/gramine/GramineStackTests.java deleted file mode 100644 index 53df352a..00000000 --- a/src/test/java/com/iexec/sms/tee/session/gramine/GramineStackTests.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.iexec.sms.tee.session.gramine; - -import com.iexec.common.tee.TeeEnclaveProvider; -import com.iexec.sms.tee.session.gramine.sps.SpsClient; -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.Mockito.mock; - -class GramineStackTests { - @Test - void shouldCreateGramineStack() { - final GramineStack stack = - new GramineStack(mock(GramineSessionService.class), mock(SpsClient.class)); - assertEquals(TeeEnclaveProvider.GRAMINE, stack.getTeeEnclaveProvider()); - } - -} \ No newline at end of file diff --git a/src/test/java/com/iexec/sms/tee/session/gramine/sps/SpsClientTests.java b/src/test/java/com/iexec/sms/tee/session/gramine/sps/SpsClientTests.java deleted file mode 100644 index d7bec7b3..00000000 --- a/src/test/java/com/iexec/sms/tee/session/gramine/sps/SpsClientTests.java +++ /dev/null @@ -1,58 +0,0 @@ -package com.iexec.sms.tee.session.gramine.sps; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.*; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.ResponseEntity; -import org.springframework.web.client.RestTemplate; - -import static org.mockito.Mockito.*; - -class SpsClientTests { - private static final String SPS_URL = "localhost:8080"; - private static final String SPS_LOGIN = "admin"; - private static final String SPS_PASSWORD = "admin"; - - @Captor - ArgumentCaptor sessionPostUrlCaptor; - @Captor - ArgumentCaptor> sessionPostRequestCaptor; - - @Mock - private SpsConfiguration spsConfiguration; - - @InjectMocks - @Spy - private SpsClient spsClient; - - @BeforeEach - void setUp() { - MockitoAnnotations.openMocks(this); - } - - @Test - void shouldPostSession() { - byte[] session = new byte[10]; - - final RestTemplate restTemplate = mock(RestTemplate.class); - when(spsClient.createRestTemplate()).thenReturn(restTemplate); - when(restTemplate.postForEntity(any(), any(), eq(String.class))).thenReturn(ResponseEntity.ok("OK")); - - when(spsConfiguration.getWebUrl()).thenReturn(SPS_URL); - when(spsConfiguration.getWebLogin()).thenReturn(SPS_LOGIN); - when(spsConfiguration.getWebPassword()).thenReturn(SPS_PASSWORD); - - spsClient.postSession(session); - - verify(restTemplate).postForEntity(sessionPostUrlCaptor.capture(), sessionPostRequestCaptor.capture(), eq(String.class)); - - Assertions.assertEquals(SPS_URL + "/api/session", sessionPostUrlCaptor.getValue()); - Assertions.assertEquals("Basic YWRtaW46YWRtaW4=", sessionPostRequestCaptor.getValue() - .getHeaders() - .get(HttpHeaders.AUTHORIZATION) - .get(0)); - } -} \ No newline at end of file diff --git a/src/test/java/com/iexec/sms/tee/session/scone/SconeStackTests.java b/src/test/java/com/iexec/sms/tee/session/scone/SconeStackTests.java deleted file mode 100644 index 84232fec..00000000 --- a/src/test/java/com/iexec/sms/tee/session/scone/SconeStackTests.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.iexec.sms.tee.session.scone; - -import com.iexec.common.tee.TeeEnclaveProvider; -import com.iexec.sms.tee.session.scone.cas.CasClient; -import com.iexec.sms.tee.session.scone.palaemon.PalaemonSessionService; -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.Mockito.mock; - -class SconeStackTests { - @Test - void shouldCreateSconeStack() { - final SconeStack stack = - new SconeStack(mock(PalaemonSessionService.class), mock(CasClient.class)); - assertEquals(TeeEnclaveProvider.SCONE, stack.getTeeEnclaveProvider()); - } -} \ No newline at end of file diff --git a/src/test/java/com/iexec/sms/tee/session/scone/palaemon/PalaemonSessionServiceTests.java b/src/test/java/com/iexec/sms/tee/session/scone/palaemon/PalaemonSessionServiceTests.java index c55f96b0..81a2089d 100644 --- a/src/test/java/com/iexec/sms/tee/session/scone/palaemon/PalaemonSessionServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/scone/palaemon/PalaemonSessionServiceTests.java @@ -25,10 +25,7 @@ import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.mockito.Spy; +import org.mockito.*; import org.springframework.test.util.ReflectionTestUtils; import org.yaml.snakeyaml.Yaml; From b73fd60c113c994ae5a2cfc2f856e4299ae25e86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20James=20Toussaint?= Date: Fri, 22 Jul 2022 12:52:28 +0200 Subject: [PATCH 010/293] Remove useless comment --- .../sms/tee/session/gramine/GramineSessionHandlerService.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerService.java b/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerService.java index 9a2fc481..a0d3ba1c 100644 --- a/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerService.java +++ b/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerService.java @@ -1,7 +1,3 @@ -/* - * This is the default license template. - * - * File: GramineSessionHandlerService.GHIJ /* * Copyright 2022 IEXEC BLOCKCHAIN TECH * From 3314142d0db604bc3f699aebc1a8664c0bfadfb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20James=20Toussaint?= Date: Fri, 22 Jul 2022 15:33:32 +0200 Subject: [PATCH 011/293] Update gitignore for vscode --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index ac541123..defb9780 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,7 @@ build /.nb-gradle/ /bin/ +/iexec-sms-library/bin .vscode/ ### iExec ### From ef006cee2a56d2478b2566b31c32d4a3f09eaec4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20James=20Toussaint?= Date: Mon, 25 Jul 2022 15:17:12 +0200 Subject: [PATCH 012/293] Add GramineSessionHandlerService tests --- .../gramine/GramineSessionHandlerService.java | 14 ++- .../session/gramine/sps/SpsConfiguration.java | 14 ++- .../GramineSessionHandlerServiceTests.java | 112 ++++++++++++++++++ 3 files changed, 130 insertions(+), 10 deletions(-) create mode 100644 src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerServiceTests.java diff --git a/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerService.java b/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerService.java index a0d3ba1c..9b5e1cc6 100644 --- a/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerService.java +++ b/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerService.java @@ -17,10 +17,12 @@ package com.iexec.sms.tee.session.gramine; import com.iexec.sms.api.TeeSessionGenerationError; -import com.iexec.sms.tee.session.*; +import com.iexec.sms.tee.session.TeeSecretsSessionRequest; +import com.iexec.sms.tee.session.TeeSessionGenerationException; +import com.iexec.sms.tee.session.TeeSessionLogConfiguration; import com.iexec.sms.tee.session.generic.TeeSessionHandler; -import com.iexec.sms.tee.session.gramine.sps.*; -import feign.Logger.Level; +import com.iexec.sms.tee.session.gramine.sps.SpsConfiguration; +import com.iexec.sms.tee.session.gramine.sps.SpsSession; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @@ -28,15 +30,15 @@ @Component public class GramineSessionHandlerService implements TeeSessionHandler { private GramineSessionMakerService sessionService; - private SpsApiClient spsClient; + private SpsConfiguration spsConfiguration; private TeeSessionLogConfiguration teeSessionLogConfiguration; public GramineSessionHandlerService(GramineSessionMakerService sessionService, SpsConfiguration spsConfiguration, TeeSessionLogConfiguration teeSessionLogConfiguration) { this.sessionService = sessionService; + this.spsConfiguration = spsConfiguration; this.teeSessionLogConfiguration = teeSessionLogConfiguration; - this.spsClient = spsConfiguration.getInstanceWithBasicAuth(Level.FULL); } public void buildAndPostSession(TeeSecretsSessionRequest request) @@ -49,7 +51,7 @@ public void buildAndPostSession(TeeSecretsSessionRequest request) } try { - spsClient.postSession(session); + spsConfiguration.getInstanceWithBasicAuth().postSession(session); } catch (Exception e) { throw new TeeSessionGenerationException( TeeSessionGenerationError.SECURE_SESSION_STORAGE_CALL_FAILED, diff --git a/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsConfiguration.java b/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsConfiguration.java index e7e11ddc..2a45dcad 100644 --- a/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsConfiguration.java +++ b/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsConfiguration.java @@ -17,7 +17,7 @@ package com.iexec.sms.tee.session.gramine.sps; import com.iexec.common.utils.FeignBuilder; -import feign.Logger; +import feign.Logger.Level; import lombok.Getter; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; @@ -43,6 +43,8 @@ public class SpsConfiguration { @Value("${gramine.sps.enclave.port}") private String enclavePort; + private SpsApiClient spsApiClient; + public String getWebUrl() { return "http://" + webHost + ":" + webPort; } @@ -51,9 +53,13 @@ public String getEnclaveUrl() { return "https://" + enclaveHost + ":" + enclavePort; } - public SpsApiClient getInstanceWithBasicAuth(Logger.Level logLevel) { - return FeignBuilder.createBuilderWithBasicAuth(logLevel, webLogin, webPassword) - .target(SpsApiClient.class, getWebUrl()); + public SpsApiClient getInstanceWithBasicAuth() { + if (spsApiClient == null) { + spsApiClient = FeignBuilder.createBuilderWithBasicAuth(Level.FULL, + webLogin, webPassword) + .target(SpsApiClient.class, getWebUrl()); + } + return spsApiClient; } } diff --git a/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerServiceTests.java b/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerServiceTests.java new file mode 100644 index 00000000..8a267b8a --- /dev/null +++ b/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerServiceTests.java @@ -0,0 +1,112 @@ +/* + * Copyright 2022 IEXEC BLOCKCHAIN TECH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.iexec.sms.tee.session.gramine; + +import com.iexec.common.task.TaskDescription; +import com.iexec.sms.api.TeeSessionGenerationError; +import com.iexec.sms.tee.session.TeeSecretsSessionRequest; +import com.iexec.sms.tee.session.TeeSessionGenerationException; +import com.iexec.sms.tee.session.TeeSessionLogConfiguration; +import com.iexec.sms.tee.session.gramine.sps.SpsApiClient; +import com.iexec.sms.tee.session.gramine.sps.SpsConfiguration; +import com.iexec.sms.tee.session.gramine.sps.SpsSession; +import feign.FeignException; +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.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.springframework.boot.test.system.CapturedOutput; +import org.springframework.boot.test.system.OutputCaptureExtension; + +import static org.junit.Assert.assertThrows; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +@ExtendWith(OutputCaptureExtension.class) +public class GramineSessionHandlerServiceTests { + + @Mock + private GramineSessionMakerService sessionService; + @Mock + private SpsConfiguration spsConfiguration; + @Mock + private TeeSessionLogConfiguration teeSessionLogConfiguration; + @InjectMocks + private GramineSessionHandlerService gramineSessionHandlerService; + + @BeforeEach + void beforeEach() { + MockitoAnnotations.openMocks(this); + } + + @Test + void shouldBuildAndPostSession(CapturedOutput output) throws TeeSessionGenerationException { + TeeSecretsSessionRequest request = mock(TeeSecretsSessionRequest.class); + TaskDescription taskDescription = mock(TaskDescription.class); + when(request.getTaskDescription()).thenReturn(taskDescription); + SpsSession spsSession = mock(SpsSession.class); + when(spsSession.toString()).thenReturn("sessionContent"); + when(sessionService.generateSession(request)).thenReturn(spsSession); + when(teeSessionLogConfiguration.isDisplayDebugSessionEnabled()).thenReturn(true); + SpsApiClient spsClient = mock(SpsApiClient.class); + when(spsClient.postSession(spsSession)).thenReturn("sessionId"); + when(spsConfiguration.getInstanceWithBasicAuth()).thenReturn(spsClient); + + assertDoesNotThrow(() -> gramineSessionHandlerService.buildAndPostSession(request)); + // Testing output here since it reflects a business feature (ability to catch a + // session in debug mode) + assertTrue(output.getOut().contains("Session content [taskId:null]\nsessionContent\n")); + } + + @Test + void shouldNotBuildAndPostSessionSinceBuildSessionFailed() + throws TeeSessionGenerationException { + TeeSecretsSessionRequest request = mock(TeeSecretsSessionRequest.class); + SpsSession spsSession = mock(SpsSession.class); + when(spsSession.toString()).thenReturn("sessionContent"); + TeeSessionGenerationException teeSessionGenerationException = new TeeSessionGenerationException( + TeeSessionGenerationError.SECURE_SESSION_GENERATION_FAILED, "some error"); + when(sessionService.generateSession(request)).thenThrow(teeSessionGenerationException); + + assertThrows(teeSessionGenerationException.getClass(), + () -> gramineSessionHandlerService.buildAndPostSession(request)); + } + + @Test + void shouldNotBuildAndPostSessionSincePostSessionFailed() + throws TeeSessionGenerationException { + TeeSecretsSessionRequest request = mock(TeeSecretsSessionRequest.class); + TaskDescription taskDescription = mock(TaskDescription.class); + when(request.getTaskDescription()).thenReturn(taskDescription); + SpsSession spsSession = mock(SpsSession.class); + when(spsSession.toString()).thenReturn("sessionContent"); + when(sessionService.generateSession(request)).thenReturn(spsSession); + when(teeSessionLogConfiguration.isDisplayDebugSessionEnabled()).thenReturn(true); + SpsApiClient spsClient = mock(SpsApiClient.class); + when(spsConfiguration.getInstanceWithBasicAuth()).thenReturn(spsClient); + FeignException apiClientException = mock(FeignException.class); + when(spsClient.postSession(spsSession)).thenThrow(apiClientException); + + assertThrows(TeeSessionGenerationException.class, + () -> gramineSessionHandlerService.buildAndPostSession(request)); + } + +} From fa964be5d36eaf3adeb995591c89e4afc9edddb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20James=20Toussaint?= Date: Mon, 25 Jul 2022 16:43:19 +0200 Subject: [PATCH 013/293] Add SconeSessionHandlerService tests --- .../scone/SconeSessionHandlerService.java | 12 +-- .../session/generic/TeeSessionStackTests.java | 67 --------------- .../GramineSessionHandlerServiceTests.java | 10 +-- .../SconeSessionHandlerServiceTests.java | 85 +++++++++++++++++++ 4 files changed, 96 insertions(+), 78 deletions(-) delete mode 100644 src/test/java/com/iexec/sms/tee/session/generic/TeeSessionStackTests.java create mode 100644 src/test/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerServiceTests.java diff --git a/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerService.java b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerService.java index 749ed191..713b7308 100644 --- a/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerService.java +++ b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerService.java @@ -17,7 +17,9 @@ package com.iexec.sms.tee.session.scone; import com.iexec.sms.api.TeeSessionGenerationError; -import com.iexec.sms.tee.session.*; +import com.iexec.sms.tee.session.TeeSecretsSessionRequest; +import com.iexec.sms.tee.session.TeeSessionGenerationException; +import com.iexec.sms.tee.session.TeeSessionLogConfiguration; import com.iexec.sms.tee.session.generic.TeeSessionHandler; import com.iexec.sms.tee.session.scone.cas.CasClient; import com.iexec.sms.tee.session.scone.palaemon.PalaemonSessionService; @@ -29,14 +31,14 @@ @Component public class SconeSessionHandlerService implements TeeSessionHandler { private PalaemonSessionService sessionService; - private CasClient client; + private CasClient apiClient; private TeeSessionLogConfiguration teeSessionLogConfiguration; public SconeSessionHandlerService(PalaemonSessionService sessionService, - CasClient client, + CasClient apiClient, TeeSessionLogConfiguration teeSessionLogConfiguration) { this.sessionService = sessionService; - this.client = client; + this.apiClient = apiClient; this.teeSessionLogConfiguration = teeSessionLogConfiguration; } @@ -49,7 +51,7 @@ public void buildAndPostSession(TeeSecretsSessionRequest request) log.info("Session content [taskId:{}]\n{}", request.getTaskDescription().getChainTaskId(), session); } - ResponseEntity postSession = client.postSession(session); + ResponseEntity postSession = apiClient.postSession(session); int httpCode = postSession != null ? postSession.getStatusCodeValue() : null; if (httpCode != 200) { throw new TeeSessionGenerationException( diff --git a/src/test/java/com/iexec/sms/tee/session/generic/TeeSessionStackTests.java b/src/test/java/com/iexec/sms/tee/session/generic/TeeSessionStackTests.java deleted file mode 100644 index 24dd5080..00000000 --- a/src/test/java/com/iexec/sms/tee/session/generic/TeeSessionStackTests.java +++ /dev/null @@ -1,67 +0,0 @@ -package com.iexec.sms.tee.session.generic; - -class TeeSessionStackTests { - - - // private final TeeEnclaveProvider teeEnclaveProvider = TeeEnclaveProvider.GRAMINE; - // @Mock - // private TeeSessionMaker sessionService; - // @Mock - // private TeeSessionUploader client; - - // private TeeSessionHandler teeSessionStack; - - // @BeforeEach - // void setUp() { - // MockitoAnnotations.openMocks(this); - // teeSessionStack = new TeeSessionHandler(teeEnclaveProvider, sessionService, client) {}; - // } - - // // region generateSession - // @Test - // void shouldGenerateSession() throws TeeSessionGenerationException { - // TeeSecretsSessionRequest request = mock(TeeSecretsSessionRequest.class); - // assertDoesNotThrow(() -> teeSessionStack.generateSession(request)); - // verify(sessionService, times(1)).generateSession(request); - // verify(client, times(0)).postSession(any()); - // } - - // @Test - // void shouldNotGenerateSessionSinceExceptionThrown() throws TeeSessionGenerationException { - // TeeSecretsSessionRequest request = mock(TeeSecretsSessionRequest.class); - // final TeeSessionGenerationException expectedException = - // new TeeSessionGenerationException(TeeSessionGenerationError.APP_COMPUTE_INVALID_ENCLAVE_CONFIG, ""); - // when(sessionService.generateSession(request)).thenThrow(expectedException); - - // final TeeSessionGenerationException exception = - // assertThrows(TeeSessionGenerationException.class, () -> teeSessionStack.generateSession(request)); - // assertEquals(expectedException, exception); - // verify(sessionService, times(1)).generateSession(request); - // verify(client, times(0)).postSession(any()); - // } - // // endregion - - // // region postSession - // @Test - // void shouldPostSession() throws TeeSessionGenerationException { - // byte[] sessionFile = new byte[10]; - // assertDoesNotThrow(() -> teeSessionStack.postSession(sessionFile)); - // verify(sessionService, times(0)).generateSession(any()); - // verify(client, times(1)).postSession(sessionFile); - // } - - // @Test - // void shouldNotPostSessionSinceExceptionThrown() throws TeeSessionGenerationException { - // byte[] sessionFile = new byte[10]; - // final RuntimeException expectedException = new RuntimeException(); - // when(client.postSession(sessionFile)).thenThrow(expectedException); - - // final RuntimeException exception = - // assertThrows(RuntimeException.class, () -> teeSessionStack.postSession(sessionFile)); - // assertEquals(expectedException, exception); - // verify(sessionService, times(0)).generateSession(any()); - // verify(client, times(1)).postSession(sessionFile); - // } - // // endregion - -} \ No newline at end of file diff --git a/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerServiceTests.java b/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerServiceTests.java index 8a267b8a..2dee45b3 100644 --- a/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerServiceTests.java @@ -50,7 +50,7 @@ public class GramineSessionHandlerServiceTests { @Mock private TeeSessionLogConfiguration teeSessionLogConfiguration; @InjectMocks - private GramineSessionHandlerService gramineSessionHandlerService; + private GramineSessionHandlerService sessionHandlerService; @BeforeEach void beforeEach() { @@ -70,7 +70,7 @@ void shouldBuildAndPostSession(CapturedOutput output) throws TeeSessionGeneratio when(spsClient.postSession(spsSession)).thenReturn("sessionId"); when(spsConfiguration.getInstanceWithBasicAuth()).thenReturn(spsClient); - assertDoesNotThrow(() -> gramineSessionHandlerService.buildAndPostSession(request)); + assertDoesNotThrow(() -> sessionHandlerService.buildAndPostSession(request)); // Testing output here since it reflects a business feature (ability to catch a // session in debug mode) assertTrue(output.getOut().contains("Session content [taskId:null]\nsessionContent\n")); @@ -80,14 +80,12 @@ void shouldBuildAndPostSession(CapturedOutput output) throws TeeSessionGeneratio void shouldNotBuildAndPostSessionSinceBuildSessionFailed() throws TeeSessionGenerationException { TeeSecretsSessionRequest request = mock(TeeSecretsSessionRequest.class); - SpsSession spsSession = mock(SpsSession.class); - when(spsSession.toString()).thenReturn("sessionContent"); TeeSessionGenerationException teeSessionGenerationException = new TeeSessionGenerationException( TeeSessionGenerationError.SECURE_SESSION_GENERATION_FAILED, "some error"); when(sessionService.generateSession(request)).thenThrow(teeSessionGenerationException); assertThrows(teeSessionGenerationException.getClass(), - () -> gramineSessionHandlerService.buildAndPostSession(request)); + () -> sessionHandlerService.buildAndPostSession(request)); } @Test @@ -106,7 +104,7 @@ void shouldNotBuildAndPostSessionSincePostSessionFailed() when(spsClient.postSession(spsSession)).thenThrow(apiClientException); assertThrows(TeeSessionGenerationException.class, - () -> gramineSessionHandlerService.buildAndPostSession(request)); + () -> sessionHandlerService.buildAndPostSession(request)); } } diff --git a/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerServiceTests.java b/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerServiceTests.java new file mode 100644 index 00000000..394bfd49 --- /dev/null +++ b/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerServiceTests.java @@ -0,0 +1,85 @@ +package com.iexec.sms.tee.session.scone; + +import com.iexec.common.task.TaskDescription; +import com.iexec.sms.api.TeeSessionGenerationError; +import com.iexec.sms.tee.session.TeeSecretsSessionRequest; +import com.iexec.sms.tee.session.TeeSessionGenerationException; +import com.iexec.sms.tee.session.TeeSessionLogConfiguration; +import com.iexec.sms.tee.session.scone.cas.CasClient; +import com.iexec.sms.tee.session.scone.palaemon.PalaemonSessionService; +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.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.springframework.boot.test.system.CapturedOutput; +import org.springframework.boot.test.system.OutputCaptureExtension; +import org.springframework.http.ResponseEntity; + +import static org.junit.Assert.assertThrows; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +@ExtendWith(OutputCaptureExtension.class) +public class SconeSessionHandlerServiceTests { + + @Mock + private PalaemonSessionService sessionService; + @Mock + private CasClient apiClient; + @Mock + private TeeSessionLogConfiguration teeSessionLogConfiguration; + @InjectMocks + private SconeSessionHandlerService sessionHandlerService; + + @BeforeEach + void beforeEach() { + MockitoAnnotations.openMocks(this); + } + + @Test + void shouldBuildAndPostSession(CapturedOutput output) throws TeeSessionGenerationException { + TeeSecretsSessionRequest request = mock(TeeSecretsSessionRequest.class); + TaskDescription taskDescription = mock(TaskDescription.class); + when(request.getTaskDescription()).thenReturn(taskDescription); + String casSession = "sessionContent"; + when(sessionService.generateSession(request)).thenReturn(casSession); + when(teeSessionLogConfiguration.isDisplayDebugSessionEnabled()).thenReturn(true); + when(apiClient.postSession(casSession)).thenReturn(ResponseEntity.ok("sessionId")); + + assertDoesNotThrow(() -> sessionHandlerService.buildAndPostSession(request)); + // Testing output here since it reflects a business feature (ability to catch a + // session in debug mode) + assertTrue(output.getOut().contains("Session content [taskId:null]\nsessionContent\n")); + } + + @Test + void shouldNotBuildAndPostSessionSinceBuildSessionFailed() + throws TeeSessionGenerationException { + TeeSecretsSessionRequest request = mock(TeeSecretsSessionRequest.class); + TeeSessionGenerationException teeSessionGenerationException = new TeeSessionGenerationException( + TeeSessionGenerationError.SECURE_SESSION_GENERATION_FAILED, "some error"); + when(sessionService.generateSession(request)).thenThrow(teeSessionGenerationException); + + assertThrows(teeSessionGenerationException.getClass(), + () -> sessionHandlerService.buildAndPostSession(request)); + } + + @Test + void shouldNotBuildAndPostSessionSincePostSessionFailed() + throws TeeSessionGenerationException { + TeeSecretsSessionRequest request = mock(TeeSecretsSessionRequest.class); + TaskDescription taskDescription = mock(TaskDescription.class); + when(request.getTaskDescription()).thenReturn(taskDescription); + String casSession = "sessionContent"; + when(sessionService.generateSession(request)).thenReturn(casSession); + when(teeSessionLogConfiguration.isDisplayDebugSessionEnabled()).thenReturn(true); + when(apiClient.postSession(casSession)).thenReturn(ResponseEntity.internalServerError().build()); + + assertThrows(TeeSessionGenerationException.class, + () -> sessionHandlerService.buildAndPostSession(request)); + } +} From ef4195406d981b2bca1a33e2a53f57fe3226c7f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20James=20Toussaint?= Date: Mon, 25 Jul 2022 17:28:27 +0200 Subject: [PATCH 014/293] Update tee session package organizaton --- .../java/com/iexec/sms/tee/TeeController.java | 4 ++-- .../{generic => }/TeeSecretsService.java | 16 +++++++++---- .../sms/tee/session/TeeSessionService.java | 2 ++ .../TeeSecretsSessionRequest.java | 2 +- .../TeeSessionGenerationException.java | 2 +- .../session/generic/TeeSessionHandler.java | 3 --- .../gramine/GramineSessionHandlerService.java | 4 ++-- .../gramine/GramineSessionMakerService.java | 6 ++--- .../scone/SconeSessionHandlerService.java | 9 ++++--- ...ice.java => SconeSessionMakerService.java} | 17 +++++++------ ...g.java => SconeSessionSecurityConfig.java} | 4 ++-- .../com/iexec/sms/tee/TeeControllerTests.java | 4 ++-- .../{generic => }/TeeSecretsServiceTests.java | 24 ++++++++++++------- .../tee/session/TeeSessionServiceTests.java | 5 +++- .../sms/tee/session/TeeSessionTestUtils.java | 12 ++++++---- .../GramineSessionHandlerServiceTests.java | 4 ++-- .../gramine/GramineSessionServiceTests.java | 9 ++++--- .../SconeSessionHandlerServiceTests.java | 7 +++--- ...ava => SconeSessionMakerServiceTests.java} | 20 +++++++++------- 19 files changed, 88 insertions(+), 66 deletions(-) rename src/main/java/com/iexec/sms/tee/session/{generic => }/TeeSecretsService.java (97%) rename src/main/java/com/iexec/sms/tee/session/{ => generic}/TeeSecretsSessionRequest.java (95%) rename src/main/java/com/iexec/sms/tee/session/{ => generic}/TeeSessionGenerationException.java (95%) rename src/main/java/com/iexec/sms/tee/session/scone/{palaemon/PalaemonSessionService.java => SconeSessionMakerService.java} (91%) rename src/main/java/com/iexec/sms/tee/session/scone/{attestation/AttestationSecurityConfig.java => SconeSessionSecurityConfig.java} (91%) rename src/test/java/com/iexec/sms/tee/session/{generic => }/TeeSecretsServiceTests.java (97%) rename src/test/java/com/iexec/sms/tee/session/scone/{palaemon/PalaemonSessionServiceTests.java => SconeSessionMakerServiceTests.java} (86%) diff --git a/src/main/java/com/iexec/sms/tee/TeeController.java b/src/main/java/com/iexec/sms/tee/TeeController.java index 917eb875..81c0736e 100644 --- a/src/main/java/com/iexec/sms/tee/TeeController.java +++ b/src/main/java/com/iexec/sms/tee/TeeController.java @@ -18,15 +18,15 @@ import com.iexec.common.chain.WorkerpoolAuthorization; -import com.iexec.sms.api.TeeSessionGenerationError; import com.iexec.common.tee.TeeWorkflowSharedConfiguration; import com.iexec.common.web.ApiResponseBody; +import com.iexec.sms.api.TeeSessionGenerationError; import com.iexec.sms.authorization.AuthorizationError; import com.iexec.sms.authorization.AuthorizationService; import com.iexec.sms.tee.challenge.TeeChallenge; import com.iexec.sms.tee.challenge.TeeChallengeService; -import com.iexec.sms.tee.session.TeeSessionGenerationException; import com.iexec.sms.tee.session.TeeSessionService; +import com.iexec.sms.tee.session.generic.TeeSessionGenerationException; import com.iexec.sms.tee.workflow.TeeWorkflowConfiguration; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; diff --git a/src/main/java/com/iexec/sms/tee/session/generic/TeeSecretsService.java b/src/main/java/com/iexec/sms/tee/session/TeeSecretsService.java similarity index 97% rename from src/main/java/com/iexec/sms/tee/session/generic/TeeSecretsService.java rename to src/main/java/com/iexec/sms/tee/session/TeeSecretsService.java index 69b64522..15608a71 100644 --- a/src/main/java/com/iexec/sms/tee/session/generic/TeeSecretsService.java +++ b/src/main/java/com/iexec/sms/tee/session/TeeSecretsService.java @@ -14,27 +14,33 @@ * limitations under the License. */ -package com.iexec.sms.tee.session.generic; +package com.iexec.sms.tee.session; import com.iexec.common.sms.secret.ReservedSecretKeyName; import com.iexec.common.task.TaskDescription; import com.iexec.common.tee.TeeEnclaveConfiguration; import com.iexec.common.utils.IexecEnvUtils; import com.iexec.sms.secret.Secret; -import com.iexec.sms.secret.compute.*; +import com.iexec.sms.secret.compute.OnChainObjectType; +import com.iexec.sms.secret.compute.SecretOwnerRole; +import com.iexec.sms.secret.compute.TeeTaskComputeSecret; +import com.iexec.sms.secret.compute.TeeTaskComputeSecretService; import com.iexec.sms.secret.web2.Web2SecretsService; import com.iexec.sms.secret.web3.Web3SecretService; import com.iexec.sms.tee.challenge.TeeChallenge; import com.iexec.sms.tee.challenge.TeeChallengeService; -import com.iexec.sms.tee.session.TeeSecretsSessionRequest; -import com.iexec.sms.tee.session.TeeSessionGenerationException; +import com.iexec.sms.tee.session.generic.TeeSecretsSessionRequest; +import com.iexec.sms.tee.session.generic.TeeSessionGenerationException; import com.iexec.sms.tee.workflow.TeeWorkflowConfiguration; import com.iexec.sms.utils.EthereumCredentials; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; -import java.util.*; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; import java.util.stream.Collectors; import static com.iexec.common.chain.DealParams.DROPBOX_RESULT_STORAGE_PROVIDER; diff --git a/src/main/java/com/iexec/sms/tee/session/TeeSessionService.java b/src/main/java/com/iexec/sms/tee/session/TeeSessionService.java index ecb0c8eb..c3dd0cfe 100644 --- a/src/main/java/com/iexec/sms/tee/session/TeeSessionService.java +++ b/src/main/java/com/iexec/sms/tee/session/TeeSessionService.java @@ -19,6 +19,8 @@ import com.iexec.common.task.TaskDescription; import com.iexec.common.tee.TeeEnclaveProvider; import com.iexec.sms.blockchain.IexecHubService; +import com.iexec.sms.tee.session.generic.TeeSecretsSessionRequest; +import com.iexec.sms.tee.session.generic.TeeSessionGenerationException; import com.iexec.sms.tee.session.generic.TeeSessionHandler; import com.iexec.sms.tee.session.gramine.GramineSessionHandlerService; import com.iexec.sms.tee.session.scone.SconeSessionHandlerService; diff --git a/src/main/java/com/iexec/sms/tee/session/TeeSecretsSessionRequest.java b/src/main/java/com/iexec/sms/tee/session/generic/TeeSecretsSessionRequest.java similarity index 95% rename from src/main/java/com/iexec/sms/tee/session/TeeSecretsSessionRequest.java rename to src/main/java/com/iexec/sms/tee/session/generic/TeeSecretsSessionRequest.java index 8423f637..85be0e99 100644 --- a/src/main/java/com/iexec/sms/tee/session/TeeSecretsSessionRequest.java +++ b/src/main/java/com/iexec/sms/tee/session/generic/TeeSecretsSessionRequest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.iexec.sms.tee.session; +package com.iexec.sms.tee.session.generic; import com.iexec.common.task.TaskDescription; import lombok.AllArgsConstructor; diff --git a/src/main/java/com/iexec/sms/tee/session/TeeSessionGenerationException.java b/src/main/java/com/iexec/sms/tee/session/generic/TeeSessionGenerationException.java similarity index 95% rename from src/main/java/com/iexec/sms/tee/session/TeeSessionGenerationException.java rename to src/main/java/com/iexec/sms/tee/session/generic/TeeSessionGenerationException.java index 04fa9761..f02c257e 100644 --- a/src/main/java/com/iexec/sms/tee/session/TeeSessionGenerationException.java +++ b/src/main/java/com/iexec/sms/tee/session/generic/TeeSessionGenerationException.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.iexec.sms.tee.session; +package com.iexec.sms.tee.session.generic; import com.iexec.sms.api.TeeSessionGenerationError; diff --git a/src/main/java/com/iexec/sms/tee/session/generic/TeeSessionHandler.java b/src/main/java/com/iexec/sms/tee/session/generic/TeeSessionHandler.java index 741929d3..7d86c315 100644 --- a/src/main/java/com/iexec/sms/tee/session/generic/TeeSessionHandler.java +++ b/src/main/java/com/iexec/sms/tee/session/generic/TeeSessionHandler.java @@ -16,9 +16,6 @@ package com.iexec.sms.tee.session.generic; -import com.iexec.sms.tee.session.TeeSecretsSessionRequest; -import com.iexec.sms.tee.session.TeeSessionGenerationException; - public interface TeeSessionHandler { void buildAndPostSession(TeeSecretsSessionRequest request) throws TeeSessionGenerationException; diff --git a/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerService.java b/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerService.java index 9b5e1cc6..efebba39 100644 --- a/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerService.java +++ b/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerService.java @@ -17,9 +17,9 @@ package com.iexec.sms.tee.session.gramine; import com.iexec.sms.api.TeeSessionGenerationError; -import com.iexec.sms.tee.session.TeeSecretsSessionRequest; -import com.iexec.sms.tee.session.TeeSessionGenerationException; import com.iexec.sms.tee.session.TeeSessionLogConfiguration; +import com.iexec.sms.tee.session.generic.TeeSecretsSessionRequest; +import com.iexec.sms.tee.session.generic.TeeSessionGenerationException; import com.iexec.sms.tee.session.generic.TeeSessionHandler; import com.iexec.sms.tee.session.gramine.sps.SpsConfiguration; import com.iexec.sms.tee.session.gramine.sps.SpsSession; diff --git a/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerService.java b/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerService.java index 30d34d5d..6cabc90b 100644 --- a/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerService.java +++ b/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerService.java @@ -19,9 +19,9 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.iexec.common.utils.FileHelper; import com.iexec.sms.api.TeeSessionGenerationError; -import com.iexec.sms.tee.session.TeeSecretsSessionRequest; -import com.iexec.sms.tee.session.TeeSessionGenerationException; -import com.iexec.sms.tee.session.generic.TeeSecretsService; +import com.iexec.sms.tee.session.TeeSecretsService; +import com.iexec.sms.tee.session.generic.TeeSecretsSessionRequest; +import com.iexec.sms.tee.session.generic.TeeSessionGenerationException; import com.iexec.sms.tee.session.gramine.sps.SpsSession; import org.apache.commons.lang3.StringUtils; import org.apache.velocity.Template; diff --git a/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerService.java b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerService.java index 713b7308..94a4bb1d 100644 --- a/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerService.java +++ b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerService.java @@ -17,12 +17,11 @@ package com.iexec.sms.tee.session.scone; import com.iexec.sms.api.TeeSessionGenerationError; -import com.iexec.sms.tee.session.TeeSecretsSessionRequest; -import com.iexec.sms.tee.session.TeeSessionGenerationException; import com.iexec.sms.tee.session.TeeSessionLogConfiguration; +import com.iexec.sms.tee.session.generic.TeeSecretsSessionRequest; +import com.iexec.sms.tee.session.generic.TeeSessionGenerationException; import com.iexec.sms.tee.session.generic.TeeSessionHandler; import com.iexec.sms.tee.session.scone.cas.CasClient; -import com.iexec.sms.tee.session.scone.palaemon.PalaemonSessionService; import lombok.extern.slf4j.Slf4j; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; @@ -30,11 +29,11 @@ @Slf4j @Component public class SconeSessionHandlerService implements TeeSessionHandler { - private PalaemonSessionService sessionService; + private SconeSessionMakerService sessionService; private CasClient apiClient; private TeeSessionLogConfiguration teeSessionLogConfiguration; - public SconeSessionHandlerService(PalaemonSessionService sessionService, + public SconeSessionHandlerService(SconeSessionMakerService sessionService, CasClient apiClient, TeeSessionLogConfiguration teeSessionLogConfiguration) { this.sessionService = sessionService; diff --git a/src/main/java/com/iexec/sms/tee/session/scone/palaemon/PalaemonSessionService.java b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionMakerService.java similarity index 91% rename from src/main/java/com/iexec/sms/tee/session/scone/palaemon/PalaemonSessionService.java rename to src/main/java/com/iexec/sms/tee/session/scone/SconeSessionMakerService.java index 50672e46..f748634c 100644 --- a/src/main/java/com/iexec/sms/tee/session/scone/palaemon/PalaemonSessionService.java +++ b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionMakerService.java @@ -14,15 +14,14 @@ * limitations under the License. */ -package com.iexec.sms.tee.session.scone.palaemon; +package com.iexec.sms.tee.session.scone; import com.iexec.common.task.TaskDescription; import com.iexec.common.tee.TeeEnclaveConfiguration; import com.iexec.common.utils.FileHelper; -import com.iexec.sms.tee.session.TeeSecretsSessionRequest; -import com.iexec.sms.tee.session.TeeSessionGenerationException; -import com.iexec.sms.tee.session.generic.TeeSecretsService; -import com.iexec.sms.tee.session.scone.attestation.AttestationSecurityConfig; +import com.iexec.sms.tee.session.TeeSecretsService; +import com.iexec.sms.tee.session.generic.TeeSecretsSessionRequest; +import com.iexec.sms.tee.session.generic.TeeSessionGenerationException; import com.iexec.sms.tee.workflow.TeeWorkflowConfiguration; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; @@ -42,7 +41,7 @@ //TODO Rename and move @Slf4j @Service -public class PalaemonSessionService { +public class SconeSessionMakerService { // Internal values required for setting up a palaemon session // Generic @@ -57,15 +56,15 @@ public class PalaemonSessionService { private final TeeSecretsService teeSecretsService; private final TeeWorkflowConfiguration teeWorkflowConfig; - private final AttestationSecurityConfig attestationSecurityConfig; + private final SconeSessionSecurityConfig attestationSecurityConfig; @Value("${scone.cas.palaemon}") private String palaemonTemplateFilePath; - public PalaemonSessionService( + public SconeSessionMakerService( TeeSecretsService teeSecretsService, TeeWorkflowConfiguration teeWorkflowConfig, - AttestationSecurityConfig attestationSecurityConfig) { + SconeSessionSecurityConfig attestationSecurityConfig) { this.teeSecretsService = teeSecretsService; this.teeWorkflowConfig = teeWorkflowConfig; this.attestationSecurityConfig = attestationSecurityConfig; diff --git a/src/main/java/com/iexec/sms/tee/session/scone/attestation/AttestationSecurityConfig.java b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionSecurityConfig.java similarity index 91% rename from src/main/java/com/iexec/sms/tee/session/scone/attestation/AttestationSecurityConfig.java rename to src/main/java/com/iexec/sms/tee/session/scone/SconeSessionSecurityConfig.java index 5f8b1720..9e0c6eab 100644 --- a/src/main/java/com/iexec/sms/tee/session/scone/attestation/AttestationSecurityConfig.java +++ b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionSecurityConfig.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.iexec.sms.tee.session.scone.attestation; +package com.iexec.sms.tee.session.scone; import lombok.Getter; import org.springframework.beans.factory.annotation.Value; @@ -23,7 +23,7 @@ import java.util.List; @Configuration -public class AttestationSecurityConfig { +public class SconeSessionSecurityConfig { @Value("${scone.attestation.tolerated-insecure-options}") @Getter diff --git a/src/test/java/com/iexec/sms/tee/TeeControllerTests.java b/src/test/java/com/iexec/sms/tee/TeeControllerTests.java index 2b2d09d6..40f4c865 100644 --- a/src/test/java/com/iexec/sms/tee/TeeControllerTests.java +++ b/src/test/java/com/iexec/sms/tee/TeeControllerTests.java @@ -1,13 +1,13 @@ package com.iexec.sms.tee; import com.iexec.common.chain.WorkerpoolAuthorization; -import com.iexec.sms.api.TeeSessionGenerationError; import com.iexec.common.web.ApiResponseBody; +import com.iexec.sms.api.TeeSessionGenerationError; import com.iexec.sms.authorization.AuthorizationError; import com.iexec.sms.authorization.AuthorizationService; import com.iexec.sms.tee.challenge.TeeChallengeService; -import com.iexec.sms.tee.session.TeeSessionGenerationException; import com.iexec.sms.tee.session.TeeSessionService; +import com.iexec.sms.tee.session.generic.TeeSessionGenerationException; import com.iexec.sms.tee.workflow.TeeWorkflowConfiguration; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; diff --git a/src/test/java/com/iexec/sms/tee/session/generic/TeeSecretsServiceTests.java b/src/test/java/com/iexec/sms/tee/session/TeeSecretsServiceTests.java similarity index 97% rename from src/test/java/com/iexec/sms/tee/session/generic/TeeSecretsServiceTests.java rename to src/test/java/com/iexec/sms/tee/session/TeeSecretsServiceTests.java index 90b12c84..be458ae7 100644 --- a/src/test/java/com/iexec/sms/tee/session/generic/TeeSecretsServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/TeeSecretsServiceTests.java @@ -1,4 +1,4 @@ -package com.iexec.sms.tee.session.generic; +package com.iexec.sms.tee.session; import com.iexec.common.precompute.PreComputeUtils; import com.iexec.common.sms.secret.ReservedSecretKeyName; @@ -9,21 +9,29 @@ import com.iexec.common.worker.result.ResultUtils; import com.iexec.sms.api.TeeSessionGenerationError; import com.iexec.sms.secret.Secret; -import com.iexec.sms.secret.compute.*; +import com.iexec.sms.secret.compute.OnChainObjectType; +import com.iexec.sms.secret.compute.SecretOwnerRole; +import com.iexec.sms.secret.compute.TeeTaskComputeSecret; +import com.iexec.sms.secret.compute.TeeTaskComputeSecretService; import com.iexec.sms.secret.web2.Web2SecretsService; import com.iexec.sms.secret.web3.Web3Secret; import com.iexec.sms.secret.web3.Web3SecretService; import com.iexec.sms.tee.challenge.TeeChallenge; import com.iexec.sms.tee.challenge.TeeChallengeService; -import com.iexec.sms.tee.session.TeeSecretsSessionRequest; -import com.iexec.sms.tee.session.TeeSessionGenerationException; +import com.iexec.sms.tee.session.generic.TeeSecretsSessionRequest; +import com.iexec.sms.tee.session.generic.TeeSessionGenerationException; import com.iexec.sms.tee.workflow.TeeWorkflowConfiguration; import com.iexec.sms.utils.EthereumCredentials; -import org.junit.jupiter.api.*; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.NullSource; import org.junit.jupiter.params.provider.ValueSource; -import org.mockito.*; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.Spy; import java.security.GeneralSecurityException; import java.util.*; @@ -37,9 +45,9 @@ import static com.iexec.common.worker.result.ResultUtils.*; import static com.iexec.sms.Web3jUtils.createEthereumAddress; import static com.iexec.sms.api.TeeSessionGenerationError.*; +import static com.iexec.sms.tee.session.TeeSecretsService.*; +import static com.iexec.sms.tee.session.TeeSecretsService.SESSION_ID; import static com.iexec.sms.tee.session.TeeSessionTestUtils.*; -import static com.iexec.sms.tee.session.generic.TeeSecretsService.*; -import static com.iexec.sms.tee.session.generic.TeeSecretsService.SESSION_ID; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.any; diff --git a/src/test/java/com/iexec/sms/tee/session/TeeSessionServiceTests.java b/src/test/java/com/iexec/sms/tee/session/TeeSessionServiceTests.java index e9f4c780..7faeca50 100644 --- a/src/test/java/com/iexec/sms/tee/session/TeeSessionServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/TeeSessionServiceTests.java @@ -4,6 +4,7 @@ import com.iexec.common.tee.TeeEnclaveProvider; import com.iexec.sms.api.TeeSessionGenerationError; import com.iexec.sms.blockchain.IexecHubService; +import com.iexec.sms.tee.session.generic.TeeSessionGenerationException; import com.iexec.sms.tee.session.generic.TeeSessionHandler; import com.iexec.sms.tee.session.gramine.GramineSessionHandlerService; import com.iexec.sms.tee.session.scone.SconeSessionHandlerService; @@ -11,7 +12,9 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; -import org.mockito.*; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; import java.util.Map; import java.util.stream.Stream; diff --git a/src/test/java/com/iexec/sms/tee/session/TeeSessionTestUtils.java b/src/test/java/com/iexec/sms/tee/session/TeeSessionTestUtils.java index fcd4a824..5f7fe2b3 100644 --- a/src/test/java/com/iexec/sms/tee/session/TeeSessionTestUtils.java +++ b/src/test/java/com/iexec/sms/tee/session/TeeSessionTestUtils.java @@ -20,16 +20,20 @@ import com.iexec.common.task.TaskDescription; import com.iexec.common.tee.TeeEnclaveConfiguration; import com.iexec.common.utils.IexecEnvUtils; -import com.iexec.sms.secret.compute.*; -import com.iexec.sms.tee.session.generic.TeeSecretsService; +import com.iexec.sms.secret.compute.OnChainObjectType; +import com.iexec.sms.secret.compute.SecretOwnerRole; +import com.iexec.sms.secret.compute.TeeTaskComputeSecret; +import com.iexec.sms.tee.session.generic.TeeSecretsSessionRequest; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.ClassUtils; -import java.util.*; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import static com.iexec.common.worker.result.ResultUtils.*; import static com.iexec.sms.Web3jUtils.createEthereumAddress; -import static com.iexec.sms.tee.session.generic.TeeSecretsService.*; +import static com.iexec.sms.tee.session.TeeSecretsService.*; import static org.assertj.core.api.Assertions.assertThat; @Slf4j diff --git a/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerServiceTests.java b/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerServiceTests.java index 2dee45b3..09f27b01 100644 --- a/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerServiceTests.java @@ -18,9 +18,9 @@ import com.iexec.common.task.TaskDescription; import com.iexec.sms.api.TeeSessionGenerationError; -import com.iexec.sms.tee.session.TeeSecretsSessionRequest; -import com.iexec.sms.tee.session.TeeSessionGenerationException; import com.iexec.sms.tee.session.TeeSessionLogConfiguration; +import com.iexec.sms.tee.session.generic.TeeSecretsSessionRequest; +import com.iexec.sms.tee.session.generic.TeeSessionGenerationException; import com.iexec.sms.tee.session.gramine.sps.SpsApiClient; import com.iexec.sms.tee.session.gramine.sps.SpsConfiguration; import com.iexec.sms.tee.session.gramine.sps.SpsSession; diff --git a/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionServiceTests.java b/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionServiceTests.java index 236e1b0c..cdd7fd24 100644 --- a/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionServiceTests.java @@ -1,14 +1,17 @@ package com.iexec.sms.tee.session.gramine; import com.iexec.common.tee.TeeEnclaveConfiguration; -import com.iexec.sms.tee.session.TeeSecretsSessionRequest; -import com.iexec.sms.tee.session.generic.TeeSecretsService; +import com.iexec.sms.tee.session.TeeSecretsService; +import com.iexec.sms.tee.session.generic.TeeSecretsSessionRequest; import com.iexec.sms.tee.session.gramine.sps.SpsSession; import com.iexec.sms.tee.workflow.TeeWorkflowConfiguration; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.mockito.*; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.Spy; import org.springframework.test.util.ReflectionTestUtils; import static com.iexec.sms.tee.session.TeeSessionTestUtils.*; diff --git a/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerServiceTests.java b/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerServiceTests.java index 394bfd49..81be4892 100644 --- a/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerServiceTests.java @@ -2,11 +2,10 @@ import com.iexec.common.task.TaskDescription; import com.iexec.sms.api.TeeSessionGenerationError; -import com.iexec.sms.tee.session.TeeSecretsSessionRequest; -import com.iexec.sms.tee.session.TeeSessionGenerationException; import com.iexec.sms.tee.session.TeeSessionLogConfiguration; +import com.iexec.sms.tee.session.generic.TeeSecretsSessionRequest; +import com.iexec.sms.tee.session.generic.TeeSessionGenerationException; import com.iexec.sms.tee.session.scone.cas.CasClient; -import com.iexec.sms.tee.session.scone.palaemon.PalaemonSessionService; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -27,7 +26,7 @@ public class SconeSessionHandlerServiceTests { @Mock - private PalaemonSessionService sessionService; + private SconeSessionMakerService sessionService; @Mock private CasClient apiClient; @Mock diff --git a/src/test/java/com/iexec/sms/tee/session/scone/palaemon/PalaemonSessionServiceTests.java b/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionMakerServiceTests.java similarity index 86% rename from src/test/java/com/iexec/sms/tee/session/scone/palaemon/PalaemonSessionServiceTests.java rename to src/test/java/com/iexec/sms/tee/session/scone/SconeSessionMakerServiceTests.java index 81a2089d..43c917a0 100644 --- a/src/test/java/com/iexec/sms/tee/session/scone/palaemon/PalaemonSessionServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionMakerServiceTests.java @@ -14,18 +14,20 @@ * limitations under the License. */ -package com.iexec.sms.tee.session.scone.palaemon; +package com.iexec.sms.tee.session.scone; import com.iexec.common.tee.TeeEnclaveConfiguration; import com.iexec.common.utils.FileHelper; -import com.iexec.sms.tee.session.TeeSecretsSessionRequest; -import com.iexec.sms.tee.session.generic.TeeSecretsService; -import com.iexec.sms.tee.session.scone.attestation.AttestationSecurityConfig; +import com.iexec.sms.tee.session.TeeSecretsService; +import com.iexec.sms.tee.session.generic.TeeSecretsSessionRequest; import com.iexec.sms.tee.workflow.TeeWorkflowConfiguration; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.mockito.*; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.Spy; import org.springframework.test.util.ReflectionTestUtils; import org.yaml.snakeyaml.Yaml; @@ -36,7 +38,7 @@ import static org.mockito.Mockito.*; @Slf4j -class PalaemonSessionServiceTests { +class SconeSessionMakerServiceTests { private static final String TEMPLATE_SESSION_FILE = "src/main/resources/palaemonTemplate.vm"; private static final String EXPECTED_SESSION_FILE = "src/test/resources/palaemon-tee-session.yml"; @@ -54,14 +56,14 @@ class PalaemonSessionServiceTests { @InjectMocks private TeeSecretsService teeSecretsService; @Mock - private AttestationSecurityConfig attestationSecurityConfig; + private SconeSessionSecurityConfig attestationSecurityConfig; - private PalaemonSessionService palaemonSessionService; + private SconeSessionMakerService palaemonSessionService; @BeforeEach void beforeEach() { MockitoAnnotations.openMocks(this); - palaemonSessionService = spy(new PalaemonSessionService(teeSecretsService, teeWorkflowConfig, attestationSecurityConfig)); + palaemonSessionService = spy(new SconeSessionMakerService(teeSecretsService, teeWorkflowConfig, attestationSecurityConfig)); ReflectionTestUtils.setField(palaemonSessionService, "palaemonTemplateFilePath", TEMPLATE_SESSION_FILE); when(enclaveConfig.getFingerprint()).thenReturn(APP_FINGERPRINT); From 7a4654f65f6e53d1dd4b32013032b01ecb31aba4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20James=20Toussaint?= Date: Wed, 27 Jul 2022 15:30:39 +0200 Subject: [PATCH 015/293] Upgrade to CasSession --- .../sms/tee/session/EnclaveEnvironment.java | 38 ++++++ .../sms/tee/session/EnclaveEnvironments.java | 32 +++++ .../sms/tee/session/TeeSecretsService.java | 90 ++++++++------ .../gramine/GramineSessionMakerService.java | 30 ++++- .../scone/SconeSessionHandlerService.java | 7 +- .../scone/SconeSessionMakerService.java | 105 +++++++++++++--- .../sms/tee/session/scone/cas/CasSession.java | 112 +++++++++++++++++ .../session/scone/cas/CasSessionEnclave.java | 59 +++++++++ .../tee/session/TeeSecretsServiceTests.java | 49 ++------ .../SconeSessionHandlerServiceTests.java | 10 +- .../scone/SconeSessionMakerServiceTests.java | 113 +++++++++++++----- 11 files changed, 508 insertions(+), 137 deletions(-) create mode 100644 src/main/java/com/iexec/sms/tee/session/EnclaveEnvironment.java create mode 100644 src/main/java/com/iexec/sms/tee/session/EnclaveEnvironments.java create mode 100644 src/main/java/com/iexec/sms/tee/session/scone/cas/CasSession.java create mode 100644 src/main/java/com/iexec/sms/tee/session/scone/cas/CasSessionEnclave.java diff --git a/src/main/java/com/iexec/sms/tee/session/EnclaveEnvironment.java b/src/main/java/com/iexec/sms/tee/session/EnclaveEnvironment.java new file mode 100644 index 00000000..12442fc1 --- /dev/null +++ b/src/main/java/com/iexec/sms/tee/session/EnclaveEnvironment.java @@ -0,0 +1,38 @@ +/* + * Copyright 2022 IEXEC BLOCKCHAIN TECH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.iexec.sms.tee.session; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.*; + +import java.util.Map; + +@Builder +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class EnclaveEnvironment { + + @JsonProperty("name") + private String name; + @JsonProperty("mrenclave") + private String mrenclave; + @JsonProperty("environment") + private Map environment; + +} diff --git a/src/main/java/com/iexec/sms/tee/session/EnclaveEnvironments.java b/src/main/java/com/iexec/sms/tee/session/EnclaveEnvironments.java new file mode 100644 index 00000000..39cd92af --- /dev/null +++ b/src/main/java/com/iexec/sms/tee/session/EnclaveEnvironments.java @@ -0,0 +1,32 @@ +/* + * Copyright 2022 IEXEC BLOCKCHAIN TECH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.iexec.sms.tee.session; + +import lombok.*; + +@Builder +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class EnclaveEnvironments { + + private EnclaveEnvironment preCompute; + private EnclaveEnvironment appCompute; + private EnclaveEnvironment postCompute; + +} diff --git a/src/main/java/com/iexec/sms/tee/session/TeeSecretsService.java b/src/main/java/com/iexec/sms/tee/session/TeeSecretsService.java index 15608a71..c5a50ae2 100644 --- a/src/main/java/com/iexec/sms/tee/session/TeeSecretsService.java +++ b/src/main/java/com/iexec/sms/tee/session/TeeSecretsService.java @@ -29,6 +29,8 @@ import com.iexec.sms.secret.web3.Web3SecretService; import com.iexec.sms.tee.challenge.TeeChallenge; import com.iexec.sms.tee.challenge.TeeChallengeService; +import com.iexec.sms.tee.session.EnclaveEnvironment.EnclaveEnvironmentBuilder; +import com.iexec.sms.tee.session.EnclaveEnvironments.EnclaveEnvironmentsBuilder; import com.iexec.sms.tee.session.generic.TeeSecretsSessionRequest; import com.iexec.sms.tee.session.generic.TeeSessionGenerationException; import com.iexec.sms.tee.workflow.TeeWorkflowConfiguration; @@ -57,8 +59,6 @@ public class TeeSecretsService { public static final String EMPTY_YML_VALUE = ""; - // Generic - public static final String SESSION_ID = "SESSION_ID"; public static final String INPUT_FILE_URLS = "INPUT_FILE_URLS"; public static final String INPUT_FILE_NAMES = "INPUT_FILE_NAMES"; // PreCompute @@ -98,7 +98,7 @@ public TeeSecretsService( * @param request session request details * @return All common tokens for a session, whatever TEE technology is used */ - public Map getSecretsTokens(TeeSecretsSessionRequest request) throws TeeSessionGenerationException { + public EnclaveEnvironments getSecretsTokens(TeeSecretsSessionRequest request) throws TeeSessionGenerationException { if (request == null) { throw new TeeSessionGenerationException( NO_SESSION_REQUEST, @@ -111,28 +111,35 @@ public Map getSecretsTokens(TeeSecretsSessionRequest request) th "Task description must not be null" ); } - + EnclaveEnvironmentsBuilder enclaveEnvironmentsBuilder = EnclaveEnvironments.builder(); TaskDescription taskDescription = request.getTaskDescription(); - Map secretsTokens = new HashMap<>(); - secretsTokens.put(SESSION_ID, request.getSessionId()); + //tokens.put(SESSION_ID, request.getSessionId()); + //enclaveEnvironmentsBuilder.sessionId(request.getSessionId()); + + //Map secretsTokens = new HashMap<>(); + //secretsTokens.put(SESSION_ID, request.getSessionId()); // pre-compute boolean isPreComputeRequired = taskDescription.containsDataset() || !taskDescription.getInputFiles().isEmpty(); - secretsTokens.put(IS_PRE_COMPUTE_REQUIRED, isPreComputeRequired); + //secretsTokens.put(IS_PRE_COMPUTE_REQUIRED, isPreComputeRequired); if (isPreComputeRequired) { - secretsTokens.putAll(getPreComputeTokens(request)); + //secretsTokens.putAll(getPreComputeTokens(request)); + enclaveEnvironmentsBuilder.preCompute(getPreComputeTokens(request)); } // app - secretsTokens.putAll(getAppTokens(request)); + //secretsTokens.putAll(getAppTokens(request)); + enclaveEnvironmentsBuilder.appCompute(getAppTokens(request)); // post compute - secretsTokens.putAll(getPostComputeTokens(request)); + //secretsTokens.putAll(getPostComputeTokens(request)); + enclaveEnvironmentsBuilder.postCompute(getPostComputeTokens(request)); // env variables - Map env = IexecEnvUtils.getAllIexecEnv(taskDescription); + //TODO: Required? + //Map env = IexecEnvUtils.getAllIexecEnv(taskDescription); // Null value should be replaced by an empty string. - env.forEach((key, value) -> env.replace(key, null, EMPTY_YML_VALUE)); - secretsTokens.put(ENV_PROPERTY, env); + //env.forEach((key, value) -> env.replace(key, null, EMPTY_YML_VALUE)); + //secretsTokens.put(ENV_PROPERTY, env); - return secretsTokens; + return enclaveEnvironmentsBuilder.build(); } /** @@ -141,15 +148,17 @@ public Map getSecretsTokens(TeeSecretsSessionRequest request) th * @return map of pre-compute tokens * @throws TeeSessionGenerationException if dataset secret is not found. */ - public Map getPreComputeTokens(TeeSecretsSessionRequest request) + public EnclaveEnvironment getPreComputeTokens(TeeSecretsSessionRequest request) throws TeeSessionGenerationException { + EnclaveEnvironmentBuilder environmentBuilder = EnclaveEnvironment.builder(); + environmentBuilder.name("pre-compute"); + Map environmentVariables = new HashMap<>(); TaskDescription taskDescription = request.getTaskDescription(); String taskId = taskDescription.getChainTaskId(); - Map tokens = new HashMap<>(); String fingerprint = teeWorkflowConfig.getPreComputeFingerprint(); - tokens.put(PRE_COMPUTE_MRENCLAVE, fingerprint); - tokens.put(IS_DATASET_REQUIRED, taskDescription.containsDataset()); - tokens.put(IEXEC_DATASET_KEY, EMPTY_YML_VALUE); + environmentBuilder.mrenclave(fingerprint); + environmentVariables.put(IS_DATASET_REQUIRED, taskDescription.containsDataset()); + environmentVariables.put(IEXEC_DATASET_KEY, EMPTY_YML_VALUE); if (taskDescription.containsDataset()) { String datasetKey = web3SecretService .getSecret(taskDescription.getDatasetAddress(), true) @@ -158,7 +167,7 @@ public Map getPreComputeTokens(TeeSecretsSessionRequest request) "Empty dataset secret - taskId: " + taskId )) .getTrimmedValue(); - tokens.put(IEXEC_DATASET_KEY, datasetKey); + environmentVariables.put(IEXEC_DATASET_KEY, datasetKey); } else { log.info("No dataset key needed for this task [taskId:{}]", taskId); } @@ -169,15 +178,19 @@ public Map getPreComputeTokens(TeeSecretsSessionRequest request) .stream() .filter(e -> e.getKey().contains(IexecEnvUtils.IEXEC_INPUT_FILE_URL_PREFIX)) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); - tokens.put(INPUT_FILE_URLS, inputFileUrls); - return tokens; + environmentVariables.put(INPUT_FILE_URLS, inputFileUrls); + environmentBuilder.environment(environmentVariables); + return environmentBuilder.build(); } /* * Compute (App) */ - public Map getAppTokens(TeeSecretsSessionRequest request) + public EnclaveEnvironment getAppTokens(TeeSecretsSessionRequest request) throws TeeSessionGenerationException{ + EnclaveEnvironmentBuilder environmentBuilder = EnclaveEnvironment.builder(); + environmentBuilder.name("app"); + Map environmentVariables = new HashMap<>(); TaskDescription taskDescription = request.getTaskDescription(); if (taskDescription == null) { throw new TeeSessionGenerationException( @@ -186,7 +199,7 @@ public Map getAppTokens(TeeSecretsSessionRequest request) ); } - Map tokens = new HashMap<>(); + //Map tokens = new HashMap<>(); TeeEnclaveConfiguration enclaveConfig = taskDescription.getAppEnclaveConfiguration(); if (enclaveConfig == null) { throw new TeeSessionGenerationException( @@ -202,7 +215,8 @@ public Map getAppTokens(TeeSecretsSessionRequest request) ); } - tokens.put(APP_MRENCLAVE, enclaveConfig.getFingerprint()); + //tokens.put(APP_MRENCLAVE, enclaveConfig.getFingerprint()); + environmentBuilder.mrenclave(enclaveConfig.getFingerprint()); // extract // this map will be empty (not null) if no input file is found Map inputFileNames = IexecEnvUtils.getComputeStageEnvMap(taskDescription) @@ -210,12 +224,12 @@ public Map getAppTokens(TeeSecretsSessionRequest request) .stream() .filter(e -> e.getKey().contains(IexecEnvUtils.IEXEC_INPUT_FILE_NAME_PREFIX)) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); - tokens.put(INPUT_FILE_NAMES, inputFileNames); + environmentVariables.put(INPUT_FILE_NAMES, inputFileNames); final Map computeSecrets = getApplicationComputeSecrets(taskDescription); - tokens.putAll(computeSecrets); - - return tokens; + environmentVariables.putAll(computeSecrets); + environmentBuilder.environment(environmentVariables); + return environmentBuilder.build(); } private Map getApplicationComputeSecrets(TaskDescription taskDescription) { @@ -273,14 +287,15 @@ private Map getApplicationComputeSecrets(TaskDescription taskDes /* * Post-Compute (Result) */ - public Map getPostComputeTokens(TeeSecretsSessionRequest request) + public EnclaveEnvironment getPostComputeTokens(TeeSecretsSessionRequest request) throws TeeSessionGenerationException { + EnclaveEnvironmentBuilder environmentBuilder = EnclaveEnvironment.builder(); + environmentBuilder.name("post-compute"); + Map environmentVariables = new HashMap<>(); TaskDescription taskDescription = request.getTaskDescription(); if (taskDescription == null) { throw new TeeSessionGenerationException(NO_TASK_DESCRIPTION, "Task description must not be null"); } - - Map tokens = new HashMap<>(); String teePostComputeFingerprint = teeWorkflowConfig.getPostComputeFingerprint(); // ############################################################################### // TODO: activate this when user specific post-compute is properly @@ -291,17 +306,18 @@ public Map getPostComputeTokens(TeeSecretsSessionRequest request // teePostComputeFingerprint = taskDescription.getTeePostComputeFingerprint(); // //add entrypoint too //} - tokens.put(POST_COMPUTE_MRENCLAVE, teePostComputeFingerprint); + environmentVariables.put(POST_COMPUTE_MRENCLAVE, teePostComputeFingerprint); // encryption Map encryptionTokens = getPostComputeEncryptionTokens(request); - tokens.putAll(encryptionTokens); + environmentVariables.putAll(encryptionTokens); // storage Map storageTokens = getPostComputeStorageTokens(request); - tokens.putAll(storageTokens); + environmentVariables.putAll(storageTokens); // enclave signature Map signTokens = getPostComputeSignTokens(request); - tokens.putAll(signTokens); - return tokens; + environmentVariables.putAll(signTokens); + environmentBuilder.environment(environmentVariables); + return environmentBuilder.build(); } public Map getPostComputeEncryptionTokens(TeeSecretsSessionRequest request) diff --git a/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerService.java b/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerService.java index 6cabc90b..94de323b 100644 --- a/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerService.java +++ b/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerService.java @@ -16,13 +16,16 @@ package com.iexec.sms.tee.session.gramine; -import com.fasterxml.jackson.databind.ObjectMapper; import com.iexec.common.utils.FileHelper; -import com.iexec.sms.api.TeeSessionGenerationError; +import com.iexec.sms.tee.session.EnclaveEnvironment; +import com.iexec.sms.tee.session.EnclaveEnvironments; import com.iexec.sms.tee.session.TeeSecretsService; import com.iexec.sms.tee.session.generic.TeeSecretsSessionRequest; import com.iexec.sms.tee.session.generic.TeeSessionGenerationException; import com.iexec.sms.tee.session.gramine.sps.SpsSession; +import com.iexec.sms.tee.session.gramine.sps.SpsSession.SpsSessionBuilder; +import com.iexec.sms.tee.session.gramine.sps.SpsSessionEnclave; +import com.iexec.sms.tee.session.gramine.sps.SpsSessionEnclave.SpsSessionEnclaveBuilder; import org.apache.commons.lang3.StringUtils; import org.apache.velocity.Template; import org.apache.velocity.VelocityContext; @@ -34,6 +37,7 @@ import java.io.FileNotFoundException; import java.io.StringWriter; +import java.util.Arrays; import java.util.Map; @Service @@ -66,9 +70,18 @@ void postConstruct() throws FileNotFoundException { * @return session config */ public SpsSession generateSession(TeeSecretsSessionRequest request) throws TeeSessionGenerationException { - Map tokens = teeSecretsService.getSecretsTokens(request); + EnclaveEnvironments enclaveEnvironments = teeSecretsService.getSecretsTokens(request); // Merge template with tokens - String sessionJsonAsString = getFilledGramineTemplate(this.gramineTemplateFilePath, tokens); + //String sessionJsonAsString = getFilledGramineTemplate(this.gramineTemplateFilePath, enclaveEnvironments); + SpsSessionBuilder sessionBuilder = SpsSession.builder(); + sessionBuilder.session(request.getSessionId()); + sessionBuilder.enclaves(Arrays.asList( + toSpsSessionEnclave(enclaveEnvironments.getPreCompute()), + toSpsSessionEnclave(enclaveEnvironments.getAppCompute()), + toSpsSessionEnclave(enclaveEnvironments.getPostCompute()) + )); + return sessionBuilder.build(); + /* try { return new ObjectMapper().readValue(sessionJsonAsString, SpsSession.class); } catch (Exception e) { @@ -76,6 +89,15 @@ public SpsSession generateSession(TeeSecretsSessionRequest request) throws TeeSe TeeSessionGenerationError.SECURE_SESSION_GENERATION_FAILED, "Failed to parse SPS session:" + e.getMessage()); } + */ + } + + private SpsSessionEnclave toSpsSessionEnclave(EnclaveEnvironment preCompute) { + SpsSessionEnclaveBuilder enclavebuilder = SpsSessionEnclave.builder(); + enclavebuilder.name(preCompute.getName()); + enclavebuilder.mrenclave(preCompute.getMrenclave()); + enclavebuilder.environment(preCompute.getEnvironment()); + return enclavebuilder.build(); } private String getFilledGramineTemplate(String templatePath, Map tokens) { diff --git a/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerService.java b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerService.java index 94a4bb1d..4404f27c 100644 --- a/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerService.java +++ b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerService.java @@ -22,6 +22,7 @@ import com.iexec.sms.tee.session.generic.TeeSessionGenerationException; import com.iexec.sms.tee.session.generic.TeeSessionHandler; import com.iexec.sms.tee.session.scone.cas.CasClient; +import com.iexec.sms.tee.session.scone.cas.CasSession; import lombok.extern.slf4j.Slf4j; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; @@ -44,13 +45,13 @@ public SconeSessionHandlerService(SconeSessionMakerService sessionService, @Override public void buildAndPostSession(TeeSecretsSessionRequest request) throws TeeSessionGenerationException { - String session = sessionService.generateSession(request); + CasSession session = sessionService.generateSession(request); if (session != null && teeSessionLogConfiguration.isDisplayDebugSessionEnabled()) { log.info("Session content [taskId:{}]\n{}", - request.getTaskDescription().getChainTaskId(), session); + request.getTaskDescription().getChainTaskId(), session.toString()); } - ResponseEntity postSession = apiClient.postSession(session); + ResponseEntity postSession = apiClient.postSession(session.toString()); int httpCode = postSession != null ? postSession.getStatusCodeValue() : null; if (httpCode != 200) { throw new TeeSessionGenerationException( diff --git a/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionMakerService.java b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionMakerService.java index f748634c..d1b1913a 100644 --- a/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionMakerService.java +++ b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionMakerService.java @@ -19,9 +19,17 @@ import com.iexec.common.task.TaskDescription; import com.iexec.common.tee.TeeEnclaveConfiguration; import com.iexec.common.utils.FileHelper; +import com.iexec.sms.tee.session.EnclaveEnvironment; +import com.iexec.sms.tee.session.EnclaveEnvironments; import com.iexec.sms.tee.session.TeeSecretsService; import com.iexec.sms.tee.session.generic.TeeSecretsSessionRequest; import com.iexec.sms.tee.session.generic.TeeSessionGenerationException; +import com.iexec.sms.tee.session.scone.cas.CasSession; +import com.iexec.sms.tee.session.scone.cas.CasSession.AccessPolicy; +import com.iexec.sms.tee.session.scone.cas.CasSession.Image.Volume; +import com.iexec.sms.tee.session.scone.cas.CasSession.Security; +import com.iexec.sms.tee.session.scone.cas.CasSession.Volumes; +import com.iexec.sms.tee.session.scone.cas.CasSessionEnclave; import com.iexec.sms.tee.workflow.TeeWorkflowConfiguration; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; @@ -35,7 +43,9 @@ import java.io.FileNotFoundException; import java.io.StringWriter; +import java.util.Arrays; import java.util.HashMap; +import java.util.List; import java.util.Map; //TODO Rename and move @@ -60,6 +70,8 @@ public class SconeSessionMakerService { @Value("${scone.cas.palaemon}") private String palaemonTemplateFilePath; + // Generic + public static final String SESSION_ID = "SESSION_ID"; public SconeSessionMakerService( TeeSecretsService teeSecretsService, @@ -91,11 +103,73 @@ void postConstruct() throws FileNotFoundException { * @param request session request details * @return session config in yaml string format */ - public String generateSession(TeeSecretsSessionRequest request) throws TeeSessionGenerationException { - Map tokens = teeSecretsService.getSecretsTokens(request); - tokens.putAll(getSpecificPalaemonTokens(request)); + public CasSession generateSession(TeeSecretsSessionRequest request) throws TeeSessionGenerationException { + EnclaveEnvironments enclaveEnvironments = teeSecretsService.getSecretsTokens(request); + + CasSessionEnclave preEnclave = toCasSessionEnclave(enclaveEnvironments.getPreCompute()); + preEnclave.setCommand(teeWorkflowConfig.getPreComputeEntrypoint()); + CasSessionEnclave appEnclave = toCasSessionEnclave(enclaveEnvironments.getAppCompute()); + appEnclave.setCommand(getAppCommand(request.getTaskDescription())); + CasSessionEnclave postEnclave = toCasSessionEnclave(enclaveEnvironments.getPostCompute()); + postEnclave.setCommand(teeWorkflowConfig.getPostComputeEntrypoint()); + + addJavaEnvVars(preEnclave); + addJavaEnvVars(postEnclave); + + List policy = Arrays.asList("CREATOR"); + + CasSession casSession = CasSession.builder() + .name(request.getSessionId()) + .version("0.3") + .accessPolicy(new AccessPolicy(policy, policy)) + .services(Arrays.asList(preEnclave, appEnclave, postEnclave)) + .security(new Security(attestationSecurityConfig.getToleratedInsecureOptions(), + attestationSecurityConfig.getIgnoredSgxAdvisories())) + .build(); + + Volume iexecInVolume = new Volume("iexec_in", "/iexec_in"); + Volume iexecOutVolume = new Volume("iexec_out", "/iexec_out"); + Volume postComputeTmpVolume = new Volume("post-compute-tmp", "/post-compute-tmp"); + + casSession.setVolumes(Arrays.asList( + new Volumes(iexecInVolume.getName()), + new Volumes(iexecOutVolume.getName()), + new Volumes(postComputeTmpVolume.getName()) + )); + + casSession.setImages(Arrays.asList( + new CasSession.Image(preEnclave.getImageName(), Arrays.asList(iexecInVolume)), + new CasSession.Image(appEnclave.getImageName(), Arrays.asList(iexecInVolume, iexecOutVolume)), + new CasSession.Image(postEnclave.getImageName(), Arrays.asList(iexecOutVolume, postComputeTmpVolume)) + + )); + + return casSession; + + //enclaveEnvironments.putAll(getSpecificPalaemonTokens(request)); // Merge template with tokens and return the result - return getFilledPalaemonTemplate(this.palaemonTemplateFilePath, tokens); + //return getFilledPalaemonTemplate(this.palaemonTemplateFilePath, enclaveEnvironments); + } + + private void addJavaEnvVars(CasSessionEnclave casSessionEnclave) { + Map additionalJavaEnv = + Map.of("LD_LIBRARY_PATH", "/usr/lib/jvm/java-11-openjdk/lib/server:/usr/lib/jvm/java-11-openjdk/lib:/usr/lib/jvm/java-11-openjdk/../lib", + "JAVA_TOOL_OPTIONS", "-Xmx256m"); + HashMap newEnvironment = new HashMap<>(); + newEnvironment.putAll(casSessionEnclave.getEnvironment()); + newEnvironment.putAll(additionalJavaEnv); + casSessionEnclave.setEnvironment(newEnvironment); + } + + private CasSessionEnclave toCasSessionEnclave(EnclaveEnvironment enclaveEnvironment) { + return CasSessionEnclave.builder() + .name(enclaveEnvironment.getName()) + .imageName(enclaveEnvironment.getName() + "-image") + .mrenclaves(Arrays.asList(enclaveEnvironment.getMrenclave())) + .pwd("/") + // TODO .command(command) + .environment(enclaveEnvironment.getEnvironment()) + .build(); } Map getSpecificPalaemonTokens(TeeSecretsSessionRequest request) { @@ -106,23 +180,26 @@ Map getSpecificPalaemonTokens(TeeSecretsSessionRequest request) tokens.put(POST_COMPUTE_ENTRYPOINT, teeWorkflowConfig.getPostComputeEntrypoint()); // Add attestation security config - String toleratedInsecureOptions = - String.join(",", attestationSecurityConfig.getToleratedInsecureOptions()); - String ignoredSgxAdvisories = - String.join(",", attestationSecurityConfig.getIgnoredSgxAdvisories()); - tokens.put(TOLERATED_INSECURE_OPTIONS, toleratedInsecureOptions); - tokens.put(IGNORED_SGX_ADVISORIES, ignoredSgxAdvisories); + // String toleratedInsecureOptions = + // String.join(",", attestationSecurityConfig.getToleratedInsecureOptions()); + // String ignoredSgxAdvisories = + // String.join(",", attestationSecurityConfig.getIgnoredSgxAdvisories()); + // tokens.put(TOLERATED_INSECURE_OPTIONS, toleratedInsecureOptions); + // tokens.put(IGNORED_SGX_ADVISORIES, ignoredSgxAdvisories); + + + return tokens; + } + + private String getAppCommand(TaskDescription taskDescription) { // Add app args - TaskDescription taskDescription = request.getTaskDescription(); TeeEnclaveConfiguration enclaveConfig = taskDescription.getAppEnclaveConfiguration(); String appArgs = enclaveConfig.getEntrypoint(); if (!StringUtils.isEmpty(taskDescription.getCmd())) { appArgs = appArgs + " " + taskDescription.getCmd(); } - tokens.put(APP_ARGS, appArgs); - - return tokens; + return appArgs; } private String getFilledPalaemonTemplate(String templatePath, Map tokens) { diff --git a/src/main/java/com/iexec/sms/tee/session/scone/cas/CasSession.java b/src/main/java/com/iexec/sms/tee/session/scone/cas/CasSession.java new file mode 100644 index 00000000..6cd56709 --- /dev/null +++ b/src/main/java/com/iexec/sms/tee/session/scone/cas/CasSession.java @@ -0,0 +1,112 @@ +/* + * Copyright 2022 IEXEC BLOCKCHAIN TECH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.iexec.sms.tee.session.scone.cas; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.dataformat.yaml.YAMLMapper; +import lombok.*; +import lombok.extern.slf4j.Slf4j; + +import java.util.List; + +@Slf4j +@Builder +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class CasSession { + + @JsonProperty("name") + private String name; + @JsonProperty("version") + private String version; + @JsonProperty("access_policy") + private AccessPolicy accessPolicy; + @JsonProperty("services") + private List services; + @JsonProperty("images") + private List images; + @JsonProperty("volumes") + private List volumes; + @JsonProperty("security") + private Security security; + + @AllArgsConstructor + @Getter + public static class AccessPolicy { + @JsonProperty("read") + private List read; + @JsonProperty("update") + private List update; + } + + @AllArgsConstructor + public static class Image { + @JsonProperty("name") + private String name; + @JsonProperty("volumes") + private List volumes; + + @Getter + @AllArgsConstructor + public static class Volume { + @JsonProperty("name") + private String name; + @JsonProperty("path") + private String path; + } + } + + @AllArgsConstructor + public static class Volumes { + @JsonProperty("name") + private String name; + } + + @AllArgsConstructor + @Getter + public static class Security { + @JsonProperty("attestation") + private Attestation attestation; + + public Security(List tolerate, List ignoreAdvisories) { + this.attestation = new Attestation(tolerate, ignoreAdvisories); + } + + @AllArgsConstructor + @Getter + public class Attestation { + @JsonProperty("tolerate") + private List tolerate; + @JsonProperty("ignore_advisories") + private List ignoreAdvisories; + } + } + + @Override + public String toString() { + try { + return new YAMLMapper().writeValueAsString(this); + } catch (JsonProcessingException e) { + log.error("Failed to write SPS session as string [session:{}]", name, e); + return ""; + } + } + +} diff --git a/src/main/java/com/iexec/sms/tee/session/scone/cas/CasSessionEnclave.java b/src/main/java/com/iexec/sms/tee/session/scone/cas/CasSessionEnclave.java new file mode 100644 index 00000000..3dcf5e47 --- /dev/null +++ b/src/main/java/com/iexec/sms/tee/session/scone/cas/CasSessionEnclave.java @@ -0,0 +1,59 @@ +/* + * Copyright 2022 IEXEC BLOCKCHAIN TECH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.iexec.sms.tee.session.scone.cas; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.*; +import lombok.extern.slf4j.Slf4j; + +import java.util.List; +import java.util.Map; + +@Slf4j +@Builder +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class CasSessionEnclave { + + @JsonProperty("name") + private String name; + @JsonProperty("image_name") + private String imageName; + @JsonProperty("mrenclaves") + private List mrenclaves; + @JsonProperty("pwd") + private String pwd; + @JsonProperty("command") + private String command; + @JsonProperty("environment") + private Map environment; + + @Override + public String toString() { + try { + return new ObjectMapper().writeValueAsString(this); + } catch (JsonProcessingException e) { + log.error("Failed to write CAS session as string [session:{}]", name, e); + return ""; + } + } + +} diff --git a/src/test/java/com/iexec/sms/tee/session/TeeSecretsServiceTests.java b/src/test/java/com/iexec/sms/tee/session/TeeSecretsServiceTests.java index be458ae7..b82d328d 100644 --- a/src/test/java/com/iexec/sms/tee/session/TeeSecretsServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/TeeSecretsServiceTests.java @@ -1,58 +1,20 @@ package com.iexec.sms.tee.session; -import com.iexec.common.precompute.PreComputeUtils; -import com.iexec.common.sms.secret.ReservedSecretKeyName; -import com.iexec.common.task.TaskDescription; import com.iexec.common.tee.TeeEnclaveConfiguration; -import com.iexec.common.tee.TeeEnclaveConfigurationValidator; -import com.iexec.common.utils.IexecEnvUtils; -import com.iexec.common.worker.result.ResultUtils; -import com.iexec.sms.api.TeeSessionGenerationError; -import com.iexec.sms.secret.Secret; -import com.iexec.sms.secret.compute.OnChainObjectType; -import com.iexec.sms.secret.compute.SecretOwnerRole; -import com.iexec.sms.secret.compute.TeeTaskComputeSecret; import com.iexec.sms.secret.compute.TeeTaskComputeSecretService; import com.iexec.sms.secret.web2.Web2SecretsService; -import com.iexec.sms.secret.web3.Web3Secret; import com.iexec.sms.secret.web3.Web3SecretService; -import com.iexec.sms.tee.challenge.TeeChallenge; import com.iexec.sms.tee.challenge.TeeChallengeService; -import com.iexec.sms.tee.session.generic.TeeSecretsSessionRequest; -import com.iexec.sms.tee.session.generic.TeeSessionGenerationException; import com.iexec.sms.tee.workflow.TeeWorkflowConfiguration; -import com.iexec.sms.utils.EthereumCredentials; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.NullSource; -import org.junit.jupiter.params.provider.ValueSource; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.Spy; -import java.security.GeneralSecurityException; -import java.util.*; - -import static com.iexec.common.chain.DealParams.DROPBOX_RESULT_STORAGE_PROVIDER; -import static com.iexec.common.precompute.PreComputeUtils.IEXEC_DATASET_KEY; -import static com.iexec.common.precompute.PreComputeUtils.IS_DATASET_REQUIRED; -import static com.iexec.common.sms.secret.ReservedSecretKeyName.IEXEC_RESULT_DROPBOX_TOKEN; -import static com.iexec.common.sms.secret.ReservedSecretKeyName.IEXEC_RESULT_ENCRYPTION_PUBLIC_KEY; -import static com.iexec.common.utils.IexecEnvUtils.*; -import static com.iexec.common.worker.result.ResultUtils.*; -import static com.iexec.sms.Web3jUtils.createEthereumAddress; -import static com.iexec.sms.api.TeeSessionGenerationError.*; -import static com.iexec.sms.tee.session.TeeSecretsService.*; -import static com.iexec.sms.tee.session.TeeSecretsService.SESSION_ID; -import static com.iexec.sms.tee.session.TeeSessionTestUtils.*; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.*; +import static com.iexec.sms.tee.session.TeeSessionTestUtils.APP_ENTRYPOINT; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; class TeeSecretsServiceTests { private static final String APP_FINGERPRINT = "01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b"; @@ -83,6 +45,7 @@ void beforeEach() { when(enclaveConfig.getEntrypoint()).thenReturn(APP_ENTRYPOINT); } + /* TODO: Enable //region getSecretsTokens @Test void shouldGetSecretsTokens() throws Exception { @@ -140,7 +103,7 @@ void shouldGetSecretsTokens() throws Exception { "IEXEC_INPUT_FILE_URL_2", "http://host/file2" )); expectedTokens.put("env", expectedEnvTokens); - expectedTokens.put(SESSION_ID, "sessionId"); + expectedTokens.put(SconeSessionMakerService.SESSION_ID, "sessionId"); assertRecursively(expectedTokens, actualTokens); } @@ -724,4 +687,6 @@ private void addRequesterSecret(String requesterAddress, String secretKey, Strin .thenReturn(Optional.of(requesterSecret)); } //endregion + + */ } \ No newline at end of file diff --git a/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerServiceTests.java b/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerServiceTests.java index 81be4892..bf2b2242 100644 --- a/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerServiceTests.java @@ -6,6 +6,7 @@ import com.iexec.sms.tee.session.generic.TeeSecretsSessionRequest; import com.iexec.sms.tee.session.generic.TeeSessionGenerationException; import com.iexec.sms.tee.session.scone.cas.CasClient; +import com.iexec.sms.tee.session.scone.cas.CasSession; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -44,10 +45,11 @@ void shouldBuildAndPostSession(CapturedOutput output) throws TeeSessionGeneratio TeeSecretsSessionRequest request = mock(TeeSecretsSessionRequest.class); TaskDescription taskDescription = mock(TaskDescription.class); when(request.getTaskDescription()).thenReturn(taskDescription); - String casSession = "sessionContent"; + CasSession casSession = mock(CasSession.class); + when(casSession.toString()).thenReturn("sessionContent"); when(sessionService.generateSession(request)).thenReturn(casSession); when(teeSessionLogConfiguration.isDisplayDebugSessionEnabled()).thenReturn(true); - when(apiClient.postSession(casSession)).thenReturn(ResponseEntity.ok("sessionId")); + when(apiClient.postSession(casSession.toString())).thenReturn(ResponseEntity.ok("sessionId")); assertDoesNotThrow(() -> sessionHandlerService.buildAndPostSession(request)); // Testing output here since it reflects a business feature (ability to catch a @@ -73,10 +75,10 @@ void shouldNotBuildAndPostSessionSincePostSessionFailed() TeeSecretsSessionRequest request = mock(TeeSecretsSessionRequest.class); TaskDescription taskDescription = mock(TaskDescription.class); when(request.getTaskDescription()).thenReturn(taskDescription); - String casSession = "sessionContent"; + CasSession casSession = mock(CasSession.class); when(sessionService.generateSession(request)).thenReturn(casSession); when(teeSessionLogConfiguration.isDisplayDebugSessionEnabled()).thenReturn(true); - when(apiClient.postSession(casSession)).thenReturn(ResponseEntity.internalServerError().build()); + when(apiClient.postSession(casSession.toString())).thenReturn(ResponseEntity.internalServerError().build()); assertThrows(TeeSessionGenerationException.class, () -> sessionHandlerService.buildAndPostSession(request)); diff --git a/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionMakerServiceTests.java b/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionMakerServiceTests.java index 43c917a0..98219486 100644 --- a/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionMakerServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionMakerServiceTests.java @@ -18,8 +18,11 @@ import com.iexec.common.tee.TeeEnclaveConfiguration; import com.iexec.common.utils.FileHelper; +import com.iexec.sms.tee.session.EnclaveEnvironment; +import com.iexec.sms.tee.session.EnclaveEnvironments; import com.iexec.sms.tee.session.TeeSecretsService; import com.iexec.sms.tee.session.generic.TeeSecretsSessionRequest; +import com.iexec.sms.tee.session.scone.cas.CasSession; import com.iexec.sms.tee.workflow.TeeWorkflowConfiguration; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.BeforeEach; @@ -27,80 +30,124 @@ import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import org.mockito.Spy; -import org.springframework.test.util.ReflectionTestUtils; import org.yaml.snakeyaml.Yaml; import java.util.List; import java.util.Map; import static com.iexec.sms.tee.session.TeeSessionTestUtils.*; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; @Slf4j class SconeSessionMakerServiceTests { - private static final String TEMPLATE_SESSION_FILE = "src/main/resources/palaemonTemplate.vm"; - private static final String EXPECTED_SESSION_FILE = "src/test/resources/palaemon-tee-session.yml"; private static final String PRE_COMPUTE_ENTRYPOINT = "entrypoint1"; private static final String APP_FINGERPRINT = "01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b"; private static final String APP_ENTRYPOINT = "appEntrypoint"; - private static final TeeEnclaveConfiguration enclaveConfig = - mock(TeeEnclaveConfiguration.class); private static final String POST_COMPUTE_ENTRYPOINT = "entrypoint3"; @Mock private TeeWorkflowConfiguration teeWorkflowConfig; - - @Spy - @InjectMocks + @Mock private TeeSecretsService teeSecretsService; @Mock private SconeSessionSecurityConfig attestationSecurityConfig; + @InjectMocks private SconeSessionMakerService palaemonSessionService; @BeforeEach void beforeEach() { MockitoAnnotations.openMocks(this); - palaemonSessionService = spy(new SconeSessionMakerService(teeSecretsService, teeWorkflowConfig, attestationSecurityConfig)); - ReflectionTestUtils.setField(palaemonSessionService, "palaemonTemplateFilePath", TEMPLATE_SESSION_FILE); - - when(enclaveConfig.getFingerprint()).thenReturn(APP_FINGERPRINT); - when(enclaveConfig.getEntrypoint()).thenReturn(APP_ENTRYPOINT); } - //region getSessionYml - /** - * FIXME - * This is currently not a unit test. - * It relies on {@link TeeSecretsService} implementation to work. - * This should be fixed. - */ + // region getSessionYml @Test void shouldGetSessionYml() throws Exception { + TeeEnclaveConfiguration enclaveConfig = mock(TeeEnclaveConfiguration.class); TeeSecretsSessionRequest request = createSessionRequest(createTaskDescription(enclaveConfig)); - doReturn(getPreComputeTokens()).when(teeSecretsService) - .getPreComputeTokens(request); - doReturn(getAppTokens()).when(teeSecretsService) - .getAppTokens(request); - doReturn(getPostComputeTokens()).when(teeSecretsService) - .getPostComputeTokens(request); - when(teeWorkflowConfig.getPreComputeEntrypoint()).thenReturn(PRE_COMPUTE_ENTRYPOINT); when(teeWorkflowConfig.getPostComputeEntrypoint()).thenReturn(POST_COMPUTE_ENTRYPOINT); + when(enclaveConfig.getFingerprint()).thenReturn(APP_FINGERPRINT); + when(enclaveConfig.getEntrypoint()).thenReturn(APP_ENTRYPOINT); + + EnclaveEnvironment preCompute = EnclaveEnvironment.builder() + .name("pre-compute") + .mrenclave("mrEnclave1") + .environment(Map.ofEntries( // Map of until 10 + // Keeping these test env vars for now + // (could be less but keeping same resource file for now) + Map.entry("IEXEC_TASK_ID", "taskId"), + Map.entry("IEXEC_PRE_COMPUTE_OUT", "/iexec_in"), + Map.entry("IS_DATASET_REQUIRED", "true"), + Map.entry("IEXEC_DATASET_KEY", "datasetKey"), + Map.entry("IEXEC_DATASET_URL", "http://datasetUrl"), + Map.entry("IEXEC_DATASET_FILENAME", "datasetName"), + Map.entry("IEXEC_DATASET_CHECKSUM", "datasetChecksum"), + Map.entry("IEXEC_INPUT_FILES_FOLDER", "/iexec_in"), + Map.entry("IEXEC_INPUT_FILES_NUMBER", "2"), + Map.entry("IEXEC_INPUT_FILE_URL_1", "http://host/file1"), + Map.entry("IEXEC_INPUT_FILE_URL_2", "http://host/file2"))) + .build(); + EnclaveEnvironment appCompute = EnclaveEnvironment.builder() + .name("app") + .mrenclave(APP_FINGERPRINT) + .environment(Map.ofEntries( + Map.entry("IEXEC_TASK_ID", "taskId"), + Map.entry("IEXEC_IN", "/iexec_in"), + Map.entry("IEXEC_OUT", "/iexec_out"), + Map.entry("IEXEC_DATASET_ADDRESS", "0xDatasetAddress"), + Map.entry("IEXEC_DATASET_FILENAME", "datasetName"), + Map.entry("IEXEC_BOT_SIZE", "1"), + Map.entry("IEXEC_BOT_FIRST_INDEX", "0"), + Map.entry("IEXEC_BOT_TASK_INDEX", "0"), + Map.entry("IEXEC_INPUT_FILES_FOLDER", "/iexec_in"), + Map.entry("IEXEC_INPUT_FILES_NUMBER", "2"), + Map.entry("IEXEC_INPUT_FILE_NAME_1", "file1"), + Map.entry("IEXEC_INPUT_FILE_NAME_2", "file2"))) + .build(); + EnclaveEnvironment postCompute = EnclaveEnvironment.builder() + .name("post-compute") + .mrenclave("mrEnclave3") + .environment(Map.ofEntries( + Map.entry("RESULT_TASK_ID", "taskId"), + Map.entry("RESULT_ENCRYPTION", "yes"), + Map.entry("RESULT_ENCRYPTION_PUBLIC_KEY", "encryptionPublicKey"), + Map.entry("RESULT_STORAGE_PROVIDER", "ipfs"), + Map.entry("RESULT_STORAGE_PROXY", "storageProxy"), + Map.entry("RESULT_STORAGE_TOKEN", "storageToken"), + Map.entry("RESULT_STORAGE_CALLBACK", "no"), + Map.entry("RESULT_SIGN_WORKER_ADDRESS", "workerAddress"), + Map.entry("RESULT_SIGN_TEE_CHALLENGE_PRIVATE_KEY", "teeChallengePrivateKey"))) + .build(); + + when(teeSecretsService.getSecretsTokens(request)) + .thenReturn(EnclaveEnvironments.builder() + .preCompute(preCompute) + .appCompute(appCompute) + .postCompute(postCompute) + .build()); when(attestationSecurityConfig.getToleratedInsecureOptions()) .thenReturn(List.of("hyperthreading", "debug-mode")); when(attestationSecurityConfig.getIgnoredSgxAdvisories()) .thenReturn(List.of("INTEL-SA-00161", "INTEL-SA-00289")); - String actualYmlString = palaemonSessionService.generateSession(request); - Map actualYmlMap = new Yaml().load(actualYmlString); - String expectedYamlString = FileHelper.readFile(EXPECTED_SESSION_FILE); + when(teeSecretsService.getSecretsTokens(request)) + .thenReturn(EnclaveEnvironments.builder() + .preCompute(preCompute) + .appCompute(appCompute) + .postCompute(postCompute) + .build()); + + CasSession actualCasSession = palaemonSessionService.generateSession(request); + System.out.println(actualCasSession.toString()); + Map actualYmlMap = new Yaml().load(actualCasSession.toString()); + String expectedYamlString = FileHelper.readFile("src/test/resources/palaemon-tee-session.yml"); Map expectedYmlMap = new Yaml().load(expectedYamlString); assertRecursively(expectedYmlMap, actualYmlMap); } - //endregion + // endregion } From 2e119c598aa98dc35152318916567e991ee68efe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20James=20Toussaint?= Date: Wed, 27 Jul 2022 17:16:30 +0200 Subject: [PATCH 016/293] Removed some session templates --- .../sms/tee/session/TeeSecretsService.java | 14 ++- .../gramine/GramineSessionMakerService.java | 77 +++++----------- .../scone/SconeSessionMakerService.java | 88 ++---------------- src/main/resources/Dockerfile.untrusted | 3 - src/main/resources/application.yml | 2 - .../gramine/GramineSessionServiceTests.java | 92 +++++++++++-------- src/test/resources/gramine-tee-session.json | 15 +-- 7 files changed, 102 insertions(+), 189 deletions(-) diff --git a/src/main/java/com/iexec/sms/tee/session/TeeSecretsService.java b/src/main/java/com/iexec/sms/tee/session/TeeSecretsService.java index c5a50ae2..46a2a988 100644 --- a/src/main/java/com/iexec/sms/tee/session/TeeSecretsService.java +++ b/src/main/java/com/iexec/sms/tee/session/TeeSecretsService.java @@ -39,7 +39,6 @@ import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; -import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Optional; @@ -224,10 +223,15 @@ public EnclaveEnvironment getAppTokens(TeeSecretsSessionRequest request) .stream() .filter(e -> e.getKey().contains(IexecEnvUtils.IEXEC_INPUT_FILE_NAME_PREFIX)) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); - environmentVariables.put(INPUT_FILE_NAMES, inputFileNames); + if(inputFileNames.size() > 0){ + environmentVariables.put(INPUT_FILE_NAMES, inputFileNames); + } final Map computeSecrets = getApplicationComputeSecrets(taskDescription); environmentVariables.putAll(computeSecrets); + // trusted env variables (not confidential) + Map env = IexecEnvUtils.getAllIexecEnv(taskDescription); + environmentVariables.putAll(env); environmentBuilder.environment(environmentVariables); return environmentBuilder.build(); } @@ -251,7 +255,7 @@ private Map getApplicationComputeSecrets(TaskDescription taskDes } if (taskDescription.getSecrets() == null || taskDescription.getRequester() == null) { - tokens.put(REQUESTER_SECRETS, Collections.emptyMap()); + //tokens.put(REQUESTER_SECRETS, Collections.emptyMap()); return tokens; } @@ -279,7 +283,9 @@ private Map getApplicationComputeSecrets(TaskDescription taskDes .orElse(EMPTY_YML_VALUE); requesterSecrets.put(IexecEnvUtils.IEXEC_REQUESTER_SECRET_PREFIX + secretEntry.getKey(), requesterSecret); } - tokens.put(REQUESTER_SECRETS, requesterSecrets); + if(requesterSecrets.size() > 0){ + tokens.put(REQUESTER_SECRETS, requesterSecrets); + } return tokens; } diff --git a/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerService.java b/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerService.java index 94de323b..cd6506cb 100644 --- a/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerService.java +++ b/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerService.java @@ -16,7 +16,6 @@ package com.iexec.sms.tee.session.gramine; -import com.iexec.common.utils.FileHelper; import com.iexec.sms.tee.session.EnclaveEnvironment; import com.iexec.sms.tee.session.EnclaveEnvironments; import com.iexec.sms.tee.session.TeeSecretsService; @@ -26,40 +25,22 @@ import com.iexec.sms.tee.session.gramine.sps.SpsSession.SpsSessionBuilder; import com.iexec.sms.tee.session.gramine.sps.SpsSessionEnclave; import com.iexec.sms.tee.session.gramine.sps.SpsSessionEnclave.SpsSessionEnclaveBuilder; -import org.apache.commons.lang3.StringUtils; -import org.apache.velocity.Template; -import org.apache.velocity.VelocityContext; -import org.apache.velocity.app.VelocityEngine; -import org.springframework.beans.factory.annotation.Value; +import com.iexec.sms.tee.workflow.TeeWorkflowConfiguration; import org.springframework.stereotype.Service; -import javax.annotation.PostConstruct; - -import java.io.FileNotFoundException; -import java.io.StringWriter; import java.util.Arrays; -import java.util.Map; +import java.util.List; @Service public class GramineSessionMakerService { private final TeeSecretsService teeSecretsService; + private TeeWorkflowConfiguration teeWorkflowConfiguration; - @Value("${gramine.sps.templateFile}") - private String gramineTemplateFilePath; - - public GramineSessionMakerService(TeeSecretsService teeSecretsService) { + public GramineSessionMakerService(TeeSecretsService teeSecretsService, + TeeWorkflowConfiguration teeWorkflowConfiguration) { this.teeSecretsService = teeSecretsService; - } - - @PostConstruct - void postConstruct() throws FileNotFoundException { - if (StringUtils.isEmpty(gramineTemplateFilePath)) { - throw new IllegalArgumentException("Missing gramine template filepath"); - } - if (!FileHelper.exists(gramineTemplateFilePath)) { - throw new FileNotFoundException("Missing gramine template file"); - } + this.teeWorkflowConfiguration = teeWorkflowConfiguration; } /** @@ -71,43 +52,31 @@ void postConstruct() throws FileNotFoundException { */ public SpsSession generateSession(TeeSecretsSessionRequest request) throws TeeSessionGenerationException { EnclaveEnvironments enclaveEnvironments = teeSecretsService.getSecretsTokens(request); - // Merge template with tokens - //String sessionJsonAsString = getFilledGramineTemplate(this.gramineTemplateFilePath, enclaveEnvironments); SpsSessionBuilder sessionBuilder = SpsSession.builder(); sessionBuilder.session(request.getSessionId()); + SpsSessionEnclave appSessionEnclave = toSpsSessionEnclave(enclaveEnvironments.getAppCompute()); + appSessionEnclave.setCommand(request.getTaskDescription().getAppCommand()); + SpsSessionEnclave postSessionEnclave = toSpsSessionEnclave(enclaveEnvironments.getPostCompute()); + postSessionEnclave.setMrenclave(teeWorkflowConfiguration.getPreComputeFingerprint()); + postSessionEnclave.setCommand(teeWorkflowConfiguration.getPostComputeEntrypoint()); + + //TODO: Remove useless volumes when SPS is ready + appSessionEnclave.setVolumes(List.of()); + postSessionEnclave.setVolumes(List.of()); + sessionBuilder.enclaves(Arrays.asList( - toSpsSessionEnclave(enclaveEnvironments.getPreCompute()), - toSpsSessionEnclave(enclaveEnvironments.getAppCompute()), - toSpsSessionEnclave(enclaveEnvironments.getPostCompute()) - )); + // No pre-compute for now + appSessionEnclave, + postSessionEnclave)); return sessionBuilder.build(); - /* - try { - return new ObjectMapper().readValue(sessionJsonAsString, SpsSession.class); - } catch (Exception e) { - throw new TeeSessionGenerationException( - TeeSessionGenerationError.SECURE_SESSION_GENERATION_FAILED, - "Failed to parse SPS session:" + e.getMessage()); - } - */ } - private SpsSessionEnclave toSpsSessionEnclave(EnclaveEnvironment preCompute) { + private SpsSessionEnclave toSpsSessionEnclave(EnclaveEnvironment enclaveEnvironment) { SpsSessionEnclaveBuilder enclavebuilder = SpsSessionEnclave.builder(); - enclavebuilder.name(preCompute.getName()); - enclavebuilder.mrenclave(preCompute.getMrenclave()); - enclavebuilder.environment(preCompute.getEnvironment()); + enclavebuilder.name(enclaveEnvironment.getName()); + enclavebuilder.mrenclave(enclaveEnvironment.getMrenclave()); + enclavebuilder.environment(enclaveEnvironment.getEnvironment()); return enclavebuilder.build(); } - private String getFilledGramineTemplate(String templatePath, Map tokens) { - VelocityEngine ve = new VelocityEngine(); - ve.init(); - Template template = ve.getTemplate(templatePath); - VelocityContext context = new VelocityContext(); - tokens.forEach(context::put); // copy all data from the tokens into context - StringWriter writer = new StringWriter(); - template.merge(context, writer); - return writer.toString(); - } } diff --git a/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionMakerService.java b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionMakerService.java index d1b1913a..07a0175d 100644 --- a/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionMakerService.java +++ b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionMakerService.java @@ -16,9 +16,6 @@ package com.iexec.sms.tee.session.scone; -import com.iexec.common.task.TaskDescription; -import com.iexec.common.tee.TeeEnclaveConfiguration; -import com.iexec.common.utils.FileHelper; import com.iexec.sms.tee.session.EnclaveEnvironment; import com.iexec.sms.tee.session.EnclaveEnvironments; import com.iexec.sms.tee.session.TeeSecretsService; @@ -32,17 +29,8 @@ import com.iexec.sms.tee.session.scone.cas.CasSessionEnclave; import com.iexec.sms.tee.workflow.TeeWorkflowConfiguration; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; -import org.apache.velocity.Template; -import org.apache.velocity.VelocityContext; -import org.apache.velocity.app.VelocityEngine; -import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; -import javax.annotation.PostConstruct; - -import java.io.FileNotFoundException; -import java.io.StringWriter; import java.util.Arrays; import java.util.HashMap; import java.util.List; @@ -68,11 +56,6 @@ public class SconeSessionMakerService { private final TeeWorkflowConfiguration teeWorkflowConfig; private final SconeSessionSecurityConfig attestationSecurityConfig; - @Value("${scone.cas.palaemon}") - private String palaemonTemplateFilePath; - // Generic - public static final String SESSION_ID = "SESSION_ID"; - public SconeSessionMakerService( TeeSecretsService teeSecretsService, TeeWorkflowConfiguration teeWorkflowConfig, @@ -82,16 +65,6 @@ public SconeSessionMakerService( this.attestationSecurityConfig = attestationSecurityConfig; } - @PostConstruct - void postConstruct() throws FileNotFoundException { - if (StringUtils.isEmpty(palaemonTemplateFilePath)) { - throw new IllegalArgumentException("Missing palaemon template filepath"); - } - if (!FileHelper.exists(palaemonTemplateFilePath)) { - throw new FileNotFoundException("Missing palaemon template file"); - } - } - /** * Collect tokens required for different compute stages (pre, in, post) * and build the yaml config of the TEE session. @@ -109,7 +82,7 @@ public CasSession generateSession(TeeSecretsSessionRequest request) throws TeeSe CasSessionEnclave preEnclave = toCasSessionEnclave(enclaveEnvironments.getPreCompute()); preEnclave.setCommand(teeWorkflowConfig.getPreComputeEntrypoint()); CasSessionEnclave appEnclave = toCasSessionEnclave(enclaveEnvironments.getAppCompute()); - appEnclave.setCommand(getAppCommand(request.getTaskDescription())); + appEnclave.setCommand(request.getTaskDescription().getAppCommand()); CasSessionEnclave postEnclave = toCasSessionEnclave(enclaveEnvironments.getPostCompute()); postEnclave.setCommand(teeWorkflowConfig.getPostComputeEntrypoint()); @@ -124,7 +97,7 @@ public CasSession generateSession(TeeSecretsSessionRequest request) throws TeeSe .accessPolicy(new AccessPolicy(policy, policy)) .services(Arrays.asList(preEnclave, appEnclave, postEnclave)) .security(new Security(attestationSecurityConfig.getToleratedInsecureOptions(), - attestationSecurityConfig.getIgnoredSgxAdvisories())) + attestationSecurityConfig.getIgnoredSgxAdvisories())) .build(); Volume iexecInVolume = new Volume("iexec_in", "/iexec_in"); @@ -132,10 +105,9 @@ public CasSession generateSession(TeeSecretsSessionRequest request) throws TeeSe Volume postComputeTmpVolume = new Volume("post-compute-tmp", "/post-compute-tmp"); casSession.setVolumes(Arrays.asList( - new Volumes(iexecInVolume.getName()), - new Volumes(iexecOutVolume.getName()), - new Volumes(postComputeTmpVolume.getName()) - )); + new Volumes(iexecInVolume.getName()), + new Volumes(iexecOutVolume.getName()), + new Volumes(postComputeTmpVolume.getName()))); casSession.setImages(Arrays.asList( new CasSession.Image(preEnclave.getImageName(), Arrays.asList(iexecInVolume)), @@ -145,16 +117,12 @@ public CasSession generateSession(TeeSecretsSessionRequest request) throws TeeSe )); return casSession; - - //enclaveEnvironments.putAll(getSpecificPalaemonTokens(request)); - // Merge template with tokens and return the result - //return getFilledPalaemonTemplate(this.palaemonTemplateFilePath, enclaveEnvironments); } private void addJavaEnvVars(CasSessionEnclave casSessionEnclave) { - Map additionalJavaEnv = - Map.of("LD_LIBRARY_PATH", "/usr/lib/jvm/java-11-openjdk/lib/server:/usr/lib/jvm/java-11-openjdk/lib:/usr/lib/jvm/java-11-openjdk/../lib", - "JAVA_TOOL_OPTIONS", "-Xmx256m"); + Map additionalJavaEnv = Map.of("LD_LIBRARY_PATH", + "/usr/lib/jvm/java-11-openjdk/lib/server:/usr/lib/jvm/java-11-openjdk/lib:/usr/lib/jvm/java-11-openjdk/../lib", + "JAVA_TOOL_OPTIONS", "-Xmx256m"); HashMap newEnvironment = new HashMap<>(); newEnvironment.putAll(casSessionEnclave.getEnvironment()); newEnvironment.putAll(additionalJavaEnv); @@ -172,44 +140,4 @@ private CasSessionEnclave toCasSessionEnclave(EnclaveEnvironment enclaveEnvironm .build(); } - Map getSpecificPalaemonTokens(TeeSecretsSessionRequest request) { - Map tokens = new HashMap<>(); - - // Add entrypoints - tokens.put(PRE_COMPUTE_ENTRYPOINT, teeWorkflowConfig.getPreComputeEntrypoint()); - tokens.put(POST_COMPUTE_ENTRYPOINT, teeWorkflowConfig.getPostComputeEntrypoint()); - - // Add attestation security config - // String toleratedInsecureOptions = - // String.join(",", attestationSecurityConfig.getToleratedInsecureOptions()); - // String ignoredSgxAdvisories = - // String.join(",", attestationSecurityConfig.getIgnoredSgxAdvisories()); - // tokens.put(TOLERATED_INSECURE_OPTIONS, toleratedInsecureOptions); - // tokens.put(IGNORED_SGX_ADVISORIES, ignoredSgxAdvisories); - - - - return tokens; - } - - private String getAppCommand(TaskDescription taskDescription) { - // Add app args - TeeEnclaveConfiguration enclaveConfig = taskDescription.getAppEnclaveConfiguration(); - String appArgs = enclaveConfig.getEntrypoint(); - if (!StringUtils.isEmpty(taskDescription.getCmd())) { - appArgs = appArgs + " " + taskDescription.getCmd(); - } - return appArgs; - } - - private String getFilledPalaemonTemplate(String templatePath, Map tokens) { - VelocityEngine ve = new VelocityEngine(); - ve.init(); - Template template = ve.getTemplate(templatePath); - VelocityContext context = new VelocityContext(); - tokens.forEach(context::put); // copy all data from the tokens into context - StringWriter writer = new StringWriter(); - template.merge(context, writer); - return writer.toString(); - } } diff --git a/src/main/resources/Dockerfile.untrusted b/src/main/resources/Dockerfile.untrusted index 9aa093e4..c315d756 100644 --- a/src/main/resources/Dockerfile.untrusted +++ b/src/main/resources/Dockerfile.untrusted @@ -5,11 +5,8 @@ ARG jar RUN test -n "$jar" COPY $jar /app/iexec-sms.jar -COPY build/resources/main/*.vm /app/ COPY src/main/resources/ssl-keystore-dev.p12 /app/ssl-keystore-dev.p12 -ENV IEXEC_PALAEMON_TEMPLATE=/app/palaemonTemplate.vm -ENV IEXEC_GRAMINE_TEMPLATE=/app/gramineSessionTemplate.json.vm ENV IEXEC_SMS_SSL_KEYSTORE=/app/ssl-keystore-dev.p12 ENV IEXEC_SMS_SSL_KEYSTORE=/app/ssl-keystore-dev.p12 ENV IEXEC_SMS_STORAGE_ENCRYPTION_AES_KEY_PATH=/scone/iexec-sms-aes.key diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index af3befc9..97753cd3 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -55,7 +55,6 @@ scone: port: ${IEXEC_SCONE_CAS_PORT:8081} public-host: ${IEXEC_SCONE_CAS_PUBLIC_HOST:localhost} enclave-port: ${IEXEC_SCONE_CAS_ENCLAVE_PORT:18765} - palaemon: ${IEXEC_PALAEMON_TEMPLATE:./src/main/resources/palaemonTemplate.vm} attestation: tolerated-insecure-options: ${IEXEC_SCONE_TOLERATED_INSECURE_OPTIONS:} # e.g.: hyperthreading,software-hardening-needed,insecure-igpu,outdated-tcb,debug-mode ignored-sgx-advisories: ${IEXEC_IGNORED_SGX_ADVISORIES:} # e.g.: INTEL-SA-00220,INTEL-SA-00270 @@ -70,7 +69,6 @@ gramine: enclave: host: ${IEXEC_GRAPHENE_SPS_ENCLAVE_HOST:localhost} port: ${IEXEC_GRAPHENE_SPS_ENCLAVE_PORT:4443} - templateFile: ${IEXEC_GRAMINE_TEMPLATE:./src/main/resources/gramineSessionTemplate.json.vm} # TODO /!\ remove the option of env variable for releases. tee.workflow: diff --git a/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionServiceTests.java b/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionServiceTests.java index cdd7fd24..32ef8fa2 100644 --- a/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionServiceTests.java @@ -1,6 +1,9 @@ package com.iexec.sms.tee.session.gramine; import com.iexec.common.tee.TeeEnclaveConfiguration; +import com.iexec.common.utils.FileHelper; +import com.iexec.sms.tee.session.EnclaveEnvironment; +import com.iexec.sms.tee.session.EnclaveEnvironments; import com.iexec.sms.tee.session.TeeSecretsService; import com.iexec.sms.tee.session.generic.TeeSecretsSessionRequest; import com.iexec.sms.tee.session.gramine.sps.SpsSession; @@ -11,66 +14,83 @@ import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import org.mockito.Spy; -import org.springframework.test.util.ReflectionTestUtils; +import org.testcontainers.shaded.org.yaml.snakeyaml.Yaml; + +import java.util.Map; import static com.iexec.sms.tee.session.TeeSessionTestUtils.*; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; @Slf4j class GramineSessionServiceTests { - private static final String TEMPLATE_SESSION_FILE = "src/main/resources/gramineSessionTemplate.json.vm"; - private static final String EXPECTED_SESSION_FILE = "src/test/resources/gramine-tee-session.json"; - - private static final TeeEnclaveConfiguration enclaveConfig = - mock(TeeEnclaveConfiguration.class); - @Mock private TeeWorkflowConfiguration teeWorkflowConfig; - - @Spy - @InjectMocks + @Mock private TeeSecretsService teeSecretsService; - + @InjectMocks private GramineSessionMakerService gramineSessionService; @BeforeEach void beforeEach() { MockitoAnnotations.openMocks(this); - - gramineSessionService = spy(new GramineSessionMakerService(teeSecretsService)); - ReflectionTestUtils.setField(gramineSessionService, "gramineTemplateFilePath", TEMPLATE_SESSION_FILE); } //region getSessionYml - /** - * FIXME - * This is currently not a unit test. - * It relies on {@link TeeSecretsService} implementation to work. - * This should be fixed. - */ @Test void shouldGetSessionJson() throws Exception { + TeeEnclaveConfiguration enclaveConfig = mock(TeeEnclaveConfiguration.class); TeeSecretsSessionRequest request = createSessionRequest(createTaskDescription(enclaveConfig)); - doReturn(getPreComputeTokens()).when(teeSecretsService) - .getPreComputeTokens(request); - doReturn(getAppTokens()).when(teeSecretsService) - .getAppTokens(request); - doReturn(getPostComputeTokens()).when(teeSecretsService) - .getPostComputeTokens(request); - - when(teeWorkflowConfig.getPreComputeEntrypoint()).thenReturn(PRE_COMPUTE_ENTRYPOINT); when(teeWorkflowConfig.getPostComputeEntrypoint()).thenReturn(POST_COMPUTE_ENTRYPOINT); + when(enclaveConfig.getFingerprint()).thenReturn(APP_FINGERPRINT); + when(enclaveConfig.getEntrypoint()).thenReturn("/apploader.sh"); + + EnclaveEnvironment appCompute = EnclaveEnvironment.builder() + .name("app") + .mrenclave(APP_FINGERPRINT) + .environment(Map.ofEntries( + Map.entry("IEXEC_TASK_ID", "taskId"), + Map.entry("IEXEC_IN", "/iexec_in"), + Map.entry("IEXEC_OUT", "/iexec_out"), + Map.entry("IEXEC_DATASET_ADDRESS", "0xDatasetAddress"), + Map.entry("IEXEC_DATASET_FILENAME", "datasetName"), + Map.entry("IEXEC_BOT_SIZE", "1"), + Map.entry("IEXEC_BOT_FIRST_INDEX", "0"), + Map.entry("IEXEC_BOT_TASK_INDEX", "0"), + Map.entry("IEXEC_INPUT_FILES_FOLDER", "/iexec_in"), + Map.entry("IEXEC_INPUT_FILES_NUMBER", "2"), + Map.entry("IEXEC_INPUT_FILE_NAME_1", "file1"), + Map.entry("IEXEC_INPUT_FILE_NAME_2", "file2"))) + .build(); + EnclaveEnvironment postCompute = EnclaveEnvironment.builder() + .name("post-compute") + .mrenclave("mrEnclave3") + .environment(Map.ofEntries( + Map.entry("RESULT_TASK_ID", "taskId"), + Map.entry("RESULT_ENCRYPTION", "yes"), + Map.entry("RESULT_ENCRYPTION_PUBLIC_KEY", "encryptionPublicKey"), + Map.entry("RESULT_STORAGE_PROVIDER", "ipfs"), + Map.entry("RESULT_STORAGE_PROXY", "storageProxy"), + Map.entry("RESULT_STORAGE_TOKEN", "storageToken"), + Map.entry("RESULT_STORAGE_CALLBACK", "no"), + Map.entry("RESULT_SIGN_WORKER_ADDRESS", "workerAddress"), + Map.entry("RESULT_SIGN_TEE_CHALLENGE_PRIVATE_KEY", "teeChallengePrivateKey"))) + .build(); + + when(teeSecretsService.getSecretsTokens(request)) + .thenReturn(EnclaveEnvironments.builder() + .appCompute(appCompute) + .postCompute(postCompute) + .build()); + - SpsSession actualJsonString = gramineSessionService.generateSession(request); - log.info(actualJsonString.toString()); -/* - Map actualJsonMap = new Yaml().load(actualJsonString); - String expectedJsonString = FileHelper.readFile(EXPECTED_SESSION_FILE); + SpsSession actualSpsSession = gramineSessionService.generateSession(request); + log.info(actualSpsSession.toString()); + Map actualJsonMap = new Yaml().load(actualSpsSession.toString()); + String expectedJsonString = FileHelper.readFile("src/test/resources/gramine-tee-session.json"); Map expectedYmlMap = new Yaml().load(expectedJsonString); assertRecursively(expectedYmlMap, actualJsonMap); - */ } //endregion } \ No newline at end of file diff --git a/src/test/resources/gramine-tee-session.json b/src/test/resources/gramine-tee-session.json index 7b39ec98..6c48f62a 100644 --- a/src/test/resources/gramine-tee-session.json +++ b/src/test/resources/gramine-tee-session.json @@ -4,7 +4,7 @@ { "name": "app", "mrenclave": "01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b", - "command": "/apploader.sh", + "command": "/apploader.sh args", "environment": { "IEXEC_TASK_ID": "taskId", "IEXEC_IN": "/iexec_in", @@ -22,15 +22,12 @@ "IEXEC_INPUT_FILE_NAME_1": "file1", "IEXEC_INPUT_FILE_NAME_2": "file2" }, - "volumes": [ - "/iexec_in", - "/iexec_out" - ] + "volumes": [] }, { - "name": "Post Compute", + "name": "post-compute", "mrenclave": "mrEnclave3", - "command": "/apploader.sh", + "command": "entrypoint3", "environment": { "RESULT_TASK_ID": "taskId", "RESULT_ENCRYPTION": "yes", @@ -42,9 +39,7 @@ "RESULT_SIGN_WORKER_ADDRESS": "workerAddress", "RESULT_SIGN_TEE_CHALLENGE_PRIVATE_KEY": "teeChallengePrivateKey" }, - "volumes": [ - "/iexec_out" - ] + "volumes": [] } ] } \ No newline at end of file From a9c821bed554d23d65d149de8883125e889eb550 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20James=20Toussaint?= Date: Thu, 28 Jul 2022 11:06:48 +0200 Subject: [PATCH 017/293] Secret provisioning url in session creation reply --- build.gradle | 2 +- iexec-sms-library/build.gradle | 1 + iexec-sms-library/lombok.config | 3 + .../java/com/iexec/sms/api/SmsClient.java | 8 +-- .../sms/api/TeeSessionGenerationResponse.java | 33 +++++++++ .../java/com/iexec/sms/tee/TeeController.java | 27 ++++---- .../sms/tee/session/TeeSessionService.java | 7 +- .../session/generic/TeeSessionHandler.java | 9 ++- .../gramine/GramineSessionHandlerService.java | 11 ++- .../gramine/GramineSessionMakerService.java | 2 +- .../sps/SpsConfigurationController.java | 43 ------------ .../scone/SconeSessionHandlerService.java | 16 ++++- .../scone/cas/CasConfigurationController.java | 42 ----------- .../com/iexec/sms/tee/TeeControllerTests.java | 69 +++++++++++-------- .../tee/session/TeeSessionServiceTests.java | 11 ++- .../GramineSessionHandlerServiceTests.java | 6 +- ...a => GramineSessionMakerServiceTests.java} | 10 +-- .../SconeSessionHandlerServiceTests.java | 11 ++- 18 files changed, 155 insertions(+), 156 deletions(-) create mode 100644 iexec-sms-library/lombok.config create mode 100644 iexec-sms-library/src/main/java/com/iexec/sms/api/TeeSessionGenerationResponse.java delete mode 100644 src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsConfigurationController.java delete mode 100644 src/main/java/com/iexec/sms/tee/session/scone/cas/CasConfigurationController.java rename src/test/java/com/iexec/sms/tee/session/gramine/{GramineSessionServiceTests.java => GramineSessionMakerServiceTests.java} (94%) diff --git a/build.gradle b/build.gradle index 036f2994..629b083c 100644 --- a/build.gradle +++ b/build.gradle @@ -1,4 +1,4 @@ -import org.apache.tools.ant.filters.ReplaceTokens +//import org.apache.tools.ant.filters.ReplaceTokens plugins { id 'java' diff --git a/iexec-sms-library/build.gradle b/iexec-sms-library/build.gradle index 80b9cdc6..2fc03736 100644 --- a/iexec-sms-library/build.gradle +++ b/iexec-sms-library/build.gradle @@ -2,6 +2,7 @@ plugins { id 'java-library' id 'jacoco' id 'maven-publish' + id 'io.freefair.lombok' } dependencies { diff --git a/iexec-sms-library/lombok.config b/iexec-sms-library/lombok.config new file mode 100644 index 00000000..189c0bef --- /dev/null +++ b/iexec-sms-library/lombok.config @@ -0,0 +1,3 @@ +# This file is generated by the 'io.freefair.lombok' Gradle plugin +config.stopBubbling = true +lombok.addLombokGeneratedAnnotation = true diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java index 87672e3a..5cc66df5 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java @@ -49,12 +49,6 @@ ApiResponseBody> isAppDeveloperAppComputeSecretPresent( @Param("secretIndex") String secretIndex ); - @RequestLine("GET /cas/url") - String getSconeCasUrl(); - - @RequestLine("GET /sps/url") - String getGramineSpsUrl(); - @RequestLine("POST /requesters/{requesterAddress}/secrets/{secretKey}") @Headers("Authorization: {authorization}") ApiResponseBody> addRequesterAppComputeSecret( @@ -92,7 +86,7 @@ String setWeb3Secret( @RequestLine("POST /tee/sessions") @Headers("Authorization: {authorization}") - ApiResponseBody generateTeeSession( + ApiResponseBody generateTeeSession( @Param("authorization") String authorization, WorkerpoolAuthorization workerpoolAuthorization ); diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/TeeSessionGenerationResponse.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/TeeSessionGenerationResponse.java new file mode 100644 index 00000000..123099ba --- /dev/null +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/TeeSessionGenerationResponse.java @@ -0,0 +1,33 @@ +/* + * Copyright 2022 IEXEC BLOCKCHAIN TECH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.iexec.sms.api; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.ToString; + +@ToString +@NoArgsConstructor +@AllArgsConstructor +@Getter +public class TeeSessionGenerationResponse { + + private String sessionId; + private String secretProvisioningUrl; + +} diff --git a/src/main/java/com/iexec/sms/tee/TeeController.java b/src/main/java/com/iexec/sms/tee/TeeController.java index 81c0736e..a12a480f 100644 --- a/src/main/java/com/iexec/sms/tee/TeeController.java +++ b/src/main/java/com/iexec/sms/tee/TeeController.java @@ -21,6 +21,7 @@ import com.iexec.common.tee.TeeWorkflowSharedConfiguration; import com.iexec.common.web.ApiResponseBody; import com.iexec.sms.api.TeeSessionGenerationError; +import com.iexec.sms.api.TeeSessionGenerationResponse; import com.iexec.sms.authorization.AuthorizationError; import com.iexec.sms.authorization.AuthorizationService; import com.iexec.sms.tee.challenge.TeeChallenge; @@ -111,14 +112,14 @@ public ResponseEntity generateTeeChallenge(@PathVariable String chainTas * 500 INTERNAL_SERVER_ERROR otherwise. */ @PostMapping("/sessions") - public ResponseEntity> generateTeeSession( + public ResponseEntity> generateTeeSession( @RequestHeader("Authorization") String authorization, @RequestBody WorkerpoolAuthorization workerpoolAuthorization) { String workerAddress = workerpoolAuthorization.getWorkerWallet(); String challenge = authorizationService.getChallengeForWorker(workerpoolAuthorization); if (!authorizationService.isSignedByHimself(challenge, authorization, workerAddress)) { - final ApiResponseBody body = - ApiResponseBody.builder() + final ApiResponseBody body = + ApiResponseBody.builder() .error(INVALID_AUTHORIZATION) .build(); @@ -132,8 +133,8 @@ public ResponseEntity> genera final TeeSessionGenerationError teeSessionGenerationError = authorizationToGenerationError.get(authorizationError.get()); - final ApiResponseBody body = - ApiResponseBody.builder() + final ApiResponseBody body = + ApiResponseBody.builder() .error(teeSessionGenerationError) .build(); @@ -147,19 +148,21 @@ public ResponseEntity> genera log.info("TEE session request [taskId:{}, workerAddress:{}]", taskId, workerAddress); try { - String sessionId = teeSessionService + TeeSessionGenerationResponse teeSessionGenerationResponse = teeSessionService .generateTeeSession(taskId, workerAddress, attestingEnclave); - if (sessionId.isEmpty()) { + if (teeSessionGenerationResponse == null) { return ResponseEntity.notFound().build(); } - return ResponseEntity.ok(ApiResponseBody.builder().data(sessionId).build()); + return ResponseEntity.ok(ApiResponseBody.builder() + .data(teeSessionGenerationResponse) + .build()); } catch(TeeSessionGenerationException e) { log.error("Failed to generate secure session [taskId:{}, workerAddress:{}]", taskId, workerAddress, e); - final ApiResponseBody body = - ApiResponseBody.builder() + final ApiResponseBody body = + ApiResponseBody.builder() .error(e.getError()) .build(); return ResponseEntity @@ -168,8 +171,8 @@ public ResponseEntity> genera } catch (Exception e) { log.error("Failed to generate secure session with unknown reason [taskId:{}, workerAddress:{}]", taskId, workerAddress, e); - final ApiResponseBody body = - ApiResponseBody.builder() + final ApiResponseBody body = + ApiResponseBody.builder() .error(SECURE_SESSION_GENERATION_FAILED) .build(); return ResponseEntity diff --git a/src/main/java/com/iexec/sms/tee/session/TeeSessionService.java b/src/main/java/com/iexec/sms/tee/session/TeeSessionService.java index c3dd0cfe..b74a79ea 100644 --- a/src/main/java/com/iexec/sms/tee/session/TeeSessionService.java +++ b/src/main/java/com/iexec/sms/tee/session/TeeSessionService.java @@ -18,6 +18,7 @@ import com.iexec.common.task.TaskDescription; import com.iexec.common.tee.TeeEnclaveProvider; +import com.iexec.sms.api.TeeSessionGenerationResponse; import com.iexec.sms.blockchain.IexecHubService; import com.iexec.sms.tee.session.generic.TeeSecretsSessionRequest; import com.iexec.sms.tee.session.generic.TeeSessionGenerationException; @@ -50,7 +51,7 @@ public TeeSessionService( TeeEnclaveProvider.GRAMINE, gramineService); } - public String generateTeeSession( + public TeeSessionGenerationResponse generateTeeSession( String taskId, String workerAddress, String teeChallenge) throws TeeSessionGenerationException { @@ -83,8 +84,8 @@ public String generateTeeSession( } // /!\ TODO clean expired tasks sessions - teeSessionHandler.buildAndPostSession(request); - return sessionId; + String secretProvisioningUrl = teeSessionHandler.buildAndPostSession(request); + return new TeeSessionGenerationResponse(sessionId, secretProvisioningUrl); } private String createSessionId(String taskId) { diff --git a/src/main/java/com/iexec/sms/tee/session/generic/TeeSessionHandler.java b/src/main/java/com/iexec/sms/tee/session/generic/TeeSessionHandler.java index 7d86c315..5958ea0a 100644 --- a/src/main/java/com/iexec/sms/tee/session/generic/TeeSessionHandler.java +++ b/src/main/java/com/iexec/sms/tee/session/generic/TeeSessionHandler.java @@ -18,6 +18,13 @@ public interface TeeSessionHandler { - void buildAndPostSession(TeeSecretsSessionRequest request) throws TeeSessionGenerationException; + /** + * Build and post secret session on secret provisioning service. + * + * @param request tee session generation request + * @return String secret provisioning service url + * @throws TeeSessionGenerationException + */ + String buildAndPostSession(TeeSecretsSessionRequest request) throws TeeSessionGenerationException; } diff --git a/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerService.java b/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerService.java index efebba39..7968d98c 100644 --- a/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerService.java +++ b/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerService.java @@ -41,7 +41,15 @@ public GramineSessionHandlerService(GramineSessionMakerService sessionService, this.teeSessionLogConfiguration = teeSessionLogConfiguration; } - public void buildAndPostSession(TeeSecretsSessionRequest request) + /** + * Build and post secret session on secret provisioning service. + * + * @param request tee session generation request + * @return String secret provisioning service url + * @throws TeeSessionGenerationException + */ + @Override + public String buildAndPostSession(TeeSecretsSessionRequest request) throws TeeSessionGenerationException { SpsSession session = sessionService.generateSession(request); if (session != null @@ -52,6 +60,7 @@ public void buildAndPostSession(TeeSecretsSessionRequest request) try { spsConfiguration.getInstanceWithBasicAuth().postSession(session); + return spsConfiguration.getEnclaveUrl(); } catch (Exception e) { throw new TeeSessionGenerationException( TeeSessionGenerationError.SECURE_SESSION_STORAGE_CALL_FAILED, diff --git a/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerService.java b/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerService.java index cd6506cb..f3ed4e6e 100644 --- a/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerService.java +++ b/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerService.java @@ -57,7 +57,7 @@ public SpsSession generateSession(TeeSecretsSessionRequest request) throws TeeSe SpsSessionEnclave appSessionEnclave = toSpsSessionEnclave(enclaveEnvironments.getAppCompute()); appSessionEnclave.setCommand(request.getTaskDescription().getAppCommand()); SpsSessionEnclave postSessionEnclave = toSpsSessionEnclave(enclaveEnvironments.getPostCompute()); - postSessionEnclave.setMrenclave(teeWorkflowConfiguration.getPreComputeFingerprint()); + postSessionEnclave.setMrenclave(teeWorkflowConfiguration.getPostComputeFingerprint()); postSessionEnclave.setCommand(teeWorkflowConfiguration.getPostComputeEntrypoint()); //TODO: Remove useless volumes when SPS is ready diff --git a/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsConfigurationController.java b/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsConfigurationController.java deleted file mode 100644 index d3ba1b90..00000000 --- a/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsConfigurationController.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2021 IEXEC BLOCKCHAIN TECH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.iexec.sms.tee.session.gramine.sps; - -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@RequestMapping("/sps") -public class SpsConfigurationController { - - private final SpsConfiguration spsConfiguration; - - public SpsConfigurationController(SpsConfiguration spsConfiguration) { - this.spsConfiguration = spsConfiguration; - } - - /** - * Get SPS public url intended for enclaves. - * - * @return SPS url - */ - @GetMapping("/url") - public String getGramineSpsEnclaveUrl() { - return spsConfiguration.getEnclaveUrl(); - } - -} diff --git a/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerService.java b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerService.java index 4404f27c..9855d3ba 100644 --- a/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerService.java +++ b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerService.java @@ -22,6 +22,7 @@ import com.iexec.sms.tee.session.generic.TeeSessionGenerationException; import com.iexec.sms.tee.session.generic.TeeSessionHandler; import com.iexec.sms.tee.session.scone.cas.CasClient; +import com.iexec.sms.tee.session.scone.cas.CasConfiguration; import com.iexec.sms.tee.session.scone.cas.CasSession; import lombok.extern.slf4j.Slf4j; import org.springframework.http.ResponseEntity; @@ -33,17 +34,27 @@ public class SconeSessionHandlerService implements TeeSessionHandler { private SconeSessionMakerService sessionService; private CasClient apiClient; private TeeSessionLogConfiguration teeSessionLogConfiguration; + private CasConfiguration casConfiguration; public SconeSessionHandlerService(SconeSessionMakerService sessionService, CasClient apiClient, - TeeSessionLogConfiguration teeSessionLogConfiguration) { + TeeSessionLogConfiguration teeSessionLogConfiguration, + CasConfiguration casConfiguration) { this.sessionService = sessionService; this.apiClient = apiClient; this.teeSessionLogConfiguration = teeSessionLogConfiguration; + this.casConfiguration = casConfiguration; } + /** + * Build and post secret session on secret provisioning service. + * + * @param request tee session generation request + * @return String secret provisioning service url + * @throws TeeSessionGenerationException + */ @Override - public void buildAndPostSession(TeeSecretsSessionRequest request) + public String buildAndPostSession(TeeSecretsSessionRequest request) throws TeeSessionGenerationException { CasSession session = sessionService.generateSession(request); if (session != null @@ -58,6 +69,7 @@ public void buildAndPostSession(TeeSecretsSessionRequest request) TeeSessionGenerationError.SECURE_SESSION_STORAGE_CALL_FAILED, "Failed to post session: " + httpCode); } + return casConfiguration.getEnclaveUrl(); } } diff --git a/src/main/java/com/iexec/sms/tee/session/scone/cas/CasConfigurationController.java b/src/main/java/com/iexec/sms/tee/session/scone/cas/CasConfigurationController.java deleted file mode 100644 index 758f9498..00000000 --- a/src/main/java/com/iexec/sms/tee/session/scone/cas/CasConfigurationController.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2021 IEXEC BLOCKCHAIN TECH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.iexec.sms.tee.session.scone.cas; - -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@RequestMapping("/cas") -public class CasConfigurationController { - - private final CasConfiguration casConfiguration; - - public CasConfigurationController(CasConfiguration casConfiguration) { - this.casConfiguration = casConfiguration; - } - - /** - * Get CAS public url intended for enclaves. - * - * @return enclave dedicated url - */ - @GetMapping("/url") - public String getCasEnclaveUrl() { - return casConfiguration.getEnclaveUrl(); - } -} diff --git a/src/test/java/com/iexec/sms/tee/TeeControllerTests.java b/src/test/java/com/iexec/sms/tee/TeeControllerTests.java index 40f4c865..61e1b8e4 100644 --- a/src/test/java/com/iexec/sms/tee/TeeControllerTests.java +++ b/src/test/java/com/iexec/sms/tee/TeeControllerTests.java @@ -3,6 +3,7 @@ import com.iexec.common.chain.WorkerpoolAuthorization; import com.iexec.common.web.ApiResponseBody; import com.iexec.sms.api.TeeSessionGenerationError; +import com.iexec.sms.api.TeeSessionGenerationResponse; import com.iexec.sms.authorization.AuthorizationError; import com.iexec.sms.authorization.AuthorizationService; import com.iexec.sms.tee.challenge.TeeChallengeService; @@ -36,6 +37,7 @@ class TeeControllerTests { private final static String AUTHORIZATION = "0x2"; private final static String CHALLENGE = "CHALLENGE"; private final static String SESSION_ID = "SESSION_ID"; + private static final String SECRET_PROVISIONING_URL = "https://secretProvisioningUrl"; @Mock AuthorizationService authorizationService; @@ -66,15 +68,18 @@ void shouldGenerateTeeSession() throws TeeSessionGenerationException { when(authorizationService.getChallengeForWorker(workerpoolAuthorization)).thenReturn(CHALLENGE); when(authorizationService.isSignedByHimself(CHALLENGE, AUTHORIZATION, WORKER_ADDRESS)).thenReturn(true); - when(authorizationService.isAuthorizedOnExecutionWithDetailedIssue(workerpoolAuthorization, true)).thenReturn(Optional.empty()); - when(teeSessionService.generateTeeSession(TASK_ID, Keys.toChecksumAddress(WORKER_ADDRESS), ENCLAVE_CHALLENGE)).thenReturn(SESSION_ID); + when(authorizationService.isAuthorizedOnExecutionWithDetailedIssue(workerpoolAuthorization, true)) + .thenReturn(Optional.empty()); + when(teeSessionService.generateTeeSession(TASK_ID, Keys.toChecksumAddress(WORKER_ADDRESS), ENCLAVE_CHALLENGE)) + .thenReturn(new TeeSessionGenerationResponse(SESSION_ID, SECRET_PROVISIONING_URL)); - final ResponseEntity> response = - teeController.generateTeeSession(AUTHORIZATION, workerpoolAuthorization); + final ResponseEntity> response = teeController + .generateTeeSession(AUTHORIZATION, workerpoolAuthorization); assertEquals(HttpStatus.OK, response.getStatusCode()); - assertNotEquals(null, response.getBody()); - assertNotEquals(null, response.getBody().getData()); - assertNotEquals("", response.getBody().getData()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getData()); + assertEquals(SESSION_ID, response.getBody().getData().getSessionId()); + assertEquals(SECRET_PROVISIONING_URL, response.getBody().getData().getSecretProvisioningUrl()); assertNull(response.getBody().getError()); } @@ -90,8 +95,8 @@ void shouldNotGenerateTeeSessionSinceNotSignedByHimself() { when(authorizationService.getChallengeForWorker(workerpoolAuthorization)).thenReturn(CHALLENGE); when(authorizationService.isSignedByHimself(CHALLENGE, AUTHORIZATION, WORKER_ADDRESS)).thenReturn(false); - final ResponseEntity> response = - teeController.generateTeeSession(AUTHORIZATION, workerpoolAuthorization); + final ResponseEntity> response = teeController + .generateTeeSession(AUTHORIZATION, workerpoolAuthorization); assertEquals(HttpStatus.UNAUTHORIZED, response.getStatusCode()); assertNotEquals(null, response.getBody()); assertNull(response.getBody().getData()); @@ -106,13 +111,13 @@ private static Stream notAuthorizedParams() { Arguments.of(GET_CHAIN_TASK_FAILED, EXECUTION_NOT_AUTHORIZED_GET_CHAIN_TASK_FAILED), Arguments.of(TASK_NOT_ACTIVE, EXECUTION_NOT_AUTHORIZED_TASK_NOT_ACTIVE), Arguments.of(GET_CHAIN_DEAL_FAILED, EXECUTION_NOT_AUTHORIZED_GET_CHAIN_DEAL_FAILED), - Arguments.of(INVALID_SIGNATURE, EXECUTION_NOT_AUTHORIZED_INVALID_SIGNATURE) - ); + Arguments.of(INVALID_SIGNATURE, EXECUTION_NOT_AUTHORIZED_INVALID_SIGNATURE)); } @ParameterizedTest @MethodSource("notAuthorizedParams") - void shouldNotGenerateTeeSessionSinceNotAuthorized(AuthorizationError cause, TeeSessionGenerationError consequence) { + void shouldNotGenerateTeeSessionSinceNotAuthorized(AuthorizationError cause, + TeeSessionGenerationError consequence) { final WorkerpoolAuthorization workerpoolAuthorization = WorkerpoolAuthorization .builder() .chainTaskId(TASK_ID) @@ -122,10 +127,11 @@ void shouldNotGenerateTeeSessionSinceNotAuthorized(AuthorizationError cause, Tee when(authorizationService.getChallengeForWorker(workerpoolAuthorization)).thenReturn(CHALLENGE); when(authorizationService.isSignedByHimself(CHALLENGE, AUTHORIZATION, WORKER_ADDRESS)).thenReturn(true); - when(authorizationService.isAuthorizedOnExecutionWithDetailedIssue(workerpoolAuthorization, true)).thenReturn(Optional.of(cause)); + when(authorizationService.isAuthorizedOnExecutionWithDetailedIssue(workerpoolAuthorization, true)) + .thenReturn(Optional.of(cause)); - final ResponseEntity> response = - teeController.generateTeeSession(AUTHORIZATION, workerpoolAuthorization); + final ResponseEntity> response = teeController + .generateTeeSession(AUTHORIZATION, workerpoolAuthorization); assertEquals(HttpStatus.UNAUTHORIZED, response.getStatusCode()); assertNotEquals(null, response.getBody()); assertNull(response.getBody().getData()); @@ -134,7 +140,7 @@ void shouldNotGenerateTeeSessionSinceNotAuthorized(AuthorizationError cause, Tee } @Test - void shouldNotGenerateTeeSessionSinceEmptySessionId() throws TeeSessionGenerationException { + void shouldNotGenerateTeeSessionSinceEmptyResponse() throws TeeSessionGenerationException { final WorkerpoolAuthorization workerpoolAuthorization = WorkerpoolAuthorization .builder() .chainTaskId(TASK_ID) @@ -144,11 +150,13 @@ void shouldNotGenerateTeeSessionSinceEmptySessionId() throws TeeSessionGeneratio when(authorizationService.getChallengeForWorker(workerpoolAuthorization)).thenReturn(CHALLENGE); when(authorizationService.isSignedByHimself(CHALLENGE, AUTHORIZATION, WORKER_ADDRESS)).thenReturn(true); - when(authorizationService.isAuthorizedOnExecutionWithDetailedIssue(workerpoolAuthorization, true)).thenReturn(Optional.empty()); - when(teeSessionService.generateTeeSession(TASK_ID, Keys.toChecksumAddress(WORKER_ADDRESS), ENCLAVE_CHALLENGE)).thenReturn(""); + when(authorizationService.isAuthorizedOnExecutionWithDetailedIssue(workerpoolAuthorization, true)) + .thenReturn(Optional.empty()); + when(teeSessionService.generateTeeSession(TASK_ID, Keys.toChecksumAddress(WORKER_ADDRESS), ENCLAVE_CHALLENGE)) + .thenReturn(null); - final ResponseEntity> response = - teeController.generateTeeSession(AUTHORIZATION, workerpoolAuthorization); + final ResponseEntity> response = teeController + .generateTeeSession(AUTHORIZATION, workerpoolAuthorization); assertEquals(HttpStatus.NOT_FOUND, response.getStatusCode()); assertNull(response.getBody()); } @@ -158,11 +166,9 @@ private static Stream exceptionOnSessionIdGeneration() { Arguments.of( new TeeSessionGenerationException( SECURE_SESSION_GENERATION_FAILED, - String.format("Failed to generate secure session [taskId:%s, workerAddress:%s]", TASK_ID, WORKER_ADDRESS) - ) - ), - Arguments.of(new RuntimeException()) - ); + String.format("Failed to generate secure session [taskId:%s, workerAddress:%s]", + TASK_ID, WORKER_ADDRESS))), + Arguments.of(new RuntimeException())); } /** @@ -172,7 +178,8 @@ private static Stream exceptionOnSessionIdGeneration() { */ @ParameterizedTest @MethodSource("exceptionOnSessionIdGeneration") - void shouldNotGenerateTeeSessionSinceSessionIdGenerationFailed(Exception exception) throws TeeSessionGenerationException { + void shouldNotGenerateTeeSessionSinceSessionIdGenerationFailed(Exception exception) + throws TeeSessionGenerationException { final WorkerpoolAuthorization workerpoolAuthorization = WorkerpoolAuthorization .builder() .chainTaskId(TASK_ID) @@ -182,11 +189,13 @@ void shouldNotGenerateTeeSessionSinceSessionIdGenerationFailed(Exception excepti when(authorizationService.getChallengeForWorker(workerpoolAuthorization)).thenReturn(CHALLENGE); when(authorizationService.isSignedByHimself(CHALLENGE, AUTHORIZATION, WORKER_ADDRESS)).thenReturn(true); - when(authorizationService.isAuthorizedOnExecutionWithDetailedIssue(workerpoolAuthorization, true)).thenReturn(Optional.empty()); - when(teeSessionService.generateTeeSession(TASK_ID, Keys.toChecksumAddress(WORKER_ADDRESS), ENCLAVE_CHALLENGE)).thenThrow(exception); + when(authorizationService.isAuthorizedOnExecutionWithDetailedIssue(workerpoolAuthorization, true)) + .thenReturn(Optional.empty()); + when(teeSessionService.generateTeeSession(TASK_ID, Keys.toChecksumAddress(WORKER_ADDRESS), ENCLAVE_CHALLENGE)) + .thenThrow(exception); - final ResponseEntity> response = - teeController.generateTeeSession(AUTHORIZATION, workerpoolAuthorization); + final ResponseEntity> response = teeController + .generateTeeSession(AUTHORIZATION, workerpoolAuthorization); assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode()); assertNotEquals(null, response.getBody()); assertNull(response.getBody().getData()); diff --git a/src/test/java/com/iexec/sms/tee/session/TeeSessionServiceTests.java b/src/test/java/com/iexec/sms/tee/session/TeeSessionServiceTests.java index 7faeca50..16300808 100644 --- a/src/test/java/com/iexec/sms/tee/session/TeeSessionServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/TeeSessionServiceTests.java @@ -3,6 +3,7 @@ import com.iexec.common.task.TaskDescription; import com.iexec.common.tee.TeeEnclaveProvider; import com.iexec.sms.api.TeeSessionGenerationError; +import com.iexec.sms.api.TeeSessionGenerationResponse; import com.iexec.sms.blockchain.IexecHubService; import com.iexec.sms.tee.session.generic.TeeSessionGenerationException; import com.iexec.sms.tee.session.generic.TeeSessionHandler; @@ -27,6 +28,7 @@ class TeeSessionServiceTests { private final static String TASK_ID = "0x0"; private final static String WORKER_ADDRESS = "0x1"; private final static String TEE_CHALLENGE = "0x2"; + private static final String SECRET_PROVISIONING_URL = "https://secretProvisioningUrl"; @Mock private SconeSessionHandlerService sconeService; @Mock @@ -60,12 +62,15 @@ void shouldGenerateTeeSession(TeeEnclaveProvider teeEnclaveProvider) .teeEnclaveProvider(teeEnclaveProvider) .build(); when(iexecHubService.getTaskDescription(TASK_ID)).thenReturn(taskDescription); + TeeSessionHandler teeProviderSessionHandler = getTeeSessionHandler(teeEnclaveProvider); + when(teeProviderSessionHandler.buildAndPostSession(any())).thenReturn(SECRET_PROVISIONING_URL); - final String teeSession = assertDoesNotThrow( + final TeeSessionGenerationResponse teeSessionReponse = assertDoesNotThrow( () -> teeSessionService.generateTeeSession(TASK_ID, WORKER_ADDRESS, TEE_CHALLENGE)); - verify(getTeeSessionHandler(teeEnclaveProvider), times(1)) + verify(teeProviderSessionHandler, times(1)) .buildAndPostSession(any()); - assertNotNull(teeSession); + assertFalse(teeSessionReponse.getSessionId().isEmpty()); + assertEquals(SECRET_PROVISIONING_URL, teeSessionReponse.getSecretProvisioningUrl()); } @Test diff --git a/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerServiceTests.java b/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerServiceTests.java index 09f27b01..00055a8e 100644 --- a/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerServiceTests.java @@ -35,7 +35,7 @@ import org.springframework.boot.test.system.OutputCaptureExtension; import static org.junit.Assert.assertThrows; -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -43,6 +43,7 @@ @ExtendWith(OutputCaptureExtension.class) public class GramineSessionHandlerServiceTests { + private static String SPS_URL = "spsUrl"; @Mock private GramineSessionMakerService sessionService; @Mock @@ -55,6 +56,7 @@ public class GramineSessionHandlerServiceTests { @BeforeEach void beforeEach() { MockitoAnnotations.openMocks(this); + when(spsConfiguration.getEnclaveUrl()).thenReturn(SPS_URL); } @Test @@ -70,7 +72,7 @@ void shouldBuildAndPostSession(CapturedOutput output) throws TeeSessionGeneratio when(spsClient.postSession(spsSession)).thenReturn("sessionId"); when(spsConfiguration.getInstanceWithBasicAuth()).thenReturn(spsClient); - assertDoesNotThrow(() -> sessionHandlerService.buildAndPostSession(request)); + assertEquals(SPS_URL, sessionHandlerService.buildAndPostSession(request)); // Testing output here since it reflects a business feature (ability to catch a // session in debug mode) assertTrue(output.getOut().contains("Session content [taskId:null]\nsessionContent\n")); diff --git a/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionServiceTests.java b/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerServiceTests.java similarity index 94% rename from src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionServiceTests.java rename to src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerServiceTests.java index 32ef8fa2..7c9b29fc 100644 --- a/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerServiceTests.java @@ -23,7 +23,7 @@ import static org.mockito.Mockito.when; @Slf4j -class GramineSessionServiceTests { +class GramineSessionMakerServiceTests { @Mock private TeeWorkflowConfiguration teeWorkflowConfig; @Mock @@ -36,12 +36,13 @@ void beforeEach() { MockitoAnnotations.openMocks(this); } - //region getSessionYml + // region getSessionYml @Test void shouldGetSessionJson() throws Exception { TeeEnclaveConfiguration enclaveConfig = mock(TeeEnclaveConfiguration.class); TeeSecretsSessionRequest request = createSessionRequest(createTaskDescription(enclaveConfig)); + when(teeWorkflowConfig.getPostComputeFingerprint()).thenReturn(POST_COMPUTE_FINGERPRINT); when(teeWorkflowConfig.getPostComputeEntrypoint()).thenReturn(POST_COMPUTE_ENTRYPOINT); when(enclaveConfig.getFingerprint()).thenReturn(APP_FINGERPRINT); when(enclaveConfig.getEntrypoint()).thenReturn("/apploader.sh"); @@ -78,13 +79,12 @@ void shouldGetSessionJson() throws Exception { Map.entry("RESULT_SIGN_TEE_CHALLENGE_PRIVATE_KEY", "teeChallengePrivateKey"))) .build(); - when(teeSecretsService.getSecretsTokens(request)) + when(teeSecretsService.getSecretsTokens(request)) .thenReturn(EnclaveEnvironments.builder() .appCompute(appCompute) .postCompute(postCompute) .build()); - SpsSession actualSpsSession = gramineSessionService.generateSession(request); log.info(actualSpsSession.toString()); Map actualJsonMap = new Yaml().load(actualSpsSession.toString()); @@ -92,5 +92,5 @@ void shouldGetSessionJson() throws Exception { Map expectedYmlMap = new Yaml().load(expectedJsonString); assertRecursively(expectedYmlMap, actualJsonMap); } - //endregion + // endregion } \ No newline at end of file diff --git a/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerServiceTests.java b/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerServiceTests.java index bf2b2242..37ca2fd6 100644 --- a/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerServiceTests.java @@ -6,6 +6,7 @@ import com.iexec.sms.tee.session.generic.TeeSecretsSessionRequest; import com.iexec.sms.tee.session.generic.TeeSessionGenerationException; import com.iexec.sms.tee.session.scone.cas.CasClient; +import com.iexec.sms.tee.session.scone.cas.CasConfiguration; import com.iexec.sms.tee.session.scone.cas.CasSession; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -18,7 +19,7 @@ import org.springframework.http.ResponseEntity; import static org.junit.Assert.assertThrows; -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -26,18 +27,22 @@ @ExtendWith(OutputCaptureExtension.class) public class SconeSessionHandlerServiceTests { + private static final String CAS_URL = "casUrl"; @Mock private SconeSessionMakerService sessionService; @Mock private CasClient apiClient; @Mock private TeeSessionLogConfiguration teeSessionLogConfiguration; + @Mock + private CasConfiguration casConfiguration; @InjectMocks private SconeSessionHandlerService sessionHandlerService; @BeforeEach void beforeEach() { MockitoAnnotations.openMocks(this); + when(casConfiguration.getEnclaveUrl()).thenReturn(CAS_URL); } @Test @@ -50,8 +55,8 @@ void shouldBuildAndPostSession(CapturedOutput output) throws TeeSessionGeneratio when(sessionService.generateSession(request)).thenReturn(casSession); when(teeSessionLogConfiguration.isDisplayDebugSessionEnabled()).thenReturn(true); when(apiClient.postSession(casSession.toString())).thenReturn(ResponseEntity.ok("sessionId")); - - assertDoesNotThrow(() -> sessionHandlerService.buildAndPostSession(request)); + + assertEquals(CAS_URL, sessionHandlerService.buildAndPostSession(request)); // Testing output here since it reflects a business feature (ability to catch a // session in debug mode) assertTrue(output.getOut().contains("Session content [taskId:null]\nsessionContent\n")); From 585a2a71cfc053f201b78c0c302e2c0e5f7de225 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20James=20Toussaint?= Date: Thu, 28 Jul 2022 12:32:10 +0200 Subject: [PATCH 018/293] Add envs for pre-compute --- .../sms/tee/session/TeeSecretsService.java | 154 ++++++++---------- 1 file changed, 66 insertions(+), 88 deletions(-) diff --git a/src/main/java/com/iexec/sms/tee/session/TeeSecretsService.java b/src/main/java/com/iexec/sms/tee/session/TeeSecretsService.java index 46a2a988..b8220c7e 100644 --- a/src/main/java/com/iexec/sms/tee/session/TeeSecretsService.java +++ b/src/main/java/com/iexec/sms/tee/session/TeeSecretsService.java @@ -40,12 +40,12 @@ import org.springframework.stereotype.Service; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Optional; import java.util.stream.Collectors; import static com.iexec.common.chain.DealParams.DROPBOX_RESULT_STORAGE_PROVIDER; -import static com.iexec.common.precompute.PreComputeUtils.IEXEC_DATASET_KEY; import static com.iexec.common.precompute.PreComputeUtils.IS_DATASET_REQUIRED; import static com.iexec.common.sms.secret.ReservedSecretKeyName.IEXEC_RESULT_ENCRYPTION_PUBLIC_KEY; import static com.iexec.common.tee.TeeUtils.booleanToYesNo; @@ -69,8 +69,7 @@ public class TeeSecretsService { public static final String POST_COMPUTE_MRENCLAVE = "POST_COMPUTE_MRENCLAVE"; // Secrets public static final String REQUESTER_SECRETS = "REQUESTER_SECRETS"; - // Env - private static final String ENV_PROPERTY = "env"; + private final Web3SecretService web3SecretService; private final Web2SecretsService web2SecretsService; @@ -101,43 +100,25 @@ public EnclaveEnvironments getSecretsTokens(TeeSecretsSessionRequest request) th if (request == null) { throw new TeeSessionGenerationException( NO_SESSION_REQUEST, - "Session request must not be null" - ); + "Session request must not be null"); } if (request.getTaskDescription() == null) { throw new TeeSessionGenerationException( NO_TASK_DESCRIPTION, - "Task description must not be null" - ); + "Task description must not be null"); } EnclaveEnvironmentsBuilder enclaveEnvironmentsBuilder = EnclaveEnvironments.builder(); TaskDescription taskDescription = request.getTaskDescription(); - //tokens.put(SESSION_ID, request.getSessionId()); - //enclaveEnvironmentsBuilder.sessionId(request.getSessionId()); - - //Map secretsTokens = new HashMap<>(); - //secretsTokens.put(SESSION_ID, request.getSessionId()); // pre-compute boolean isPreComputeRequired = taskDescription.containsDataset() || !taskDescription.getInputFiles().isEmpty(); - //secretsTokens.put(IS_PRE_COMPUTE_REQUIRED, isPreComputeRequired); if (isPreComputeRequired) { - //secretsTokens.putAll(getPreComputeTokens(request)); enclaveEnvironmentsBuilder.preCompute(getPreComputeTokens(request)); } // app - //secretsTokens.putAll(getAppTokens(request)); enclaveEnvironmentsBuilder.appCompute(getAppTokens(request)); // post compute - //secretsTokens.putAll(getPostComputeTokens(request)); enclaveEnvironmentsBuilder.postCompute(getPostComputeTokens(request)); - // env variables - //TODO: Required? - //Map env = IexecEnvUtils.getAllIexecEnv(taskDescription); - // Null value should be replaced by an empty string. - //env.forEach((key, value) -> env.replace(key, null, EMPTY_YML_VALUE)); - //secretsTokens.put(ENV_PROPERTY, env); - return enclaveEnvironmentsBuilder.build(); } @@ -151,25 +132,38 @@ public EnclaveEnvironment getPreComputeTokens(TeeSecretsSessionRequest request) throws TeeSessionGenerationException { EnclaveEnvironmentBuilder environmentBuilder = EnclaveEnvironment.builder(); environmentBuilder.name("pre-compute"); - Map environmentVariables = new HashMap<>(); + Map tokens = new HashMap<>(); TaskDescription taskDescription = request.getTaskDescription(); String taskId = taskDescription.getChainTaskId(); String fingerprint = teeWorkflowConfig.getPreComputeFingerprint(); environmentBuilder.mrenclave(fingerprint); - environmentVariables.put(IS_DATASET_REQUIRED, taskDescription.containsDataset()); - environmentVariables.put(IEXEC_DATASET_KEY, EMPTY_YML_VALUE); + tokens.put("IEXEC_PRE_COMPUTE_OUT", "/iexec_in"); + // `IS_DATASET_REQUIRED` still meaningful? + tokens.put(IS_DATASET_REQUIRED, taskDescription.containsDataset()); if (taskDescription.containsDataset()) { String datasetKey = web3SecretService .getSecret(taskDescription.getDatasetAddress(), true) .orElseThrow(() -> new TeeSessionGenerationException( PRE_COMPUTE_GET_DATASET_SECRET_FAILED, - "Empty dataset secret - taskId: " + taskId - )) + "Empty dataset secret - taskId: " + taskId)) .getTrimmedValue(); - environmentVariables.put(IEXEC_DATASET_KEY, datasetKey); + tokens.put("IEXEC_DATASET_KEY", datasetKey); } else { log.info("No dataset key needed for this task [taskId:{}]", taskId); } + List toInclude = List.of( + IexecEnvUtils.IEXEC_TASK_ID, + IexecEnvUtils.IEXEC_DATASET_URL, + IexecEnvUtils.IEXEC_DATASET_FILENAME, + IexecEnvUtils.IEXEC_DATASET_CHECKSUM, + IexecEnvUtils.IEXEC_INPUT_FILES_FOLDER, + IexecEnvUtils.IEXEC_INPUT_FILES_NUMBER); + Map sharedEnvVars = IexecEnvUtils.getAllIexecEnv(taskDescription) + .entrySet() + .stream() + .filter(e -> toInclude.contains(e.getKey())) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + tokens.putAll(sharedEnvVars); // extract // this map will be empty (not null) if no input file is found Map inputFileUrls = IexecEnvUtils.getAllIexecEnv(taskDescription) @@ -177,8 +171,8 @@ public EnclaveEnvironment getPreComputeTokens(TeeSecretsSessionRequest request) .stream() .filter(e -> e.getKey().contains(IexecEnvUtils.IEXEC_INPUT_FILE_URL_PREFIX)) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); - environmentVariables.put(INPUT_FILE_URLS, inputFileUrls); - environmentBuilder.environment(environmentVariables); + tokens.putAll(inputFileUrls); + environmentBuilder.environment(tokens); return environmentBuilder.build(); } @@ -186,35 +180,30 @@ public EnclaveEnvironment getPreComputeTokens(TeeSecretsSessionRequest request) * Compute (App) */ public EnclaveEnvironment getAppTokens(TeeSecretsSessionRequest request) - throws TeeSessionGenerationException{ + throws TeeSessionGenerationException { EnclaveEnvironmentBuilder environmentBuilder = EnclaveEnvironment.builder(); environmentBuilder.name("app"); - Map environmentVariables = new HashMap<>(); TaskDescription taskDescription = request.getTaskDescription(); if (taskDescription == null) { throw new TeeSessionGenerationException( NO_TASK_DESCRIPTION, - "Task description must no be null" - ); + "Task description must no be null"); } - //Map tokens = new HashMap<>(); + Map tokens = new HashMap<>(); TeeEnclaveConfiguration enclaveConfig = taskDescription.getAppEnclaveConfiguration(); if (enclaveConfig == null) { throw new TeeSessionGenerationException( APP_COMPUTE_NO_ENCLAVE_CONFIG, - "Enclave configuration must no be null" - ); + "Enclave configuration must no be null"); } - if (!enclaveConfig.getValidator().isValid()){ + if (!enclaveConfig.getValidator().isValid()) { throw new TeeSessionGenerationException( APP_COMPUTE_INVALID_ENCLAVE_CONFIG, "Invalid enclave configuration: " + - enclaveConfig.getValidator().validate().toString() - ); + enclaveConfig.getValidator().validate().toString()); } - //tokens.put(APP_MRENCLAVE, enclaveConfig.getFingerprint()); environmentBuilder.mrenclave(enclaveConfig.getFingerprint()); // extract // this map will be empty (not null) if no input file is found @@ -223,16 +212,14 @@ public EnclaveEnvironment getAppTokens(TeeSecretsSessionRequest request) .stream() .filter(e -> e.getKey().contains(IexecEnvUtils.IEXEC_INPUT_FILE_NAME_PREFIX)) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); - if(inputFileNames.size() > 0){ - environmentVariables.put(INPUT_FILE_NAMES, inputFileNames); - } + tokens.putAll(inputFileNames); final Map computeSecrets = getApplicationComputeSecrets(taskDescription); - environmentVariables.putAll(computeSecrets); - // trusted env variables (not confidential) - Map env = IexecEnvUtils.getAllIexecEnv(taskDescription); - environmentVariables.putAll(env); - environmentBuilder.environment(environmentVariables); + tokens.putAll(computeSecrets); + // trusted env variables (not confidential) + Map env = IexecEnvUtils.getComputeStageEnvMap(taskDescription); + tokens.putAll(env); + environmentBuilder.environment(tokens); return environmentBuilder.build(); } @@ -242,25 +229,23 @@ private Map getApplicationComputeSecrets(TaskDescription taskDes if (applicationAddress != null) { final String secretIndex = "1"; - String appDeveloperSecret = - teeTaskComputeSecretService.getSecret( - OnChainObjectType.APPLICATION, - applicationAddress.toLowerCase(), - SecretOwnerRole.APPLICATION_DEVELOPER, - "", - secretIndex) - .map(TeeTaskComputeSecret::getValue) - .orElse(EMPTY_YML_VALUE); + String appDeveloperSecret = teeTaskComputeSecretService.getSecret( + OnChainObjectType.APPLICATION, + applicationAddress.toLowerCase(), + SecretOwnerRole.APPLICATION_DEVELOPER, + "", + secretIndex) + .map(TeeTaskComputeSecret::getValue) + .orElse(EMPTY_YML_VALUE); tokens.put(IexecEnvUtils.IEXEC_APP_DEVELOPER_SECRET_PREFIX + secretIndex, appDeveloperSecret); } if (taskDescription.getSecrets() == null || taskDescription.getRequester() == null) { - //tokens.put(REQUESTER_SECRETS, Collections.emptyMap()); return tokens; } final HashMap requesterSecrets = new HashMap<>(); - for (Map.Entry secretEntry: taskDescription.getSecrets().entrySet()) { + for (Map.Entry secretEntry : taskDescription.getSecrets().entrySet()) { try { int requesterSecretIndex = Integer.parseInt(secretEntry.getKey()); if (requesterSecretIndex <= 0) { @@ -269,24 +254,21 @@ private Map getApplicationComputeSecrets(TaskDescription taskDes log.warn(message); throw new NumberFormatException(message); } - } catch(NumberFormatException e) { + } catch (NumberFormatException e) { log.warn("Invalid entry found in deal parameters secrets map", e); continue; } String requesterSecret = teeTaskComputeSecretService.getSecret( - OnChainObjectType.APPLICATION, - "", - SecretOwnerRole.REQUESTER, - taskDescription.getRequester().toLowerCase(), - secretEntry.getValue()) + OnChainObjectType.APPLICATION, + "", + SecretOwnerRole.REQUESTER, + taskDescription.getRequester().toLowerCase(), + secretEntry.getValue()) .map(TeeTaskComputeSecret::getValue) .orElse(EMPTY_YML_VALUE); requesterSecrets.put(IexecEnvUtils.IEXEC_REQUESTER_SECRET_PREFIX + secretEntry.getKey(), requesterSecret); } - if(requesterSecrets.size() > 0){ - tokens.put(REQUESTER_SECRETS, requesterSecrets); - } - + tokens.putAll(requesterSecrets); return tokens; } @@ -305,13 +287,14 @@ public EnclaveEnvironment getPostComputeTokens(TeeSecretsSessionRequest request) String teePostComputeFingerprint = teeWorkflowConfig.getPostComputeFingerprint(); // ############################################################################### // TODO: activate this when user specific post-compute is properly - // supported. See https://github.com/iExecBlockchainComputing/iexec-sms/issues/52. + // supported. See + // https://github.com/iExecBlockchainComputing/iexec-sms/issues/52. // ############################################################################### // // Use specific post-compute image if requested. - //if (taskDescription.containsPostCompute()) { - // teePostComputeFingerprint = taskDescription.getTeePostComputeFingerprint(); - // //add entrypoint too - //} + // if (taskDescription.containsPostCompute()) { + // teePostComputeFingerprint = taskDescription.getTeePostComputeFingerprint(); + // //add entrypoint too + // } environmentVariables.put(POST_COMPUTE_MRENCLAVE, teePostComputeFingerprint); // encryption Map encryptionTokens = getPostComputeEncryptionTokens(request); @@ -345,8 +328,7 @@ public Map getPostComputeEncryptionTokens(TeeSecretsSessionReque if (beneficiaryResultEncryptionKeySecret.isEmpty()) { throw new TeeSessionGenerationException( POST_COMPUTE_GET_ENCRYPTION_TOKENS_FAILED_EMPTY_BENEFICIARY_KEY, - "Empty beneficiary encryption key - taskId: " + taskId - ); + "Empty beneficiary encryption key - taskId: " + taskId); } String publicKeyValue = beneficiaryResultEncryptionKeySecret.get().getTrimmedValue(); tokens.put(RESULT_ENCRYPTION_PUBLIC_KEY, publicKeyValue); // base64 encoded by client @@ -375,8 +357,8 @@ public Map getPostComputeStorageTokens(TeeSecretsSessionRequest String keyName = storageProvider.equals(DROPBOX_RESULT_STORAGE_PROVIDER) ? ReservedSecretKeyName.IEXEC_RESULT_DROPBOX_TOKEN : ReservedSecretKeyName.IEXEC_RESULT_IEXEC_IPFS_TOKEN; - Optional requesterStorageTokenSecret = - web2SecretsService.getSecret(taskDescription.getRequester(), keyName, true); + Optional requesterStorageTokenSecret = web2SecretsService.getSecret(taskDescription.getRequester(), + keyName, true); if (requesterStorageTokenSecret.isEmpty()) { log.error("Failed to get storage token [taskId:{}, storageProvider:{}, requester:{}]", taskId, storageProvider, taskDescription.getRequester()); @@ -399,28 +381,24 @@ public Map getPostComputeSignTokens(TeeSecretsSessionRequest req if (StringUtils.isEmpty(workerAddress)) { throw new TeeSessionGenerationException( POST_COMPUTE_GET_SIGNATURE_TOKENS_FAILED_EMPTY_WORKER_ADDRESS, - "Empty worker address - taskId: " + taskId - ); + "Empty worker address - taskId: " + taskId); } if (StringUtils.isEmpty(request.getEnclaveChallenge())) { throw new TeeSessionGenerationException( POST_COMPUTE_GET_SIGNATURE_TOKENS_FAILED_EMPTY_PUBLIC_ENCLAVE_CHALLENGE, - "Empty public enclave challenge - taskId: " + taskId - ); + "Empty public enclave challenge - taskId: " + taskId); } Optional teeChallenge = teeChallengeService.getOrCreate(taskId, true); if (teeChallenge.isEmpty()) { throw new TeeSessionGenerationException( POST_COMPUTE_GET_SIGNATURE_TOKENS_FAILED_EMPTY_TEE_CHALLENGE, - "Empty TEE challenge - taskId: " + taskId - ); + "Empty TEE challenge - taskId: " + taskId); } EthereumCredentials enclaveCredentials = teeChallenge.get().getCredentials(); if (enclaveCredentials == null || enclaveCredentials.getPrivateKey().isEmpty()) { throw new TeeSessionGenerationException( POST_COMPUTE_GET_SIGNATURE_TOKENS_FAILED_EMPTY_TEE_CREDENTIALS, - "Empty TEE challenge credentials - taskId: " + taskId - ); + "Empty TEE challenge credentials - taskId: " + taskId); } tokens.put(RESULT_TASK_ID, taskId); tokens.put(RESULT_SIGN_WORKER_ADDRESS, workerAddress); From 3af52364a7daa0c8b75d9586188c06565961e7e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20James=20Toussaint?= Date: Thu, 28 Jul 2022 14:10:18 +0200 Subject: [PATCH 019/293] Update wording --- .../sms/tee/session/TeeSecretsService.java | 89 +++++++++---------- 1 file changed, 43 insertions(+), 46 deletions(-) diff --git a/src/main/java/com/iexec/sms/tee/session/TeeSecretsService.java b/src/main/java/com/iexec/sms/tee/session/TeeSecretsService.java index b8220c7e..0bc09e21 100644 --- a/src/main/java/com/iexec/sms/tee/session/TeeSecretsService.java +++ b/src/main/java/com/iexec/sms/tee/session/TeeSecretsService.java @@ -20,6 +20,7 @@ import com.iexec.common.task.TaskDescription; import com.iexec.common.tee.TeeEnclaveConfiguration; import com.iexec.common.utils.IexecEnvUtils; +import com.iexec.common.utils.IexecFileHelper; import com.iexec.sms.secret.Secret; import com.iexec.sms.secret.compute.OnChainObjectType; import com.iexec.sms.secret.compute.SecretOwnerRole; @@ -56,20 +57,19 @@ @Service public class TeeSecretsService { - public static final String EMPTY_YML_VALUE = ""; + static final String EMPTY_YML_VALUE = ""; - public static final String INPUT_FILE_URLS = "INPUT_FILE_URLS"; - public static final String INPUT_FILE_NAMES = "INPUT_FILE_NAMES"; + static final String INPUT_FILE_URLS = "INPUT_FILE_URLS"; + static final String INPUT_FILE_NAMES = "INPUT_FILE_NAMES"; // PreCompute - public static final String IS_PRE_COMPUTE_REQUIRED = "IS_PRE_COMPUTE_REQUIRED"; - public static final String PRE_COMPUTE_MRENCLAVE = "PRE_COMPUTE_MRENCLAVE"; + static final String IS_PRE_COMPUTE_REQUIRED = "IS_PRE_COMPUTE_REQUIRED"; + static final String PRE_COMPUTE_MRENCLAVE = "PRE_COMPUTE_MRENCLAVE"; + static final String IEXEC_PRE_COMPUTE_OUT = "IEXEC_PRE_COMPUTE_OUT"; + static final String IEXEC_DATASET_KEY = "IEXEC_DATASET_KEY"; // Compute - public static final String APP_MRENCLAVE = "APP_MRENCLAVE"; + static final String APP_MRENCLAVE = "APP_MRENCLAVE"; // PostCompute - public static final String POST_COMPUTE_MRENCLAVE = "POST_COMPUTE_MRENCLAVE"; - // Secrets - public static final String REQUESTER_SECRETS = "REQUESTER_SECRETS"; - + static final String POST_COMPUTE_MRENCLAVE = "POST_COMPUTE_MRENCLAVE"; private final Web3SecretService web3SecretService; private final Web2SecretsService web2SecretsService; @@ -130,14 +130,13 @@ public EnclaveEnvironments getSecretsTokens(TeeSecretsSessionRequest request) th */ public EnclaveEnvironment getPreComputeTokens(TeeSecretsSessionRequest request) throws TeeSessionGenerationException { - EnclaveEnvironmentBuilder environmentBuilder = EnclaveEnvironment.builder(); - environmentBuilder.name("pre-compute"); + EnclaveEnvironmentBuilder builder = EnclaveEnvironment.builder(); + builder.name("pre-compute"); Map tokens = new HashMap<>(); TaskDescription taskDescription = request.getTaskDescription(); String taskId = taskDescription.getChainTaskId(); - String fingerprint = teeWorkflowConfig.getPreComputeFingerprint(); - environmentBuilder.mrenclave(fingerprint); - tokens.put("IEXEC_PRE_COMPUTE_OUT", "/iexec_in"); + builder.mrenclave(teeWorkflowConfig.getPreComputeFingerprint()); + tokens.put(IEXEC_PRE_COMPUTE_OUT, IexecFileHelper.SLASH_IEXEC_IN); // `IS_DATASET_REQUIRED` still meaningful? tokens.put(IS_DATASET_REQUIRED, taskDescription.containsDataset()); if (taskDescription.containsDataset()) { @@ -147,33 +146,30 @@ public EnclaveEnvironment getPreComputeTokens(TeeSecretsSessionRequest request) PRE_COMPUTE_GET_DATASET_SECRET_FAILED, "Empty dataset secret - taskId: " + taskId)) .getTrimmedValue(); - tokens.put("IEXEC_DATASET_KEY", datasetKey); + tokens.put(IEXEC_DATASET_KEY, datasetKey); } else { log.info("No dataset key needed for this task [taskId:{}]", taskId); } - List toInclude = List.of( + List trustedKeys = List.of( IexecEnvUtils.IEXEC_TASK_ID, IexecEnvUtils.IEXEC_DATASET_URL, IexecEnvUtils.IEXEC_DATASET_FILENAME, IexecEnvUtils.IEXEC_DATASET_CHECKSUM, IexecEnvUtils.IEXEC_INPUT_FILES_FOLDER, IexecEnvUtils.IEXEC_INPUT_FILES_NUMBER); - Map sharedEnvVars = IexecEnvUtils.getAllIexecEnv(taskDescription) - .entrySet() - .stream() - .filter(e -> toInclude.contains(e.getKey())) - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); - tokens.putAll(sharedEnvVars); - // extract - // this map will be empty (not null) if no input file is found - Map inputFileUrls = IexecEnvUtils.getAllIexecEnv(taskDescription) + Map trustedEnvVars = IexecEnvUtils.getAllIexecEnv(taskDescription) .entrySet() .stream() - .filter(e -> e.getKey().contains(IexecEnvUtils.IEXEC_INPUT_FILE_URL_PREFIX)) + .filter(e -> + // extract trusted en vars to include + trustedKeys.contains(e.getKey()) + // extract + || e.getKey().contains(IexecEnvUtils.IEXEC_INPUT_FILE_URL_PREFIX)) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); - tokens.putAll(inputFileUrls); - environmentBuilder.environment(tokens); - return environmentBuilder.build(); + tokens.putAll(trustedEnvVars); + return builder + .environment(tokens) + .build(); } /* @@ -181,8 +177,8 @@ public EnclaveEnvironment getPreComputeTokens(TeeSecretsSessionRequest request) */ public EnclaveEnvironment getAppTokens(TeeSecretsSessionRequest request) throws TeeSessionGenerationException { - EnclaveEnvironmentBuilder environmentBuilder = EnclaveEnvironment.builder(); - environmentBuilder.name("app"); + EnclaveEnvironmentBuilder builder = EnclaveEnvironment.builder(); + builder.name("app"); TaskDescription taskDescription = request.getTaskDescription(); if (taskDescription == null) { throw new TeeSessionGenerationException( @@ -204,7 +200,7 @@ public EnclaveEnvironment getAppTokens(TeeSecretsSessionRequest request) enclaveConfig.getValidator().validate().toString()); } - environmentBuilder.mrenclave(enclaveConfig.getFingerprint()); + builder.mrenclave(enclaveConfig.getFingerprint()); // extract // this map will be empty (not null) if no input file is found Map inputFileNames = IexecEnvUtils.getComputeStageEnvMap(taskDescription) @@ -217,10 +213,10 @@ public EnclaveEnvironment getAppTokens(TeeSecretsSessionRequest request) final Map computeSecrets = getApplicationComputeSecrets(taskDescription); tokens.putAll(computeSecrets); // trusted env variables (not confidential) - Map env = IexecEnvUtils.getComputeStageEnvMap(taskDescription); - tokens.putAll(env); - environmentBuilder.environment(tokens); - return environmentBuilder.build(); + tokens.putAll(IexecEnvUtils.getComputeStageEnvMap(taskDescription)); + return builder + .environment(tokens) + .build(); } private Map getApplicationComputeSecrets(TaskDescription taskDescription) { @@ -277,9 +273,9 @@ private Map getApplicationComputeSecrets(TaskDescription taskDes */ public EnclaveEnvironment getPostComputeTokens(TeeSecretsSessionRequest request) throws TeeSessionGenerationException { - EnclaveEnvironmentBuilder environmentBuilder = EnclaveEnvironment.builder(); - environmentBuilder.name("post-compute"); - Map environmentVariables = new HashMap<>(); + EnclaveEnvironmentBuilder builder = EnclaveEnvironment.builder(); + builder.name("post-compute"); + Map tokens = new HashMap<>(); TaskDescription taskDescription = request.getTaskDescription(); if (taskDescription == null) { throw new TeeSessionGenerationException(NO_TASK_DESCRIPTION, "Task description must not be null"); @@ -295,18 +291,19 @@ public EnclaveEnvironment getPostComputeTokens(TeeSecretsSessionRequest request) // teePostComputeFingerprint = taskDescription.getTeePostComputeFingerprint(); // //add entrypoint too // } - environmentVariables.put(POST_COMPUTE_MRENCLAVE, teePostComputeFingerprint); + tokens.put(POST_COMPUTE_MRENCLAVE, teePostComputeFingerprint); // encryption Map encryptionTokens = getPostComputeEncryptionTokens(request); - environmentVariables.putAll(encryptionTokens); + tokens.putAll(encryptionTokens); // storage Map storageTokens = getPostComputeStorageTokens(request); - environmentVariables.putAll(storageTokens); + tokens.putAll(storageTokens); // enclave signature Map signTokens = getPostComputeSignTokens(request); - environmentVariables.putAll(signTokens); - environmentBuilder.environment(environmentVariables); - return environmentBuilder.build(); + tokens.putAll(signTokens); + return builder + .environment(tokens) + .build(); } public Map getPostComputeEncryptionTokens(TeeSecretsSessionRequest request) From d999b874b4b8c388e087147c5342fd53beb11bf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20James=20Toussaint?= Date: Thu, 28 Jul 2022 14:58:38 +0200 Subject: [PATCH 020/293] Reorg session packages --- build.gradle | 2 - .../sms/tee/session/TeeSessionService.java | 4 +- .../SecretEnclaveBase.java} | 4 +- .../SecretSessionBase.java} | 10 +-- .../SecretSessionBaseService.java} | 68 +++++++++---------- .../session/generic/TeeSessionHandler.java | 2 +- ...ionRequest.java => TeeSessionRequest.java} | 2 +- .../gramine/GramineSessionHandlerService.java | 4 +- .../gramine/GramineSessionMakerService.java | 62 ++++++++--------- ...SpsSessionEnclave.java => SpsEnclave.java} | 2 +- .../tee/session/gramine/sps/SpsSession.java | 2 +- .../scone/SconeSessionHandlerService.java | 4 +- .../scone/SconeSessionMakerService.java | 58 ++++++++-------- ...CasSessionEnclave.java => CasEnclave.java} | 2 +- .../sms/tee/session/scone/cas/CasSession.java | 2 +- .../sms/tee/session/TeeSessionTestUtils.java | 11 +-- .../SecretSessionServiceTests.java} | 6 +- .../GramineSessionHandlerServiceTests.java | 8 +-- .../GramineSessionMakerServiceTests.java | 18 ++--- .../SconeSessionHandlerServiceTests.java | 8 +-- .../scone/SconeSessionMakerServiceTests.java | 22 +++--- 21 files changed, 150 insertions(+), 151 deletions(-) rename src/main/java/com/iexec/sms/tee/session/{EnclaveEnvironment.java => base/SecretEnclaveBase.java} (92%) rename src/main/java/com/iexec/sms/tee/session/{EnclaveEnvironments.java => base/SecretSessionBase.java} (77%) rename src/main/java/com/iexec/sms/tee/session/{TeeSecretsService.java => base/SecretSessionBaseService.java} (89%) rename src/main/java/com/iexec/sms/tee/session/generic/{TeeSecretsSessionRequest.java => TeeSessionRequest.java} (96%) rename src/main/java/com/iexec/sms/tee/session/gramine/sps/{SpsSessionEnclave.java => SpsEnclave.java} (97%) rename src/main/java/com/iexec/sms/tee/session/scone/cas/{CasSessionEnclave.java => CasEnclave.java} (97%) rename src/test/java/com/iexec/sms/tee/session/{TeeSecretsServiceTests.java => base/SecretSessionServiceTests.java} (99%) diff --git a/build.gradle b/build.gradle index 629b083c..5fefb0bf 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,3 @@ -//import org.apache.tools.ant.filters.ReplaceTokens - plugins { id 'java' id 'io.freefair.lombok' version '5.3.0' diff --git a/src/main/java/com/iexec/sms/tee/session/TeeSessionService.java b/src/main/java/com/iexec/sms/tee/session/TeeSessionService.java index b74a79ea..0f571441 100644 --- a/src/main/java/com/iexec/sms/tee/session/TeeSessionService.java +++ b/src/main/java/com/iexec/sms/tee/session/TeeSessionService.java @@ -20,9 +20,9 @@ import com.iexec.common.tee.TeeEnclaveProvider; import com.iexec.sms.api.TeeSessionGenerationResponse; import com.iexec.sms.blockchain.IexecHubService; -import com.iexec.sms.tee.session.generic.TeeSecretsSessionRequest; import com.iexec.sms.tee.session.generic.TeeSessionGenerationException; import com.iexec.sms.tee.session.generic.TeeSessionHandler; +import com.iexec.sms.tee.session.generic.TeeSessionRequest; import com.iexec.sms.tee.session.gramine.GramineSessionHandlerService; import com.iexec.sms.tee.session.scone.SconeSessionHandlerService; import lombok.extern.slf4j.Slf4j; @@ -62,7 +62,7 @@ public TeeSessionGenerationResponse generateTeeSession( GET_TASK_DESCRIPTION_FAILED, String.format("Failed to get task description [taskId:%s]", taskId)); } - TeeSecretsSessionRequest request = TeeSecretsSessionRequest.builder() + TeeSessionRequest request = TeeSessionRequest.builder() .sessionId(sessionId) .taskDescription(taskDescription) .workerAddress(workerAddress) diff --git a/src/main/java/com/iexec/sms/tee/session/EnclaveEnvironment.java b/src/main/java/com/iexec/sms/tee/session/base/SecretEnclaveBase.java similarity index 92% rename from src/main/java/com/iexec/sms/tee/session/EnclaveEnvironment.java rename to src/main/java/com/iexec/sms/tee/session/base/SecretEnclaveBase.java index 12442fc1..6dc934b7 100644 --- a/src/main/java/com/iexec/sms/tee/session/EnclaveEnvironment.java +++ b/src/main/java/com/iexec/sms/tee/session/base/SecretEnclaveBase.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.iexec.sms.tee.session; +package com.iexec.sms.tee.session.base; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.*; @@ -26,7 +26,7 @@ @Setter @AllArgsConstructor @NoArgsConstructor -public class EnclaveEnvironment { +public class SecretEnclaveBase { @JsonProperty("name") private String name; diff --git a/src/main/java/com/iexec/sms/tee/session/EnclaveEnvironments.java b/src/main/java/com/iexec/sms/tee/session/base/SecretSessionBase.java similarity index 77% rename from src/main/java/com/iexec/sms/tee/session/EnclaveEnvironments.java rename to src/main/java/com/iexec/sms/tee/session/base/SecretSessionBase.java index 39cd92af..52c68889 100644 --- a/src/main/java/com/iexec/sms/tee/session/EnclaveEnvironments.java +++ b/src/main/java/com/iexec/sms/tee/session/base/SecretSessionBase.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.iexec.sms.tee.session; +package com.iexec.sms.tee.session.base; import lombok.*; @@ -23,10 +23,10 @@ @Setter @AllArgsConstructor @NoArgsConstructor -public class EnclaveEnvironments { +public class SecretSessionBase { - private EnclaveEnvironment preCompute; - private EnclaveEnvironment appCompute; - private EnclaveEnvironment postCompute; + private SecretEnclaveBase preCompute; + private SecretEnclaveBase appCompute; + private SecretEnclaveBase postCompute; } diff --git a/src/main/java/com/iexec/sms/tee/session/TeeSecretsService.java b/src/main/java/com/iexec/sms/tee/session/base/SecretSessionBaseService.java similarity index 89% rename from src/main/java/com/iexec/sms/tee/session/TeeSecretsService.java rename to src/main/java/com/iexec/sms/tee/session/base/SecretSessionBaseService.java index 0bc09e21..7fd31139 100644 --- a/src/main/java/com/iexec/sms/tee/session/TeeSecretsService.java +++ b/src/main/java/com/iexec/sms/tee/session/base/SecretSessionBaseService.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.iexec.sms.tee.session; +package com.iexec.sms.tee.session.base; import com.iexec.common.sms.secret.ReservedSecretKeyName; import com.iexec.common.task.TaskDescription; @@ -30,10 +30,10 @@ import com.iexec.sms.secret.web3.Web3SecretService; import com.iexec.sms.tee.challenge.TeeChallenge; import com.iexec.sms.tee.challenge.TeeChallengeService; -import com.iexec.sms.tee.session.EnclaveEnvironment.EnclaveEnvironmentBuilder; -import com.iexec.sms.tee.session.EnclaveEnvironments.EnclaveEnvironmentsBuilder; -import com.iexec.sms.tee.session.generic.TeeSecretsSessionRequest; +import com.iexec.sms.tee.session.base.SecretEnclaveBase.SecretEnclaveBaseBuilder; +import com.iexec.sms.tee.session.base.SecretSessionBase.SecretSessionBaseBuilder; import com.iexec.sms.tee.session.generic.TeeSessionGenerationException; +import com.iexec.sms.tee.session.generic.TeeSessionRequest; import com.iexec.sms.tee.workflow.TeeWorkflowConfiguration; import com.iexec.sms.utils.EthereumCredentials; import lombok.extern.slf4j.Slf4j; @@ -55,21 +55,21 @@ @Slf4j @Service -public class TeeSecretsService { +public class SecretSessionBaseService { static final String EMPTY_YML_VALUE = ""; - static final String INPUT_FILE_URLS = "INPUT_FILE_URLS"; - static final String INPUT_FILE_NAMES = "INPUT_FILE_NAMES"; + public static final String INPUT_FILE_URLS = "INPUT_FILE_URLS"; + public static final String INPUT_FILE_NAMES = "INPUT_FILE_NAMES"; // PreCompute static final String IS_PRE_COMPUTE_REQUIRED = "IS_PRE_COMPUTE_REQUIRED"; - static final String PRE_COMPUTE_MRENCLAVE = "PRE_COMPUTE_MRENCLAVE"; + public static final String PRE_COMPUTE_MRENCLAVE = "PRE_COMPUTE_MRENCLAVE"; static final String IEXEC_PRE_COMPUTE_OUT = "IEXEC_PRE_COMPUTE_OUT"; static final String IEXEC_DATASET_KEY = "IEXEC_DATASET_KEY"; // Compute - static final String APP_MRENCLAVE = "APP_MRENCLAVE"; + public static final String APP_MRENCLAVE = "APP_MRENCLAVE"; // PostCompute - static final String POST_COMPUTE_MRENCLAVE = "POST_COMPUTE_MRENCLAVE"; + public static final String POST_COMPUTE_MRENCLAVE = "POST_COMPUTE_MRENCLAVE"; private final Web3SecretService web3SecretService; private final Web2SecretsService web2SecretsService; @@ -77,7 +77,7 @@ public class TeeSecretsService { private final TeeWorkflowConfiguration teeWorkflowConfig; private final TeeTaskComputeSecretService teeTaskComputeSecretService; - public TeeSecretsService( + public SecretSessionBaseService( Web3SecretService web3SecretService, Web2SecretsService web2SecretsService, TeeChallengeService teeChallengeService, @@ -96,7 +96,7 @@ public TeeSecretsService( * @param request session request details * @return All common tokens for a session, whatever TEE technology is used */ - public EnclaveEnvironments getSecretsTokens(TeeSecretsSessionRequest request) throws TeeSessionGenerationException { + public SecretSessionBase getSecretsTokens(TeeSessionRequest request) throws TeeSessionGenerationException { if (request == null) { throw new TeeSessionGenerationException( NO_SESSION_REQUEST, @@ -107,19 +107,19 @@ public EnclaveEnvironments getSecretsTokens(TeeSecretsSessionRequest request) th NO_TASK_DESCRIPTION, "Task description must not be null"); } - EnclaveEnvironmentsBuilder enclaveEnvironmentsBuilder = EnclaveEnvironments.builder(); + SecretSessionBaseBuilder sessionBase = SecretSessionBase.builder(); TaskDescription taskDescription = request.getTaskDescription(); // pre-compute boolean isPreComputeRequired = taskDescription.containsDataset() || !taskDescription.getInputFiles().isEmpty(); if (isPreComputeRequired) { - enclaveEnvironmentsBuilder.preCompute(getPreComputeTokens(request)); + sessionBase.preCompute(getPreComputeTokens(request)); } // app - enclaveEnvironmentsBuilder.appCompute(getAppTokens(request)); + sessionBase.appCompute(getAppTokens(request)); // post compute - enclaveEnvironmentsBuilder.postCompute(getPostComputeTokens(request)); - return enclaveEnvironmentsBuilder.build(); + sessionBase.postCompute(getPostComputeTokens(request)); + return sessionBase.build(); } /** @@ -128,14 +128,14 @@ public EnclaveEnvironments getSecretsTokens(TeeSecretsSessionRequest request) th * @return map of pre-compute tokens * @throws TeeSessionGenerationException if dataset secret is not found. */ - public EnclaveEnvironment getPreComputeTokens(TeeSecretsSessionRequest request) + public SecretEnclaveBase getPreComputeTokens(TeeSessionRequest request) throws TeeSessionGenerationException { - EnclaveEnvironmentBuilder builder = EnclaveEnvironment.builder(); - builder.name("pre-compute"); + SecretEnclaveBaseBuilder enclaveBase = SecretEnclaveBase.builder(); + enclaveBase.name("pre-compute"); Map tokens = new HashMap<>(); TaskDescription taskDescription = request.getTaskDescription(); String taskId = taskDescription.getChainTaskId(); - builder.mrenclave(teeWorkflowConfig.getPreComputeFingerprint()); + enclaveBase.mrenclave(teeWorkflowConfig.getPreComputeFingerprint()); tokens.put(IEXEC_PRE_COMPUTE_OUT, IexecFileHelper.SLASH_IEXEC_IN); // `IS_DATASET_REQUIRED` still meaningful? tokens.put(IS_DATASET_REQUIRED, taskDescription.containsDataset()); @@ -167,7 +167,7 @@ public EnclaveEnvironment getPreComputeTokens(TeeSecretsSessionRequest request) || e.getKey().contains(IexecEnvUtils.IEXEC_INPUT_FILE_URL_PREFIX)) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); tokens.putAll(trustedEnvVars); - return builder + return enclaveBase .environment(tokens) .build(); } @@ -175,10 +175,10 @@ public EnclaveEnvironment getPreComputeTokens(TeeSecretsSessionRequest request) /* * Compute (App) */ - public EnclaveEnvironment getAppTokens(TeeSecretsSessionRequest request) + public SecretEnclaveBase getAppTokens(TeeSessionRequest request) throws TeeSessionGenerationException { - EnclaveEnvironmentBuilder builder = EnclaveEnvironment.builder(); - builder.name("app"); + SecretEnclaveBaseBuilder enclaveBase = SecretEnclaveBase.builder(); + enclaveBase.name("app"); TaskDescription taskDescription = request.getTaskDescription(); if (taskDescription == null) { throw new TeeSessionGenerationException( @@ -200,7 +200,7 @@ public EnclaveEnvironment getAppTokens(TeeSecretsSessionRequest request) enclaveConfig.getValidator().validate().toString()); } - builder.mrenclave(enclaveConfig.getFingerprint()); + enclaveBase.mrenclave(enclaveConfig.getFingerprint()); // extract // this map will be empty (not null) if no input file is found Map inputFileNames = IexecEnvUtils.getComputeStageEnvMap(taskDescription) @@ -214,7 +214,7 @@ public EnclaveEnvironment getAppTokens(TeeSecretsSessionRequest request) tokens.putAll(computeSecrets); // trusted env variables (not confidential) tokens.putAll(IexecEnvUtils.getComputeStageEnvMap(taskDescription)); - return builder + return enclaveBase .environment(tokens) .build(); } @@ -271,10 +271,10 @@ private Map getApplicationComputeSecrets(TaskDescription taskDes /* * Post-Compute (Result) */ - public EnclaveEnvironment getPostComputeTokens(TeeSecretsSessionRequest request) + public SecretEnclaveBase getPostComputeTokens(TeeSessionRequest request) throws TeeSessionGenerationException { - EnclaveEnvironmentBuilder builder = EnclaveEnvironment.builder(); - builder.name("post-compute"); + SecretEnclaveBaseBuilder enclaveBase = SecretEnclaveBase.builder(); + enclaveBase.name("post-compute"); Map tokens = new HashMap<>(); TaskDescription taskDescription = request.getTaskDescription(); if (taskDescription == null) { @@ -301,12 +301,12 @@ public EnclaveEnvironment getPostComputeTokens(TeeSecretsSessionRequest request) // enclave signature Map signTokens = getPostComputeSignTokens(request); tokens.putAll(signTokens); - return builder + return enclaveBase .environment(tokens) .build(); } - public Map getPostComputeEncryptionTokens(TeeSecretsSessionRequest request) + public Map getPostComputeEncryptionTokens(TeeSessionRequest request) throws TeeSessionGenerationException { TaskDescription taskDescription = request.getTaskDescription(); String taskId = taskDescription.getChainTaskId(); @@ -336,7 +336,7 @@ public Map getPostComputeEncryptionTokens(TeeSecretsSessionReque // to the beneficiary private storage space waiting for // that feature we only allow to push to the requester // private storage space - public Map getPostComputeStorageTokens(TeeSecretsSessionRequest request) + public Map getPostComputeStorageTokens(TeeSessionRequest request) throws TeeSessionGenerationException { TaskDescription taskDescription = request.getTaskDescription(); String taskId = taskDescription.getChainTaskId(); @@ -370,7 +370,7 @@ public Map getPostComputeStorageTokens(TeeSecretsSessionRequest return tokens; } - public Map getPostComputeSignTokens(TeeSecretsSessionRequest request) + public Map getPostComputeSignTokens(TeeSessionRequest request) throws TeeSessionGenerationException { String taskId = request.getTaskDescription().getChainTaskId(); String workerAddress = request.getWorkerAddress(); diff --git a/src/main/java/com/iexec/sms/tee/session/generic/TeeSessionHandler.java b/src/main/java/com/iexec/sms/tee/session/generic/TeeSessionHandler.java index 5958ea0a..f69d83bb 100644 --- a/src/main/java/com/iexec/sms/tee/session/generic/TeeSessionHandler.java +++ b/src/main/java/com/iexec/sms/tee/session/generic/TeeSessionHandler.java @@ -25,6 +25,6 @@ public interface TeeSessionHandler { * @return String secret provisioning service url * @throws TeeSessionGenerationException */ - String buildAndPostSession(TeeSecretsSessionRequest request) throws TeeSessionGenerationException; + String buildAndPostSession(TeeSessionRequest request) throws TeeSessionGenerationException; } diff --git a/src/main/java/com/iexec/sms/tee/session/generic/TeeSecretsSessionRequest.java b/src/main/java/com/iexec/sms/tee/session/generic/TeeSessionRequest.java similarity index 96% rename from src/main/java/com/iexec/sms/tee/session/generic/TeeSecretsSessionRequest.java rename to src/main/java/com/iexec/sms/tee/session/generic/TeeSessionRequest.java index 85be0e99..117d62ef 100644 --- a/src/main/java/com/iexec/sms/tee/session/generic/TeeSecretsSessionRequest.java +++ b/src/main/java/com/iexec/sms/tee/session/generic/TeeSessionRequest.java @@ -26,7 +26,7 @@ @Builder @NoArgsConstructor @AllArgsConstructor -public class TeeSecretsSessionRequest { +public class TeeSessionRequest { private String sessionId; private TaskDescription taskDescription; diff --git a/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerService.java b/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerService.java index 7968d98c..98336779 100644 --- a/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerService.java +++ b/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerService.java @@ -18,9 +18,9 @@ import com.iexec.sms.api.TeeSessionGenerationError; import com.iexec.sms.tee.session.TeeSessionLogConfiguration; -import com.iexec.sms.tee.session.generic.TeeSecretsSessionRequest; import com.iexec.sms.tee.session.generic.TeeSessionGenerationException; import com.iexec.sms.tee.session.generic.TeeSessionHandler; +import com.iexec.sms.tee.session.generic.TeeSessionRequest; import com.iexec.sms.tee.session.gramine.sps.SpsConfiguration; import com.iexec.sms.tee.session.gramine.sps.SpsSession; import lombok.extern.slf4j.Slf4j; @@ -49,7 +49,7 @@ public GramineSessionHandlerService(GramineSessionMakerService sessionService, * @throws TeeSessionGenerationException */ @Override - public String buildAndPostSession(TeeSecretsSessionRequest request) + public String buildAndPostSession(TeeSessionRequest request) throws TeeSessionGenerationException { SpsSession session = sessionService.generateSession(request); if (session != null diff --git a/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerService.java b/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerService.java index f3ed4e6e..552befdc 100644 --- a/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerService.java +++ b/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerService.java @@ -16,15 +16,15 @@ package com.iexec.sms.tee.session.gramine; -import com.iexec.sms.tee.session.EnclaveEnvironment; -import com.iexec.sms.tee.session.EnclaveEnvironments; -import com.iexec.sms.tee.session.TeeSecretsService; -import com.iexec.sms.tee.session.generic.TeeSecretsSessionRequest; +import com.iexec.sms.tee.session.base.SecretEnclaveBase; +import com.iexec.sms.tee.session.base.SecretSessionBase; +import com.iexec.sms.tee.session.base.SecretSessionBaseService; import com.iexec.sms.tee.session.generic.TeeSessionGenerationException; +import com.iexec.sms.tee.session.generic.TeeSessionRequest; +import com.iexec.sms.tee.session.gramine.sps.SpsEnclave; +import com.iexec.sms.tee.session.gramine.sps.SpsEnclave.SpsEnclaveBuilder; import com.iexec.sms.tee.session.gramine.sps.SpsSession; import com.iexec.sms.tee.session.gramine.sps.SpsSession.SpsSessionBuilder; -import com.iexec.sms.tee.session.gramine.sps.SpsSessionEnclave; -import com.iexec.sms.tee.session.gramine.sps.SpsSessionEnclave.SpsSessionEnclaveBuilder; import com.iexec.sms.tee.workflow.TeeWorkflowConfiguration; import org.springframework.stereotype.Service; @@ -34,12 +34,12 @@ @Service public class GramineSessionMakerService { - private final TeeSecretsService teeSecretsService; + private final SecretSessionBaseService secretSessionBaseService; private TeeWorkflowConfiguration teeWorkflowConfiguration; - public GramineSessionMakerService(TeeSecretsService teeSecretsService, + public GramineSessionMakerService(SecretSessionBaseService secretSessionBaseService, TeeWorkflowConfiguration teeWorkflowConfiguration) { - this.teeSecretsService = teeSecretsService; + this.secretSessionBaseService = secretSessionBaseService; this.teeWorkflowConfiguration = teeWorkflowConfiguration; } @@ -50,33 +50,33 @@ public GramineSessionMakerService(TeeSecretsService teeSecretsService, * @param request session request details * @return session config */ - public SpsSession generateSession(TeeSecretsSessionRequest request) throws TeeSessionGenerationException { - EnclaveEnvironments enclaveEnvironments = teeSecretsService.getSecretsTokens(request); - SpsSessionBuilder sessionBuilder = SpsSession.builder(); - sessionBuilder.session(request.getSessionId()); - SpsSessionEnclave appSessionEnclave = toSpsSessionEnclave(enclaveEnvironments.getAppCompute()); - appSessionEnclave.setCommand(request.getTaskDescription().getAppCommand()); - SpsSessionEnclave postSessionEnclave = toSpsSessionEnclave(enclaveEnvironments.getPostCompute()); - postSessionEnclave.setMrenclave(teeWorkflowConfiguration.getPostComputeFingerprint()); - postSessionEnclave.setCommand(teeWorkflowConfiguration.getPostComputeEntrypoint()); + public SpsSession generateSession(TeeSessionRequest request) throws TeeSessionGenerationException { + SecretSessionBase baseSession = secretSessionBaseService.getSecretsTokens(request); + SpsSessionBuilder spsSession = SpsSession.builder(); + spsSession.session(request.getSessionId()); + SpsEnclave spsAppEnclave = toSpsSessionEnclave(baseSession.getAppCompute()); + spsAppEnclave.setCommand(request.getTaskDescription().getAppCommand()); + SpsEnclave spsPostEnclave = toSpsSessionEnclave(baseSession.getPostCompute()); + spsPostEnclave.setMrenclave(teeWorkflowConfiguration.getPostComputeFingerprint()); + spsPostEnclave.setCommand(teeWorkflowConfiguration.getPostComputeEntrypoint()); - //TODO: Remove useless volumes when SPS is ready - appSessionEnclave.setVolumes(List.of()); - postSessionEnclave.setVolumes(List.of()); + // TODO: Remove useless volumes when SPS is ready + spsAppEnclave.setVolumes(List.of()); + spsPostEnclave.setVolumes(List.of()); - sessionBuilder.enclaves(Arrays.asList( + spsSession.enclaves(Arrays.asList( // No pre-compute for now - appSessionEnclave, - postSessionEnclave)); - return sessionBuilder.build(); + spsAppEnclave, + spsPostEnclave)); + return spsSession.build(); } - private SpsSessionEnclave toSpsSessionEnclave(EnclaveEnvironment enclaveEnvironment) { - SpsSessionEnclaveBuilder enclavebuilder = SpsSessionEnclave.builder(); - enclavebuilder.name(enclaveEnvironment.getName()); - enclavebuilder.mrenclave(enclaveEnvironment.getMrenclave()); - enclavebuilder.environment(enclaveEnvironment.getEnvironment()); - return enclavebuilder.build(); + private SpsEnclave toSpsSessionEnclave(SecretEnclaveBase enclaveBase) { + SpsEnclaveBuilder spsEnclave = SpsEnclave.builder(); + spsEnclave.name(enclaveBase.getName()); + spsEnclave.mrenclave(enclaveBase.getMrenclave()); + spsEnclave.environment(enclaveBase.getEnvironment()); + return spsEnclave.build(); } } diff --git a/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsSessionEnclave.java b/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsEnclave.java similarity index 97% rename from src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsSessionEnclave.java rename to src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsEnclave.java index 588e4470..33ff4915 100644 --- a/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsSessionEnclave.java +++ b/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsEnclave.java @@ -27,7 +27,7 @@ @Setter @AllArgsConstructor @NoArgsConstructor -public class SpsSessionEnclave { +public class SpsEnclave { @JsonProperty("name") private String name; diff --git a/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsSession.java b/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsSession.java index 7a718f7a..d2ea9d40 100644 --- a/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsSession.java +++ b/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsSession.java @@ -35,7 +35,7 @@ public class SpsSession { @JsonProperty("session") private String session; @JsonProperty("enclaves") - private List enclaves; + private List enclaves; @Override public String toString() { diff --git a/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerService.java b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerService.java index 9855d3ba..338e5177 100644 --- a/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerService.java +++ b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerService.java @@ -18,9 +18,9 @@ import com.iexec.sms.api.TeeSessionGenerationError; import com.iexec.sms.tee.session.TeeSessionLogConfiguration; -import com.iexec.sms.tee.session.generic.TeeSecretsSessionRequest; import com.iexec.sms.tee.session.generic.TeeSessionGenerationException; import com.iexec.sms.tee.session.generic.TeeSessionHandler; +import com.iexec.sms.tee.session.generic.TeeSessionRequest; import com.iexec.sms.tee.session.scone.cas.CasClient; import com.iexec.sms.tee.session.scone.cas.CasConfiguration; import com.iexec.sms.tee.session.scone.cas.CasSession; @@ -54,7 +54,7 @@ public SconeSessionHandlerService(SconeSessionMakerService sessionService, * @throws TeeSessionGenerationException */ @Override - public String buildAndPostSession(TeeSecretsSessionRequest request) + public String buildAndPostSession(TeeSessionRequest request) throws TeeSessionGenerationException { CasSession session = sessionService.generateSession(request); if (session != null diff --git a/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionMakerService.java b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionMakerService.java index 07a0175d..83fb93a9 100644 --- a/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionMakerService.java +++ b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionMakerService.java @@ -16,17 +16,17 @@ package com.iexec.sms.tee.session.scone; -import com.iexec.sms.tee.session.EnclaveEnvironment; -import com.iexec.sms.tee.session.EnclaveEnvironments; -import com.iexec.sms.tee.session.TeeSecretsService; -import com.iexec.sms.tee.session.generic.TeeSecretsSessionRequest; +import com.iexec.sms.tee.session.base.SecretEnclaveBase; +import com.iexec.sms.tee.session.base.SecretSessionBase; +import com.iexec.sms.tee.session.base.SecretSessionBaseService; import com.iexec.sms.tee.session.generic.TeeSessionGenerationException; +import com.iexec.sms.tee.session.generic.TeeSessionRequest; +import com.iexec.sms.tee.session.scone.cas.CasEnclave; import com.iexec.sms.tee.session.scone.cas.CasSession; import com.iexec.sms.tee.session.scone.cas.CasSession.AccessPolicy; import com.iexec.sms.tee.session.scone.cas.CasSession.Image.Volume; import com.iexec.sms.tee.session.scone.cas.CasSession.Security; import com.iexec.sms.tee.session.scone.cas.CasSession.Volumes; -import com.iexec.sms.tee.session.scone.cas.CasSessionEnclave; import com.iexec.sms.tee.workflow.TeeWorkflowConfiguration; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -52,15 +52,15 @@ public class SconeSessionMakerService { // PostCompute static final String POST_COMPUTE_ENTRYPOINT = "POST_COMPUTE_ENTRYPOINT"; - private final TeeSecretsService teeSecretsService; + private final SecretSessionBaseService secretSessionBaseService; private final TeeWorkflowConfiguration teeWorkflowConfig; private final SconeSessionSecurityConfig attestationSecurityConfig; public SconeSessionMakerService( - TeeSecretsService teeSecretsService, + SecretSessionBaseService secretSessionBaseService, TeeWorkflowConfiguration teeWorkflowConfig, SconeSessionSecurityConfig attestationSecurityConfig) { - this.teeSecretsService = teeSecretsService; + this.secretSessionBaseService = secretSessionBaseService; this.teeWorkflowConfig = teeWorkflowConfig; this.attestationSecurityConfig = attestationSecurityConfig; } @@ -76,18 +76,18 @@ public SconeSessionMakerService( * @param request session request details * @return session config in yaml string format */ - public CasSession generateSession(TeeSecretsSessionRequest request) throws TeeSessionGenerationException { - EnclaveEnvironments enclaveEnvironments = teeSecretsService.getSecretsTokens(request); + public CasSession generateSession(TeeSessionRequest request) throws TeeSessionGenerationException { + SecretSessionBase baseSession = secretSessionBaseService.getSecretsTokens(request); - CasSessionEnclave preEnclave = toCasSessionEnclave(enclaveEnvironments.getPreCompute()); - preEnclave.setCommand(teeWorkflowConfig.getPreComputeEntrypoint()); - CasSessionEnclave appEnclave = toCasSessionEnclave(enclaveEnvironments.getAppCompute()); - appEnclave.setCommand(request.getTaskDescription().getAppCommand()); - CasSessionEnclave postEnclave = toCasSessionEnclave(enclaveEnvironments.getPostCompute()); - postEnclave.setCommand(teeWorkflowConfig.getPostComputeEntrypoint()); + CasEnclave casPreEnclave = toCasSessionEnclave(baseSession.getPreCompute()); + casPreEnclave.setCommand(teeWorkflowConfig.getPreComputeEntrypoint()); + CasEnclave casAppEnclave = toCasSessionEnclave(baseSession.getAppCompute()); + casAppEnclave.setCommand(request.getTaskDescription().getAppCommand()); + CasEnclave casPostEnclave = toCasSessionEnclave(baseSession.getPostCompute()); + casPostEnclave.setCommand(teeWorkflowConfig.getPostComputeEntrypoint()); - addJavaEnvVars(preEnclave); - addJavaEnvVars(postEnclave); + addJavaEnvVars(casPreEnclave); + addJavaEnvVars(casPostEnclave); List policy = Arrays.asList("CREATOR"); @@ -95,7 +95,7 @@ public CasSession generateSession(TeeSecretsSessionRequest request) throws TeeSe .name(request.getSessionId()) .version("0.3") .accessPolicy(new AccessPolicy(policy, policy)) - .services(Arrays.asList(preEnclave, appEnclave, postEnclave)) + .services(Arrays.asList(casPreEnclave, casAppEnclave, casPostEnclave)) .security(new Security(attestationSecurityConfig.getToleratedInsecureOptions(), attestationSecurityConfig.getIgnoredSgxAdvisories())) .build(); @@ -110,16 +110,16 @@ public CasSession generateSession(TeeSecretsSessionRequest request) throws TeeSe new Volumes(postComputeTmpVolume.getName()))); casSession.setImages(Arrays.asList( - new CasSession.Image(preEnclave.getImageName(), Arrays.asList(iexecInVolume)), - new CasSession.Image(appEnclave.getImageName(), Arrays.asList(iexecInVolume, iexecOutVolume)), - new CasSession.Image(postEnclave.getImageName(), Arrays.asList(iexecOutVolume, postComputeTmpVolume)) + new CasSession.Image(casPreEnclave.getImageName(), Arrays.asList(iexecInVolume)), + new CasSession.Image(casAppEnclave.getImageName(), Arrays.asList(iexecInVolume, iexecOutVolume)), + new CasSession.Image(casPostEnclave.getImageName(), Arrays.asList(iexecOutVolume, postComputeTmpVolume)) )); return casSession; } - private void addJavaEnvVars(CasSessionEnclave casSessionEnclave) { + private void addJavaEnvVars(CasEnclave casSessionEnclave) { Map additionalJavaEnv = Map.of("LD_LIBRARY_PATH", "/usr/lib/jvm/java-11-openjdk/lib/server:/usr/lib/jvm/java-11-openjdk/lib:/usr/lib/jvm/java-11-openjdk/../lib", "JAVA_TOOL_OPTIONS", "-Xmx256m"); @@ -129,14 +129,14 @@ private void addJavaEnvVars(CasSessionEnclave casSessionEnclave) { casSessionEnclave.setEnvironment(newEnvironment); } - private CasSessionEnclave toCasSessionEnclave(EnclaveEnvironment enclaveEnvironment) { - return CasSessionEnclave.builder() - .name(enclaveEnvironment.getName()) - .imageName(enclaveEnvironment.getName() + "-image") - .mrenclaves(Arrays.asList(enclaveEnvironment.getMrenclave())) + private CasEnclave toCasSessionEnclave(SecretEnclaveBase enclaveBase) { + return CasEnclave.builder() + .name(enclaveBase.getName()) + .imageName(enclaveBase.getName() + "-image") + .mrenclaves(Arrays.asList(enclaveBase.getMrenclave())) .pwd("/") // TODO .command(command) - .environment(enclaveEnvironment.getEnvironment()) + .environment(enclaveBase.getEnvironment()) .build(); } diff --git a/src/main/java/com/iexec/sms/tee/session/scone/cas/CasSessionEnclave.java b/src/main/java/com/iexec/sms/tee/session/scone/cas/CasEnclave.java similarity index 97% rename from src/main/java/com/iexec/sms/tee/session/scone/cas/CasSessionEnclave.java rename to src/main/java/com/iexec/sms/tee/session/scone/cas/CasEnclave.java index 3dcf5e47..5fd09d23 100644 --- a/src/main/java/com/iexec/sms/tee/session/scone/cas/CasSessionEnclave.java +++ b/src/main/java/com/iexec/sms/tee/session/scone/cas/CasEnclave.java @@ -31,7 +31,7 @@ @Setter @AllArgsConstructor @NoArgsConstructor -public class CasSessionEnclave { +public class CasEnclave { @JsonProperty("name") private String name; diff --git a/src/main/java/com/iexec/sms/tee/session/scone/cas/CasSession.java b/src/main/java/com/iexec/sms/tee/session/scone/cas/CasSession.java index 6cd56709..d93def5f 100644 --- a/src/main/java/com/iexec/sms/tee/session/scone/cas/CasSession.java +++ b/src/main/java/com/iexec/sms/tee/session/scone/cas/CasSession.java @@ -39,7 +39,7 @@ public class CasSession { @JsonProperty("access_policy") private AccessPolicy accessPolicy; @JsonProperty("services") - private List services; + private List services; @JsonProperty("images") private List images; @JsonProperty("volumes") diff --git a/src/test/java/com/iexec/sms/tee/session/TeeSessionTestUtils.java b/src/test/java/com/iexec/sms/tee/session/TeeSessionTestUtils.java index 5f7fe2b3..d17bde7c 100644 --- a/src/test/java/com/iexec/sms/tee/session/TeeSessionTestUtils.java +++ b/src/test/java/com/iexec/sms/tee/session/TeeSessionTestUtils.java @@ -23,7 +23,8 @@ import com.iexec.sms.secret.compute.OnChainObjectType; import com.iexec.sms.secret.compute.SecretOwnerRole; import com.iexec.sms.secret.compute.TeeTaskComputeSecret; -import com.iexec.sms.tee.session.generic.TeeSecretsSessionRequest; +import com.iexec.sms.tee.session.base.SecretSessionBaseService; +import com.iexec.sms.tee.session.generic.TeeSessionRequest; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.ClassUtils; @@ -33,7 +34,7 @@ import static com.iexec.common.worker.result.ResultUtils.*; import static com.iexec.sms.Web3jUtils.createEthereumAddress; -import static com.iexec.sms.tee.session.TeeSecretsService.*; +import static com.iexec.sms.tee.session.base.SecretSessionBaseService.*; import static org.assertj.core.api.Assertions.assertThat; @Slf4j @@ -99,8 +100,8 @@ public static TeeTaskComputeSecret getRequesterSecret(String requesterAddress, S .build(); } - public static TeeSecretsSessionRequest createSessionRequest(TaskDescription taskDescription) { - return TeeSecretsSessionRequest.builder() + public static TeeSessionRequest createSessionRequest(TaskDescription taskDescription) { + return TeeSessionRequest.builder() .sessionId(SESSION_ID) .workerAddress(WORKER_ADDRESS) .enclaveChallenge(ENCLAVE_CHALLENGE) @@ -146,7 +147,7 @@ public static Map getPreComputeTokens() { public static Map getAppTokens() { return Map.of( APP_MRENCLAVE, APP_FINGERPRINT, - TeeSecretsService.INPUT_FILE_NAMES, Map.of( + SecretSessionBaseService.INPUT_FILE_NAMES, Map.of( IexecEnvUtils.IEXEC_INPUT_FILE_NAME_PREFIX + "1", INPUT_FILE_NAME_1, IexecEnvUtils.IEXEC_INPUT_FILE_NAME_PREFIX + "2", INPUT_FILE_NAME_2)); } diff --git a/src/test/java/com/iexec/sms/tee/session/TeeSecretsServiceTests.java b/src/test/java/com/iexec/sms/tee/session/base/SecretSessionServiceTests.java similarity index 99% rename from src/test/java/com/iexec/sms/tee/session/TeeSecretsServiceTests.java rename to src/test/java/com/iexec/sms/tee/session/base/SecretSessionServiceTests.java index b82d328d..78a547ad 100644 --- a/src/test/java/com/iexec/sms/tee/session/TeeSecretsServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/base/SecretSessionServiceTests.java @@ -1,4 +1,4 @@ -package com.iexec.sms.tee.session; +package com.iexec.sms.tee.session.base; import com.iexec.common.tee.TeeEnclaveConfiguration; import com.iexec.sms.secret.compute.TeeTaskComputeSecretService; @@ -16,7 +16,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -class TeeSecretsServiceTests { +class SecretSessionServiceTests { private static final String APP_FINGERPRINT = "01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b"; private static final TeeEnclaveConfiguration enclaveConfig = @@ -34,7 +34,7 @@ class TeeSecretsServiceTests { @Spy @InjectMocks - private TeeSecretsService teeSecretsService; + private SecretSessionBaseService teeSecretsService; @BeforeEach void beforeEach() { diff --git a/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerServiceTests.java b/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerServiceTests.java index 00055a8e..23101fe8 100644 --- a/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerServiceTests.java @@ -19,8 +19,8 @@ import com.iexec.common.task.TaskDescription; import com.iexec.sms.api.TeeSessionGenerationError; import com.iexec.sms.tee.session.TeeSessionLogConfiguration; -import com.iexec.sms.tee.session.generic.TeeSecretsSessionRequest; import com.iexec.sms.tee.session.generic.TeeSessionGenerationException; +import com.iexec.sms.tee.session.generic.TeeSessionRequest; import com.iexec.sms.tee.session.gramine.sps.SpsApiClient; import com.iexec.sms.tee.session.gramine.sps.SpsConfiguration; import com.iexec.sms.tee.session.gramine.sps.SpsSession; @@ -61,7 +61,7 @@ void beforeEach() { @Test void shouldBuildAndPostSession(CapturedOutput output) throws TeeSessionGenerationException { - TeeSecretsSessionRequest request = mock(TeeSecretsSessionRequest.class); + TeeSessionRequest request = mock(TeeSessionRequest.class); TaskDescription taskDescription = mock(TaskDescription.class); when(request.getTaskDescription()).thenReturn(taskDescription); SpsSession spsSession = mock(SpsSession.class); @@ -81,7 +81,7 @@ void shouldBuildAndPostSession(CapturedOutput output) throws TeeSessionGeneratio @Test void shouldNotBuildAndPostSessionSinceBuildSessionFailed() throws TeeSessionGenerationException { - TeeSecretsSessionRequest request = mock(TeeSecretsSessionRequest.class); + TeeSessionRequest request = mock(TeeSessionRequest.class); TeeSessionGenerationException teeSessionGenerationException = new TeeSessionGenerationException( TeeSessionGenerationError.SECURE_SESSION_GENERATION_FAILED, "some error"); when(sessionService.generateSession(request)).thenThrow(teeSessionGenerationException); @@ -93,7 +93,7 @@ void shouldNotBuildAndPostSessionSinceBuildSessionFailed() @Test void shouldNotBuildAndPostSessionSincePostSessionFailed() throws TeeSessionGenerationException { - TeeSecretsSessionRequest request = mock(TeeSecretsSessionRequest.class); + TeeSessionRequest request = mock(TeeSessionRequest.class); TaskDescription taskDescription = mock(TaskDescription.class); when(request.getTaskDescription()).thenReturn(taskDescription); SpsSession spsSession = mock(SpsSession.class); diff --git a/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerServiceTests.java b/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerServiceTests.java index 7c9b29fc..b4df5968 100644 --- a/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerServiceTests.java @@ -2,10 +2,10 @@ import com.iexec.common.tee.TeeEnclaveConfiguration; import com.iexec.common.utils.FileHelper; -import com.iexec.sms.tee.session.EnclaveEnvironment; -import com.iexec.sms.tee.session.EnclaveEnvironments; -import com.iexec.sms.tee.session.TeeSecretsService; -import com.iexec.sms.tee.session.generic.TeeSecretsSessionRequest; +import com.iexec.sms.tee.session.base.SecretEnclaveBase; +import com.iexec.sms.tee.session.base.SecretSessionBase; +import com.iexec.sms.tee.session.base.SecretSessionBaseService; +import com.iexec.sms.tee.session.generic.TeeSessionRequest; import com.iexec.sms.tee.session.gramine.sps.SpsSession; import com.iexec.sms.tee.workflow.TeeWorkflowConfiguration; import lombok.extern.slf4j.Slf4j; @@ -27,7 +27,7 @@ class GramineSessionMakerServiceTests { @Mock private TeeWorkflowConfiguration teeWorkflowConfig; @Mock - private TeeSecretsService teeSecretsService; + private SecretSessionBaseService teeSecretsService; @InjectMocks private GramineSessionMakerService gramineSessionService; @@ -40,14 +40,14 @@ void beforeEach() { @Test void shouldGetSessionJson() throws Exception { TeeEnclaveConfiguration enclaveConfig = mock(TeeEnclaveConfiguration.class); - TeeSecretsSessionRequest request = createSessionRequest(createTaskDescription(enclaveConfig)); + TeeSessionRequest request = createSessionRequest(createTaskDescription(enclaveConfig)); when(teeWorkflowConfig.getPostComputeFingerprint()).thenReturn(POST_COMPUTE_FINGERPRINT); when(teeWorkflowConfig.getPostComputeEntrypoint()).thenReturn(POST_COMPUTE_ENTRYPOINT); when(enclaveConfig.getFingerprint()).thenReturn(APP_FINGERPRINT); when(enclaveConfig.getEntrypoint()).thenReturn("/apploader.sh"); - EnclaveEnvironment appCompute = EnclaveEnvironment.builder() + SecretEnclaveBase appCompute = SecretEnclaveBase.builder() .name("app") .mrenclave(APP_FINGERPRINT) .environment(Map.ofEntries( @@ -64,7 +64,7 @@ void shouldGetSessionJson() throws Exception { Map.entry("IEXEC_INPUT_FILE_NAME_1", "file1"), Map.entry("IEXEC_INPUT_FILE_NAME_2", "file2"))) .build(); - EnclaveEnvironment postCompute = EnclaveEnvironment.builder() + SecretEnclaveBase postCompute = SecretEnclaveBase.builder() .name("post-compute") .mrenclave("mrEnclave3") .environment(Map.ofEntries( @@ -80,7 +80,7 @@ void shouldGetSessionJson() throws Exception { .build(); when(teeSecretsService.getSecretsTokens(request)) - .thenReturn(EnclaveEnvironments.builder() + .thenReturn(SecretSessionBase.builder() .appCompute(appCompute) .postCompute(postCompute) .build()); diff --git a/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerServiceTests.java b/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerServiceTests.java index 37ca2fd6..6d3d93de 100644 --- a/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerServiceTests.java @@ -3,8 +3,8 @@ import com.iexec.common.task.TaskDescription; import com.iexec.sms.api.TeeSessionGenerationError; import com.iexec.sms.tee.session.TeeSessionLogConfiguration; -import com.iexec.sms.tee.session.generic.TeeSecretsSessionRequest; import com.iexec.sms.tee.session.generic.TeeSessionGenerationException; +import com.iexec.sms.tee.session.generic.TeeSessionRequest; import com.iexec.sms.tee.session.scone.cas.CasClient; import com.iexec.sms.tee.session.scone.cas.CasConfiguration; import com.iexec.sms.tee.session.scone.cas.CasSession; @@ -47,7 +47,7 @@ void beforeEach() { @Test void shouldBuildAndPostSession(CapturedOutput output) throws TeeSessionGenerationException { - TeeSecretsSessionRequest request = mock(TeeSecretsSessionRequest.class); + TeeSessionRequest request = mock(TeeSessionRequest.class); TaskDescription taskDescription = mock(TaskDescription.class); when(request.getTaskDescription()).thenReturn(taskDescription); CasSession casSession = mock(CasSession.class); @@ -65,7 +65,7 @@ void shouldBuildAndPostSession(CapturedOutput output) throws TeeSessionGeneratio @Test void shouldNotBuildAndPostSessionSinceBuildSessionFailed() throws TeeSessionGenerationException { - TeeSecretsSessionRequest request = mock(TeeSecretsSessionRequest.class); + TeeSessionRequest request = mock(TeeSessionRequest.class); TeeSessionGenerationException teeSessionGenerationException = new TeeSessionGenerationException( TeeSessionGenerationError.SECURE_SESSION_GENERATION_FAILED, "some error"); when(sessionService.generateSession(request)).thenThrow(teeSessionGenerationException); @@ -77,7 +77,7 @@ void shouldNotBuildAndPostSessionSinceBuildSessionFailed() @Test void shouldNotBuildAndPostSessionSincePostSessionFailed() throws TeeSessionGenerationException { - TeeSecretsSessionRequest request = mock(TeeSecretsSessionRequest.class); + TeeSessionRequest request = mock(TeeSessionRequest.class); TaskDescription taskDescription = mock(TaskDescription.class); when(request.getTaskDescription()).thenReturn(taskDescription); CasSession casSession = mock(CasSession.class); diff --git a/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionMakerServiceTests.java b/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionMakerServiceTests.java index 98219486..cc126d92 100644 --- a/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionMakerServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionMakerServiceTests.java @@ -18,10 +18,10 @@ import com.iexec.common.tee.TeeEnclaveConfiguration; import com.iexec.common.utils.FileHelper; -import com.iexec.sms.tee.session.EnclaveEnvironment; -import com.iexec.sms.tee.session.EnclaveEnvironments; -import com.iexec.sms.tee.session.TeeSecretsService; -import com.iexec.sms.tee.session.generic.TeeSecretsSessionRequest; +import com.iexec.sms.tee.session.base.SecretEnclaveBase; +import com.iexec.sms.tee.session.base.SecretSessionBase; +import com.iexec.sms.tee.session.base.SecretSessionBaseService; +import com.iexec.sms.tee.session.generic.TeeSessionRequest; import com.iexec.sms.tee.session.scone.cas.CasSession; import com.iexec.sms.tee.workflow.TeeWorkflowConfiguration; import lombok.extern.slf4j.Slf4j; @@ -50,7 +50,7 @@ class SconeSessionMakerServiceTests { @Mock private TeeWorkflowConfiguration teeWorkflowConfig; @Mock - private TeeSecretsService teeSecretsService; + private SecretSessionBaseService teeSecretsService; @Mock private SconeSessionSecurityConfig attestationSecurityConfig; @@ -66,14 +66,14 @@ void beforeEach() { @Test void shouldGetSessionYml() throws Exception { TeeEnclaveConfiguration enclaveConfig = mock(TeeEnclaveConfiguration.class); - TeeSecretsSessionRequest request = createSessionRequest(createTaskDescription(enclaveConfig)); + TeeSessionRequest request = createSessionRequest(createTaskDescription(enclaveConfig)); when(teeWorkflowConfig.getPreComputeEntrypoint()).thenReturn(PRE_COMPUTE_ENTRYPOINT); when(teeWorkflowConfig.getPostComputeEntrypoint()).thenReturn(POST_COMPUTE_ENTRYPOINT); when(enclaveConfig.getFingerprint()).thenReturn(APP_FINGERPRINT); when(enclaveConfig.getEntrypoint()).thenReturn(APP_ENTRYPOINT); - EnclaveEnvironment preCompute = EnclaveEnvironment.builder() + SecretEnclaveBase preCompute = SecretEnclaveBase.builder() .name("pre-compute") .mrenclave("mrEnclave1") .environment(Map.ofEntries( // Map of until 10 @@ -91,7 +91,7 @@ void shouldGetSessionYml() throws Exception { Map.entry("IEXEC_INPUT_FILE_URL_1", "http://host/file1"), Map.entry("IEXEC_INPUT_FILE_URL_2", "http://host/file2"))) .build(); - EnclaveEnvironment appCompute = EnclaveEnvironment.builder() + SecretEnclaveBase appCompute = SecretEnclaveBase.builder() .name("app") .mrenclave(APP_FINGERPRINT) .environment(Map.ofEntries( @@ -108,7 +108,7 @@ void shouldGetSessionYml() throws Exception { Map.entry("IEXEC_INPUT_FILE_NAME_1", "file1"), Map.entry("IEXEC_INPUT_FILE_NAME_2", "file2"))) .build(); - EnclaveEnvironment postCompute = EnclaveEnvironment.builder() + SecretEnclaveBase postCompute = SecretEnclaveBase.builder() .name("post-compute") .mrenclave("mrEnclave3") .environment(Map.ofEntries( @@ -124,7 +124,7 @@ void shouldGetSessionYml() throws Exception { .build(); when(teeSecretsService.getSecretsTokens(request)) - .thenReturn(EnclaveEnvironments.builder() + .thenReturn(SecretSessionBase.builder() .preCompute(preCompute) .appCompute(appCompute) .postCompute(postCompute) @@ -136,7 +136,7 @@ void shouldGetSessionYml() throws Exception { .thenReturn(List.of("INTEL-SA-00161", "INTEL-SA-00289")); when(teeSecretsService.getSecretsTokens(request)) - .thenReturn(EnclaveEnvironments.builder() + .thenReturn(SecretSessionBase.builder() .preCompute(preCompute) .appCompute(appCompute) .postCompute(postCompute) From 51533aaef161acf9d6d1a81d6cc3d33e17aabe20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20James=20Toussaint?= Date: Fri, 29 Jul 2022 16:17:19 +0200 Subject: [PATCH 021/293] Update tests for SecretSessionBaseService --- .../base/SecretSessionBaseService.java | 32 +- .../base/SecretSessionBaseServiceTests.java | 698 ++++++++++++++++++ .../base/SecretSessionServiceTests.java | 692 ----------------- 3 files changed, 715 insertions(+), 707 deletions(-) create mode 100644 src/test/java/com/iexec/sms/tee/session/base/SecretSessionBaseServiceTests.java delete mode 100644 src/test/java/com/iexec/sms/tee/session/base/SecretSessionServiceTests.java diff --git a/src/main/java/com/iexec/sms/tee/session/base/SecretSessionBaseService.java b/src/main/java/com/iexec/sms/tee/session/base/SecretSessionBaseService.java index 7fd31139..66941d93 100644 --- a/src/main/java/com/iexec/sms/tee/session/base/SecretSessionBaseService.java +++ b/src/main/java/com/iexec/sms/tee/session/base/SecretSessionBaseService.java @@ -40,10 +40,7 @@ import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; +import java.util.*; import java.util.stream.Collectors; import static com.iexec.common.chain.DealParams.DROPBOX_RESULT_STORAGE_PROVIDER; @@ -139,6 +136,8 @@ public SecretEnclaveBase getPreComputeTokens(TeeSessionRequest request) tokens.put(IEXEC_PRE_COMPUTE_OUT, IexecFileHelper.SLASH_IEXEC_IN); // `IS_DATASET_REQUIRED` still meaningful? tokens.put(IS_DATASET_REQUIRED, taskDescription.containsDataset()); + + List trustedEnv = new ArrayList<>(); if (taskDescription.containsDataset()) { String datasetKey = web3SecretService .getSecret(taskDescription.getDatasetAddress(), true) @@ -147,22 +146,23 @@ public SecretEnclaveBase getPreComputeTokens(TeeSessionRequest request) "Empty dataset secret - taskId: " + taskId)) .getTrimmedValue(); tokens.put(IEXEC_DATASET_KEY, datasetKey); + trustedEnv.addAll(List.of( + IexecEnvUtils.IEXEC_DATASET_URL, + IexecEnvUtils.IEXEC_DATASET_FILENAME, + IexecEnvUtils.IEXEC_DATASET_CHECKSUM)); } else { log.info("No dataset key needed for this task [taskId:{}]", taskId); } - List trustedKeys = List.of( + trustedEnv.addAll(List.of( IexecEnvUtils.IEXEC_TASK_ID, - IexecEnvUtils.IEXEC_DATASET_URL, - IexecEnvUtils.IEXEC_DATASET_FILENAME, - IexecEnvUtils.IEXEC_DATASET_CHECKSUM, IexecEnvUtils.IEXEC_INPUT_FILES_FOLDER, - IexecEnvUtils.IEXEC_INPUT_FILES_NUMBER); + IexecEnvUtils.IEXEC_INPUT_FILES_NUMBER)); Map trustedEnvVars = IexecEnvUtils.getAllIexecEnv(taskDescription) .entrySet() .stream() .filter(e -> // extract trusted en vars to include - trustedKeys.contains(e.getKey()) + trustedEnv.contains(e.getKey()) // extract || e.getKey().contains(IexecEnvUtils.IEXEC_INPUT_FILE_URL_PREFIX)) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); @@ -233,7 +233,10 @@ private Map getApplicationComputeSecrets(TaskDescription taskDes secretIndex) .map(TeeTaskComputeSecret::getValue) .orElse(EMPTY_YML_VALUE); - tokens.put(IexecEnvUtils.IEXEC_APP_DEVELOPER_SECRET_PREFIX + secretIndex, appDeveloperSecret); + if (!StringUtils.isEmpty(appDeveloperSecret)) { + tokens.put("IEXEC_APP_DEVELOPER_SECRET", appDeveloperSecret); + tokens.put(IexecEnvUtils.IEXEC_APP_DEVELOPER_SECRET_PREFIX + secretIndex, appDeveloperSecret); + } } if (taskDescription.getSecrets() == null || taskDescription.getRequester() == null) { @@ -273,14 +276,14 @@ private Map getApplicationComputeSecrets(TaskDescription taskDes */ public SecretEnclaveBase getPostComputeTokens(TeeSessionRequest request) throws TeeSessionGenerationException { - SecretEnclaveBaseBuilder enclaveBase = SecretEnclaveBase.builder(); - enclaveBase.name("post-compute"); + SecretEnclaveBaseBuilder enclaveBase = SecretEnclaveBase.builder() + .name("post-compute") + .mrenclave(teeWorkflowConfig.getPostComputeFingerprint()); Map tokens = new HashMap<>(); TaskDescription taskDescription = request.getTaskDescription(); if (taskDescription == null) { throw new TeeSessionGenerationException(NO_TASK_DESCRIPTION, "Task description must not be null"); } - String teePostComputeFingerprint = teeWorkflowConfig.getPostComputeFingerprint(); // ############################################################################### // TODO: activate this when user specific post-compute is properly // supported. See @@ -291,7 +294,6 @@ public SecretEnclaveBase getPostComputeTokens(TeeSessionRequest request) // teePostComputeFingerprint = taskDescription.getTeePostComputeFingerprint(); // //add entrypoint too // } - tokens.put(POST_COMPUTE_MRENCLAVE, teePostComputeFingerprint); // encryption Map encryptionTokens = getPostComputeEncryptionTokens(request); tokens.putAll(encryptionTokens); diff --git a/src/test/java/com/iexec/sms/tee/session/base/SecretSessionBaseServiceTests.java b/src/test/java/com/iexec/sms/tee/session/base/SecretSessionBaseServiceTests.java new file mode 100644 index 00000000..09e7df1d --- /dev/null +++ b/src/test/java/com/iexec/sms/tee/session/base/SecretSessionBaseServiceTests.java @@ -0,0 +1,698 @@ +package com.iexec.sms.tee.session.base; + +import com.iexec.common.chain.DealParams; +import com.iexec.common.sms.secret.ReservedSecretKeyName; +import com.iexec.common.task.TaskDescription; +import com.iexec.common.tee.TeeEnclaveConfiguration; +import com.iexec.common.tee.TeeEnclaveProvider; +import com.iexec.common.utils.IexecEnvUtils; +import com.iexec.sms.api.TeeSessionGenerationError; +import com.iexec.sms.secret.Secret; +import com.iexec.sms.secret.compute.OnChainObjectType; +import com.iexec.sms.secret.compute.SecretOwnerRole; +import com.iexec.sms.secret.compute.TeeTaskComputeSecret; +import com.iexec.sms.secret.compute.TeeTaskComputeSecretService; +import com.iexec.sms.secret.web2.Web2SecretsService; +import com.iexec.sms.secret.web3.Web3Secret; +import com.iexec.sms.secret.web3.Web3SecretService; +import com.iexec.sms.tee.challenge.TeeChallenge; +import com.iexec.sms.tee.challenge.TeeChallengeService; +import com.iexec.sms.tee.session.generic.TeeSessionGenerationException; +import com.iexec.sms.tee.session.generic.TeeSessionRequest; +import com.iexec.sms.tee.workflow.TeeWorkflowConfiguration; +import com.iexec.sms.utils.EthereumCredentials; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.NullSource; +import org.junit.jupiter.params.provider.ValueSource; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.security.GeneralSecurityException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import static com.iexec.sms.tee.session.TeeSessionTestUtils.*; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertThrows; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.*; + +class SecretSessionBaseServiceTests { + + private static final TeeEnclaveConfiguration enclaveConfig = TeeEnclaveConfiguration.builder() + .provider(TeeEnclaveProvider.SCONE)// any would be fine + .entrypoint(APP_ENTRYPOINT) + .fingerprint(APP_FINGERPRINT) + .heapSize(1) + .build(); + + @Mock + private Web3SecretService web3SecretService; + @Mock + private Web2SecretsService web2SecretsService; + @Mock + private TeeChallengeService teeChallengeService; + @Mock + private TeeWorkflowConfiguration teeWorkflowConfig; + @Mock + private TeeTaskComputeSecretService teeTaskComputeSecretService; + + @InjectMocks + private SecretSessionBaseService teeSecretsService; + + @BeforeEach + void beforeEach() { + MockitoAnnotations.openMocks(this); + } + + // region getSecretsTokens + @Test + void shouldGetSecretsTokens() throws Exception { + TaskDescription taskDescription = createTaskDescription(enclaveConfig); + TeeSessionRequest request = createSessionRequest(taskDescription); + + // pre + when(teeWorkflowConfig.getPreComputeFingerprint()) + .thenReturn(PRE_COMPUTE_FINGERPRINT); + Web3Secret secret = new Web3Secret(DATASET_ADDRESS, DATASET_KEY); + when(web3SecretService.getSecret(DATASET_ADDRESS, true)) + .thenReturn(Optional.of(secret)); + // post + Secret publicKeySecret = new Secret("address", ENCRYPTION_PUBLIC_KEY); + when(teeWorkflowConfig.getPostComputeFingerprint()) + .thenReturn(POST_COMPUTE_FINGERPRINT); + when(web2SecretsService.getSecret( + request.getTaskDescription().getBeneficiary(), + ReservedSecretKeyName.IEXEC_RESULT_ENCRYPTION_PUBLIC_KEY, + true)) + .thenReturn(Optional.of(publicKeySecret)); + Secret storageSecret = new Secret("address", STORAGE_TOKEN); + when(web2SecretsService.getSecret(taskDescription.getRequester(), + ReservedSecretKeyName.IEXEC_RESULT_IEXEC_IPFS_TOKEN, true)) + .thenReturn(Optional.of(storageSecret)); + TeeChallenge challenge = TeeChallenge.builder() + .credentials(EthereumCredentials.generate()) + .build(); + when(teeChallengeService.getOrCreate(TASK_ID, true)) + .thenReturn(Optional.of(challenge)); + + SecretSessionBase sessionBase = teeSecretsService.getSecretsTokens(request); + + SecretEnclaveBase preComputeBase = sessionBase.getPreCompute(); + assertEquals("pre-compute", preComputeBase.getName()); + assertEquals(PRE_COMPUTE_FINGERPRINT, preComputeBase.getMrenclave()); + // environment content checks are handled in dedicated tests below + assertEquals(teeSecretsService.getPreComputeTokens(request).getEnvironment(), + preComputeBase.getEnvironment()); + + SecretEnclaveBase appComputeBase = sessionBase.getAppCompute(); + assertEquals("app", appComputeBase.getName()); + assertEquals(APP_FINGERPRINT, appComputeBase.getMrenclave()); + // environment content checks are handled in dedicated tests below + assertEquals(teeSecretsService.getAppTokens(request).getEnvironment(), + appComputeBase.getEnvironment()); + + SecretEnclaveBase postComputeBase = sessionBase.getPostCompute(); + assertEquals("post-compute", postComputeBase.getName()); + assertEquals(POST_COMPUTE_FINGERPRINT, postComputeBase.getMrenclave()); + // environment content checks are handled in dedicated tests below + assertEquals(teeSecretsService.getPostComputeTokens(request).getEnvironment(), + postComputeBase.getEnvironment()); + } + + @Test + void shouldNotGetSecretsTokensSinceRequestIsNull() { + final TeeSessionGenerationException exception = assertThrows( + TeeSessionGenerationException.class, + () -> teeSecretsService.getSecretsTokens(null)); + assertEquals(TeeSessionGenerationError.NO_SESSION_REQUEST, exception.getError()); + assertEquals("Session request must not be null", exception.getMessage()); + } + + @Test + void shouldNotGetSecretsTokensSinceTaskDescriptionIsMissing() { + TeeSessionRequest request = TeeSessionRequest.builder().build(); + + final TeeSessionGenerationException exception = assertThrows( + TeeSessionGenerationException.class, + () -> teeSecretsService.getSecretsTokens(request)); + assertEquals(TeeSessionGenerationError.NO_TASK_DESCRIPTION, exception.getError()); + assertEquals("Task description must not be null", exception.getMessage()); + } + // endregion + + // region getPreComputeTokens + @Test + void shouldGetPreComputeTokens() throws Exception { + TaskDescription taskDescription = createTaskDescription(enclaveConfig); + TeeSessionRequest request = createSessionRequest(taskDescription); + when(teeWorkflowConfig.getPreComputeFingerprint()) + .thenReturn(PRE_COMPUTE_FINGERPRINT); + Web3Secret secret = new Web3Secret(DATASET_ADDRESS, DATASET_KEY); + when(web3SecretService.getSecret(DATASET_ADDRESS, true)) + .thenReturn(Optional.of(secret)); + + SecretEnclaveBase enclaveBase = teeSecretsService.getPreComputeTokens(request); + assertThat(enclaveBase.getName()).isEqualTo("pre-compute"); + assertThat(enclaveBase.getMrenclave()).isEqualTo(PRE_COMPUTE_FINGERPRINT); + Map expectedTokens = new HashMap<>(); + expectedTokens.put("IEXEC_TASK_ID", TASK_ID); + expectedTokens.put("IEXEC_PRE_COMPUTE_OUT", "/iexec_in"); + expectedTokens.put("IS_DATASET_REQUIRED", true); + expectedTokens.put("IEXEC_DATASET_KEY", secret.getTrimmedValue()); + expectedTokens.put("IEXEC_DATASET_URL", DATASET_URL); + expectedTokens.put("IEXEC_DATASET_FILENAME", DATASET_NAME); + expectedTokens.put("IEXEC_DATASET_CHECKSUM", DATASET_CHECKSUM); + expectedTokens.put("IEXEC_INPUT_FILES_FOLDER", "/iexec_in"); + expectedTokens.put("IEXEC_INPUT_FILES_NUMBER", "2"); + expectedTokens.put("IEXEC_INPUT_FILE_URL_1", INPUT_FILE_URL_1); + expectedTokens.put("IEXEC_INPUT_FILE_URL_2", INPUT_FILE_URL_2); + assertThat(enclaveBase.getEnvironment()).containsExactlyInAnyOrderEntriesOf(expectedTokens); + } + + @Test + void shouldGetPreComputeTokensWithoutDataset() throws Exception { + TeeSessionRequest request = TeeSessionRequest.builder() + .sessionId(SESSION_ID) + .workerAddress(WORKER_ADDRESS) + .enclaveChallenge(ENCLAVE_CHALLENGE) + .taskDescription(TaskDescription.builder() + .chainTaskId(TASK_ID) + .inputFiles(List.of(INPUT_FILE_URL_1, INPUT_FILE_URL_2)) + .build()) + .build(); + when(teeWorkflowConfig.getPreComputeFingerprint()) + .thenReturn(PRE_COMPUTE_FINGERPRINT); + + SecretEnclaveBase enclaveBase = teeSecretsService.getPreComputeTokens(request); + assertThat(enclaveBase.getName()).isEqualTo("pre-compute"); + assertThat(enclaveBase.getMrenclave()).isEqualTo(PRE_COMPUTE_FINGERPRINT); + Map expectedTokens = new HashMap<>(); + expectedTokens.put("IEXEC_TASK_ID", TASK_ID); + expectedTokens.put("IEXEC_PRE_COMPUTE_OUT", "/iexec_in"); + expectedTokens.put("IS_DATASET_REQUIRED", false); + expectedTokens.put("IEXEC_INPUT_FILES_FOLDER", "/iexec_in"); + expectedTokens.put("IEXEC_INPUT_FILES_NUMBER", "2"); + expectedTokens.put("IEXEC_INPUT_FILE_URL_1", INPUT_FILE_URL_1); + expectedTokens.put("IEXEC_INPUT_FILE_URL_2", INPUT_FILE_URL_2); + assertThat(enclaveBase.getEnvironment()).containsExactlyInAnyOrderEntriesOf(expectedTokens); + } + // endregion + + // region getAppTokens + @Test + void shouldGetAppTokensForAdvancedTaskDescription() throws TeeSessionGenerationException { + TeeSessionRequest request = createSessionRequest(createTaskDescription(enclaveConfig)); + + String appAddress = request.getTaskDescription().getAppAddress(); + String requesterAddress = request.getTaskDescription().getRequester(); + + addApplicationDeveloperSecret(appAddress); + addRequesterSecret(requesterAddress, REQUESTER_SECRET_KEY_1, REQUESTER_SECRET_VALUE_1); + addRequesterSecret(requesterAddress, REQUESTER_SECRET_KEY_2, REQUESTER_SECRET_VALUE_2); + + SecretEnclaveBase enclaveBase = teeSecretsService.getAppTokens(request); + assertThat(enclaveBase.getName()).isEqualTo("app"); + assertThat(enclaveBase.getMrenclave()).isEqualTo(APP_FINGERPRINT); + Map expectedTokens = new HashMap<>(); + expectedTokens.put("IEXEC_TASK_ID", TASK_ID); + expectedTokens.put("IEXEC_IN", "/iexec_in"); + expectedTokens.put("IEXEC_OUT", "/iexec_out"); + expectedTokens.put("IEXEC_DATASET_ADDRESS", DATASET_ADDRESS); + expectedTokens.put("IEXEC_DATASET_FILENAME", DATASET_NAME); + expectedTokens.put("IEXEC_BOT_SIZE", "1"); + expectedTokens.put("IEXEC_BOT_FIRST_INDEX", "0"); + expectedTokens.put("IEXEC_BOT_TASK_INDEX", "0"); + expectedTokens.put("IEXEC_INPUT_FILES_FOLDER", "/iexec_in"); + expectedTokens.put("IEXEC_INPUT_FILES_NUMBER", "2"); + expectedTokens.put("IEXEC_INPUT_FILE_NAME_1", INPUT_FILE_NAME_1); + expectedTokens.put("IEXEC_INPUT_FILE_NAME_2", INPUT_FILE_NAME_2); + expectedTokens.put("IEXEC_APP_DEVELOPER_SECRET", APP_DEVELOPER_SECRET_VALUE); + expectedTokens.put("IEXEC_APP_DEVELOPER_SECRET_1", APP_DEVELOPER_SECRET_VALUE); + expectedTokens.put("IEXEC_REQUESTER_SECRET_1", REQUESTER_SECRET_VALUE_1); + expectedTokens.put("IEXEC_REQUESTER_SECRET_2", REQUESTER_SECRET_VALUE_2); + assertThat(enclaveBase.getEnvironment()).containsExactlyInAnyOrderEntriesOf(expectedTokens); + + verify(teeTaskComputeSecretService).getSecret(OnChainObjectType.APPLICATION, appAddress, + SecretOwnerRole.APPLICATION_DEVELOPER, "", APP_DEVELOPER_SECRET_INDEX); + verify(teeTaskComputeSecretService).getSecret(OnChainObjectType.APPLICATION, "", SecretOwnerRole.REQUESTER, + requesterAddress, REQUESTER_SECRET_KEY_1); + verify(teeTaskComputeSecretService).getSecret(OnChainObjectType.APPLICATION, "", SecretOwnerRole.REQUESTER, + requesterAddress, REQUESTER_SECRET_KEY_2); + } + + @Test + void shouldGetTokensWithEmptyAppComputeSecretWhenSecretsDoNotExist() throws TeeSessionGenerationException { + final String appAddress = "0xapp"; + final String requesterAddress = "0xrequester"; + final TaskDescription taskDescription = TaskDescription.builder() + .chainTaskId(TASK_ID) + .appUri(APP_URI) + .appAddress(appAddress) + .appEnclaveConfiguration(enclaveConfig) + .datasetAddress(DATASET_ADDRESS) + .datasetUri(DATASET_URL) + .datasetName(DATASET_NAME) + .datasetChecksum(DATASET_CHECKSUM) + .requester(requesterAddress) + .cmd(ARGS) + .inputFiles(List.of(INPUT_FILE_URL_1, INPUT_FILE_URL_2)) + .isResultEncryption(true) + .resultStorageProvider(STORAGE_PROVIDER) + .resultStorageProxy(STORAGE_PROXY) + .botSize(1) + .botFirstIndex(0) + .botIndex(0) + .build(); + TeeSessionRequest request = createSessionRequest(taskDescription); + + when(teeTaskComputeSecretService.getSecret( + OnChainObjectType.APPLICATION, + appAddress, + SecretOwnerRole.APPLICATION_DEVELOPER, + "", + APP_DEVELOPER_SECRET_INDEX)) + .thenReturn(Optional.empty()); + + SecretEnclaveBase enclaveBase = teeSecretsService.getAppTokens(request); + assertThat(enclaveBase.getName()).isEqualTo("app"); + assertThat(enclaveBase.getMrenclave()).isEqualTo(APP_FINGERPRINT); + Map expectedTokens = new HashMap<>(); + expectedTokens.put("IEXEC_TASK_ID", TASK_ID); + expectedTokens.put("IEXEC_IN", "/iexec_in"); + expectedTokens.put("IEXEC_OUT", "/iexec_out"); + expectedTokens.put("IEXEC_DATASET_ADDRESS", DATASET_ADDRESS); + expectedTokens.put("IEXEC_DATASET_FILENAME", DATASET_NAME); + expectedTokens.put("IEXEC_BOT_SIZE", "1"); + expectedTokens.put("IEXEC_BOT_FIRST_INDEX", "0"); + expectedTokens.put("IEXEC_BOT_TASK_INDEX", "0"); + expectedTokens.put("IEXEC_INPUT_FILES_FOLDER", "/iexec_in"); + expectedTokens.put("IEXEC_INPUT_FILES_NUMBER", "2"); + expectedTokens.put("IEXEC_INPUT_FILE_NAME_1", INPUT_FILE_NAME_1); + expectedTokens.put("IEXEC_INPUT_FILE_NAME_2", INPUT_FILE_NAME_2); + assertThat(enclaveBase.getEnvironment()).containsExactlyInAnyOrderEntriesOf(expectedTokens); + + verify(teeTaskComputeSecretService).getSecret(eq(OnChainObjectType.APPLICATION), eq(appAddress), + eq(SecretOwnerRole.APPLICATION_DEVELOPER), eq(""), any()); + verify(teeTaskComputeSecretService, never()).getSecret(eq(OnChainObjectType.APPLICATION), eq(""), + eq(SecretOwnerRole.REQUESTER), any(), any()); + } + + @Test + void shouldFailToGetAppTokensSinceNoTaskDescription() { + TeeSessionRequest request = TeeSessionRequest.builder() + .build(); + TeeSessionGenerationException exception = assertThrows(TeeSessionGenerationException.class, + () -> teeSecretsService.getAppTokens(request)); + Assertions.assertEquals(TeeSessionGenerationError.NO_TASK_DESCRIPTION, exception.getError()); + Assertions.assertEquals("Task description must no be null", exception.getMessage()); + } + + @Test + void shouldFailToGetAppTokensSinceNoEnclaveConfig() { + TeeSessionRequest request = TeeSessionRequest.builder() + .sessionId(SESSION_ID) + .workerAddress(WORKER_ADDRESS) + .enclaveChallenge(ENCLAVE_CHALLENGE) + .taskDescription(TaskDescription.builder().build()) + .build(); + TeeSessionGenerationException exception = assertThrows(TeeSessionGenerationException.class, + () -> teeSecretsService.getAppTokens(request)); + Assertions.assertEquals(TeeSessionGenerationError.APP_COMPUTE_NO_ENCLAVE_CONFIG, exception.getError()); + Assertions.assertEquals("Enclave configuration must no be null", exception.getMessage()); + } + + @Test + void shouldFailToGetAppTokensInvalidEnclaveConfig() { + // invalid enclave config + TeeSessionRequest request = createSessionRequest(createTaskDescription(new TeeEnclaveConfiguration())); + + TeeSessionGenerationException exception = assertThrows(TeeSessionGenerationException.class, + () -> teeSecretsService.getAppTokens(request)); + Assertions.assertEquals(TeeSessionGenerationError.APP_COMPUTE_INVALID_ENCLAVE_CONFIG, exception.getError()); + } + + @Test + void shouldAddMultipleRequesterSecrets() { + TeeSessionRequest request = createSessionRequest(createTaskDescription(enclaveConfig)); + String requesterAddress = request.getTaskDescription().getRequester(); + + addRequesterSecret(requesterAddress, REQUESTER_SECRET_KEY_1, REQUESTER_SECRET_VALUE_1); + addRequesterSecret(requesterAddress, REQUESTER_SECRET_KEY_2, REQUESTER_SECRET_VALUE_2); + SecretEnclaveBase enclaveBase = assertDoesNotThrow(() -> teeSecretsService.getAppTokens(request)); + verify(teeTaskComputeSecretService, times(2)) + .getSecret(eq(OnChainObjectType.APPLICATION), eq(""), eq(SecretOwnerRole.REQUESTER), any(), any()); + verify(teeTaskComputeSecretService).getSecret(OnChainObjectType.APPLICATION, "", SecretOwnerRole.REQUESTER, + requesterAddress, REQUESTER_SECRET_KEY_1); + verify(teeTaskComputeSecretService).getSecret(OnChainObjectType.APPLICATION, "", SecretOwnerRole.REQUESTER, + requesterAddress, REQUESTER_SECRET_KEY_2); + assertThat(enclaveBase.getEnvironment()).containsAllEntriesOf( + Map.of( + IexecEnvUtils.IEXEC_REQUESTER_SECRET_PREFIX + "1", REQUESTER_SECRET_VALUE_1, + IexecEnvUtils.IEXEC_REQUESTER_SECRET_PREFIX + "2", REQUESTER_SECRET_VALUE_2)); + } + + @Test + void shouldFilterRequesterSecretIndexLowerThanZero() { + TeeSessionRequest request = createSessionRequest(createTaskDescription(enclaveConfig)); + String requesterAddress = request.getTaskDescription().getRequester(); + + request.getTaskDescription() + .setSecrets(Map.of("1", REQUESTER_SECRET_KEY_1, "-1", "out-of-bound-requester-secret")); + addRequesterSecret(requesterAddress, REQUESTER_SECRET_KEY_1, REQUESTER_SECRET_VALUE_1); + SecretEnclaveBase enclaveBase = assertDoesNotThrow(() -> teeSecretsService.getAppTokens(request)); + verify(teeTaskComputeSecretService).getSecret(eq(OnChainObjectType.APPLICATION), eq(""), + eq(SecretOwnerRole.REQUESTER), any(), any()); + assertThat(enclaveBase.getEnvironment()).containsAllEntriesOf( + Map.of(IexecEnvUtils.IEXEC_REQUESTER_SECRET_PREFIX + "1", REQUESTER_SECRET_VALUE_1)); + } + // endregion + + // region getPostComputeTokens + @Test + void shouldGetPostComputeTokens() throws Exception { + TeeSessionRequest request = createSessionRequest(createTaskDescription(enclaveConfig)); + + String requesterAddress = request.getTaskDescription().getRequester(); + + Secret publicKeySecret = new Secret("address", ENCRYPTION_PUBLIC_KEY); + when(teeWorkflowConfig.getPostComputeFingerprint()) + .thenReturn(POST_COMPUTE_FINGERPRINT); + when(web2SecretsService.getSecret( + request.getTaskDescription().getBeneficiary(), + ReservedSecretKeyName.IEXEC_RESULT_ENCRYPTION_PUBLIC_KEY, + true)) + .thenReturn(Optional.of(publicKeySecret)); + Secret storageSecret = new Secret("address", STORAGE_TOKEN); + when(web2SecretsService.getSecret( + requesterAddress, + ReservedSecretKeyName.IEXEC_RESULT_IEXEC_IPFS_TOKEN, + true)) + .thenReturn(Optional.of(storageSecret)); + + TeeChallenge challenge = TeeChallenge.builder() + .credentials(EthereumCredentials.generate()) + .build(); + when(teeChallengeService.getOrCreate(TASK_ID, true)) + .thenReturn(Optional.of(challenge)); + + SecretEnclaveBase enclaveBase = teeSecretsService.getPostComputeTokens(request); + assertThat(enclaveBase.getName()).isEqualTo("post-compute"); + assertThat(enclaveBase.getMrenclave()).isEqualTo(POST_COMPUTE_FINGERPRINT); + Map expectedTokens = new HashMap<>(); + // encryption tokens + expectedTokens.put("RESULT_ENCRYPTION", "yes"); + expectedTokens.put("RESULT_ENCRYPTION_PUBLIC_KEY", ENCRYPTION_PUBLIC_KEY); + // storage tokens + expectedTokens.put("RESULT_STORAGE_CALLBACK", "no"); + expectedTokens.put("RESULT_STORAGE_PROVIDER", STORAGE_PROVIDER); + expectedTokens.put("RESULT_STORAGE_PROXY", STORAGE_PROXY); + expectedTokens.put("RESULT_STORAGE_TOKEN", STORAGE_TOKEN); + // sign tokens + expectedTokens.put("RESULT_TASK_ID", TASK_ID); + expectedTokens.put("RESULT_SIGN_WORKER_ADDRESS", WORKER_ADDRESS); + expectedTokens.put("RESULT_SIGN_TEE_CHALLENGE_PRIVATE_KEY", challenge.getCredentials().getPrivateKey()); + + assertThat(enclaveBase.getEnvironment()).containsExactlyEntriesOf(expectedTokens); + } + + @Test + void shouldNotGetPostComputeTokensSinceTaskDescriptionMissing() { + TeeSessionRequest request = TeeSessionRequest.builder().build(); + + final TeeSessionGenerationException exception = assertThrows( + TeeSessionGenerationException.class, + () -> teeSecretsService.getPostComputeTokens(request)); + assertEquals(TeeSessionGenerationError.NO_TASK_DESCRIPTION, exception.getError()); + assertEquals("Task description must not be null", exception.getMessage()); + } + // endregion + + // region getPostComputeEncryptionTokens + @Test + void shouldGetPostComputeStorageTokensWithCallback() { + final TeeSessionRequest sessionRequest = createSessionRequest(createTaskDescription(enclaveConfig)); + sessionRequest.getTaskDescription().setCallback("callback"); + + final Map tokens = assertDoesNotThrow( + () -> teeSecretsService.getPostComputeStorageTokens(sessionRequest)); + + assertThat(tokens) + .containsExactlyInAnyOrderEntriesOf( + Map.of( + "RESULT_STORAGE_CALLBACK", "yes", + "RESULT_STORAGE_PROVIDER", "", + "RESULT_STORAGE_PROXY", "", + "RESULT_STORAGE_TOKEN", "")); + } + + @Test + void shouldGetPostComputeStorageTokensOnIpfs() { + final TeeSessionRequest sessionRequest = createSessionRequest(createTaskDescription(enclaveConfig)); + final TaskDescription taskDescription = sessionRequest.getTaskDescription(); + + final String secretValue = "Secret value"; + when(web2SecretsService.getSecret(taskDescription.getRequester(), + ReservedSecretKeyName.IEXEC_RESULT_IEXEC_IPFS_TOKEN, true)) + .thenReturn(Optional.of(new Secret(null, secretValue))); + + final Map tokens = assertDoesNotThrow( + () -> teeSecretsService.getPostComputeStorageTokens(sessionRequest)); + + assertThat(tokens) + .containsExactlyInAnyOrderEntriesOf( + Map.of( + "RESULT_STORAGE_CALLBACK", "no", + "RESULT_STORAGE_PROVIDER", STORAGE_PROVIDER, + "RESULT_STORAGE_PROXY", STORAGE_PROXY, + "RESULT_STORAGE_TOKEN", secretValue)); + } + + @Test + void shouldGetPostComputeStorageTokensOnDropbox() { + final TeeSessionRequest sessionRequest = createSessionRequest(createTaskDescription(enclaveConfig)); + final TaskDescription taskDescription = sessionRequest.getTaskDescription(); + taskDescription.setResultStorageProvider(DealParams.DROPBOX_RESULT_STORAGE_PROVIDER); + + final String secretValue = "Secret value"; + when(web2SecretsService.getSecret(taskDescription.getRequester(), + ReservedSecretKeyName.IEXEC_RESULT_DROPBOX_TOKEN, true)) + .thenReturn(Optional.of(new Secret(null, secretValue))); + + final Map tokens = assertDoesNotThrow( + () -> teeSecretsService.getPostComputeStorageTokens(sessionRequest)); + + assertThat(tokens) + .containsExactlyInAnyOrderEntriesOf( + Map.of( + "RESULT_STORAGE_CALLBACK", "no", + "RESULT_STORAGE_PROVIDER", "dropbox", + "RESULT_STORAGE_PROXY", STORAGE_PROXY, + "RESULT_STORAGE_TOKEN", secretValue)); + } + + @Test + void shouldNotGetPostComputeStorageTokensSinceNoSecret() { + final TeeSessionRequest sessionRequest = createSessionRequest(createTaskDescription(enclaveConfig)); + final TaskDescription taskDescription = sessionRequest.getTaskDescription(); + + when(web2SecretsService.getSecret(taskDescription.getRequester(), + ReservedSecretKeyName.IEXEC_RESULT_IEXEC_IPFS_TOKEN, true)) + .thenReturn(Optional.empty()); + + final TeeSessionGenerationException exception = assertThrows( + TeeSessionGenerationException.class, + () -> teeSecretsService.getPostComputeStorageTokens(sessionRequest)); + + assertThat(exception.getError()).isEqualTo(TeeSessionGenerationError.POST_COMPUTE_GET_STORAGE_TOKENS_FAILED); + assertThat(exception.getMessage()) + .isEqualTo("Empty requester storage token - taskId: " + taskDescription.getChainTaskId()); + } + + @Test + void shouldGetPostComputeSignTokens() throws GeneralSecurityException { + final TeeSessionRequest sessionRequest = createSessionRequest(createTaskDescription(enclaveConfig)); + final TaskDescription taskDescription = sessionRequest.getTaskDescription(); + final String taskId = taskDescription.getChainTaskId(); + final EthereumCredentials credentials = EthereumCredentials.generate(); + + when(teeChallengeService.getOrCreate(taskId, true)) + .thenReturn(Optional.of(TeeChallenge.builder().credentials(credentials).build())); + + final Map tokens = assertDoesNotThrow( + () -> teeSecretsService.getPostComputeSignTokens(sessionRequest)); + + assertThat(tokens) + .containsExactlyInAnyOrderEntriesOf( + Map.of( + "RESULT_TASK_ID", taskId, + "RESULT_SIGN_WORKER_ADDRESS", sessionRequest.getWorkerAddress(), + "RESULT_SIGN_TEE_CHALLENGE_PRIVATE_KEY", credentials.getPrivateKey())); + } + + @ParameterizedTest + @NullSource + @ValueSource(strings = { "" }) + void shouldNotGetPostComputeSignTokensSinceNoWorkerAddress(String emptyWorkerAddress) { + final TeeSessionRequest sessionRequest = createSessionRequest(createTaskDescription(enclaveConfig)); + final String taskId = sessionRequest.getTaskDescription().getChainTaskId(); + sessionRequest.setWorkerAddress(emptyWorkerAddress); + + final TeeSessionGenerationException exception = assertThrows( + TeeSessionGenerationException.class, + () -> teeSecretsService.getPostComputeSignTokens(sessionRequest)); + + assertThat(exception.getError()) + .isEqualTo(TeeSessionGenerationError.POST_COMPUTE_GET_SIGNATURE_TOKENS_FAILED_EMPTY_WORKER_ADDRESS); + assertThat(exception.getMessage()).isEqualTo("Empty worker address - taskId: " + taskId); + } + + @ParameterizedTest + @NullSource + @ValueSource(strings = { "" }) + void shouldNotGetPostComputeSignTokensSinceNoEnclaveChallenge(String emptyEnclaveChallenge) { + final TeeSessionRequest sessionRequest = createSessionRequest(createTaskDescription(enclaveConfig)); + final String taskId = sessionRequest.getTaskDescription().getChainTaskId(); + sessionRequest.setEnclaveChallenge(emptyEnclaveChallenge); + + final TeeSessionGenerationException exception = assertThrows( + TeeSessionGenerationException.class, + () -> teeSecretsService.getPostComputeSignTokens(sessionRequest)); + + assertThat(exception.getError()).isEqualTo( + TeeSessionGenerationError.POST_COMPUTE_GET_SIGNATURE_TOKENS_FAILED_EMPTY_PUBLIC_ENCLAVE_CHALLENGE); + assertThat(exception.getMessage()).isEqualTo("Empty public enclave challenge - taskId: " + taskId); + } + + @Test + void shouldNotGetPostComputeSignTokensSinceNoTeeChallenge() { + final TeeSessionRequest sessionRequest = createSessionRequest(createTaskDescription(enclaveConfig)); + final String taskId = sessionRequest.getTaskDescription().getChainTaskId(); + + when(teeChallengeService.getOrCreate(taskId, true)) + .thenReturn(Optional.empty()); + + final TeeSessionGenerationException exception = assertThrows( + TeeSessionGenerationException.class, + () -> teeSecretsService.getPostComputeSignTokens(sessionRequest)); + + assertThat(exception.getError()) + .isEqualTo(TeeSessionGenerationError.POST_COMPUTE_GET_SIGNATURE_TOKENS_FAILED_EMPTY_TEE_CHALLENGE); + assertThat(exception.getMessage()).isEqualTo("Empty TEE challenge - taskId: " + taskId); + } + + @Test + void shouldNotGetPostComputeSignTokensSinceNoEnclaveCredentials() { + final TeeSessionRequest sessionRequest = createSessionRequest(createTaskDescription(enclaveConfig)); + final String taskId = sessionRequest.getTaskDescription().getChainTaskId(); + + when(teeChallengeService.getOrCreate(taskId, true)) + .thenReturn(Optional.of(TeeChallenge.builder().credentials(null).build())); + + final TeeSessionGenerationException exception = assertThrows( + TeeSessionGenerationException.class, + () -> teeSecretsService.getPostComputeSignTokens(sessionRequest)); + + assertThat(exception.getError()) + .isEqualTo(TeeSessionGenerationError.POST_COMPUTE_GET_SIGNATURE_TOKENS_FAILED_EMPTY_TEE_CREDENTIALS); + assertThat(exception.getMessage()).isEqualTo("Empty TEE challenge credentials - taskId: " + taskId); + } + + @Test + void shouldNotGetPostComputeSignTokensSinceNoEnclaveCredentialsPrivateKey() { + final TeeSessionRequest sessionRequest = createSessionRequest(createTaskDescription(enclaveConfig)); + final String taskId = sessionRequest.getTaskDescription().getChainTaskId(); + + when(teeChallengeService.getOrCreate(taskId, true)) + .thenReturn(Optional + .of(TeeChallenge.builder().credentials(new EthereumCredentials("", "", false, "")).build())); + + final TeeSessionGenerationException exception = assertThrows( + TeeSessionGenerationException.class, + () -> teeSecretsService.getPostComputeSignTokens(sessionRequest)); + + assertThat(exception.getError()) + .isEqualTo(TeeSessionGenerationError.POST_COMPUTE_GET_SIGNATURE_TOKENS_FAILED_EMPTY_TEE_CREDENTIALS); + assertThat(exception.getMessage()).isEqualTo("Empty TEE challenge credentials - taskId: " + taskId); + } + + @Test + void shouldGetPostComputeEncryptionTokensWithEncryption() { + TeeSessionRequest request = createSessionRequest(createTaskDescription(enclaveConfig)); + + Secret publicKeySecret = new Secret("address", ENCRYPTION_PUBLIC_KEY); + when(web2SecretsService.getSecret( + request.getTaskDescription().getBeneficiary(), + ReservedSecretKeyName.IEXEC_RESULT_ENCRYPTION_PUBLIC_KEY, + true)) + .thenReturn(Optional.of(publicKeySecret)); + + final Map encryptionTokens = assertDoesNotThrow( + () -> teeSecretsService.getPostComputeEncryptionTokens(request)); + assertThat(encryptionTokens) + .containsExactlyInAnyOrderEntriesOf( + Map.of( + "RESULT_ENCRYPTION", "yes", + "RESULT_ENCRYPTION_PUBLIC_KEY", ENCRYPTION_PUBLIC_KEY)); + } + + @Test + void shouldGetPostComputeEncryptionTokensWithoutEncryption() { + TeeSessionRequest request = createSessionRequest(createTaskDescription(enclaveConfig)); + request.getTaskDescription().setResultEncryption(false); + + final Map encryptionTokens = assertDoesNotThrow( + () -> teeSecretsService.getPostComputeEncryptionTokens(request)); + assertThat(encryptionTokens) + .containsExactlyInAnyOrderEntriesOf( + Map.of( + "RESULT_ENCRYPTION", "no", + "RESULT_ENCRYPTION_PUBLIC_KEY", "")); + } + + @Test + void shouldNotGetPostComputeEncryptionTokensSinceEmptyBeneficiaryKey() { + TeeSessionRequest request = createSessionRequest(createTaskDescription(enclaveConfig)); + + when(web2SecretsService.getSecret( + request.getTaskDescription().getBeneficiary(), + ReservedSecretKeyName.IEXEC_RESULT_ENCRYPTION_PUBLIC_KEY, + true)) + .thenReturn(Optional.empty()); + + final TeeSessionGenerationException exception = assertThrows( + TeeSessionGenerationException.class, + () -> teeSecretsService.getPostComputeEncryptionTokens(request)); + assertEquals(TeeSessionGenerationError.POST_COMPUTE_GET_ENCRYPTION_TOKENS_FAILED_EMPTY_BENEFICIARY_KEY, + exception.getError()); + assertEquals("Empty beneficiary encryption key - taskId: taskId", exception.getMessage()); + } + + // endregion + + // region utils + private void addApplicationDeveloperSecret(String appAddress) { + TeeTaskComputeSecret applicationDeveloperSecret = getApplicationDeveloperSecret(appAddress); + when(teeTaskComputeSecretService.getSecret(OnChainObjectType.APPLICATION, appAddress, + SecretOwnerRole.APPLICATION_DEVELOPER, "", APP_DEVELOPER_SECRET_INDEX)) + .thenReturn(Optional.of(applicationDeveloperSecret)); + } + + private void addRequesterSecret(String requesterAddress, String secretKey, String secretValue) { + TeeTaskComputeSecret requesterSecret = getRequesterSecret(requesterAddress, secretKey, secretValue); + when(teeTaskComputeSecretService.getSecret(OnChainObjectType.APPLICATION, "", SecretOwnerRole.REQUESTER, + requesterAddress, secretKey)) + .thenReturn(Optional.of(requesterSecret)); + } + // endregion + +} \ No newline at end of file diff --git a/src/test/java/com/iexec/sms/tee/session/base/SecretSessionServiceTests.java b/src/test/java/com/iexec/sms/tee/session/base/SecretSessionServiceTests.java deleted file mode 100644 index 78a547ad..00000000 --- a/src/test/java/com/iexec/sms/tee/session/base/SecretSessionServiceTests.java +++ /dev/null @@ -1,692 +0,0 @@ -package com.iexec.sms.tee.session.base; - -import com.iexec.common.tee.TeeEnclaveConfiguration; -import com.iexec.sms.secret.compute.TeeTaskComputeSecretService; -import com.iexec.sms.secret.web2.Web2SecretsService; -import com.iexec.sms.secret.web3.Web3SecretService; -import com.iexec.sms.tee.challenge.TeeChallengeService; -import com.iexec.sms.tee.workflow.TeeWorkflowConfiguration; -import org.junit.jupiter.api.BeforeEach; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.mockito.Spy; - -import static com.iexec.sms.tee.session.TeeSessionTestUtils.APP_ENTRYPOINT; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -class SecretSessionServiceTests { - private static final String APP_FINGERPRINT = "01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b"; - - private static final TeeEnclaveConfiguration enclaveConfig = - mock(TeeEnclaveConfiguration.class); - - @Mock - private Web3SecretService web3SecretService; - @Mock - private Web2SecretsService web2SecretsService; - @Mock - private TeeChallengeService teeChallengeService; - @Mock - private TeeWorkflowConfiguration teeWorkflowConfig; - @Mock private TeeTaskComputeSecretService teeTaskComputeSecretService; - - @Spy - @InjectMocks - private SecretSessionBaseService teeSecretsService; - - @BeforeEach - void beforeEach() { - MockitoAnnotations.openMocks(this); - when(enclaveConfig.getFingerprint()).thenReturn(APP_FINGERPRINT); - - when(enclaveConfig.getFingerprint()).thenReturn(APP_FINGERPRINT); - when(enclaveConfig.getEntrypoint()).thenReturn(APP_ENTRYPOINT); - } - - /* TODO: Enable - //region getSecretsTokens - @Test - void shouldGetSecretsTokens() throws Exception { - TeeSecretsSessionRequest request = createSessionRequest(createTaskDescription(enclaveConfig)); - doReturn(getPreComputeTokens()).when(teeSecretsService) - .getPreComputeTokens(request); - doReturn(getAppTokens()).when(teeSecretsService) - .getAppTokens(request); - doReturn(getPostComputeTokens()).when(teeSecretsService) - .getPostComputeTokens(request); - - Map actualTokens = teeSecretsService.getSecretsTokens(request); - - Map expectedEnvTokens = new HashMap<>(); - expectedEnvTokens.put(IEXEC_TASK_ID, "taskId"); - expectedEnvTokens.put(IEXEC_IN, "/iexec_in"); - expectedEnvTokens.put(IEXEC_OUT, "/iexec_out"); - expectedEnvTokens.put(IEXEC_INPUT_FILES_FOLDER, "/iexec_in"); - expectedEnvTokens.put("IEXEC_INPUT_FILE_NAME_1", "file1"); - expectedEnvTokens.put("IEXEC_INPUT_FILE_NAME_2", "file2"); - expectedEnvTokens.put(IEXEC_DATASET_URL, "http://datasetUrl"); - expectedEnvTokens.put(IEXEC_DATASET_FILENAME, "datasetName"); - expectedEnvTokens.put(IEXEC_DATASET_ADDRESS, "0xDatasetAddress"); - expectedEnvTokens.put(IEXEC_INPUT_FILES_NUMBER, "2"); - expectedEnvTokens.put("IEXEC_INPUT_FILE_URL_1", "http://host/file1"); - expectedEnvTokens.put("IEXEC_INPUT_FILE_URL_2", "http://host/file2"); - expectedEnvTokens.put(IEXEC_BOT_SIZE, "1"); - expectedEnvTokens.put(IEXEC_BOT_TASK_INDEX, "0"); - expectedEnvTokens.put(IEXEC_DATASET_CHECKSUM, "datasetChecksum"); - expectedEnvTokens.put(IEXEC_BOT_FIRST_INDEX, "0"); - - - Map expectedTokens = new HashMap<>(); - expectedTokens.put(APP_MRENCLAVE, "01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b"); - expectedTokens.put(PRE_COMPUTE_MRENCLAVE, "mrEnclave1"); - expectedTokens.put(POST_COMPUTE_MRENCLAVE, "mrEnclave3"); - expectedTokens.put(IS_DATASET_REQUIRED, true); - expectedTokens.put(IEXEC_DATASET_KEY, "datasetKey"); - expectedTokens.put(IS_PRE_COMPUTE_REQUIRED, true); - expectedTokens.put(RESULT_TASK_ID, "taskId"); - expectedTokens.put(RESULT_STORAGE_PROXY, "storageProxy"); - expectedTokens.put(RESULT_STORAGE_TOKEN, "storageToken"); - expectedTokens.put(RESULT_SIGN_WORKER_ADDRESS, request.getWorkerAddress()); - expectedTokens.put(RESULT_SIGN_TEE_CHALLENGE_PRIVATE_KEY, "teeChallengePrivateKey"); - expectedTokens.put(RESULT_STORAGE_PROVIDER, "ipfs"); - expectedTokens.put(RESULT_STORAGE_CALLBACK, "no"); - expectedTokens.put(RESULT_ENCRYPTION, "yes"); - expectedTokens.put(RESULT_ENCRYPTION_PUBLIC_KEY, "encryptionPublicKey"); - expectedTokens.put(INPUT_FILE_NAMES, Map.of( - "IEXEC_INPUT_FILE_NAME_1", "file1", - "IEXEC_INPUT_FILE_NAME_2", "file2" - )); - expectedTokens.put(INPUT_FILE_URLS, Map.of( - "IEXEC_INPUT_FILE_URL_1", "http://host/file1", - "IEXEC_INPUT_FILE_URL_2", "http://host/file2" - )); - expectedTokens.put("env", expectedEnvTokens); - expectedTokens.put(SconeSessionMakerService.SESSION_ID, "sessionId"); - - assertRecursively(expectedTokens, actualTokens); - } - - @Test - void shouldNotGetSecretsTokensSinceRequestIsNull() { - final TeeSessionGenerationException exception = assertThrows( - TeeSessionGenerationException.class, - () -> teeSecretsService.getSecretsTokens(null) - ); - assertEquals(NO_SESSION_REQUEST, exception.getError()); - assertEquals("Session request must not be null", exception.getMessage()); - } - - @Test - void shouldNotGetSecretsTokensSinceTaskDescriptionIsMissing() { - TeeSecretsSessionRequest request = TeeSecretsSessionRequest.builder().build(); - - final TeeSessionGenerationException exception = assertThrows( - TeeSessionGenerationException.class, - () -> teeSecretsService.getSecretsTokens(request) - ); - assertEquals(NO_TASK_DESCRIPTION, exception.getError()); - assertEquals("Task description must not be null", exception.getMessage()); - } - //endregion - - //region getPreComputeTokens - @Test - void shouldGetPreComputeTokens() throws Exception { - TeeSecretsSessionRequest request = createSessionRequest(createTaskDescription(enclaveConfig)); - when(teeWorkflowConfig.getPreComputeFingerprint()) - .thenReturn(PRE_COMPUTE_FINGERPRINT); - when(teeWorkflowConfig.getPreComputeEntrypoint()) - .thenReturn(PRE_COMPUTE_ENTRYPOINT); - Web3Secret secret = new Web3Secret(DATASET_ADDRESS, DATASET_KEY); - when(web3SecretService.getSecret(DATASET_ADDRESS, true)) - .thenReturn(Optional.of(secret)); - - Map tokens = - teeSecretsService.getPreComputeTokens(request); - assertThat(tokens) - .containsExactlyInAnyOrderEntriesOf( - Map.of( - PRE_COMPUTE_MRENCLAVE, PRE_COMPUTE_FINGERPRINT, - PreComputeUtils.IEXEC_DATASET_KEY, secret.getTrimmedValue(), - PreComputeUtils.IS_DATASET_REQUIRED, true, - INPUT_FILE_URLS, - Map.of( - IexecEnvUtils.IEXEC_INPUT_FILE_URL_PREFIX + "1", INPUT_FILE_URL_1, - IexecEnvUtils.IEXEC_INPUT_FILE_URL_PREFIX + "2", INPUT_FILE_URL_2) - - ) - ); - } - - @Test - void shouldGetPreComputeTokensWithoutDataset() throws Exception { - TeeSecretsSessionRequest request = TeeSecretsSessionRequest.builder() - .sessionId(SESSION_ID) - .workerAddress(WORKER_ADDRESS) - .enclaveChallenge(ENCLAVE_CHALLENGE) - .taskDescription(TaskDescription.builder() - .chainTaskId(TASK_ID) - .inputFiles(List.of(INPUT_FILE_URL_1, INPUT_FILE_URL_2)) - .build()) - .build(); - when(teeWorkflowConfig.getPreComputeFingerprint()) - .thenReturn(PRE_COMPUTE_FINGERPRINT); - when(teeWorkflowConfig.getPreComputeEntrypoint()) - .thenReturn(PRE_COMPUTE_ENTRYPOINT); - - Map tokens = - teeSecretsService.getPreComputeTokens(request); - assertThat(tokens).isNotEmpty() - .containsExactlyInAnyOrderEntriesOf( - Map.of( - PRE_COMPUTE_MRENCLAVE, PRE_COMPUTE_FINGERPRINT, - PreComputeUtils.IEXEC_DATASET_KEY, "", - PreComputeUtils.IS_DATASET_REQUIRED, false, - INPUT_FILE_URLS, - Map.of( - IexecEnvUtils.IEXEC_INPUT_FILE_URL_PREFIX + "1", INPUT_FILE_URL_1, - IexecEnvUtils.IEXEC_INPUT_FILE_URL_PREFIX + "2", INPUT_FILE_URL_2) - - ) - ); - } - //endregion - - //region getAppTokens - @Test - void shouldGetAppTokensForAdvancedTaskDescription() { - TeeSecretsSessionRequest request = createSessionRequest(createTaskDescription(enclaveConfig)); - - String appAddress = request.getTaskDescription().getAppAddress(); - String requesterAddress = request.getTaskDescription().getRequester(); - - TeeEnclaveConfigurationValidator validator = mock(TeeEnclaveConfigurationValidator.class); - when(enclaveConfig.getValidator()).thenReturn(validator); - when(validator.isValid()).thenReturn(true); - addApplicationDeveloperSecret(appAddress); - addRequesterSecret(requesterAddress, REQUESTER_SECRET_KEY_1, REQUESTER_SECRET_VALUE_1); - addRequesterSecret(requesterAddress, REQUESTER_SECRET_KEY_2, REQUESTER_SECRET_VALUE_2); - - Map tokens = assertDoesNotThrow(() -> teeSecretsService.getAppTokens(request)); - - verify(teeTaskComputeSecretService).getSecret(OnChainObjectType.APPLICATION, appAddress, SecretOwnerRole.APPLICATION_DEVELOPER, "", APP_DEVELOPER_SECRET_INDEX); - verify(teeTaskComputeSecretService).getSecret(OnChainObjectType.APPLICATION, "", SecretOwnerRole.REQUESTER, requesterAddress, REQUESTER_SECRET_KEY_1); - verify(teeTaskComputeSecretService).getSecret(OnChainObjectType.APPLICATION, "", SecretOwnerRole.REQUESTER, requesterAddress, REQUESTER_SECRET_KEY_2); - - assertThat(tokens) - .containsExactlyInAnyOrderEntriesOf( - Map.of( - APP_MRENCLAVE, APP_FINGERPRINT, - INPUT_FILE_NAMES, - Map.of( - IexecEnvUtils.IEXEC_INPUT_FILE_NAME_PREFIX + "1", "file1", - IexecEnvUtils.IEXEC_INPUT_FILE_NAME_PREFIX + "2", "file2" - ), - IEXEC_APP_DEVELOPER_SECRET_1, APP_DEVELOPER_SECRET_VALUE, - REQUESTER_SECRETS, - Map.of( - IexecEnvUtils.IEXEC_REQUESTER_SECRET_PREFIX + "1", REQUESTER_SECRET_VALUE_1, - IexecEnvUtils.IEXEC_REQUESTER_SECRET_PREFIX + "2", REQUESTER_SECRET_VALUE_2 - ) - - ) - ); - } - - @Test - void shouldGetTokensWithEmptyAppComputeSecretWhenSecretsDoNotExist() { - final String appAddress = createEthereumAddress(); - final String requesterAddress = createEthereumAddress(); - final TaskDescription taskDescription = TaskDescription.builder() - .chainTaskId(TASK_ID) - .appUri(APP_URI) - .appAddress(appAddress) - .appEnclaveConfiguration(enclaveConfig) - .datasetAddress(DATASET_ADDRESS) - .datasetUri(DATASET_URL) - .datasetName(DATASET_NAME) - .datasetChecksum(DATASET_CHECKSUM) - .requester(requesterAddress) - .cmd(ARGS) - .inputFiles(List.of(INPUT_FILE_URL_1, INPUT_FILE_URL_2)) - .isResultEncryption(true) - .resultStorageProvider(STORAGE_PROVIDER) - .resultStorageProxy(STORAGE_PROXY) - .botSize(1) - .botFirstIndex(0) - .botIndex(0) - .build(); - TeeSecretsSessionRequest request = createSessionRequest(taskDescription); - TeeEnclaveConfigurationValidator validator = mock(TeeEnclaveConfigurationValidator.class); - when(enclaveConfig.getValidator()).thenReturn(validator); - when(validator.isValid()).thenReturn(true); - when(teeTaskComputeSecretService.getSecret( - OnChainObjectType.APPLICATION, - appAddress, - SecretOwnerRole.APPLICATION_DEVELOPER, - "", - APP_DEVELOPER_SECRET_INDEX)) - .thenReturn(Optional.empty()); - - Map tokens = assertDoesNotThrow(() -> teeSecretsService.getAppTokens(request)); - verify(teeTaskComputeSecretService).getSecret(eq(OnChainObjectType.APPLICATION), eq(appAddress), eq(SecretOwnerRole.APPLICATION_DEVELOPER), eq(""), any()); - verify(teeTaskComputeSecretService, never()).getSecret(eq(OnChainObjectType.APPLICATION), eq(""), eq(SecretOwnerRole.REQUESTER), any(), any()); - - assertThat(tokens) - .containsExactlyInAnyOrderEntriesOf( - Map.of( - APP_MRENCLAVE, APP_FINGERPRINT, - INPUT_FILE_NAMES, - Map.of( - IexecEnvUtils.IEXEC_INPUT_FILE_NAME_PREFIX + "1", "file1", - IexecEnvUtils.IEXEC_INPUT_FILE_NAME_PREFIX + "2", "file2" - ), - IEXEC_APP_DEVELOPER_SECRET_1, "", - REQUESTER_SECRETS, Collections.emptyMap() - ) - ); - } - - @Test - void shouldFailToGetAppTokensSinceNoTaskDescription() { - TeeSecretsSessionRequest request = TeeSecretsSessionRequest.builder() - .build(); - TeeSessionGenerationException exception = assertThrows(TeeSessionGenerationException.class, - () -> teeSecretsService.getAppTokens(request)); - Assertions.assertEquals(TeeSessionGenerationError.NO_TASK_DESCRIPTION, exception.getError()); - Assertions.assertEquals("Task description must no be null", exception.getMessage()); - } - - @Test - void shouldFailToGetAppTokensSinceNoEnclaveConfig() { - TeeSecretsSessionRequest request = TeeSecretsSessionRequest.builder() - .sessionId(SESSION_ID) - .workerAddress(WORKER_ADDRESS) - .enclaveChallenge(ENCLAVE_CHALLENGE) - .taskDescription(TaskDescription.builder().build()) - .build(); - TeeSessionGenerationException exception = assertThrows(TeeSessionGenerationException.class, - () -> teeSecretsService.getAppTokens(request)); - Assertions.assertEquals(TeeSessionGenerationError.APP_COMPUTE_NO_ENCLAVE_CONFIG, exception.getError()); - Assertions.assertEquals("Enclave configuration must no be null", exception.getMessage()); - } - - @Test - void shouldFailToGetAppTokensInvalidEnclaveConfig() { - TeeSecretsSessionRequest request = createSessionRequest(createTaskDescription(enclaveConfig)); - TeeEnclaveConfigurationValidator validator = mock(TeeEnclaveConfigurationValidator.class); - when(enclaveConfig.getValidator()).thenReturn(validator); - String validationError = "validation error"; - when(validator.validate()).thenReturn(Collections.singletonList(validationError)); - TeeSessionGenerationException exception = assertThrows(TeeSessionGenerationException.class, - () -> teeSecretsService.getAppTokens(request)); - Assertions.assertEquals(TeeSessionGenerationError.APP_COMPUTE_INVALID_ENCLAVE_CONFIG, exception.getError()); - } - - @Test - void shouldAddMultipleRequesterSecrets() { - TeeSecretsSessionRequest request = createSessionRequest(createTaskDescription(enclaveConfig)); - String requesterAddress = request.getTaskDescription().getRequester(); - - TeeEnclaveConfigurationValidator validator = mock(TeeEnclaveConfigurationValidator.class); - when(enclaveConfig.getValidator()).thenReturn(validator); - when(validator.isValid()).thenReturn(true); - addRequesterSecret(requesterAddress, REQUESTER_SECRET_KEY_1, REQUESTER_SECRET_VALUE_1); - addRequesterSecret(requesterAddress, REQUESTER_SECRET_KEY_2, REQUESTER_SECRET_VALUE_2); - Map tokens = assertDoesNotThrow(() -> teeSecretsService.getAppTokens(request)); - verify(teeTaskComputeSecretService, times(2)) - .getSecret(eq(OnChainObjectType.APPLICATION), eq(""), eq(SecretOwnerRole.REQUESTER), any(), any()); - verify(teeTaskComputeSecretService).getSecret(OnChainObjectType.APPLICATION, "", SecretOwnerRole.REQUESTER, requesterAddress, REQUESTER_SECRET_KEY_1); - verify(teeTaskComputeSecretService).getSecret(OnChainObjectType.APPLICATION, "", SecretOwnerRole.REQUESTER, requesterAddress, REQUESTER_SECRET_KEY_2); - assertThat(tokens).containsEntry(REQUESTER_SECRETS, - Map.of( - IexecEnvUtils.IEXEC_REQUESTER_SECRET_PREFIX + "1", REQUESTER_SECRET_VALUE_1, - IexecEnvUtils.IEXEC_REQUESTER_SECRET_PREFIX + "2", REQUESTER_SECRET_VALUE_2 - )); - } - - @Test - void shouldFilterRequesterSecretIndexLowerThanZero() { - TeeSecretsSessionRequest request = createSessionRequest(createTaskDescription(enclaveConfig)); - String requesterAddress = request.getTaskDescription().getRequester(); - - request.getTaskDescription().setSecrets(Map.of("1", REQUESTER_SECRET_KEY_1, "-1", "out-of-bound-requester-secret")); - TeeEnclaveConfigurationValidator validator = mock(TeeEnclaveConfigurationValidator.class); - when(enclaveConfig.getValidator()).thenReturn(validator); - when(validator.isValid()).thenReturn(true); - addRequesterSecret(requesterAddress, REQUESTER_SECRET_KEY_1, REQUESTER_SECRET_VALUE_1); - Map tokens = assertDoesNotThrow(() -> teeSecretsService.getAppTokens(request)); - verify(teeTaskComputeSecretService).getSecret(eq(OnChainObjectType.APPLICATION), eq(""), eq(SecretOwnerRole.REQUESTER), any(), any()); - assertThat(tokens).containsEntry(REQUESTER_SECRETS, - Map.of(IexecEnvUtils.IEXEC_REQUESTER_SECRET_PREFIX + "1", REQUESTER_SECRET_VALUE_1)); - } - //endregion - - //region getPostComputeTokens - @Test - void shouldGetPostComputeTokens() throws Exception { - TeeSecretsSessionRequest request = createSessionRequest(createTaskDescription(enclaveConfig)); - String requesterAddress = request.getTaskDescription().getRequester(); - - Secret publicKeySecret = new Secret("address", ENCRYPTION_PUBLIC_KEY); - when(teeWorkflowConfig.getPostComputeFingerprint()) - .thenReturn(POST_COMPUTE_FINGERPRINT); - when(teeWorkflowConfig.getPostComputeEntrypoint()) - .thenReturn(POST_COMPUTE_ENTRYPOINT); - when(web2SecretsService.getSecret( - request.getTaskDescription().getBeneficiary(), - ReservedSecretKeyName.IEXEC_RESULT_ENCRYPTION_PUBLIC_KEY, - true)) - .thenReturn(Optional.of(publicKeySecret)); - Secret storageSecret = new Secret("address", STORAGE_TOKEN); - when(web2SecretsService.getSecret( - requesterAddress, - ReservedSecretKeyName.IEXEC_RESULT_IEXEC_IPFS_TOKEN, - true)) - .thenReturn(Optional.of(storageSecret)); - - TeeChallenge challenge = TeeChallenge.builder() - .credentials(EthereumCredentials.generate()) - .build(); - when(teeChallengeService.getOrCreate(TASK_ID, true)) - .thenReturn(Optional.of(challenge)); - - - Map tokens = - teeSecretsService.getPostComputeTokens(request); - - final Map expectedTokens = new HashMap<>(); - expectedTokens.put(POST_COMPUTE_MRENCLAVE, POST_COMPUTE_FINGERPRINT); - // encryption tokens - expectedTokens.put(ResultUtils.RESULT_ENCRYPTION, "yes"); - expectedTokens.put(ResultUtils.RESULT_ENCRYPTION_PUBLIC_KEY, ENCRYPTION_PUBLIC_KEY); - // storage tokens - expectedTokens.put(ResultUtils.RESULT_STORAGE_CALLBACK, "no"); - expectedTokens.put(ResultUtils.RESULT_STORAGE_PROVIDER, STORAGE_PROVIDER); - expectedTokens.put(ResultUtils.RESULT_STORAGE_PROXY, STORAGE_PROXY); - expectedTokens.put(ResultUtils.RESULT_STORAGE_TOKEN, STORAGE_TOKEN); - // sign tokens - expectedTokens.put(ResultUtils.RESULT_TASK_ID, TASK_ID); - expectedTokens.put(ResultUtils.RESULT_SIGN_WORKER_ADDRESS, WORKER_ADDRESS); - expectedTokens.put(ResultUtils.RESULT_SIGN_TEE_CHALLENGE_PRIVATE_KEY, challenge.getCredentials().getPrivateKey()); - - assertThat(tokens).containsExactlyEntriesOf(expectedTokens); - } - - @Test - void shouldNotGetPostComputeTokensSinceTaskDescriptionMissing() { - TeeSecretsSessionRequest request = TeeSecretsSessionRequest.builder().build(); - - final TeeSessionGenerationException exception = assertThrows( - TeeSessionGenerationException.class, - () -> teeSecretsService.getPostComputeTokens(request) - ); - assertEquals(NO_TASK_DESCRIPTION, exception.getError()); - assertEquals("Task description must not be null", exception.getMessage()); - } - //endregion - - //region getPostComputeEncryptionTokens - @Test - void shouldGetPostComputeStorageTokensWithCallback() { - final TeeSecretsSessionRequest sessionRequest = createSessionRequest(createTaskDescription(enclaveConfig)); - sessionRequest.getTaskDescription().setCallback("callback"); - - final Map tokens = assertDoesNotThrow( - () -> teeSecretsService.getPostComputeStorageTokens(sessionRequest)); - - assertThat(tokens) - .containsExactlyInAnyOrderEntriesOf( - Map.of( - RESULT_STORAGE_CALLBACK, "yes", - RESULT_STORAGE_PROVIDER, EMPTY_YML_VALUE, - RESULT_STORAGE_PROXY, EMPTY_YML_VALUE, - RESULT_STORAGE_TOKEN, EMPTY_YML_VALUE - ) - ); - } - - @Test - void shouldGetPostComputeStorageTokensOnIpfs() { - final TeeSecretsSessionRequest sessionRequest = createSessionRequest(createTaskDescription(enclaveConfig)); - final TaskDescription taskDescription = sessionRequest.getTaskDescription(); - - final String secretValue = "Secret value"; - when(web2SecretsService.getSecret(taskDescription.getRequester(), ReservedSecretKeyName.IEXEC_RESULT_IEXEC_IPFS_TOKEN, true)) - .thenReturn(Optional.of(new Secret(null, secretValue))); - - final Map tokens = assertDoesNotThrow( - () -> teeSecretsService.getPostComputeStorageTokens(sessionRequest)); - - assertThat(tokens) - .containsExactlyInAnyOrderEntriesOf( - Map.of( - RESULT_STORAGE_CALLBACK, "no", - RESULT_STORAGE_PROVIDER, STORAGE_PROVIDER, - RESULT_STORAGE_PROXY, STORAGE_PROXY, - RESULT_STORAGE_TOKEN, secretValue - ) - ); - } - - @Test - void shouldGetPostComputeStorageTokensOnDropbox() { - final TeeSecretsSessionRequest sessionRequest = createSessionRequest(createTaskDescription(enclaveConfig)); - final TaskDescription taskDescription = sessionRequest.getTaskDescription(); - taskDescription.setResultStorageProvider(DROPBOX_RESULT_STORAGE_PROVIDER); - - final String secretValue = "Secret value"; - when(web2SecretsService.getSecret(taskDescription.getRequester(), IEXEC_RESULT_DROPBOX_TOKEN, true)) - .thenReturn(Optional.of(new Secret(null, secretValue))); - - final Map tokens = assertDoesNotThrow( - () -> teeSecretsService.getPostComputeStorageTokens(sessionRequest)); - - assertThat(tokens) - .containsExactlyInAnyOrderEntriesOf( - Map.of( - RESULT_STORAGE_CALLBACK, "no", - RESULT_STORAGE_PROVIDER, DROPBOX_RESULT_STORAGE_PROVIDER, - RESULT_STORAGE_PROXY, STORAGE_PROXY, - RESULT_STORAGE_TOKEN, secretValue - ) - ); - } - - @Test - void shouldNotGetPostComputeStorageTokensSinceNoSecret() { - final TeeSecretsSessionRequest sessionRequest = createSessionRequest(createTaskDescription(enclaveConfig)); - final TaskDescription taskDescription = sessionRequest.getTaskDescription(); - - when(web2SecretsService.getSecret(taskDescription.getRequester(), ReservedSecretKeyName.IEXEC_RESULT_IEXEC_IPFS_TOKEN, true)) - .thenReturn(Optional.empty()); - - final TeeSessionGenerationException exception = assertThrows( - TeeSessionGenerationException.class, - () -> teeSecretsService.getPostComputeStorageTokens(sessionRequest)); - - assertThat(exception.getError()).isEqualTo(POST_COMPUTE_GET_STORAGE_TOKENS_FAILED); - assertThat(exception.getMessage()).isEqualTo("Empty requester storage token - taskId: " + taskDescription.getChainTaskId()); - } - - @Test - void shouldGetPostComputeSignTokens() throws GeneralSecurityException { - final TeeSecretsSessionRequest sessionRequest = createSessionRequest(createTaskDescription(enclaveConfig)); - final TaskDescription taskDescription = sessionRequest.getTaskDescription(); - final String taskId = taskDescription.getChainTaskId(); - final EthereumCredentials credentials = EthereumCredentials.generate(); - - when(teeChallengeService.getOrCreate(taskId, true)) - .thenReturn(Optional.of(TeeChallenge.builder().credentials(credentials).build())); - - final Map tokens = assertDoesNotThrow(() -> teeSecretsService.getPostComputeSignTokens(sessionRequest)); - - assertThat(tokens) - .containsExactlyInAnyOrderEntriesOf( - Map.of( - RESULT_TASK_ID, taskId, - RESULT_SIGN_WORKER_ADDRESS, sessionRequest.getWorkerAddress(), - RESULT_SIGN_TEE_CHALLENGE_PRIVATE_KEY, credentials.getPrivateKey() - ) - ); - } - - @ParameterizedTest - @NullSource - @ValueSource(strings = {""}) - void shouldNotGetPostComputeSignTokensSinceNoWorkerAddress(String emptyWorkerAddress) { - final TeeSecretsSessionRequest sessionRequest = createSessionRequest(createTaskDescription(enclaveConfig)); - final String taskId = sessionRequest.getTaskDescription().getChainTaskId(); - sessionRequest.setWorkerAddress(emptyWorkerAddress); - - final TeeSessionGenerationException exception = assertThrows( - TeeSessionGenerationException.class, - () -> teeSecretsService.getPostComputeSignTokens(sessionRequest) - ); - - assertThat(exception.getError()).isEqualTo(POST_COMPUTE_GET_SIGNATURE_TOKENS_FAILED_EMPTY_WORKER_ADDRESS); - assertThat(exception.getMessage()).isEqualTo("Empty worker address - taskId: " + taskId); - } - - @ParameterizedTest - @NullSource - @ValueSource(strings = {""}) - void shouldNotGetPostComputeSignTokensSinceNoEnclaveChallenge(String emptyEnclaveChallenge) { - final TeeSecretsSessionRequest sessionRequest = createSessionRequest(createTaskDescription(enclaveConfig)); - final String taskId = sessionRequest.getTaskDescription().getChainTaskId(); - sessionRequest.setEnclaveChallenge(emptyEnclaveChallenge); - - final TeeSessionGenerationException exception = assertThrows( - TeeSessionGenerationException.class, - () -> teeSecretsService.getPostComputeSignTokens(sessionRequest) - ); - - assertThat(exception.getError()).isEqualTo(POST_COMPUTE_GET_SIGNATURE_TOKENS_FAILED_EMPTY_PUBLIC_ENCLAVE_CHALLENGE); - assertThat(exception.getMessage()).isEqualTo("Empty public enclave challenge - taskId: " + taskId); - } - - @Test - void shouldNotGetPostComputeSignTokensSinceNoTeeChallenge() { - final TeeSecretsSessionRequest sessionRequest = createSessionRequest(createTaskDescription(enclaveConfig)); - final String taskId = sessionRequest.getTaskDescription().getChainTaskId(); - - when(teeChallengeService.getOrCreate(taskId, true)) - .thenReturn(Optional.empty()); - - final TeeSessionGenerationException exception = assertThrows( - TeeSessionGenerationException.class, - () -> teeSecretsService.getPostComputeSignTokens(sessionRequest) - ); - - assertThat(exception.getError()).isEqualTo(POST_COMPUTE_GET_SIGNATURE_TOKENS_FAILED_EMPTY_TEE_CHALLENGE); - assertThat(exception.getMessage()).isEqualTo("Empty TEE challenge - taskId: " + taskId); - } - - @Test - void shouldNotGetPostComputeSignTokensSinceNoEnclaveCredentials() { - final TeeSecretsSessionRequest sessionRequest = createSessionRequest(createTaskDescription(enclaveConfig)); - final String taskId = sessionRequest.getTaskDescription().getChainTaskId(); - - when(teeChallengeService.getOrCreate(taskId, true)) - .thenReturn(Optional.of(TeeChallenge.builder().credentials(null).build())); - - final TeeSessionGenerationException exception = assertThrows( - TeeSessionGenerationException.class, - () -> teeSecretsService.getPostComputeSignTokens(sessionRequest) - ); - - assertThat(exception.getError()).isEqualTo(POST_COMPUTE_GET_SIGNATURE_TOKENS_FAILED_EMPTY_TEE_CREDENTIALS); - assertThat(exception.getMessage()).isEqualTo("Empty TEE challenge credentials - taskId: " + taskId); - } - - @Test - void shouldNotGetPostComputeSignTokensSinceNoEnclaveCredentialsPrivateKey() { - final TeeSecretsSessionRequest sessionRequest = createSessionRequest(createTaskDescription(enclaveConfig)); - final String taskId = sessionRequest.getTaskDescription().getChainTaskId(); - - when(teeChallengeService.getOrCreate(taskId, true)) - .thenReturn(Optional.of(TeeChallenge.builder().credentials(new EthereumCredentials("", "", false, "")).build())); - - final TeeSessionGenerationException exception = assertThrows( - TeeSessionGenerationException.class, - () -> teeSecretsService.getPostComputeSignTokens(sessionRequest) - ); - - assertThat(exception.getError()).isEqualTo(POST_COMPUTE_GET_SIGNATURE_TOKENS_FAILED_EMPTY_TEE_CREDENTIALS); - assertThat(exception.getMessage()).isEqualTo("Empty TEE challenge credentials - taskId: " + taskId); - } - - @Test - void shouldGetPostComputeEncryptionTokensWithEncryption() { - TeeSecretsSessionRequest request = createSessionRequest(createTaskDescription(enclaveConfig)); - - Secret publicKeySecret = new Secret("address", ENCRYPTION_PUBLIC_KEY); - when(web2SecretsService.getSecret( - request.getTaskDescription().getBeneficiary(), - IEXEC_RESULT_ENCRYPTION_PUBLIC_KEY, - true)) - .thenReturn(Optional.of(publicKeySecret)); - - final Map encryptionTokens = assertDoesNotThrow(() -> teeSecretsService.getPostComputeEncryptionTokens(request)); - assertThat(encryptionTokens) - .containsExactlyInAnyOrderEntriesOf( - Map.of( - RESULT_ENCRYPTION, "yes", - RESULT_ENCRYPTION_PUBLIC_KEY, ENCRYPTION_PUBLIC_KEY - ) - ); - } - - @Test - void shouldGetPostComputeEncryptionTokensWithoutEncryption() { - TeeSecretsSessionRequest request = createSessionRequest(createTaskDescription(enclaveConfig)); - request.getTaskDescription().setResultEncryption(false); - - final Map encryptionTokens = assertDoesNotThrow(() -> teeSecretsService.getPostComputeEncryptionTokens(request)); - assertThat(encryptionTokens) - .containsExactlyInAnyOrderEntriesOf( - Map.of( - RESULT_ENCRYPTION, "no", - RESULT_ENCRYPTION_PUBLIC_KEY, "" - ) - ); - } - - @Test - void shouldNotGetPostComputeEncryptionTokensSinceEmptyBeneficiaryKey() { - TeeSecretsSessionRequest request = createSessionRequest(createTaskDescription(enclaveConfig)); - - when(web2SecretsService.getSecret( - request.getTaskDescription().getBeneficiary(), - IEXEC_RESULT_ENCRYPTION_PUBLIC_KEY, - true)) - .thenReturn(Optional.empty()); - - final TeeSessionGenerationException exception = assertThrows( - TeeSessionGenerationException.class, - () -> teeSecretsService.getPostComputeEncryptionTokens(request) - ); - assertEquals(POST_COMPUTE_GET_ENCRYPTION_TOKENS_FAILED_EMPTY_BENEFICIARY_KEY, exception.getError()); - assertEquals("Empty beneficiary encryption key - taskId: taskId", exception.getMessage()); - } - - //endregion - - //region utils - private void addApplicationDeveloperSecret(String appAddress) { - TeeTaskComputeSecret applicationDeveloperSecret = getApplicationDeveloperSecret(appAddress); - when(teeTaskComputeSecretService.getSecret(OnChainObjectType.APPLICATION, appAddress, SecretOwnerRole.APPLICATION_DEVELOPER, "", APP_DEVELOPER_SECRET_INDEX)) - .thenReturn(Optional.of(applicationDeveloperSecret)); - } - - private void addRequesterSecret(String requesterAddress, String secretKey, String secretValue) { - TeeTaskComputeSecret requesterSecret = getRequesterSecret(requesterAddress, secretKey, secretValue); - when(teeTaskComputeSecretService.getSecret(OnChainObjectType.APPLICATION, "", SecretOwnerRole.REQUESTER, requesterAddress, secretKey)) - .thenReturn(Optional.of(requesterSecret)); - } - //endregion - - */ -} \ No newline at end of file From ae0fe99b2d1d97ed6cfd38b03f36ec183b2c3351 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20James=20Toussaint?= Date: Fri, 29 Jul 2022 16:35:21 +0200 Subject: [PATCH 022/293] Refactor lombok builder calls --- .../gramine/GramineSessionHandlerService.java | 2 +- .../gramine/GramineSessionMakerService.java | 29 +++++++++---------- .../session/gramine/sps/SpsConfiguration.java | 2 +- .../scone/SconeSessionMakerService.java | 8 ++--- .../GramineSessionHandlerServiceTests.java | 4 +-- .../scone/SconeSessionMakerServiceTests.java | 2 +- 6 files changed, 22 insertions(+), 25 deletions(-) diff --git a/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerService.java b/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerService.java index 98336779..392e4247 100644 --- a/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerService.java +++ b/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerService.java @@ -59,7 +59,7 @@ public String buildAndPostSession(TeeSessionRequest request) } try { - spsConfiguration.getInstanceWithBasicAuth().postSession(session); + spsConfiguration.getInstance().postSession(session); return spsConfiguration.getEnclaveUrl(); } catch (Exception e) { throw new TeeSessionGenerationException( diff --git a/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerService.java b/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerService.java index 552befdc..0ca4b04b 100644 --- a/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerService.java +++ b/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerService.java @@ -22,13 +22,11 @@ import com.iexec.sms.tee.session.generic.TeeSessionGenerationException; import com.iexec.sms.tee.session.generic.TeeSessionRequest; import com.iexec.sms.tee.session.gramine.sps.SpsEnclave; -import com.iexec.sms.tee.session.gramine.sps.SpsEnclave.SpsEnclaveBuilder; import com.iexec.sms.tee.session.gramine.sps.SpsSession; import com.iexec.sms.tee.session.gramine.sps.SpsSession.SpsSessionBuilder; import com.iexec.sms.tee.workflow.TeeWorkflowConfiguration; import org.springframework.stereotype.Service; -import java.util.Arrays; import java.util.List; @Service @@ -52,31 +50,30 @@ public GramineSessionMakerService(SecretSessionBaseService secretSessionBaseServ */ public SpsSession generateSession(TeeSessionRequest request) throws TeeSessionGenerationException { SecretSessionBase baseSession = secretSessionBaseService.getSecretsTokens(request); - SpsSessionBuilder spsSession = SpsSession.builder(); - spsSession.session(request.getSessionId()); - SpsEnclave spsAppEnclave = toSpsSessionEnclave(baseSession.getAppCompute()); + SpsSessionBuilder spsSession = SpsSession.builder() + .session(request.getSessionId()); + SpsEnclave spsAppEnclave = toSpsEnclave(baseSession.getAppCompute()); spsAppEnclave.setCommand(request.getTaskDescription().getAppCommand()); - SpsEnclave spsPostEnclave = toSpsSessionEnclave(baseSession.getPostCompute()); - spsPostEnclave.setMrenclave(teeWorkflowConfiguration.getPostComputeFingerprint()); + SpsEnclave spsPostEnclave = toSpsEnclave(baseSession.getPostCompute()); spsPostEnclave.setCommand(teeWorkflowConfiguration.getPostComputeEntrypoint()); // TODO: Remove useless volumes when SPS is ready spsAppEnclave.setVolumes(List.of()); spsPostEnclave.setVolumes(List.of()); - spsSession.enclaves(Arrays.asList( + return spsSession.enclaves(List.of( // No pre-compute for now spsAppEnclave, - spsPostEnclave)); - return spsSession.build(); + spsPostEnclave)) + .build(); } - private SpsEnclave toSpsSessionEnclave(SecretEnclaveBase enclaveBase) { - SpsEnclaveBuilder spsEnclave = SpsEnclave.builder(); - spsEnclave.name(enclaveBase.getName()); - spsEnclave.mrenclave(enclaveBase.getMrenclave()); - spsEnclave.environment(enclaveBase.getEnvironment()); - return spsEnclave.build(); + private SpsEnclave toSpsEnclave(SecretEnclaveBase enclaveBase) { + return SpsEnclave.builder() + .name(enclaveBase.getName()) + .mrenclave(enclaveBase.getMrenclave()) + .environment(enclaveBase.getEnvironment()) + .build(); } } diff --git a/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsConfiguration.java b/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsConfiguration.java index 2a45dcad..e0bd2a5c 100644 --- a/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsConfiguration.java +++ b/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsConfiguration.java @@ -53,7 +53,7 @@ public String getEnclaveUrl() { return "https://" + enclaveHost + ":" + enclavePort; } - public SpsApiClient getInstanceWithBasicAuth() { + public SpsApiClient getInstance() { if (spsApiClient == null) { spsApiClient = FeignBuilder.createBuilderWithBasicAuth(Level.FULL, webLogin, webPassword) diff --git a/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionMakerService.java b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionMakerService.java index 83fb93a9..57aeaaa6 100644 --- a/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionMakerService.java +++ b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionMakerService.java @@ -79,11 +79,11 @@ public SconeSessionMakerService( public CasSession generateSession(TeeSessionRequest request) throws TeeSessionGenerationException { SecretSessionBase baseSession = secretSessionBaseService.getSecretsTokens(request); - CasEnclave casPreEnclave = toCasSessionEnclave(baseSession.getPreCompute()); + CasEnclave casPreEnclave = toCasEnclave(baseSession.getPreCompute()); casPreEnclave.setCommand(teeWorkflowConfig.getPreComputeEntrypoint()); - CasEnclave casAppEnclave = toCasSessionEnclave(baseSession.getAppCompute()); + CasEnclave casAppEnclave = toCasEnclave(baseSession.getAppCompute()); casAppEnclave.setCommand(request.getTaskDescription().getAppCommand()); - CasEnclave casPostEnclave = toCasSessionEnclave(baseSession.getPostCompute()); + CasEnclave casPostEnclave = toCasEnclave(baseSession.getPostCompute()); casPostEnclave.setCommand(teeWorkflowConfig.getPostComputeEntrypoint()); addJavaEnvVars(casPreEnclave); @@ -129,7 +129,7 @@ private void addJavaEnvVars(CasEnclave casSessionEnclave) { casSessionEnclave.setEnvironment(newEnvironment); } - private CasEnclave toCasSessionEnclave(SecretEnclaveBase enclaveBase) { + private CasEnclave toCasEnclave(SecretEnclaveBase enclaveBase) { return CasEnclave.builder() .name(enclaveBase.getName()) .imageName(enclaveBase.getName() + "-image") diff --git a/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerServiceTests.java b/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerServiceTests.java index 23101fe8..e82e2ae7 100644 --- a/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerServiceTests.java @@ -70,7 +70,7 @@ void shouldBuildAndPostSession(CapturedOutput output) throws TeeSessionGeneratio when(teeSessionLogConfiguration.isDisplayDebugSessionEnabled()).thenReturn(true); SpsApiClient spsClient = mock(SpsApiClient.class); when(spsClient.postSession(spsSession)).thenReturn("sessionId"); - when(spsConfiguration.getInstanceWithBasicAuth()).thenReturn(spsClient); + when(spsConfiguration.getInstance()).thenReturn(spsClient); assertEquals(SPS_URL, sessionHandlerService.buildAndPostSession(request)); // Testing output here since it reflects a business feature (ability to catch a @@ -101,7 +101,7 @@ void shouldNotBuildAndPostSessionSincePostSessionFailed() when(sessionService.generateSession(request)).thenReturn(spsSession); when(teeSessionLogConfiguration.isDisplayDebugSessionEnabled()).thenReturn(true); SpsApiClient spsClient = mock(SpsApiClient.class); - when(spsConfiguration.getInstanceWithBasicAuth()).thenReturn(spsClient); + when(spsConfiguration.getInstance()).thenReturn(spsClient); FeignException apiClientException = mock(FeignException.class); when(spsClient.postSession(spsSession)).thenThrow(apiClientException); diff --git a/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionMakerServiceTests.java b/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionMakerServiceTests.java index cc126d92..8a92094c 100644 --- a/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionMakerServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionMakerServiceTests.java @@ -76,7 +76,7 @@ void shouldGetSessionYml() throws Exception { SecretEnclaveBase preCompute = SecretEnclaveBase.builder() .name("pre-compute") .mrenclave("mrEnclave1") - .environment(Map.ofEntries( // Map of until 10 + .environment(Map.ofEntries( // Keeping these test env vars for now // (could be less but keeping same resource file for now) Map.entry("IEXEC_TASK_ID", "taskId"), From 03e86a24c593a0c12a4ef98976276c431c385231 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20James=20Toussaint?= Date: Fri, 29 Jul 2022 16:46:34 +0200 Subject: [PATCH 023/293] Update enclave config wording --- .../gramine/GramineSessionHandlerService.java | 4 +- .../gramine/GramineSessionMakerService.java | 32 ++++++------ .../{SpsEnclave.java => GramineEnclave.java} | 2 +- .../{SpsSession.java => GramineSession.java} | 4 +- .../tee/session/gramine/sps/SpsApiClient.java | 2 +- .../scone/SconeSessionHandlerService.java | 4 +- .../scone/SconeSessionMakerService.java | 51 ++++++++++--------- .../{CasEnclave.java => SconeEnclave.java} | 2 +- .../{CasSession.java => SconeSession.java} | 4 +- .../GramineSessionHandlerServiceTests.java | 6 +-- .../GramineSessionMakerServiceTests.java | 4 +- .../SconeSessionHandlerServiceTests.java | 6 +-- .../scone/SconeSessionMakerServiceTests.java | 4 +- 13 files changed, 63 insertions(+), 62 deletions(-) rename src/main/java/com/iexec/sms/tee/session/gramine/sps/{SpsEnclave.java => GramineEnclave.java} (97%) rename src/main/java/com/iexec/sms/tee/session/gramine/sps/{SpsSession.java => GramineSession.java} (94%) rename src/main/java/com/iexec/sms/tee/session/scone/cas/{CasEnclave.java => SconeEnclave.java} (98%) rename src/main/java/com/iexec/sms/tee/session/scone/cas/{CasSession.java => SconeSession.java} (97%) diff --git a/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerService.java b/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerService.java index 392e4247..9181425c 100644 --- a/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerService.java +++ b/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerService.java @@ -21,8 +21,8 @@ import com.iexec.sms.tee.session.generic.TeeSessionGenerationException; import com.iexec.sms.tee.session.generic.TeeSessionHandler; import com.iexec.sms.tee.session.generic.TeeSessionRequest; +import com.iexec.sms.tee.session.gramine.sps.GramineSession; import com.iexec.sms.tee.session.gramine.sps.SpsConfiguration; -import com.iexec.sms.tee.session.gramine.sps.SpsSession; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @@ -51,7 +51,7 @@ public GramineSessionHandlerService(GramineSessionMakerService sessionService, @Override public String buildAndPostSession(TeeSessionRequest request) throws TeeSessionGenerationException { - SpsSession session = sessionService.generateSession(request); + GramineSession session = sessionService.generateSession(request); if (session != null && teeSessionLogConfiguration.isDisplayDebugSessionEnabled()) { log.info("Session content [taskId:{}]\n{}", diff --git a/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerService.java b/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerService.java index 0ca4b04b..f6616e73 100644 --- a/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerService.java +++ b/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerService.java @@ -21,9 +21,9 @@ import com.iexec.sms.tee.session.base.SecretSessionBaseService; import com.iexec.sms.tee.session.generic.TeeSessionGenerationException; import com.iexec.sms.tee.session.generic.TeeSessionRequest; -import com.iexec.sms.tee.session.gramine.sps.SpsEnclave; -import com.iexec.sms.tee.session.gramine.sps.SpsSession; -import com.iexec.sms.tee.session.gramine.sps.SpsSession.SpsSessionBuilder; +import com.iexec.sms.tee.session.gramine.sps.GramineEnclave; +import com.iexec.sms.tee.session.gramine.sps.GramineSession; +import com.iexec.sms.tee.session.gramine.sps.GramineSession.GramineSessionBuilder; import com.iexec.sms.tee.workflow.TeeWorkflowConfiguration; import org.springframework.stereotype.Service; @@ -48,28 +48,28 @@ public GramineSessionMakerService(SecretSessionBaseService secretSessionBaseServ * @param request session request details * @return session config */ - public SpsSession generateSession(TeeSessionRequest request) throws TeeSessionGenerationException { + public GramineSession generateSession(TeeSessionRequest request) throws TeeSessionGenerationException { SecretSessionBase baseSession = secretSessionBaseService.getSecretsTokens(request); - SpsSessionBuilder spsSession = SpsSession.builder() + GramineSessionBuilder gramineSession = GramineSession.builder() .session(request.getSessionId()); - SpsEnclave spsAppEnclave = toSpsEnclave(baseSession.getAppCompute()); - spsAppEnclave.setCommand(request.getTaskDescription().getAppCommand()); - SpsEnclave spsPostEnclave = toSpsEnclave(baseSession.getPostCompute()); - spsPostEnclave.setCommand(teeWorkflowConfiguration.getPostComputeEntrypoint()); + GramineEnclave gramineAppEnclave = toGramineEnclave(baseSession.getAppCompute()); + gramineAppEnclave.setCommand(request.getTaskDescription().getAppCommand()); + GramineEnclave graminePostEnclave = toGramineEnclave(baseSession.getPostCompute()); + graminePostEnclave.setCommand(teeWorkflowConfiguration.getPostComputeEntrypoint()); // TODO: Remove useless volumes when SPS is ready - spsAppEnclave.setVolumes(List.of()); - spsPostEnclave.setVolumes(List.of()); + gramineAppEnclave.setVolumes(List.of()); + graminePostEnclave.setVolumes(List.of()); - return spsSession.enclaves(List.of( + return gramineSession.enclaves(List.of( // No pre-compute for now - spsAppEnclave, - spsPostEnclave)) + gramineAppEnclave, + graminePostEnclave)) .build(); } - private SpsEnclave toSpsEnclave(SecretEnclaveBase enclaveBase) { - return SpsEnclave.builder() + private GramineEnclave toGramineEnclave(SecretEnclaveBase enclaveBase) { + return GramineEnclave.builder() .name(enclaveBase.getName()) .mrenclave(enclaveBase.getMrenclave()) .environment(enclaveBase.getEnvironment()) diff --git a/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsEnclave.java b/src/main/java/com/iexec/sms/tee/session/gramine/sps/GramineEnclave.java similarity index 97% rename from src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsEnclave.java rename to src/main/java/com/iexec/sms/tee/session/gramine/sps/GramineEnclave.java index 33ff4915..35f78060 100644 --- a/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsEnclave.java +++ b/src/main/java/com/iexec/sms/tee/session/gramine/sps/GramineEnclave.java @@ -27,7 +27,7 @@ @Setter @AllArgsConstructor @NoArgsConstructor -public class SpsEnclave { +public class GramineEnclave { @JsonProperty("name") private String name; diff --git a/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsSession.java b/src/main/java/com/iexec/sms/tee/session/gramine/sps/GramineSession.java similarity index 94% rename from src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsSession.java rename to src/main/java/com/iexec/sms/tee/session/gramine/sps/GramineSession.java index d2ea9d40..36c12edc 100644 --- a/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsSession.java +++ b/src/main/java/com/iexec/sms/tee/session/gramine/sps/GramineSession.java @@ -30,12 +30,12 @@ @Setter @AllArgsConstructor @NoArgsConstructor -public class SpsSession { +public class GramineSession { @JsonProperty("session") private String session; @JsonProperty("enclaves") - private List enclaves; + private List enclaves; @Override public String toString() { diff --git a/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsApiClient.java b/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsApiClient.java index 794b2aa2..daff5d02 100644 --- a/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsApiClient.java +++ b/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsApiClient.java @@ -21,6 +21,6 @@ public interface SpsApiClient { @RequestLine("POST /api/session") - String postSession(SpsSession spsSession); + String postSession(GramineSession spsSession); } diff --git a/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerService.java b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerService.java index 338e5177..a5b0387d 100644 --- a/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerService.java +++ b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerService.java @@ -23,7 +23,7 @@ import com.iexec.sms.tee.session.generic.TeeSessionRequest; import com.iexec.sms.tee.session.scone.cas.CasClient; import com.iexec.sms.tee.session.scone.cas.CasConfiguration; -import com.iexec.sms.tee.session.scone.cas.CasSession; +import com.iexec.sms.tee.session.scone.cas.SconeSession; import lombok.extern.slf4j.Slf4j; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; @@ -56,7 +56,7 @@ public SconeSessionHandlerService(SconeSessionMakerService sessionService, @Override public String buildAndPostSession(TeeSessionRequest request) throws TeeSessionGenerationException { - CasSession session = sessionService.generateSession(request); + SconeSession session = sessionService.generateSession(request); if (session != null && teeSessionLogConfiguration.isDisplayDebugSessionEnabled()) { log.info("Session content [taskId:{}]\n{}", diff --git a/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionMakerService.java b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionMakerService.java index 57aeaaa6..70d4292f 100644 --- a/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionMakerService.java +++ b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionMakerService.java @@ -21,12 +21,12 @@ import com.iexec.sms.tee.session.base.SecretSessionBaseService; import com.iexec.sms.tee.session.generic.TeeSessionGenerationException; import com.iexec.sms.tee.session.generic.TeeSessionRequest; -import com.iexec.sms.tee.session.scone.cas.CasEnclave; -import com.iexec.sms.tee.session.scone.cas.CasSession; -import com.iexec.sms.tee.session.scone.cas.CasSession.AccessPolicy; -import com.iexec.sms.tee.session.scone.cas.CasSession.Image.Volume; -import com.iexec.sms.tee.session.scone.cas.CasSession.Security; -import com.iexec.sms.tee.session.scone.cas.CasSession.Volumes; +import com.iexec.sms.tee.session.scone.cas.SconeEnclave; +import com.iexec.sms.tee.session.scone.cas.SconeSession; +import com.iexec.sms.tee.session.scone.cas.SconeSession.AccessPolicy; +import com.iexec.sms.tee.session.scone.cas.SconeSession.Image.Volume; +import com.iexec.sms.tee.session.scone.cas.SconeSession.Security; +import com.iexec.sms.tee.session.scone.cas.SconeSession.Volumes; import com.iexec.sms.tee.workflow.TeeWorkflowConfiguration; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -76,26 +76,26 @@ public SconeSessionMakerService( * @param request session request details * @return session config in yaml string format */ - public CasSession generateSession(TeeSessionRequest request) throws TeeSessionGenerationException { + public SconeSession generateSession(TeeSessionRequest request) throws TeeSessionGenerationException { SecretSessionBase baseSession = secretSessionBaseService.getSecretsTokens(request); - CasEnclave casPreEnclave = toCasEnclave(baseSession.getPreCompute()); - casPreEnclave.setCommand(teeWorkflowConfig.getPreComputeEntrypoint()); - CasEnclave casAppEnclave = toCasEnclave(baseSession.getAppCompute()); - casAppEnclave.setCommand(request.getTaskDescription().getAppCommand()); - CasEnclave casPostEnclave = toCasEnclave(baseSession.getPostCompute()); - casPostEnclave.setCommand(teeWorkflowConfig.getPostComputeEntrypoint()); + SconeEnclave sconePreEnclave = toSconeEnclave(baseSession.getPreCompute()); + sconePreEnclave.setCommand(teeWorkflowConfig.getPreComputeEntrypoint()); + SconeEnclave sconeAppEnclave = toSconeEnclave(baseSession.getAppCompute()); + sconeAppEnclave.setCommand(request.getTaskDescription().getAppCommand()); + SconeEnclave sconePostEnclave = toSconeEnclave(baseSession.getPostCompute()); + sconePostEnclave.setCommand(teeWorkflowConfig.getPostComputeEntrypoint()); - addJavaEnvVars(casPreEnclave); - addJavaEnvVars(casPostEnclave); + addJavaEnvVars(sconePreEnclave); + addJavaEnvVars(sconePostEnclave); List policy = Arrays.asList("CREATOR"); - CasSession casSession = CasSession.builder() + SconeSession casSession = SconeSession.builder() .name(request.getSessionId()) .version("0.3") .accessPolicy(new AccessPolicy(policy, policy)) - .services(Arrays.asList(casPreEnclave, casAppEnclave, casPostEnclave)) + .services(Arrays.asList(sconePreEnclave, sconeAppEnclave, sconePostEnclave)) .security(new Security(attestationSecurityConfig.getToleratedInsecureOptions(), attestationSecurityConfig.getIgnoredSgxAdvisories())) .build(); @@ -110,27 +110,28 @@ public CasSession generateSession(TeeSessionRequest request) throws TeeSessionGe new Volumes(postComputeTmpVolume.getName()))); casSession.setImages(Arrays.asList( - new CasSession.Image(casPreEnclave.getImageName(), Arrays.asList(iexecInVolume)), - new CasSession.Image(casAppEnclave.getImageName(), Arrays.asList(iexecInVolume, iexecOutVolume)), - new CasSession.Image(casPostEnclave.getImageName(), Arrays.asList(iexecOutVolume, postComputeTmpVolume)) + new SconeSession.Image(sconePreEnclave.getImageName(), Arrays.asList(iexecInVolume)), + new SconeSession.Image(sconeAppEnclave.getImageName(), Arrays.asList(iexecInVolume, iexecOutVolume)), + new SconeSession.Image(sconePostEnclave.getImageName(), + Arrays.asList(iexecOutVolume, postComputeTmpVolume)) )); return casSession; } - private void addJavaEnvVars(CasEnclave casSessionEnclave) { + private void addJavaEnvVars(SconeEnclave sconeEnclave) { Map additionalJavaEnv = Map.of("LD_LIBRARY_PATH", "/usr/lib/jvm/java-11-openjdk/lib/server:/usr/lib/jvm/java-11-openjdk/lib:/usr/lib/jvm/java-11-openjdk/../lib", "JAVA_TOOL_OPTIONS", "-Xmx256m"); HashMap newEnvironment = new HashMap<>(); - newEnvironment.putAll(casSessionEnclave.getEnvironment()); + newEnvironment.putAll(sconeEnclave.getEnvironment()); newEnvironment.putAll(additionalJavaEnv); - casSessionEnclave.setEnvironment(newEnvironment); + sconeEnclave.setEnvironment(newEnvironment); } - private CasEnclave toCasEnclave(SecretEnclaveBase enclaveBase) { - return CasEnclave.builder() + private SconeEnclave toSconeEnclave(SecretEnclaveBase enclaveBase) { + return SconeEnclave.builder() .name(enclaveBase.getName()) .imageName(enclaveBase.getName() + "-image") .mrenclaves(Arrays.asList(enclaveBase.getMrenclave())) diff --git a/src/main/java/com/iexec/sms/tee/session/scone/cas/CasEnclave.java b/src/main/java/com/iexec/sms/tee/session/scone/cas/SconeEnclave.java similarity index 98% rename from src/main/java/com/iexec/sms/tee/session/scone/cas/CasEnclave.java rename to src/main/java/com/iexec/sms/tee/session/scone/cas/SconeEnclave.java index 5fd09d23..f41709c0 100644 --- a/src/main/java/com/iexec/sms/tee/session/scone/cas/CasEnclave.java +++ b/src/main/java/com/iexec/sms/tee/session/scone/cas/SconeEnclave.java @@ -31,7 +31,7 @@ @Setter @AllArgsConstructor @NoArgsConstructor -public class CasEnclave { +public class SconeEnclave { @JsonProperty("name") private String name; diff --git a/src/main/java/com/iexec/sms/tee/session/scone/cas/CasSession.java b/src/main/java/com/iexec/sms/tee/session/scone/cas/SconeSession.java similarity index 97% rename from src/main/java/com/iexec/sms/tee/session/scone/cas/CasSession.java rename to src/main/java/com/iexec/sms/tee/session/scone/cas/SconeSession.java index d93def5f..7f837e04 100644 --- a/src/main/java/com/iexec/sms/tee/session/scone/cas/CasSession.java +++ b/src/main/java/com/iexec/sms/tee/session/scone/cas/SconeSession.java @@ -30,7 +30,7 @@ @Setter @AllArgsConstructor @NoArgsConstructor -public class CasSession { +public class SconeSession { @JsonProperty("name") private String name; @@ -39,7 +39,7 @@ public class CasSession { @JsonProperty("access_policy") private AccessPolicy accessPolicy; @JsonProperty("services") - private List services; + private List services; @JsonProperty("images") private List images; @JsonProperty("volumes") diff --git a/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerServiceTests.java b/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerServiceTests.java index e82e2ae7..439a6065 100644 --- a/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerServiceTests.java @@ -21,9 +21,9 @@ import com.iexec.sms.tee.session.TeeSessionLogConfiguration; import com.iexec.sms.tee.session.generic.TeeSessionGenerationException; import com.iexec.sms.tee.session.generic.TeeSessionRequest; +import com.iexec.sms.tee.session.gramine.sps.GramineSession; import com.iexec.sms.tee.session.gramine.sps.SpsApiClient; import com.iexec.sms.tee.session.gramine.sps.SpsConfiguration; -import com.iexec.sms.tee.session.gramine.sps.SpsSession; import feign.FeignException; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -64,7 +64,7 @@ void shouldBuildAndPostSession(CapturedOutput output) throws TeeSessionGeneratio TeeSessionRequest request = mock(TeeSessionRequest.class); TaskDescription taskDescription = mock(TaskDescription.class); when(request.getTaskDescription()).thenReturn(taskDescription); - SpsSession spsSession = mock(SpsSession.class); + GramineSession spsSession = mock(GramineSession.class); when(spsSession.toString()).thenReturn("sessionContent"); when(sessionService.generateSession(request)).thenReturn(spsSession); when(teeSessionLogConfiguration.isDisplayDebugSessionEnabled()).thenReturn(true); @@ -96,7 +96,7 @@ void shouldNotBuildAndPostSessionSincePostSessionFailed() TeeSessionRequest request = mock(TeeSessionRequest.class); TaskDescription taskDescription = mock(TaskDescription.class); when(request.getTaskDescription()).thenReturn(taskDescription); - SpsSession spsSession = mock(SpsSession.class); + GramineSession spsSession = mock(GramineSession.class); when(spsSession.toString()).thenReturn("sessionContent"); when(sessionService.generateSession(request)).thenReturn(spsSession); when(teeSessionLogConfiguration.isDisplayDebugSessionEnabled()).thenReturn(true); diff --git a/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerServiceTests.java b/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerServiceTests.java index b4df5968..87930adb 100644 --- a/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerServiceTests.java @@ -6,7 +6,7 @@ import com.iexec.sms.tee.session.base.SecretSessionBase; import com.iexec.sms.tee.session.base.SecretSessionBaseService; import com.iexec.sms.tee.session.generic.TeeSessionRequest; -import com.iexec.sms.tee.session.gramine.sps.SpsSession; +import com.iexec.sms.tee.session.gramine.sps.GramineSession; import com.iexec.sms.tee.workflow.TeeWorkflowConfiguration; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.BeforeEach; @@ -85,7 +85,7 @@ void shouldGetSessionJson() throws Exception { .postCompute(postCompute) .build()); - SpsSession actualSpsSession = gramineSessionService.generateSession(request); + GramineSession actualSpsSession = gramineSessionService.generateSession(request); log.info(actualSpsSession.toString()); Map actualJsonMap = new Yaml().load(actualSpsSession.toString()); String expectedJsonString = FileHelper.readFile("src/test/resources/gramine-tee-session.json"); diff --git a/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerServiceTests.java b/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerServiceTests.java index 6d3d93de..cb2e47fb 100644 --- a/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerServiceTests.java @@ -7,7 +7,7 @@ import com.iexec.sms.tee.session.generic.TeeSessionRequest; import com.iexec.sms.tee.session.scone.cas.CasClient; import com.iexec.sms.tee.session.scone.cas.CasConfiguration; -import com.iexec.sms.tee.session.scone.cas.CasSession; +import com.iexec.sms.tee.session.scone.cas.SconeSession; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -50,7 +50,7 @@ void shouldBuildAndPostSession(CapturedOutput output) throws TeeSessionGeneratio TeeSessionRequest request = mock(TeeSessionRequest.class); TaskDescription taskDescription = mock(TaskDescription.class); when(request.getTaskDescription()).thenReturn(taskDescription); - CasSession casSession = mock(CasSession.class); + SconeSession casSession = mock(SconeSession.class); when(casSession.toString()).thenReturn("sessionContent"); when(sessionService.generateSession(request)).thenReturn(casSession); when(teeSessionLogConfiguration.isDisplayDebugSessionEnabled()).thenReturn(true); @@ -80,7 +80,7 @@ void shouldNotBuildAndPostSessionSincePostSessionFailed() TeeSessionRequest request = mock(TeeSessionRequest.class); TaskDescription taskDescription = mock(TaskDescription.class); when(request.getTaskDescription()).thenReturn(taskDescription); - CasSession casSession = mock(CasSession.class); + SconeSession casSession = mock(SconeSession.class); when(sessionService.generateSession(request)).thenReturn(casSession); when(teeSessionLogConfiguration.isDisplayDebugSessionEnabled()).thenReturn(true); when(apiClient.postSession(casSession.toString())).thenReturn(ResponseEntity.internalServerError().build()); diff --git a/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionMakerServiceTests.java b/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionMakerServiceTests.java index 8a92094c..2d599aa3 100644 --- a/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionMakerServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionMakerServiceTests.java @@ -22,7 +22,7 @@ import com.iexec.sms.tee.session.base.SecretSessionBase; import com.iexec.sms.tee.session.base.SecretSessionBaseService; import com.iexec.sms.tee.session.generic.TeeSessionRequest; -import com.iexec.sms.tee.session.scone.cas.CasSession; +import com.iexec.sms.tee.session.scone.cas.SconeSession; import com.iexec.sms.tee.workflow.TeeWorkflowConfiguration; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.BeforeEach; @@ -142,7 +142,7 @@ void shouldGetSessionYml() throws Exception { .postCompute(postCompute) .build()); - CasSession actualCasSession = palaemonSessionService.generateSession(request); + SconeSession actualCasSession = palaemonSessionService.generateSession(request); System.out.println(actualCasSession.toString()); Map actualYmlMap = new Yaml().load(actualCasSession.toString()); String expectedYamlString = FileHelper.readFile("src/test/resources/palaemon-tee-session.yml"); From a8fd668b044a50bbc7aa93a55590ccd13d6acf0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20James=20Toussaint?= Date: Fri, 29 Jul 2022 16:54:14 +0200 Subject: [PATCH 024/293] Remove useless gramine session vm --- src/main/resources/Dockerfile.untrusted | 1 - .../resources/gramineSessionTemplate.json.vm | 53 ------------------- 2 files changed, 54 deletions(-) delete mode 100644 src/main/resources/gramineSessionTemplate.json.vm diff --git a/src/main/resources/Dockerfile.untrusted b/src/main/resources/Dockerfile.untrusted index c315d756..912dfe65 100644 --- a/src/main/resources/Dockerfile.untrusted +++ b/src/main/resources/Dockerfile.untrusted @@ -7,7 +7,6 @@ RUN test -n "$jar" COPY $jar /app/iexec-sms.jar COPY src/main/resources/ssl-keystore-dev.p12 /app/ssl-keystore-dev.p12 -ENV IEXEC_SMS_SSL_KEYSTORE=/app/ssl-keystore-dev.p12 ENV IEXEC_SMS_SSL_KEYSTORE=/app/ssl-keystore-dev.p12 ENV IEXEC_SMS_STORAGE_ENCRYPTION_AES_KEY_PATH=/scone/iexec-sms-aes.key ENV IEXEC_SMS_BLOCKCHAIN_NODE_ADDRESS=http://chain:8545 diff --git a/src/main/resources/gramineSessionTemplate.json.vm b/src/main/resources/gramineSessionTemplate.json.vm deleted file mode 100644 index 970ce651..00000000 --- a/src/main/resources/gramineSessionTemplate.json.vm +++ /dev/null @@ -1,53 +0,0 @@ -{ - "session": "$SESSION_ID", - "enclaves": [ - { - "name": "app", - "mrenclave": "$APP_MRENCLAVE", - "command": "/apploader.sh", - "environment": { - "IEXEC_TASK_ID": "$env.get('IEXEC_TASK_ID')", - "IEXEC_IN": "$env.get('IEXEC_IN')", - "IEXEC_OUT": "$env.get('IEXEC_OUT')", - "IEXEC_DATASET_ADDRESS": "$env.get('IEXEC_DATASET_ADDRESS')", - "IEXEC_DATASET_FILENAME": "$env.get('IEXEC_DATASET_FILENAME')", - "IEXEC_BOT_SIZE": "$env.get('IEXEC_BOT_SIZE')", - "IEXEC_BOT_FIRST_INDEX": "$env.get('IEXEC_BOT_FIRST_INDEX')", - "IEXEC_BOT_TASK_INDEX": "$env.get('IEXEC_BOT_TASK_INDEX')", - "IEXEC_INPUT_FILES_FOLDER": "$env.get('IEXEC_INPUT_FILES_FOLDER')", - "IEXEC_INPUT_FILES_NUMBER": "$env.get('IEXEC_INPUT_FILES_NUMBER')", - #foreach($key in $INPUT_FILE_NAMES.keySet()) - "$key": "$INPUT_FILE_NAMES.get($key)", - #end - #foreach($key in $REQUESTER_SECRETS.keySet()) - "$key": "$REQUESTER_SECRETS.get($key)", - #end - "IEXEC_APP_DEVELOPER_SECRET": "$IEXEC_APP_DEVELOPER_SECRET_1", - "IEXEC_APP_DEVELOPER_SECRET_1": "$IEXEC_APP_DEVELOPER_SECRET_1" - }, - "volumes": [ - "$env.get('IEXEC_IN')", - "$env.get('IEXEC_OUT')" - ] - }, - { - "name": "Post Compute", - "mrenclave": "$POST_COMPUTE_MRENCLAVE", - "command": "/apploader.sh", - "environment": { - "RESULT_TASK_ID": "$RESULT_TASK_ID", - "RESULT_ENCRYPTION": "$RESULT_ENCRYPTION", - "RESULT_ENCRYPTION_PUBLIC_KEY": "$RESULT_ENCRYPTION_PUBLIC_KEY", - "RESULT_STORAGE_PROVIDER": "$RESULT_STORAGE_PROVIDER", - "RESULT_STORAGE_PROXY": "$RESULT_STORAGE_PROXY", - "RESULT_STORAGE_TOKEN": "$RESULT_STORAGE_TOKEN", - "RESULT_STORAGE_CALLBACK": "$RESULT_STORAGE_CALLBACK", - "RESULT_SIGN_WORKER_ADDRESS": "$RESULT_SIGN_WORKER_ADDRESS", - "RESULT_SIGN_TEE_CHALLENGE_PRIVATE_KEY": "$RESULT_SIGN_TEE_CHALLENGE_PRIVATE_KEY" - }, - "volumes": [ - "$env.get('IEXEC_OUT')" - ] - } - ] -} \ No newline at end of file From b78eb41c576211985d1433cc804160d433fa8c14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20James=20Toussaint?= Date: Mon, 8 Aug 2022 14:14:02 +0200 Subject: [PATCH 025/293] Lint build.gradle --- build.gradle | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/build.gradle b/build.gradle index 5fefb0bf..5ff4c001 100644 --- a/build.gradle +++ b/build.gradle @@ -25,17 +25,17 @@ allprojects { mavenLocal() mavenCentral() maven { - url "https://docker-regis-adm.iex.ec/repository/maven-public/" + url 'https://docker-regis-adm.iex.ec/repository/maven-public/' credentials { username nexusUser password nexusPassword } } maven { - url "https://nexus.intra.iex.ec/repository/maven-public/" + url 'https://nexus.intra.iex.ec/repository/maven-public/' } maven { - url "https://jitpack.io" + url 'https://jitpack.io' } } } @@ -57,10 +57,10 @@ dependencies { implementation project(':iexec-sms-library') // spring - implementation "org.springframework.boot:spring-boot-starter-web" - implementation "org.springframework.cloud:spring-cloud-starter-openfeign" - implementation "org.springframework.retry:spring-retry" - implementation "org.springframework.cloud:spring-cloud-starter-openfeign" + implementation 'org.springframework.boot:spring-boot-starter-web' + implementation 'org.springframework.cloud:spring-cloud-starter-openfeign' + implementation 'org.springframework.retry:spring-retry' + implementation 'org.springframework.cloud:spring-cloud-starter-openfeign' implementation 'org.springframework.boot:spring-boot-starter-validation' // H2 implementation 'org.springframework.boot:spring-boot-starter-data-jpa' @@ -97,9 +97,9 @@ dependencies { testImplementation 'org.testcontainers:mongodb:1.16.0' // feign - implementation "io.github.openfeign:feign-core:$openFeignVersion" - implementation "io.github.openfeign:feign-jackson:$openFeignVersion" - implementation "io.github.openfeign:feign-slf4j:$openFeignVersion" + implementation "io.github.openfeign:feign-core:$openFeignVersion" + implementation "io.github.openfeign:feign-jackson:$openFeignVersion" + implementation "io.github.openfeign:feign-slf4j:$openFeignVersion" } sourceSets { @@ -131,7 +131,7 @@ task itest(type:Test) { } jacoco { - toolVersion = "0.8.7" + toolVersion = '0.8.7' } // sonarqube code coverage requires jacoco XML report jacocoTestReport { @@ -168,7 +168,7 @@ task buildImage(type: Exec) { group 'Build' description 'Builds an OCI image from a Dockerfile.' dependsOn bootJar - commandLine ("sh", "-c", "docker build -f build/resources/main/Dockerfile.untrusted --build-arg jar=$jarPathForOCI" + commandLine ('sh', '-c', "docker build -f build/resources/main/Dockerfile.untrusted --build-arg jar=$jarPathForOCI" + " -t $ociImageName:$gitShortCommit . && docker tag $ociImageName:$gitShortCommit $ociImageName:dev") standardOutput = new ByteArrayOutputStream() @@ -182,7 +182,7 @@ task buildTrustedImage(type: Exec) { group 'Build' description 'Builds a trusted OCI image from a trusted Dockerfile.' dependsOn bootJar - commandLine ("sh", "-c", "docker image build -f build/resources/main/Dockerfile --build-arg jar=$jarPathForOCI" + commandLine ('sh', '-c', "docker image build -f build/resources/main/Dockerfile --build-arg jar=$jarPathForOCI" + " -t $ociImageName:$gitShortCommit-trusted --no-cache . && docker tag $ociImageName:$gitShortCommit-trusted $ociImageName:dev-trusted") } @@ -196,19 +196,19 @@ task templatePalaemon { * We need to extract the 2nd occurence 'abcdef' */ ext.extractValueBetweenTags = { s, tag -> - String beginTag = "<" + tag + ">" - String endTag = "" + String beginTag = '<' + tag + '>' + String endTag = '' return s.substring(s.indexOf(beginTag, s.indexOf(beginTag) + 2) + beginTag.length(), s.indexOf(endTag, s.indexOf(endTag) + 2)) } doFirst { String logs = buildImage.output() - smsMrEnclave = extractValueBetweenTags(logs, "MRENCLAVE") - smsFspfKey = extractValueBetweenTags(logs, "FSPF_KEY") - smsFspfTag = extractValueBetweenTags(logs, "FSPF_TAG") + smsMrEnclave = extractValueBetweenTags(logs, 'MRENCLAVE') + smsFspfKey = extractValueBetweenTags(logs, 'FSPF_KEY') + smsFspfTag = extractValueBetweenTags(logs, 'FSPF_TAG') } - doLast{ + doLast { copy { // delete old one delete 'src/main/resources/boot/sms-palaemon-conf.yml' @@ -226,7 +226,6 @@ task templatePalaemon { IEXEC_SMS_FSPF_KEY: smsFspfKey, IEXEC_SMS_FSPF_TAG: smsFspfTag, ]) - } } } From f4f7338c521cbdcc15865a3a3dfb37fc368d88b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20James=20Toussaint?= Date: Mon, 8 Aug 2022 14:29:55 +0200 Subject: [PATCH 026/293] Update feign logging configuration comments --- src/main/resources/logback-spring.xml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/resources/logback-spring.xml b/src/main/resources/logback-spring.xml index 8748ead4..75e42e5f 100644 --- a/src/main/resources/logback-spring.xml +++ b/src/main/resources/logback-spring.xml @@ -24,6 +24,9 @@ - --> + + + + \ No newline at end of file From 2fb219d5fd0439a805439ee6d632c457e0cdc925 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20James=20Toussaint?= Date: Mon, 8 Aug 2022 14:40:52 +0200 Subject: [PATCH 027/293] Wording, specific startsWith and useless file --- .../test/com/iexec/sms/api/SmsClientTest.class | Bin 823 -> 0 bytes .../session/base/SecretSessionBaseService.java | 8 ++++---- .../base/SecretSessionBaseServiceTests.java | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) delete mode 100644 iexec-sms-library/bin/test/com/iexec/sms/api/SmsClientTest.class diff --git a/iexec-sms-library/bin/test/com/iexec/sms/api/SmsClientTest.class b/iexec-sms-library/bin/test/com/iexec/sms/api/SmsClientTest.class deleted file mode 100644 index 27595b02c162ad2f539077153386457148b786de..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 823 zcmah{QBM;=5dOBb96b(!0%D~KMbs7(@6p6FMr=7dY_qpVcJ~N>OJ5{D z_yhb=#@T~}8VSD4?94a&?aa6H>-UeJ0AAsRhZ@6nTI8YN7d#D3Zo=eDgrnRHq~OXP zb7MW!8CIsrc@oM*W#Pxkl&6+q{*6$=zGax}^~VhLL2<%;%%K^efq91ISSUU$^9k3- z$wYF7R$Qcs94A`1_&Qm)r@}CF@h4QRc2V&VJRiUMsMcLtIv+y2m7O<)G0p{ z)mQ$tA}?K&48f67To0rpG#>htnH7$qQHhH#XlZBzff}7?S;%@6h2$Ce#{PFKe63)g ztb>6~ERqeb3dk=}1l%LEhGjarsul8%=ygR*)!(q%+Pp;j65BU?KB2%C@pWc6gKN$j Uo)TKaGdw5n6Ke}S?7wUO0X}xgs{jB1 diff --git a/src/main/java/com/iexec/sms/tee/session/base/SecretSessionBaseService.java b/src/main/java/com/iexec/sms/tee/session/base/SecretSessionBaseService.java index 66941d93..134addf9 100644 --- a/src/main/java/com/iexec/sms/tee/session/base/SecretSessionBaseService.java +++ b/src/main/java/com/iexec/sms/tee/session/base/SecretSessionBaseService.java @@ -164,7 +164,7 @@ public SecretEnclaveBase getPreComputeTokens(TeeSessionRequest request) // extract trusted en vars to include trustedEnv.contains(e.getKey()) // extract - || e.getKey().contains(IexecEnvUtils.IEXEC_INPUT_FILE_URL_PREFIX)) + || e.getKey().startsWith(IexecEnvUtils.IEXEC_INPUT_FILE_URL_PREFIX)) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); tokens.putAll(trustedEnvVars); return enclaveBase @@ -183,7 +183,7 @@ public SecretEnclaveBase getAppTokens(TeeSessionRequest request) if (taskDescription == null) { throw new TeeSessionGenerationException( NO_TASK_DESCRIPTION, - "Task description must no be null"); + "Task description must not be null"); } Map tokens = new HashMap<>(); @@ -191,7 +191,7 @@ public SecretEnclaveBase getAppTokens(TeeSessionRequest request) if (enclaveConfig == null) { throw new TeeSessionGenerationException( APP_COMPUTE_NO_ENCLAVE_CONFIG, - "Enclave configuration must no be null"); + "Enclave configuration must not be null"); } if (!enclaveConfig.getValidator().isValid()) { throw new TeeSessionGenerationException( @@ -206,7 +206,7 @@ public SecretEnclaveBase getAppTokens(TeeSessionRequest request) Map inputFileNames = IexecEnvUtils.getComputeStageEnvMap(taskDescription) .entrySet() .stream() - .filter(e -> e.getKey().contains(IexecEnvUtils.IEXEC_INPUT_FILE_NAME_PREFIX)) + .filter(e -> e.getKey().startsWith(IexecEnvUtils.IEXEC_INPUT_FILE_NAME_PREFIX)) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); tokens.putAll(inputFileNames); diff --git a/src/test/java/com/iexec/sms/tee/session/base/SecretSessionBaseServiceTests.java b/src/test/java/com/iexec/sms/tee/session/base/SecretSessionBaseServiceTests.java index 09e7df1d..98811113 100644 --- a/src/test/java/com/iexec/sms/tee/session/base/SecretSessionBaseServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/base/SecretSessionBaseServiceTests.java @@ -314,7 +314,7 @@ void shouldFailToGetAppTokensSinceNoTaskDescription() { TeeSessionGenerationException exception = assertThrows(TeeSessionGenerationException.class, () -> teeSecretsService.getAppTokens(request)); Assertions.assertEquals(TeeSessionGenerationError.NO_TASK_DESCRIPTION, exception.getError()); - Assertions.assertEquals("Task description must no be null", exception.getMessage()); + Assertions.assertEquals("Task description must not be null", exception.getMessage()); } @Test @@ -328,7 +328,7 @@ void shouldFailToGetAppTokensSinceNoEnclaveConfig() { TeeSessionGenerationException exception = assertThrows(TeeSessionGenerationException.class, () -> teeSecretsService.getAppTokens(request)); Assertions.assertEquals(TeeSessionGenerationError.APP_COMPUTE_NO_ENCLAVE_CONFIG, exception.getError()); - Assertions.assertEquals("Enclave configuration must no be null", exception.getMessage()); + Assertions.assertEquals("Enclave configuration must not be null", exception.getMessage()); } @Test From f698c65c0e71317eb2226b97ed1f532c68588bd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20James=20Toussaint?= Date: Mon, 8 Aug 2022 16:46:36 +0200 Subject: [PATCH 028/293] Remove temporary map for trusted session env vars --- .../tee/session/base/SecretSessionBaseService.java | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/iexec/sms/tee/session/base/SecretSessionBaseService.java b/src/main/java/com/iexec/sms/tee/session/base/SecretSessionBaseService.java index 134addf9..9a0e27fd 100644 --- a/src/main/java/com/iexec/sms/tee/session/base/SecretSessionBaseService.java +++ b/src/main/java/com/iexec/sms/tee/session/base/SecretSessionBaseService.java @@ -41,7 +41,6 @@ import org.springframework.stereotype.Service; import java.util.*; -import java.util.stream.Collectors; import static com.iexec.common.chain.DealParams.DROPBOX_RESULT_STORAGE_PROVIDER; import static com.iexec.common.precompute.PreComputeUtils.IS_DATASET_REQUIRED; @@ -157,7 +156,7 @@ public SecretEnclaveBase getPreComputeTokens(TeeSessionRequest request) IexecEnvUtils.IEXEC_TASK_ID, IexecEnvUtils.IEXEC_INPUT_FILES_FOLDER, IexecEnvUtils.IEXEC_INPUT_FILES_NUMBER)); - Map trustedEnvVars = IexecEnvUtils.getAllIexecEnv(taskDescription) + IexecEnvUtils.getAllIexecEnv(taskDescription) .entrySet() .stream() .filter(e -> @@ -165,8 +164,7 @@ public SecretEnclaveBase getPreComputeTokens(TeeSessionRequest request) trustedEnv.contains(e.getKey()) // extract || e.getKey().startsWith(IexecEnvUtils.IEXEC_INPUT_FILE_URL_PREFIX)) - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); - tokens.putAll(trustedEnvVars); + .forEach(e -> tokens.put(e.getKey(), e.getValue())); return enclaveBase .environment(tokens) .build(); @@ -203,12 +201,11 @@ public SecretEnclaveBase getAppTokens(TeeSessionRequest request) enclaveBase.mrenclave(enclaveConfig.getFingerprint()); // extract // this map will be empty (not null) if no input file is found - Map inputFileNames = IexecEnvUtils.getComputeStageEnvMap(taskDescription) + IexecEnvUtils.getComputeStageEnvMap(taskDescription) .entrySet() .stream() .filter(e -> e.getKey().startsWith(IexecEnvUtils.IEXEC_INPUT_FILE_NAME_PREFIX)) - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); - tokens.putAll(inputFileNames); + .forEach(e -> tokens.put(e.getKey(), e.getValue())); final Map computeSecrets = getApplicationComputeSecrets(taskDescription); tokens.putAll(computeSecrets); From 6aa5e21aa2bd50d49fe048edf5712f7cd29093c1 Mon Sep 17 00:00:00 2001 From: mcornaton Date: Fri, 12 Aug 2022 11:21:58 +0200 Subject: [PATCH 029/293] Run Gramine task on worker --- iexec-sms-library/build.gradle | 1 + .../com/iexec/sms/api/SmsClientProvider.java | 52 +++++++++ .../sms/api/TeeSessionGenerationError.java | 1 + .../iexec/sms/api/SmsClientProviderTests.java | 107 ++++++++++++++++++ 4 files changed, 161 insertions(+) create mode 100644 iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java create mode 100644 iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientProviderTests.java diff --git a/iexec-sms-library/build.gradle b/iexec-sms-library/build.gradle index 2fc03736..9d4dac1e 100644 --- a/iexec-sms-library/build.gradle +++ b/iexec-sms-library/build.gradle @@ -8,6 +8,7 @@ plugins { dependencies { implementation "com.iexec.common:iexec-common:$iexecCommonVersion" testImplementation 'org.junit.jupiter:junit-jupiter:5.8.2' + testImplementation 'org.mockito:mockito-junit-jupiter:4.0.0' } java { diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java new file mode 100644 index 00000000..e24f38fc --- /dev/null +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java @@ -0,0 +1,52 @@ +package com.iexec.sms.api; + +import com.iexec.common.chain.IexecHubAbstractService; +import com.iexec.common.task.TaskDescription; +import feign.Logger; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +/** + * Manages the {@link SmsClient}, providing an easy way to access SMS + * and avoiding the need to create a new {@link SmsClient} instance each time. + */ +@Slf4j +public class SmsClientProvider { + private final Map smsClientForUrl = new HashMap<>(); + + private final IexecHubAbstractService iexecHubService; + + public SmsClientProvider(IexecHubAbstractService iexecHubService) { + this.iexecHubService = iexecHubService; + } + + /** + * Retrieves the specified SMS URL for this task, then: + *
    + *
  • If this SMS has already been accessed, returns the already-constructed {@link SmsClient};
  • + *
  • Otherwise, constructs, stores and returns a new {@link SmsClient}.
  • + *
+ * + * @param chainTaskId ID of the task the specified SMS URL should be retrieved. + * @return An instance of {@link SmsClient} pointing on the task's specified SMS. + */ + public Optional getSmsClientForTask(String chainTaskId) { + final TaskDescription taskDescription = iexecHubService.getTaskDescription(chainTaskId); + if (taskDescription == null) { + log.warn("No such task [chainTaskId: {}]", chainTaskId); + return Optional.empty(); + } + + final String smsUrl = taskDescription.getSmsUrl(); + if (StringUtils.isEmpty(smsUrl)) { + log.warn("No SMS URL defined for given task [chainTaskId: {}]", chainTaskId); + return Optional.empty(); + } + + return Optional.of(smsClientForUrl.computeIfAbsent(smsUrl, url -> SmsClientBuilder.getInstance(Logger.Level.NONE, url))); + } +} diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/TeeSessionGenerationError.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/TeeSessionGenerationError.java index 61c6a57e..ffdd6360 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/TeeSessionGenerationError.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/TeeSessionGenerationError.java @@ -58,6 +58,7 @@ public enum TeeSessionGenerationError { NO_SESSION_REQUEST, NO_TASK_DESCRIPTION, GET_SESSION_FAILED, + NO_SMS_FOR_TASK, UNKNOWN_ISSUE // endregion diff --git a/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientProviderTests.java b/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientProviderTests.java new file mode 100644 index 00000000..6f7bfca1 --- /dev/null +++ b/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientProviderTests.java @@ -0,0 +1,107 @@ +package com.iexec.sms.api; + +import com.iexec.common.chain.IexecHubAbstractService; +import com.iexec.common.task.TaskDescription; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; + +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.*; + +class SmsClientProviderTests { + private static final String CHAIN_TASK_ID_1 = "chainTaskId1"; + private static final String SMS_URL_1 = "smsUrl1"; + private static final TaskDescription TASK_DESCRIPTION_1 = TaskDescription.builder() + .chainTaskId(CHAIN_TASK_ID_1) + .smsUrl(SMS_URL_1) + .build(); + + private static final String CHAIN_TASK_ID_2 = "chainTaskId2"; + private static final String SMS_URL_2 = "smsUrl2"; + private static final TaskDescription TASK_DESCRIPTION_2 = TaskDescription.builder() + .chainTaskId(CHAIN_TASK_ID_2) + .smsUrl(SMS_URL_2) + .build(); + + private static final String CHAIN_TASK_ID_3 = "chainTaskId1"; + private static final TaskDescription TASK_DESCRIPTION_3 = TaskDescription.builder() + .chainTaskId(CHAIN_TASK_ID_3) + .smsUrl(SMS_URL_1) // Same as first task + .build(); + + @Mock + IexecHubAbstractService iexecHubService; + @InjectMocks + SmsClientProvider smsClientProvider; + + @BeforeEach + void init() { + MockitoAnnotations.openMocks(this); + } + + @Test + void shouldGetSmsClientForTask() { + Mockito.when(iexecHubService.getTaskDescription(CHAIN_TASK_ID_1)).thenReturn(TASK_DESCRIPTION_1); + + assertTrue(smsClientProvider.getSmsClientForTask(CHAIN_TASK_ID_1).isPresent()); + } + + @Test + void shouldNotRebuildSmsClientForSameTask() { + Mockito.when(iexecHubService.getTaskDescription(CHAIN_TASK_ID_1)).thenReturn(TASK_DESCRIPTION_1); + + final Optional smsClient1 = smsClientProvider.getSmsClientForTask(CHAIN_TASK_ID_1); + assertTrue(smsClient1.isPresent()); + + final Optional smsClient2 = smsClientProvider.getSmsClientForTask(CHAIN_TASK_ID_1); + assertTrue(smsClient2.isPresent()); + + assertEquals(smsClient1, smsClient2); + } + + @Test + void shouldNotRebuildSmsClientForSameSmsUrlOnAnotherTask() { + Mockito.when(iexecHubService.getTaskDescription(CHAIN_TASK_ID_1)).thenReturn(TASK_DESCRIPTION_1); + final Optional smsClient1 = smsClientProvider.getSmsClientForTask(CHAIN_TASK_ID_1); + assertTrue(smsClient1.isPresent()); + + Mockito.when(iexecHubService.getTaskDescription(CHAIN_TASK_ID_3)).thenReturn(TASK_DESCRIPTION_3); + final Optional smsClient2 = smsClientProvider.getSmsClientForTask(CHAIN_TASK_ID_3); + assertTrue(smsClient2.isPresent()); + + assertEquals(smsClient1, smsClient2); + } + + @Test + void shouldBuildAnotherSmsClientForTaskOnSecondCallForAnotherSms() { + Mockito.when(iexecHubService.getTaskDescription(CHAIN_TASK_ID_1)).thenReturn(TASK_DESCRIPTION_1); + Mockito.when(iexecHubService.getTaskDescription(CHAIN_TASK_ID_2)).thenReturn(TASK_DESCRIPTION_2); + + final Optional smsClientForTask1 = smsClientProvider.getSmsClientForTask(CHAIN_TASK_ID_1); + assertTrue(smsClientForTask1.isPresent()); + + final Optional smsClientForTask2 = smsClientProvider.getSmsClientForTask(CHAIN_TASK_ID_2); + assertTrue(smsClientForTask2.isPresent()); + + assertNotEquals(smsClientForTask1, smsClientForTask2); + } + + @Test + void shouldNotGetSmsClientForTaskWhenNoTask() { + Mockito.when(iexecHubService.getTaskDescription(CHAIN_TASK_ID_1)).thenReturn(null); + + assertTrue(smsClientProvider.getSmsClientForTask(CHAIN_TASK_ID_1).isEmpty()); + } + + @Test + void shouldNotGetSmsClientForTaskWhenNoSmsUrl() { + Mockito.when(iexecHubService.getTaskDescription(CHAIN_TASK_ID_1)).thenReturn(TaskDescription.builder().build()); + + assertTrue(smsClientProvider.getSmsClientForTask(CHAIN_TASK_ID_1).isEmpty()); + } +} \ No newline at end of file From 770005aae48aa012aaa191be5e2450a9efe1fc45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20James=20Toussaint?= Date: Fri, 12 Aug 2022 12:13:42 +0200 Subject: [PATCH 030/293] Update optional pre-compute templating for scone and update returned CAS http code --- .../scone/SconeSessionHandlerService.java | 2 +- .../scone/SconeSessionMakerService.java | 90 +++++++++++-------- .../SconeSessionHandlerServiceTests.java | 32 ++++--- 3 files changed, 73 insertions(+), 51 deletions(-) diff --git a/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerService.java b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerService.java index a5b0387d..f76b47ff 100644 --- a/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerService.java +++ b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerService.java @@ -64,7 +64,7 @@ public String buildAndPostSession(TeeSessionRequest request) } ResponseEntity postSession = apiClient.postSession(session.toString()); int httpCode = postSession != null ? postSession.getStatusCodeValue() : null; - if (httpCode != 200) { + if (httpCode != 201) { throw new TeeSessionGenerationException( TeeSessionGenerationError.SECURE_SESSION_STORAGE_CALL_FAILED, "Failed to post session: " + httpCode); diff --git a/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionMakerService.java b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionMakerService.java index 70d4292f..b52c173d 100644 --- a/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionMakerService.java +++ b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionMakerService.java @@ -24,6 +24,7 @@ import com.iexec.sms.tee.session.scone.cas.SconeEnclave; import com.iexec.sms.tee.session.scone.cas.SconeSession; import com.iexec.sms.tee.session.scone.cas.SconeSession.AccessPolicy; +import com.iexec.sms.tee.session.scone.cas.SconeSession.Image; import com.iexec.sms.tee.session.scone.cas.SconeSession.Image.Volume; import com.iexec.sms.tee.session.scone.cas.SconeSession.Security; import com.iexec.sms.tee.session.scone.cas.SconeSession.Volumes; @@ -31,10 +32,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; //TODO Rename and move @Slf4j @@ -76,48 +74,62 @@ public SconeSessionMakerService( * @param request session request details * @return session config in yaml string format */ - public SconeSession generateSession(TeeSessionRequest request) throws TeeSessionGenerationException { - SecretSessionBase baseSession = secretSessionBaseService.getSecretsTokens(request); - - SconeEnclave sconePreEnclave = toSconeEnclave(baseSession.getPreCompute()); - sconePreEnclave.setCommand(teeWorkflowConfig.getPreComputeEntrypoint()); - SconeEnclave sconeAppEnclave = toSconeEnclave(baseSession.getAppCompute()); - sconeAppEnclave.setCommand(request.getTaskDescription().getAppCommand()); - SconeEnclave sconePostEnclave = toSconeEnclave(baseSession.getPostCompute()); - sconePostEnclave.setCommand(teeWorkflowConfig.getPostComputeEntrypoint()); - - addJavaEnvVars(sconePreEnclave); - addJavaEnvVars(sconePostEnclave); - + public SconeSession generateSession(TeeSessionRequest request) + throws TeeSessionGenerationException { List policy = Arrays.asList("CREATOR"); + Volume iexecInVolume = new Volume("iexec_in", "/iexec_in"); + Volume iexecOutVolume = new Volume("iexec_out", "/iexec_out"); + Volume postComputeTmpVolume = new Volume("post-compute-tmp", + "/post-compute-tmp"); + List services = new ArrayList<>(); + List images = new ArrayList<>(); + + SecretSessionBase baseSession = secretSessionBaseService + .getSecretsTokens(request); + + // pre (optional) + if (baseSession.getPreCompute() != null) { + SconeEnclave sconePreEnclave = toSconeEnclave( + baseSession.getPreCompute()); + sconePreEnclave + .setCommand(teeWorkflowConfig.getPreComputeEntrypoint()); + addJavaEnvVars(sconePreEnclave); + services.add(sconePreEnclave); + images.add(new SconeSession.Image(sconePreEnclave.getImageName(), + Arrays.asList(iexecInVolume))); + } + // app + SconeEnclave sconeAppEnclave = toSconeEnclave( + baseSession.getAppCompute()); + sconeAppEnclave + .setCommand(request.getTaskDescription().getAppCommand()); + services.add(sconeAppEnclave); + images.add(new SconeSession.Image(sconeAppEnclave.getImageName(), + Arrays.asList(iexecInVolume, iexecOutVolume))); + // post + SconeEnclave sconePostEnclave = toSconeEnclave( + baseSession.getPostCompute()); + sconePostEnclave + .setCommand(teeWorkflowConfig.getPostComputeEntrypoint()); + addJavaEnvVars(sconePostEnclave); + services.add(sconePostEnclave); + images.add(new SconeSession.Image(sconePostEnclave.getImageName(), + Arrays.asList(iexecOutVolume, + postComputeTmpVolume))); - SconeSession casSession = SconeSession.builder() + return SconeSession.builder() .name(request.getSessionId()) .version("0.3") .accessPolicy(new AccessPolicy(policy, policy)) - .services(Arrays.asList(sconePreEnclave, sconeAppEnclave, sconePostEnclave)) - .security(new Security(attestationSecurityConfig.getToleratedInsecureOptions(), + .services(services) + .images(images) + .volumes(Arrays.asList(new Volumes(iexecInVolume.getName()), + new Volumes(iexecOutVolume.getName()), + new Volumes(postComputeTmpVolume.getName()))) + .security(new Security( + attestationSecurityConfig.getToleratedInsecureOptions(), attestationSecurityConfig.getIgnoredSgxAdvisories())) .build(); - - Volume iexecInVolume = new Volume("iexec_in", "/iexec_in"); - Volume iexecOutVolume = new Volume("iexec_out", "/iexec_out"); - Volume postComputeTmpVolume = new Volume("post-compute-tmp", "/post-compute-tmp"); - - casSession.setVolumes(Arrays.asList( - new Volumes(iexecInVolume.getName()), - new Volumes(iexecOutVolume.getName()), - new Volumes(postComputeTmpVolume.getName()))); - - casSession.setImages(Arrays.asList( - new SconeSession.Image(sconePreEnclave.getImageName(), Arrays.asList(iexecInVolume)), - new SconeSession.Image(sconeAppEnclave.getImageName(), Arrays.asList(iexecInVolume, iexecOutVolume)), - new SconeSession.Image(sconePostEnclave.getImageName(), - Arrays.asList(iexecOutVolume, postComputeTmpVolume)) - - )); - - return casSession; } private void addJavaEnvVars(SconeEnclave sconeEnclave) { diff --git a/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerServiceTests.java b/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerServiceTests.java index cb2e47fb..798cc80f 100644 --- a/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerServiceTests.java @@ -46,20 +46,26 @@ void beforeEach() { } @Test - void shouldBuildAndPostSession(CapturedOutput output) throws TeeSessionGenerationException { + void shouldBuildAndPostSession(CapturedOutput output) + throws TeeSessionGenerationException { TeeSessionRequest request = mock(TeeSessionRequest.class); TaskDescription taskDescription = mock(TaskDescription.class); when(request.getTaskDescription()).thenReturn(taskDescription); SconeSession casSession = mock(SconeSession.class); when(casSession.toString()).thenReturn("sessionContent"); when(sessionService.generateSession(request)).thenReturn(casSession); - when(teeSessionLogConfiguration.isDisplayDebugSessionEnabled()).thenReturn(true); - when(apiClient.postSession(casSession.toString())).thenReturn(ResponseEntity.ok("sessionId")); - - assertEquals(CAS_URL, sessionHandlerService.buildAndPostSession(request)); - // Testing output here since it reflects a business feature (ability to catch a + when(teeSessionLogConfiguration.isDisplayDebugSessionEnabled()) + .thenReturn(true); + when(apiClient.postSession(casSession.toString())) + .thenReturn(ResponseEntity.created(null).body("sessionId")); + + assertEquals(CAS_URL, + sessionHandlerService.buildAndPostSession(request)); + // Testing output here since it reflects a business feature (ability to + // catch a // session in debug mode) - assertTrue(output.getOut().contains("Session content [taskId:null]\nsessionContent\n")); + assertTrue(output.getOut() + .contains("Session content [taskId:null]\nsessionContent\n")); } @Test @@ -67,8 +73,10 @@ void shouldNotBuildAndPostSessionSinceBuildSessionFailed() throws TeeSessionGenerationException { TeeSessionRequest request = mock(TeeSessionRequest.class); TeeSessionGenerationException teeSessionGenerationException = new TeeSessionGenerationException( - TeeSessionGenerationError.SECURE_SESSION_GENERATION_FAILED, "some error"); - when(sessionService.generateSession(request)).thenThrow(teeSessionGenerationException); + TeeSessionGenerationError.SECURE_SESSION_GENERATION_FAILED, + "some error"); + when(sessionService.generateSession(request)) + .thenThrow(teeSessionGenerationException); assertThrows(teeSessionGenerationException.getClass(), () -> sessionHandlerService.buildAndPostSession(request)); @@ -82,8 +90,10 @@ void shouldNotBuildAndPostSessionSincePostSessionFailed() when(request.getTaskDescription()).thenReturn(taskDescription); SconeSession casSession = mock(SconeSession.class); when(sessionService.generateSession(request)).thenReturn(casSession); - when(teeSessionLogConfiguration.isDisplayDebugSessionEnabled()).thenReturn(true); - when(apiClient.postSession(casSession.toString())).thenReturn(ResponseEntity.internalServerError().build()); + when(teeSessionLogConfiguration.isDisplayDebugSessionEnabled()) + .thenReturn(true); + when(apiClient.postSession(casSession.toString())) + .thenReturn(ResponseEntity.internalServerError().build()); assertThrows(TeeSessionGenerationException.class, () -> sessionHandlerService.buildAndPostSession(request)); From e8bd9fff61ec45136c62fa7a537143200fce5d1f Mon Sep 17 00:00:00 2001 From: mcornaton Date: Wed, 17 Aug 2022 09:26:50 +0200 Subject: [PATCH 031/293] Fix SPS config --- .../com/iexec/sms/tee/session/gramine/sps/SpsConfiguration.java | 2 +- src/main/resources/application.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsConfiguration.java b/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsConfiguration.java index e0bd2a5c..7815a15d 100644 --- a/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsConfiguration.java +++ b/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsConfiguration.java @@ -50,7 +50,7 @@ public String getWebUrl() { } public String getEnclaveUrl() { - return "https://" + enclaveHost + ":" + enclavePort; + return enclaveHost + ":" + enclavePort; } public SpsApiClient getInstance() { diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 97753cd3..2bc81ee0 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -68,7 +68,7 @@ gramine: password: ${IEXEC_GRAPHENE_SPS_WEB_PASSWORD:admin} enclave: host: ${IEXEC_GRAPHENE_SPS_ENCLAVE_HOST:localhost} - port: ${IEXEC_GRAPHENE_SPS_ENCLAVE_PORT:4443} + port: ${IEXEC_GRAPHENE_SPS_ENCLAVE_PORT:4433} # TODO /!\ remove the option of env variable for releases. tee.workflow: From 8510a1eee205b04d1834a77a524cc4b475e28684 Mon Sep 17 00:00:00 2001 From: mcornaton Date: Tue, 23 Aug 2022 15:28:28 +0200 Subject: [PATCH 032/293] Rename `enclaveUrl` into `enclaveHost` --- .../tee/session/gramine/GramineSessionHandlerService.java | 2 +- .../iexec/sms/tee/session/gramine/sps/SpsConfiguration.java | 6 +++--- .../sms/tee/session/scone/SconeSessionHandlerService.java | 2 +- .../iexec/sms/tee/session/scone/cas/CasConfiguration.java | 2 +- src/main/resources/application.yml | 2 +- .../session/gramine/GramineSessionHandlerServiceTests.java | 2 +- .../tee/session/scone/SconeSessionHandlerServiceTests.java | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerService.java b/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerService.java index 9181425c..058a2c3d 100644 --- a/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerService.java +++ b/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerService.java @@ -60,7 +60,7 @@ public String buildAndPostSession(TeeSessionRequest request) try { spsConfiguration.getInstance().postSession(session); - return spsConfiguration.getEnclaveUrl(); + return spsConfiguration.getEnclaveHost(); } catch (Exception e) { throw new TeeSessionGenerationException( TeeSessionGenerationError.SECURE_SESSION_STORAGE_CALL_FAILED, diff --git a/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsConfiguration.java b/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsConfiguration.java index 7815a15d..b00d2cef 100644 --- a/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsConfiguration.java +++ b/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsConfiguration.java @@ -38,7 +38,7 @@ public class SpsConfiguration { private String webPassword; @Value("${gramine.sps.enclave.host}") - private String enclaveHost; + private String enclaveHostName; @Value("${gramine.sps.enclave.port}") private String enclavePort; @@ -49,8 +49,8 @@ public String getWebUrl() { return "http://" + webHost + ":" + webPort; } - public String getEnclaveUrl() { - return enclaveHost + ":" + enclavePort; + public String getEnclaveHost() { + return enclaveHostName + ":" + enclavePort; } public SpsApiClient getInstance() { diff --git a/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerService.java b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerService.java index a5b0387d..20755019 100644 --- a/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerService.java +++ b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerService.java @@ -69,7 +69,7 @@ public String buildAndPostSession(TeeSessionRequest request) TeeSessionGenerationError.SECURE_SESSION_STORAGE_CALL_FAILED, "Failed to post session: " + httpCode); } - return casConfiguration.getEnclaveUrl(); + return casConfiguration.getEnclaveHost(); } } diff --git a/src/main/java/com/iexec/sms/tee/session/scone/cas/CasConfiguration.java b/src/main/java/com/iexec/sms/tee/session/scone/cas/CasConfiguration.java index dd8f971f..e968f81f 100644 --- a/src/main/java/com/iexec/sms/tee/session/scone/cas/CasConfiguration.java +++ b/src/main/java/com/iexec/sms/tee/session/scone/cas/CasConfiguration.java @@ -55,7 +55,7 @@ public String getUrl() { return "https://" + host + ":" + port; } - public String getEnclaveUrl() { + public String getEnclaveHost() { return publicHost + ":" + enclavePort; } } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 2bc81ee0..6505dd00 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -67,7 +67,7 @@ gramine: login: ${IEXEC_GRAPHENE_SPS_WEB_LOGIN:admin} password: ${IEXEC_GRAPHENE_SPS_WEB_PASSWORD:admin} enclave: - host: ${IEXEC_GRAPHENE_SPS_ENCLAVE_HOST:localhost} + host: ${IEXEC_GRAPHENE_SPS_ENCLAVE_HOST_NAME:localhost} port: ${IEXEC_GRAPHENE_SPS_ENCLAVE_PORT:4433} # TODO /!\ remove the option of env variable for releases. diff --git a/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerServiceTests.java b/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerServiceTests.java index 439a6065..d58a0b9d 100644 --- a/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerServiceTests.java @@ -56,7 +56,7 @@ public class GramineSessionHandlerServiceTests { @BeforeEach void beforeEach() { MockitoAnnotations.openMocks(this); - when(spsConfiguration.getEnclaveUrl()).thenReturn(SPS_URL); + when(spsConfiguration.getEnclaveHost()).thenReturn(SPS_URL); } @Test diff --git a/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerServiceTests.java b/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerServiceTests.java index cb2e47fb..1ec5ff55 100644 --- a/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerServiceTests.java @@ -42,7 +42,7 @@ public class SconeSessionHandlerServiceTests { @BeforeEach void beforeEach() { MockitoAnnotations.openMocks(this); - when(casConfiguration.getEnclaveUrl()).thenReturn(CAS_URL); + when(casConfiguration.getEnclaveHost()).thenReturn(CAS_URL); } @Test From d1b089316162199c353a1368767fb34c6aa3b25a Mon Sep 17 00:00:00 2001 From: mcornaton Date: Tue, 23 Aug 2022 15:29:00 +0200 Subject: [PATCH 033/293] Rename `smsClientForUrl` into `urlToSmsClient` --- .../src/main/java/com/iexec/sms/api/SmsClientProvider.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java index e24f38fc..91406477 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java @@ -16,7 +16,7 @@ */ @Slf4j public class SmsClientProvider { - private final Map smsClientForUrl = new HashMap<>(); + private final Map urlToSmsClient = new HashMap<>(); private final IexecHubAbstractService iexecHubService; @@ -47,6 +47,6 @@ public Optional getSmsClientForTask(String chainTaskId) { return Optional.empty(); } - return Optional.of(smsClientForUrl.computeIfAbsent(smsUrl, url -> SmsClientBuilder.getInstance(Logger.Level.NONE, url))); + return Optional.of(urlToSmsClient.computeIfAbsent(smsUrl, url -> SmsClientBuilder.getInstance(Logger.Level.NONE, url))); } } From 648391e91a3deb246f05a9261dd7cfc95d931078 Mon Sep 17 00:00:00 2001 From: mcornaton Date: Tue, 23 Aug 2022 15:31:19 +0200 Subject: [PATCH 034/293] Add `Logger.Level` to `SmsClientProvider` --- .../java/com/iexec/sms/api/SmsClientProvider.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java index 91406477..8e361a47 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java @@ -19,11 +19,20 @@ public class SmsClientProvider { private final Map urlToSmsClient = new HashMap<>(); private final IexecHubAbstractService iexecHubService; + private final Logger.Level loggerLevel; public SmsClientProvider(IexecHubAbstractService iexecHubService) { this.iexecHubService = iexecHubService; + this.loggerLevel = Logger.Level.NONE; } + public SmsClientProvider(IexecHubAbstractService iexecHubService, + Logger.Level loggerLevel) { + this.iexecHubService = iexecHubService; + this.loggerLevel = loggerLevel; + } + + /** * Retrieves the specified SMS URL for this task, then: *
    @@ -47,6 +56,6 @@ public Optional getSmsClientForTask(String chainTaskId) { return Optional.empty(); } - return Optional.of(urlToSmsClient.computeIfAbsent(smsUrl, url -> SmsClientBuilder.getInstance(Logger.Level.NONE, url))); + return Optional.of(urlToSmsClient.computeIfAbsent(smsUrl, url -> SmsClientBuilder.getInstance(loggerLevel, url))); } } From 9a81560d1cc14e6e4798a6029f7c8efe48aaad5f Mon Sep 17 00:00:00 2001 From: Maxence Cornaton <87655102+mcornaton@users.noreply.github.com> Date: Tue, 23 Aug 2022 15:31:53 +0200 Subject: [PATCH 035/293] Update Junit version MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jérémy James Toussaint <33313130+jeremyjams@users.noreply.github.com> --- iexec-sms-library/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iexec-sms-library/build.gradle b/iexec-sms-library/build.gradle index 9d4dac1e..1ec202dd 100644 --- a/iexec-sms-library/build.gradle +++ b/iexec-sms-library/build.gradle @@ -8,7 +8,7 @@ plugins { dependencies { implementation "com.iexec.common:iexec-common:$iexecCommonVersion" testImplementation 'org.junit.jupiter:junit-jupiter:5.8.2' - testImplementation 'org.mockito:mockito-junit-jupiter:4.0.0' + testImplementation 'org.mockito:mockito-junit-jupiter:4.7.0' } java { From c52df25def2a9100fd573a55082912807836168f Mon Sep 17 00:00:00 2001 From: mcornaton Date: Tue, 23 Aug 2022 16:18:28 +0200 Subject: [PATCH 036/293] Fix `SmsClientProviderTests` tests --- .../test/java/com/iexec/sms/api/SmsClientProviderTests.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientProviderTests.java b/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientProviderTests.java index 6f7bfca1..15597943 100644 --- a/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientProviderTests.java +++ b/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientProviderTests.java @@ -2,9 +2,9 @@ import com.iexec.common.chain.IexecHubAbstractService; import com.iexec.common.task.TaskDescription; +import feign.Logger; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; @@ -36,12 +36,13 @@ class SmsClientProviderTests { @Mock IexecHubAbstractService iexecHubService; - @InjectMocks + SmsClientProvider smsClientProvider; @BeforeEach void init() { MockitoAnnotations.openMocks(this); + smsClientProvider = new SmsClientProvider(iexecHubService, Logger.Level.NONE); } @Test From 428ad7c48e8aafc5baa3ad63889f47849229eaff Mon Sep 17 00:00:00 2001 From: mcornaton Date: Wed, 24 Aug 2022 10:06:03 +0200 Subject: [PATCH 037/293] Get `SmsClient` & `TeeWorkflowConfig` on task start or abort --- .../sms/api/SmsClientCreationException.java | 7 ++++ .../com/iexec/sms/api/SmsClientProvider.java | 11 ++---- .../iexec/sms/api/SmsClientProviderTests.java | 38 ++++++++++--------- 3 files changed, 32 insertions(+), 24 deletions(-) create mode 100644 iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientCreationException.java diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientCreationException.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientCreationException.java new file mode 100644 index 00000000..68a8ca29 --- /dev/null +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientCreationException.java @@ -0,0 +1,7 @@ +package com.iexec.sms.api; + +public class SmsClientCreationException extends RuntimeException { + public SmsClientCreationException(String message) { + super(message); + } +} diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java index 8e361a47..b9860dc0 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java @@ -8,7 +8,6 @@ import java.util.HashMap; import java.util.Map; -import java.util.Optional; /** * Manages the {@link SmsClient}, providing an easy way to access SMS @@ -43,19 +42,17 @@ public SmsClientProvider(IexecHubAbstractService iexecHubService, * @param chainTaskId ID of the task the specified SMS URL should be retrieved. * @return An instance of {@link SmsClient} pointing on the task's specified SMS. */ - public Optional getSmsClientForTask(String chainTaskId) { + public SmsClient getOrCreateSmsClientForTask(String chainTaskId) { final TaskDescription taskDescription = iexecHubService.getTaskDescription(chainTaskId); if (taskDescription == null) { - log.warn("No such task [chainTaskId: {}]", chainTaskId); - return Optional.empty(); + throw new SmsClientCreationException("No such task [chainTaskId: " + chainTaskId +"]"); } final String smsUrl = taskDescription.getSmsUrl(); if (StringUtils.isEmpty(smsUrl)) { - log.warn("No SMS URL defined for given task [chainTaskId: {}]", chainTaskId); - return Optional.empty(); + throw new SmsClientCreationException("No SMS URL defined for given task [chainTaskId: " + chainTaskId +"]"); } - return Optional.of(urlToSmsClient.computeIfAbsent(smsUrl, url -> SmsClientBuilder.getInstance(loggerLevel, url))); + return urlToSmsClient.computeIfAbsent(smsUrl, url -> SmsClientBuilder.getInstance(loggerLevel, url)); } } diff --git a/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientProviderTests.java b/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientProviderTests.java index 15597943..de42e094 100644 --- a/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientProviderTests.java +++ b/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientProviderTests.java @@ -9,8 +9,6 @@ import org.mockito.Mockito; import org.mockito.MockitoAnnotations; -import java.util.Optional; - import static org.junit.jupiter.api.Assertions.*; class SmsClientProviderTests { @@ -49,18 +47,19 @@ void init() { void shouldGetSmsClientForTask() { Mockito.when(iexecHubService.getTaskDescription(CHAIN_TASK_ID_1)).thenReturn(TASK_DESCRIPTION_1); - assertTrue(smsClientProvider.getSmsClientForTask(CHAIN_TASK_ID_1).isPresent()); + final SmsClient smsClient = assertDoesNotThrow(() -> smsClientProvider.getOrCreateSmsClientForTask(CHAIN_TASK_ID_1)); + assertNotNull(smsClient); } @Test void shouldNotRebuildSmsClientForSameTask() { Mockito.when(iexecHubService.getTaskDescription(CHAIN_TASK_ID_1)).thenReturn(TASK_DESCRIPTION_1); - final Optional smsClient1 = smsClientProvider.getSmsClientForTask(CHAIN_TASK_ID_1); - assertTrue(smsClient1.isPresent()); + final SmsClient smsClient1 = assertDoesNotThrow(() -> smsClientProvider.getOrCreateSmsClientForTask(CHAIN_TASK_ID_1)); + assertNotNull(smsClient1); - final Optional smsClient2 = smsClientProvider.getSmsClientForTask(CHAIN_TASK_ID_1); - assertTrue(smsClient2.isPresent()); + final SmsClient smsClient2 = assertDoesNotThrow(() -> smsClientProvider.getOrCreateSmsClientForTask(CHAIN_TASK_ID_1)); + assertNotNull(smsClient2); assertEquals(smsClient1, smsClient2); } @@ -68,12 +67,12 @@ void shouldNotRebuildSmsClientForSameTask() { @Test void shouldNotRebuildSmsClientForSameSmsUrlOnAnotherTask() { Mockito.when(iexecHubService.getTaskDescription(CHAIN_TASK_ID_1)).thenReturn(TASK_DESCRIPTION_1); - final Optional smsClient1 = smsClientProvider.getSmsClientForTask(CHAIN_TASK_ID_1); - assertTrue(smsClient1.isPresent()); + final SmsClient smsClient1 = assertDoesNotThrow(() -> smsClientProvider.getOrCreateSmsClientForTask(CHAIN_TASK_ID_1)); + assertNotNull(smsClient1); Mockito.when(iexecHubService.getTaskDescription(CHAIN_TASK_ID_3)).thenReturn(TASK_DESCRIPTION_3); - final Optional smsClient2 = smsClientProvider.getSmsClientForTask(CHAIN_TASK_ID_3); - assertTrue(smsClient2.isPresent()); + final SmsClient smsClient2 = assertDoesNotThrow(() -> smsClientProvider.getOrCreateSmsClientForTask(CHAIN_TASK_ID_3)); + assertNotNull(smsClient2); assertEquals(smsClient1, smsClient2); } @@ -83,11 +82,12 @@ void shouldBuildAnotherSmsClientForTaskOnSecondCallForAnotherSms() { Mockito.when(iexecHubService.getTaskDescription(CHAIN_TASK_ID_1)).thenReturn(TASK_DESCRIPTION_1); Mockito.when(iexecHubService.getTaskDescription(CHAIN_TASK_ID_2)).thenReturn(TASK_DESCRIPTION_2); - final Optional smsClientForTask1 = smsClientProvider.getSmsClientForTask(CHAIN_TASK_ID_1); - assertTrue(smsClientForTask1.isPresent()); + final SmsClient smsClientForTask1 = assertDoesNotThrow(() -> smsClientProvider.getOrCreateSmsClientForTask(CHAIN_TASK_ID_1)); + assertNotNull(smsClientForTask1); + + final SmsClient smsClientForTask2 = assertDoesNotThrow(() -> smsClientProvider.getOrCreateSmsClientForTask(CHAIN_TASK_ID_2)); + assertNotNull(smsClientForTask2); - final Optional smsClientForTask2 = smsClientProvider.getSmsClientForTask(CHAIN_TASK_ID_2); - assertTrue(smsClientForTask2.isPresent()); assertNotEquals(smsClientForTask1, smsClientForTask2); } @@ -96,13 +96,17 @@ void shouldBuildAnotherSmsClientForTaskOnSecondCallForAnotherSms() { void shouldNotGetSmsClientForTaskWhenNoTask() { Mockito.when(iexecHubService.getTaskDescription(CHAIN_TASK_ID_1)).thenReturn(null); - assertTrue(smsClientProvider.getSmsClientForTask(CHAIN_TASK_ID_1).isEmpty()); + SmsClientCreationException e = assertThrows(SmsClientCreationException.class, + () -> smsClientProvider.getOrCreateSmsClientForTask(CHAIN_TASK_ID_1)); + assertEquals("No such task [chainTaskId: " + CHAIN_TASK_ID_1 +"]", e.getMessage()); } @Test void shouldNotGetSmsClientForTaskWhenNoSmsUrl() { Mockito.when(iexecHubService.getTaskDescription(CHAIN_TASK_ID_1)).thenReturn(TaskDescription.builder().build()); - assertTrue(smsClientProvider.getSmsClientForTask(CHAIN_TASK_ID_1).isEmpty()); + SmsClientCreationException e = assertThrows(SmsClientCreationException.class, + () -> smsClientProvider.getOrCreateSmsClientForTask(CHAIN_TASK_ID_1)); + assertEquals("No SMS URL defined for given task [chainTaskId: " + CHAIN_TASK_ID_1 +"]", e.getMessage()); } } \ No newline at end of file From 780fbbe61261a4e449fa37bb820b0f049afadd80 Mon Sep 17 00:00:00 2001 From: mcornaton Date: Wed, 24 Aug 2022 10:24:57 +0200 Subject: [PATCH 038/293] Rename `gramine.sps.enclave.host` into `gramine.sps.enclave.hostname` --- .../com/iexec/sms/tee/session/gramine/sps/SpsConfiguration.java | 2 +- src/main/resources/application.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsConfiguration.java b/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsConfiguration.java index b00d2cef..80c19adb 100644 --- a/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsConfiguration.java +++ b/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsConfiguration.java @@ -37,7 +37,7 @@ public class SpsConfiguration { @Value("${gramine.sps.web.password}") private String webPassword; - @Value("${gramine.sps.enclave.host}") + @Value("${gramine.sps.enclave.hostname}") private String enclaveHostName; @Value("${gramine.sps.enclave.port}") diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 6505dd00..47251380 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -67,7 +67,7 @@ gramine: login: ${IEXEC_GRAPHENE_SPS_WEB_LOGIN:admin} password: ${IEXEC_GRAPHENE_SPS_WEB_PASSWORD:admin} enclave: - host: ${IEXEC_GRAPHENE_SPS_ENCLAVE_HOST_NAME:localhost} + hostname: ${IEXEC_GRAPHENE_SPS_ENCLAVE_HOST_NAME:localhost} port: ${IEXEC_GRAPHENE_SPS_ENCLAVE_PORT:4433} # TODO /!\ remove the option of env variable for releases. From 1944b28dbea9025b131b4ab96219d5113356681e Mon Sep 17 00:00:00 2001 From: mcornaton Date: Wed, 24 Aug 2022 15:06:54 +0200 Subject: [PATCH 039/293] Get SMS URL from ChainDeal if task not initialized --- .../com/iexec/sms/api/SmsClientProvider.java | 45 +++++-- .../iexec/sms/api/SmsClientProviderTests.java | 116 ++++++++++++++---- 2 files changed, 133 insertions(+), 28 deletions(-) diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java index b9860dc0..25e5d94e 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java @@ -1,5 +1,6 @@ package com.iexec.sms.api; +import com.iexec.common.chain.ChainDeal; import com.iexec.common.chain.IexecHubAbstractService; import com.iexec.common.task.TaskDescription; import feign.Logger; @@ -8,6 +9,7 @@ import java.util.HashMap; import java.util.Map; +import java.util.Optional; /** * Manages the {@link SmsClient}, providing an easy way to access SMS @@ -15,6 +17,8 @@ */ @Slf4j public class SmsClientProvider { + // TODO: purge once task has been completed + private final Map> taskIdToSmsUrl = new HashMap<>(); private final Map urlToSmsClient = new HashMap<>(); private final IexecHubAbstractService iexecHubService; @@ -40,19 +44,46 @@ public SmsClientProvider(IexecHubAbstractService iexecHubService, *
* * @param chainTaskId ID of the task the specified SMS URL should be retrieved. + * @throws SmsClientCreationException if SMS URL can't be retrieved. * @return An instance of {@link SmsClient} pointing on the task's specified SMS. */ public SmsClient getOrCreateSmsClientForTask(String chainTaskId) { - final TaskDescription taskDescription = iexecHubService.getTaskDescription(chainTaskId); - if (taskDescription == null) { - throw new SmsClientCreationException("No such task [chainTaskId: " + chainTaskId +"]"); + final Optional smsUrl = getSmsUrlForTask(chainTaskId); + if (smsUrl.isEmpty() || StringUtils.isEmpty(smsUrl.get())) { + throw new SmsClientCreationException("No SMS URL defined for given task [chainTaskId: " + chainTaskId +"]"); } - final String smsUrl = taskDescription.getSmsUrl(); - if (StringUtils.isEmpty(smsUrl)) { - throw new SmsClientCreationException("No SMS URL defined for given task [chainTaskId: " + chainTaskId +"]"); + return urlToSmsClient.computeIfAbsent(smsUrl.get(), url -> SmsClientBuilder.getInstance(loggerLevel, url)); + } + + /** + * Retrieves the SMS URL defined for this task and caches the result. + *

+ * If the task has already been initialized, then gets the URL from the {@link TaskDescription}. + * Otherwise, gets the URL from the {@link ChainDeal}. + * + * @param chainTaskId ID of the task the specified SMS URL should be retrieved. + * @return The SMS URL defined for this task. + */ + Optional getSmsUrlForTask(String chainTaskId) { + if (taskIdToSmsUrl.containsKey(chainTaskId)) { + return taskIdToSmsUrl.get(chainTaskId); + } + + final Optional smsUrl; + + final TaskDescription taskDescription = iexecHubService.getTaskDescription(chainTaskId); + if (taskDescription != null) { + smsUrl = Optional.ofNullable(taskDescription.getSmsUrl()); + } else { + // Fallback: if task is not initialized yet, + // we can still get its SMS url in its deal. + final Optional chainDeal = iexecHubService.getChainDeal(chainTaskId); + smsUrl = chainDeal + .map(deal -> deal.getParams().getIexecSmsUrl()); } - return urlToSmsClient.computeIfAbsent(smsUrl, url -> SmsClientBuilder.getInstance(loggerLevel, url)); + taskIdToSmsUrl.put(chainTaskId, smsUrl); + return smsUrl; } } diff --git a/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientProviderTests.java b/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientProviderTests.java index de42e094..b00d4674 100644 --- a/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientProviderTests.java +++ b/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientProviderTests.java @@ -1,5 +1,7 @@ package com.iexec.sms.api; +import com.iexec.common.chain.ChainDeal; +import com.iexec.common.chain.DealParams; import com.iexec.common.chain.IexecHubAbstractService; import com.iexec.common.task.TaskDescription; import feign.Logger; @@ -9,7 +11,10 @@ import org.mockito.Mockito; import org.mockito.MockitoAnnotations; +import java.util.Optional; + import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; class SmsClientProviderTests { private static final String CHAIN_TASK_ID_1 = "chainTaskId1"; @@ -26,11 +31,7 @@ class SmsClientProviderTests { .smsUrl(SMS_URL_2) .build(); - private static final String CHAIN_TASK_ID_3 = "chainTaskId1"; - private static final TaskDescription TASK_DESCRIPTION_3 = TaskDescription.builder() - .chainTaskId(CHAIN_TASK_ID_3) - .smsUrl(SMS_URL_1) // Same as first task - .build(); + private static final String CHAIN_TASK_ID_3 = "chainTaskId3"; @Mock IexecHubAbstractService iexecHubService; @@ -40,12 +41,13 @@ class SmsClientProviderTests { @BeforeEach void init() { MockitoAnnotations.openMocks(this); - smsClientProvider = new SmsClientProvider(iexecHubService, Logger.Level.NONE); + smsClientProvider = spy(new SmsClientProvider(iexecHubService, Logger.Level.NONE)); } + // region getOrCreateSmsClientForTask @Test void shouldGetSmsClientForTask() { - Mockito.when(iexecHubService.getTaskDescription(CHAIN_TASK_ID_1)).thenReturn(TASK_DESCRIPTION_1); + Mockito.when(smsClientProvider.getSmsUrlForTask(CHAIN_TASK_ID_1)).thenReturn(Optional.of(SMS_URL_1)); final SmsClient smsClient = assertDoesNotThrow(() -> smsClientProvider.getOrCreateSmsClientForTask(CHAIN_TASK_ID_1)); assertNotNull(smsClient); @@ -53,7 +55,7 @@ void shouldGetSmsClientForTask() { @Test void shouldNotRebuildSmsClientForSameTask() { - Mockito.when(iexecHubService.getTaskDescription(CHAIN_TASK_ID_1)).thenReturn(TASK_DESCRIPTION_1); + Mockito.when(smsClientProvider.getSmsUrlForTask(CHAIN_TASK_ID_1)).thenReturn(Optional.of(SMS_URL_1)); final SmsClient smsClient1 = assertDoesNotThrow(() -> smsClientProvider.getOrCreateSmsClientForTask(CHAIN_TASK_ID_1)); assertNotNull(smsClient1); @@ -66,11 +68,11 @@ void shouldNotRebuildSmsClientForSameTask() { @Test void shouldNotRebuildSmsClientForSameSmsUrlOnAnotherTask() { - Mockito.when(iexecHubService.getTaskDescription(CHAIN_TASK_ID_1)).thenReturn(TASK_DESCRIPTION_1); + Mockito.when(smsClientProvider.getSmsUrlForTask(CHAIN_TASK_ID_1)).thenReturn(Optional.of(SMS_URL_1)); final SmsClient smsClient1 = assertDoesNotThrow(() -> smsClientProvider.getOrCreateSmsClientForTask(CHAIN_TASK_ID_1)); assertNotNull(smsClient1); - Mockito.when(iexecHubService.getTaskDescription(CHAIN_TASK_ID_3)).thenReturn(TASK_DESCRIPTION_3); + Mockito.when(smsClientProvider.getSmsUrlForTask(CHAIN_TASK_ID_3)).thenReturn(Optional.of(SMS_URL_1)); final SmsClient smsClient2 = assertDoesNotThrow(() -> smsClientProvider.getOrCreateSmsClientForTask(CHAIN_TASK_ID_3)); assertNotNull(smsClient2); @@ -79,8 +81,8 @@ void shouldNotRebuildSmsClientForSameSmsUrlOnAnotherTask() { @Test void shouldBuildAnotherSmsClientForTaskOnSecondCallForAnotherSms() { - Mockito.when(iexecHubService.getTaskDescription(CHAIN_TASK_ID_1)).thenReturn(TASK_DESCRIPTION_1); - Mockito.when(iexecHubService.getTaskDescription(CHAIN_TASK_ID_2)).thenReturn(TASK_DESCRIPTION_2); + Mockito.when(smsClientProvider.getSmsUrlForTask(CHAIN_TASK_ID_1)).thenReturn(Optional.of(SMS_URL_1)); + Mockito.when(smsClientProvider.getSmsUrlForTask(CHAIN_TASK_ID_2)).thenReturn(Optional.of(SMS_URL_2)); final SmsClient smsClientForTask1 = assertDoesNotThrow(() -> smsClientProvider.getOrCreateSmsClientForTask(CHAIN_TASK_ID_1)); assertNotNull(smsClientForTask1); @@ -88,25 +90,97 @@ void shouldBuildAnotherSmsClientForTaskOnSecondCallForAnotherSms() { final SmsClient smsClientForTask2 = assertDoesNotThrow(() -> smsClientProvider.getOrCreateSmsClientForTask(CHAIN_TASK_ID_2)); assertNotNull(smsClientForTask2); - assertNotEquals(smsClientForTask1, smsClientForTask2); } @Test - void shouldNotGetSmsClientForTaskWhenNoTask() { - Mockito.when(iexecHubService.getTaskDescription(CHAIN_TASK_ID_1)).thenReturn(null); + void shouldNotGetSmsClientForTaskWhenNoSmsUrl() { + Mockito.when(smsClientProvider.getSmsUrlForTask(CHAIN_TASK_ID_1)).thenReturn(Optional.empty()); SmsClientCreationException e = assertThrows(SmsClientCreationException.class, () -> smsClientProvider.getOrCreateSmsClientForTask(CHAIN_TASK_ID_1)); - assertEquals("No such task [chainTaskId: " + CHAIN_TASK_ID_1 +"]", e.getMessage()); + assertEquals("No SMS URL defined for given task [chainTaskId: " + CHAIN_TASK_ID_1 +"]", e.getMessage()); } + // endregion + // region getSmsUrlForTask @Test - void shouldNotGetSmsClientForTaskWhenNoSmsUrl() { - Mockito.when(iexecHubService.getTaskDescription(CHAIN_TASK_ID_1)).thenReturn(TaskDescription.builder().build()); + void shouldGetSmsUrlForTaskWhenTaskFound() { + Mockito.when(iexecHubService.getTaskDescription(CHAIN_TASK_ID_1)).thenReturn(TASK_DESCRIPTION_1); - SmsClientCreationException e = assertThrows(SmsClientCreationException.class, - () -> smsClientProvider.getOrCreateSmsClientForTask(CHAIN_TASK_ID_1)); - assertEquals("No SMS URL defined for given task [chainTaskId: " + CHAIN_TASK_ID_1 +"]", e.getMessage()); + Optional smsUrl = smsClientProvider.getSmsUrlForTask(CHAIN_TASK_ID_1); + assertTrue(smsUrl.isPresent()); + assertEquals(SMS_URL_1, smsUrl.get()); + + verify(iexecHubService, times(1)).getTaskDescription(any()); + verify(iexecHubService, times(0)).getChainDeal(any()); + } + + @Test + void shouldGetSmsUrlOnlyOnceForSameTask() { + Mockito.when(iexecHubService.getTaskDescription(CHAIN_TASK_ID_1)).thenReturn(TASK_DESCRIPTION_1); + + Optional smsUrlFirstCall = smsClientProvider.getSmsUrlForTask(CHAIN_TASK_ID_1); + assertTrue(smsUrlFirstCall.isPresent()); + assertEquals(SMS_URL_1, smsUrlFirstCall.get()); + + verify(iexecHubService, times(1)).getTaskDescription(any()); + verify(iexecHubService, times(0)).getChainDeal(any()); + + Optional smsUrlSecondCall = smsClientProvider.getSmsUrlForTask(CHAIN_TASK_ID_1); + assertTrue(smsUrlSecondCall.isPresent()); + assertEquals(SMS_URL_1, smsUrlSecondCall.get()); + + verify(iexecHubService, times(1)).getTaskDescription(any()); + verify(iexecHubService, times(0)).getChainDeal(any()); + } + + @Test + void shouldGetSmsUrlTwiceForDifferentTasks() { + Mockito.when(iexecHubService.getTaskDescription(CHAIN_TASK_ID_1)).thenReturn(TASK_DESCRIPTION_1); + Mockito.when(iexecHubService.getTaskDescription(CHAIN_TASK_ID_2)).thenReturn(TASK_DESCRIPTION_2); + + Optional smsUrlFirstCall = smsClientProvider.getSmsUrlForTask(CHAIN_TASK_ID_1); + assertTrue(smsUrlFirstCall.isPresent()); + assertEquals(SMS_URL_1, smsUrlFirstCall.get()); + + verify(iexecHubService, times(1)).getTaskDescription(any()); + verify(iexecHubService, times(0)).getChainDeal(any()); + + Optional smsUrlSecondCall = smsClientProvider.getSmsUrlForTask(CHAIN_TASK_ID_2); + assertTrue(smsUrlSecondCall.isPresent()); + assertEquals(SMS_URL_2, smsUrlSecondCall.get()); + + verify(iexecHubService, times(2)).getTaskDescription(any()); + verify(iexecHubService, times(0)).getChainDeal(any()); + } + + + @Test + void shouldGetSmsUrlForTaskWhenTaskNotFoundButDealFound() { + Mockito.when(iexecHubService.getTaskDescription(CHAIN_TASK_ID_1)).thenReturn(null); + Mockito.when(iexecHubService.getChainDeal(CHAIN_TASK_ID_1)).thenReturn(Optional.of( + ChainDeal.builder().params(DealParams.builder().iexecSmsUrl(SMS_URL_1).build()).build() + )); + + Optional smsUrl = smsClientProvider.getSmsUrlForTask(CHAIN_TASK_ID_1); + assertTrue(smsUrl.isPresent()); + assertEquals(SMS_URL_1, smsUrl.get()); + + verify(iexecHubService, times(1)).getTaskDescription(any()); + verify(iexecHubService, times(1)).getChainDeal(any()); + } + + @Test + void shouldNotGetSmsUrlForTaskWhenTaskAndDealNotFound() { + Mockito.when(iexecHubService.getTaskDescription(CHAIN_TASK_ID_1)).thenReturn(null); + Mockito.when(iexecHubService.getChainDeal(CHAIN_TASK_ID_1)).thenReturn(Optional.empty()); + + Optional smsUrl = smsClientProvider.getSmsUrlForTask(CHAIN_TASK_ID_1); + assertTrue(smsUrl.isEmpty()); + + verify(iexecHubService, times(1)).getTaskDescription(any()); + verify(iexecHubService, times(1)).getChainDeal(any()); } + // region } \ No newline at end of file From 0422ada359bb79fcfe490d45b57f67b1e26ee7c3 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton <87655102+mcornaton@users.noreply.github.com> Date: Wed, 24 Aug 2022 15:34:36 +0200 Subject: [PATCH 040/293] Add #TODO to application.yml MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jérémy James Toussaint <33313130+jeremyjams@users.noreply.github.com> --- src/main/resources/application.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 47251380..e5062261 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -67,6 +67,7 @@ gramine: login: ${IEXEC_GRAPHENE_SPS_WEB_LOGIN:admin} password: ${IEXEC_GRAPHENE_SPS_WEB_PASSWORD:admin} enclave: + //TODO: Merge shared conf of CAS & SPS (url, port, ..) in a common top parent in yml. Use only secret-provisioner.gramine: and secret-provisioner.scone: for additionnal properties. hostname: ${IEXEC_GRAPHENE_SPS_ENCLAVE_HOST_NAME:localhost} port: ${IEXEC_GRAPHENE_SPS_ENCLAVE_PORT:4433} From f4f5bca730e2f1fa281ccf00980556574421be95 Mon Sep 17 00:00:00 2001 From: mcornaton Date: Wed, 24 Aug 2022 17:53:13 +0200 Subject: [PATCH 041/293] Refactor `TeeWorkflowConfiguration` --- .../java/com/iexec/sms/api/SmsClient.java | 3 +- .../sms/api/TeeWorkflowConfiguration.java | 41 +++++++ .../java/com/iexec/sms/tee/TeeController.java | 18 ++-- .../base/SecretSessionBaseService.java | 6 +- .../gramine/GramineSessionMakerService.java | 6 +- .../scone/SconeSessionMakerService.java | 6 +- .../workflow/TeeWorkflowConfiguration.java | 101 ------------------ .../TeeWorkflowInternalConfiguration.java | 98 +++++++++++++++++ .../com/iexec/sms/tee/TeeControllerTests.java | 4 +- .../base/SecretSessionBaseServiceTests.java | 4 +- .../GramineSessionMakerServiceTests.java | 4 +- .../scone/SconeSessionMakerServiceTests.java | 4 +- .../TeeWorkflowConfigurationTests.java | 51 --------- 13 files changed, 164 insertions(+), 182 deletions(-) create mode 100644 iexec-sms-library/src/main/java/com/iexec/sms/api/TeeWorkflowConfiguration.java delete mode 100644 src/main/java/com/iexec/sms/tee/workflow/TeeWorkflowConfiguration.java create mode 100644 src/main/java/com/iexec/sms/tee/workflow/TeeWorkflowInternalConfiguration.java delete mode 100644 src/test/java/com/iexec/sms/tee/workflow/TeeWorkflowConfigurationTests.java diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java index 5cc66df5..9e7091dd 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java @@ -18,7 +18,6 @@ import com.iexec.common.chain.WorkerpoolAuthorization; import com.iexec.common.sms.secret.SmsSecretResponse; -import com.iexec.common.tee.TeeWorkflowSharedConfiguration; import com.iexec.common.web.ApiResponseBody; import feign.Headers; import feign.Param; @@ -92,7 +91,7 @@ ApiResponseBody generat ); @RequestLine("GET /tee/workflow/config") - TeeWorkflowSharedConfiguration getTeeWorkflowConfiguration(); + TeeWorkflowConfiguration getTeeWorkflowConfiguration(); @RequestLine("POST /untee/secrets") @Headers("Authorization: {authorization}") diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/TeeWorkflowConfiguration.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/TeeWorkflowConfiguration.java new file mode 100644 index 00000000..f56a7de5 --- /dev/null +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/TeeWorkflowConfiguration.java @@ -0,0 +1,41 @@ +/* + * Copyright 2020 IEXEC BLOCKCHAIN TECH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.iexec.sms.api; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +/** + * Configuration of tee workflow. It contains: + * pre-compute image, pre-compute heap size, pre compute entrypoint, + * post-compute image, post-compute heap size, post compute entrypoint. + */ +@Builder +@Getter +@AllArgsConstructor +@NoArgsConstructor +public class TeeWorkflowConfiguration { + private String lasImage; + private String preComputeImage; + private long preComputeHeapSize; + private String preComputeEntrypoint; + private String postComputeImage; + private long postComputeHeapSize; + private String postComputeEntrypoint; +} diff --git a/src/main/java/com/iexec/sms/tee/TeeController.java b/src/main/java/com/iexec/sms/tee/TeeController.java index a12a480f..ee076155 100644 --- a/src/main/java/com/iexec/sms/tee/TeeController.java +++ b/src/main/java/com/iexec/sms/tee/TeeController.java @@ -18,17 +18,17 @@ import com.iexec.common.chain.WorkerpoolAuthorization; -import com.iexec.common.tee.TeeWorkflowSharedConfiguration; import com.iexec.common.web.ApiResponseBody; import com.iexec.sms.api.TeeSessionGenerationError; import com.iexec.sms.api.TeeSessionGenerationResponse; +import com.iexec.sms.api.TeeWorkflowConfiguration; import com.iexec.sms.authorization.AuthorizationError; import com.iexec.sms.authorization.AuthorizationService; import com.iexec.sms.tee.challenge.TeeChallenge; import com.iexec.sms.tee.challenge.TeeChallengeService; import com.iexec.sms.tee.session.TeeSessionService; import com.iexec.sms.tee.session.generic.TeeSessionGenerationException; -import com.iexec.sms.tee.workflow.TeeWorkflowConfiguration; +import com.iexec.sms.tee.workflow.TeeWorkflowInternalConfiguration; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -58,13 +58,13 @@ public class TeeController { private final AuthorizationService authorizationService; private final TeeChallengeService teeChallengeService; private final TeeSessionService teeSessionService; - private final TeeWorkflowConfiguration teeWorkflowConfig; + private final TeeWorkflowInternalConfiguration teeWorkflowConfig; public TeeController( AuthorizationService authorizationService, TeeChallengeService teeChallengeService, TeeSessionService teeSessionService, - TeeWorkflowConfiguration teeWorkflowConfig) { + TeeWorkflowInternalConfiguration teeWorkflowConfig) { this.authorizationService = authorizationService; this.teeChallengeService = teeChallengeService; this.teeSessionService = teeSessionService; @@ -74,17 +74,13 @@ public TeeController( /** * Retrieve configuration for tee workflow. This includes configuration * for pre-compute and post-compute stages. - *

- * Note: Being able to read the fingerprints on this endpoint is not required - * for the workflow but it might be convenient to keep it for - * transparency purposes. * * @return tee workflow config (pre-compute image uri, post-compute image uri, - * pre-compute fingerprint, heap size, ...) + * heap size, ...) */ @GetMapping("/workflow/config") - public ResponseEntity getTeeWorkflowSharedConfig() { - return ResponseEntity.ok(teeWorkflowConfig.getSharedConfiguration()); + public ResponseEntity getTeeWorkflowSharedConfig() { + return ResponseEntity.ok(teeWorkflowConfig.getSharedConfig()); } /** diff --git a/src/main/java/com/iexec/sms/tee/session/base/SecretSessionBaseService.java b/src/main/java/com/iexec/sms/tee/session/base/SecretSessionBaseService.java index 66941d93..e6de7868 100644 --- a/src/main/java/com/iexec/sms/tee/session/base/SecretSessionBaseService.java +++ b/src/main/java/com/iexec/sms/tee/session/base/SecretSessionBaseService.java @@ -34,7 +34,7 @@ import com.iexec.sms.tee.session.base.SecretSessionBase.SecretSessionBaseBuilder; import com.iexec.sms.tee.session.generic.TeeSessionGenerationException; import com.iexec.sms.tee.session.generic.TeeSessionRequest; -import com.iexec.sms.tee.workflow.TeeWorkflowConfiguration; +import com.iexec.sms.tee.workflow.TeeWorkflowInternalConfiguration; import com.iexec.sms.utils.EthereumCredentials; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; @@ -71,14 +71,14 @@ public class SecretSessionBaseService { private final Web3SecretService web3SecretService; private final Web2SecretsService web2SecretsService; private final TeeChallengeService teeChallengeService; - private final TeeWorkflowConfiguration teeWorkflowConfig; + private final TeeWorkflowInternalConfiguration teeWorkflowConfig; private final TeeTaskComputeSecretService teeTaskComputeSecretService; public SecretSessionBaseService( Web3SecretService web3SecretService, Web2SecretsService web2SecretsService, TeeChallengeService teeChallengeService, - TeeWorkflowConfiguration teeWorkflowConfig, + TeeWorkflowInternalConfiguration teeWorkflowConfig, TeeTaskComputeSecretService teeTaskComputeSecretService) { this.web3SecretService = web3SecretService; this.web2SecretsService = web2SecretsService; diff --git a/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerService.java b/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerService.java index f6616e73..2486a4ae 100644 --- a/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerService.java +++ b/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerService.java @@ -24,7 +24,7 @@ import com.iexec.sms.tee.session.gramine.sps.GramineEnclave; import com.iexec.sms.tee.session.gramine.sps.GramineSession; import com.iexec.sms.tee.session.gramine.sps.GramineSession.GramineSessionBuilder; -import com.iexec.sms.tee.workflow.TeeWorkflowConfiguration; +import com.iexec.sms.tee.workflow.TeeWorkflowInternalConfiguration; import org.springframework.stereotype.Service; import java.util.List; @@ -33,10 +33,10 @@ public class GramineSessionMakerService { private final SecretSessionBaseService secretSessionBaseService; - private TeeWorkflowConfiguration teeWorkflowConfiguration; + private TeeWorkflowInternalConfiguration teeWorkflowConfiguration; public GramineSessionMakerService(SecretSessionBaseService secretSessionBaseService, - TeeWorkflowConfiguration teeWorkflowConfiguration) { + TeeWorkflowInternalConfiguration teeWorkflowConfiguration) { this.secretSessionBaseService = secretSessionBaseService; this.teeWorkflowConfiguration = teeWorkflowConfiguration; } diff --git a/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionMakerService.java b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionMakerService.java index 70d4292f..e17c4177 100644 --- a/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionMakerService.java +++ b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionMakerService.java @@ -27,7 +27,7 @@ import com.iexec.sms.tee.session.scone.cas.SconeSession.Image.Volume; import com.iexec.sms.tee.session.scone.cas.SconeSession.Security; import com.iexec.sms.tee.session.scone.cas.SconeSession.Volumes; -import com.iexec.sms.tee.workflow.TeeWorkflowConfiguration; +import com.iexec.sms.tee.workflow.TeeWorkflowInternalConfiguration; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -53,12 +53,12 @@ public class SconeSessionMakerService { static final String POST_COMPUTE_ENTRYPOINT = "POST_COMPUTE_ENTRYPOINT"; private final SecretSessionBaseService secretSessionBaseService; - private final TeeWorkflowConfiguration teeWorkflowConfig; + private final TeeWorkflowInternalConfiguration teeWorkflowConfig; private final SconeSessionSecurityConfig attestationSecurityConfig; public SconeSessionMakerService( SecretSessionBaseService secretSessionBaseService, - TeeWorkflowConfiguration teeWorkflowConfig, + TeeWorkflowInternalConfiguration teeWorkflowConfig, SconeSessionSecurityConfig attestationSecurityConfig) { this.secretSessionBaseService = secretSessionBaseService; this.teeWorkflowConfig = teeWorkflowConfig; diff --git a/src/main/java/com/iexec/sms/tee/workflow/TeeWorkflowConfiguration.java b/src/main/java/com/iexec/sms/tee/workflow/TeeWorkflowConfiguration.java deleted file mode 100644 index 9c5859a7..00000000 --- a/src/main/java/com/iexec/sms/tee/workflow/TeeWorkflowConfiguration.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright 2020 IEXEC BLOCKCHAIN TECH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.iexec.sms.tee.workflow; - -import com.iexec.common.tee.TeeWorkflowSharedConfiguration; -import lombok.AccessLevel; -import lombok.Getter; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Configuration; -import org.springframework.util.unit.DataSize; - -import javax.annotation.PostConstruct; -import javax.validation.ConstraintViolationException; -import javax.validation.Validator; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.Positive; - -@Configuration -@Getter -public class TeeWorkflowConfiguration { - - @Value("${tee.workflow.las-image}") - @NotBlank(message = "las image must be provided") - String lasImage; - - @Value("${tee.workflow.pre-compute.image}") - @NotBlank(message = "pre-compute image must be provided") - String preComputeImage; - - @Value("${tee.workflow.pre-compute.fingerprint}") - @NotBlank(message = "pre-compute fingerprint must be provided") - String preComputeFingerprint; - - @Value("${tee.workflow.pre-compute.entrypoint}") - @NotBlank(message = "pre-compute entrypoint must be provided") - String preComputeEntrypoint; - - @Value("${tee.workflow.pre-compute.heap-size-gb}") - @Positive(message = "pre-compute heap size must be provided") - int preComputeHeapSizeGb; - - @Value("${tee.workflow.post-compute.image}") - @NotBlank(message = "post-compute image must be provided") - String postComputeImage; - - @Value("${tee.workflow.post-compute.fingerprint}") - @NotBlank(message = "post-compute fingerprint must be provided") - String postComputeFingerprint; - - @Value("${tee.workflow.post-compute.entrypoint}") - @NotBlank(message = "post-compute entrypoint must be provided") - String postComputeEntrypoint; - - @Value("${tee.workflow.post-compute.heap-size-gb}") - @Positive(message = "post-compute heap size must be provided") - int postComputeHeapSizeGb; - - @Getter(AccessLevel.NONE) // no getter - private Validator validator; - - public TeeWorkflowConfiguration(Validator validator) { - this.validator = validator; - } - - @PostConstruct - private void validate() { - if (!validator.validate(this).isEmpty()) { - throw new ConstraintViolationException(validator.validate(this)); - } - } - - public TeeWorkflowSharedConfiguration getSharedConfiguration() { - return TeeWorkflowSharedConfiguration.builder() - .lasImage(lasImage) - .preComputeImage(preComputeImage) - .preComputeEntrypoint(preComputeEntrypoint) - .preComputeHeapSize(DataSize - .ofGigabytes(preComputeHeapSizeGb) - .toBytes()) - .postComputeImage(postComputeImage) - .postComputeEntrypoint(postComputeEntrypoint) - .postComputeHeapSize(DataSize - .ofGigabytes(postComputeHeapSizeGb) - .toBytes()) - .build(); - } -} diff --git a/src/main/java/com/iexec/sms/tee/workflow/TeeWorkflowInternalConfiguration.java b/src/main/java/com/iexec/sms/tee/workflow/TeeWorkflowInternalConfiguration.java new file mode 100644 index 00000000..ef5dccf0 --- /dev/null +++ b/src/main/java/com/iexec/sms/tee/workflow/TeeWorkflowInternalConfiguration.java @@ -0,0 +1,98 @@ +/* + * Copyright 2020 IEXEC BLOCKCHAIN TECH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.iexec.sms.tee.workflow; + +import com.iexec.sms.api.TeeWorkflowConfiguration; +import lombok.AccessLevel; +import lombok.Getter; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; + +import javax.annotation.PostConstruct; +import javax.validation.ConstraintViolationException; +import javax.validation.Validator; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Positive; + +@Configuration +@Getter +public class TeeWorkflowInternalConfiguration { + + private final TeeWorkflowConfiguration sharedConfig; + private final String preComputeFingerprint; + private final String postComputeFingerprint; + + @Getter(AccessLevel.NONE) // no getter + private final Validator validator; + + public TeeWorkflowInternalConfiguration( + @Value("${tee.workflow.las-image}") + @NotBlank(message = "las image must be provided") + String lasImage, + @Value("${tee.workflow.pre-compute.image}") + @NotBlank(message = "pre-compute image must be provided") + String preComputeImage, + @Value("${tee.workflow.pre-compute.fingerprint}") + @NotBlank(message = "pre-compute fingerprint must be provided") + String preComputeFingerprint, + @Value("${tee.workflow.pre-compute.entrypoint}") + @NotBlank(message = "pre-compute entrypoint must be provided") + String preComputeEntrypoint, + @Value("${tee.workflow.pre-compute.heap-size-gb}") + @Positive(message = "pre-compute heap size must be provided") + int preComputeHeapSizeGb, + @Value("${tee.workflow.post-compute.image}") + @NotBlank(message = "post-compute image must be provided") + String postComputeImage, + @Value("${tee.workflow.post-compute.fingerprint}") + @NotBlank(message = "post-compute fingerprint must be provided") + String postComputeFingerprint, + @Value("${tee.workflow.post-compute.entrypoint}") + @NotBlank(message = "post-compute entrypoint must be provided") + String postComputeEntrypoint, + @Value("${tee.workflow.post-compute.heap-size-gb}") + @Positive(message = "post-compute heap size must be provided") + int postComputeHeapSizeGb, + Validator validator) { + this.validator = validator; + this.preComputeFingerprint = preComputeFingerprint; + this.postComputeFingerprint = postComputeFingerprint; + this.sharedConfig = TeeWorkflowConfiguration.builder() + .lasImage(lasImage) + .preComputeImage(preComputeImage) + .preComputeHeapSize(preComputeHeapSizeGb) + .preComputeEntrypoint(preComputeEntrypoint) + .postComputeImage(postComputeImage) + .postComputeHeapSize(postComputeHeapSizeGb) + .postComputeEntrypoint(postComputeEntrypoint) + .build(); + } + + @PostConstruct + private void validate() { + if (!validator.validate(this).isEmpty()) { + throw new ConstraintViolationException(validator.validate(this)); + } + } + + public String getPreComputeEntrypoint() { + return sharedConfig.getPreComputeEntrypoint(); + } + public String getPostComputeEntrypoint() { + return sharedConfig.getPostComputeEntrypoint(); + } +} diff --git a/src/test/java/com/iexec/sms/tee/TeeControllerTests.java b/src/test/java/com/iexec/sms/tee/TeeControllerTests.java index 61e1b8e4..97e66dcf 100644 --- a/src/test/java/com/iexec/sms/tee/TeeControllerTests.java +++ b/src/test/java/com/iexec/sms/tee/TeeControllerTests.java @@ -9,7 +9,7 @@ import com.iexec.sms.tee.challenge.TeeChallengeService; import com.iexec.sms.tee.session.TeeSessionService; import com.iexec.sms.tee.session.generic.TeeSessionGenerationException; -import com.iexec.sms.tee.workflow.TeeWorkflowConfiguration; +import com.iexec.sms.tee.workflow.TeeWorkflowInternalConfiguration; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; @@ -46,7 +46,7 @@ class TeeControllerTests { @Mock TeeSessionService teeSessionService; @Mock - TeeWorkflowConfiguration teeWorkflowConfig; + TeeWorkflowInternalConfiguration teeWorkflowConfig; @InjectMocks TeeController teeController; diff --git a/src/test/java/com/iexec/sms/tee/session/base/SecretSessionBaseServiceTests.java b/src/test/java/com/iexec/sms/tee/session/base/SecretSessionBaseServiceTests.java index 09e7df1d..32798886 100644 --- a/src/test/java/com/iexec/sms/tee/session/base/SecretSessionBaseServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/base/SecretSessionBaseServiceTests.java @@ -19,7 +19,7 @@ import com.iexec.sms.tee.challenge.TeeChallengeService; import com.iexec.sms.tee.session.generic.TeeSessionGenerationException; import com.iexec.sms.tee.session.generic.TeeSessionRequest; -import com.iexec.sms.tee.workflow.TeeWorkflowConfiguration; +import com.iexec.sms.tee.workflow.TeeWorkflowInternalConfiguration; import com.iexec.sms.utils.EthereumCredentials; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; @@ -62,7 +62,7 @@ class SecretSessionBaseServiceTests { @Mock private TeeChallengeService teeChallengeService; @Mock - private TeeWorkflowConfiguration teeWorkflowConfig; + private TeeWorkflowInternalConfiguration teeWorkflowConfig; @Mock private TeeTaskComputeSecretService teeTaskComputeSecretService; diff --git a/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerServiceTests.java b/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerServiceTests.java index 87930adb..d4d0964a 100644 --- a/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerServiceTests.java @@ -7,7 +7,7 @@ import com.iexec.sms.tee.session.base.SecretSessionBaseService; import com.iexec.sms.tee.session.generic.TeeSessionRequest; import com.iexec.sms.tee.session.gramine.sps.GramineSession; -import com.iexec.sms.tee.workflow.TeeWorkflowConfiguration; +import com.iexec.sms.tee.workflow.TeeWorkflowInternalConfiguration; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -25,7 +25,7 @@ @Slf4j class GramineSessionMakerServiceTests { @Mock - private TeeWorkflowConfiguration teeWorkflowConfig; + private TeeWorkflowInternalConfiguration teeWorkflowConfig; @Mock private SecretSessionBaseService teeSecretsService; @InjectMocks diff --git a/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionMakerServiceTests.java b/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionMakerServiceTests.java index 2d599aa3..81e8f6e1 100644 --- a/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionMakerServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionMakerServiceTests.java @@ -23,7 +23,7 @@ import com.iexec.sms.tee.session.base.SecretSessionBaseService; import com.iexec.sms.tee.session.generic.TeeSessionRequest; import com.iexec.sms.tee.session.scone.cas.SconeSession; -import com.iexec.sms.tee.workflow.TeeWorkflowConfiguration; +import com.iexec.sms.tee.workflow.TeeWorkflowInternalConfiguration; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -48,7 +48,7 @@ class SconeSessionMakerServiceTests { private static final String POST_COMPUTE_ENTRYPOINT = "entrypoint3"; @Mock - private TeeWorkflowConfiguration teeWorkflowConfig; + private TeeWorkflowInternalConfiguration teeWorkflowConfig; @Mock private SecretSessionBaseService teeSecretsService; @Mock diff --git a/src/test/java/com/iexec/sms/tee/workflow/TeeWorkflowConfigurationTests.java b/src/test/java/com/iexec/sms/tee/workflow/TeeWorkflowConfigurationTests.java deleted file mode 100644 index fd930878..00000000 --- a/src/test/java/com/iexec/sms/tee/workflow/TeeWorkflowConfigurationTests.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.iexec.sms.tee.workflow; - -import com.iexec.common.tee.TeeWorkflowSharedConfiguration; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.springframework.test.util.ReflectionTestUtils; -import org.springframework.util.unit.DataSize; - -import static org.assertj.core.api.Assertions.assertThat; - -class TeeWorkflowConfigurationTests { - - private static final String LAS_IMAGE = "lasImage"; - private static final String PRE_COMPUTE_IMAGE = "preComputeImage"; - private static final String PRE_COMPUTE_FINGERPRINT = "preComputeFingerprint"; - private static final String PRE_COMPUTE_ENTRYPOINT = "preComputeEntrypoint"; - private static final int PRE_COMPUTE_HEAP_GB = 1; - private static final String POST_COMPUTE_IMAGE = "postComputeImage"; - private static final String POST_COMPUTE_FINGERPRINT = "postComputeFingerprint"; - private static final String POST_COMPUTE_ENTRYPOINT = "postComputeEntrypoint"; - private static final int POST_COMPUTE_HEAP_GB = 2; - - TeeWorkflowConfiguration teeWorkflowConfiguration = new TeeWorkflowConfiguration(null); - - @BeforeEach - void beforeEach() { - ReflectionTestUtils.setField(teeWorkflowConfiguration, "lasImage", LAS_IMAGE); - ReflectionTestUtils.setField(teeWorkflowConfiguration, "preComputeImage", PRE_COMPUTE_IMAGE); - ReflectionTestUtils.setField(teeWorkflowConfiguration, "preComputeFingerprint", PRE_COMPUTE_FINGERPRINT); - ReflectionTestUtils.setField(teeWorkflowConfiguration, "preComputeEntrypoint", PRE_COMPUTE_ENTRYPOINT); - ReflectionTestUtils.setField(teeWorkflowConfiguration, "preComputeHeapSizeGb", PRE_COMPUTE_HEAP_GB); - ReflectionTestUtils.setField(teeWorkflowConfiguration, "postComputeImage", POST_COMPUTE_IMAGE); - ReflectionTestUtils.setField(teeWorkflowConfiguration, "postComputeFingerprint", POST_COMPUTE_FINGERPRINT); - ReflectionTestUtils.setField(teeWorkflowConfiguration, "postComputeEntrypoint", POST_COMPUTE_ENTRYPOINT); - ReflectionTestUtils.setField(teeWorkflowConfiguration, "postComputeHeapSizeGb", POST_COMPUTE_HEAP_GB); - } - - @Test - void shouldGetPublicConfiguration() { - assertThat(teeWorkflowConfiguration.getSharedConfiguration()) - .isEqualTo(TeeWorkflowSharedConfiguration.builder() - .lasImage(LAS_IMAGE) - .preComputeImage(PRE_COMPUTE_IMAGE) - .preComputeEntrypoint(PRE_COMPUTE_ENTRYPOINT) - .preComputeHeapSize(DataSize.ofGigabytes(PRE_COMPUTE_HEAP_GB).toBytes()) - .postComputeImage(POST_COMPUTE_IMAGE) - .postComputeEntrypoint(POST_COMPUTE_ENTRYPOINT) - .postComputeHeapSize(DataSize.ofGigabytes(POST_COMPUTE_HEAP_GB).toBytes()) - .build()); - } -} From b7cd1ef38df455b1aaf278ecac8d7b591fb1cc91 Mon Sep 17 00:00:00 2001 From: mcornaton Date: Thu, 25 Aug 2022 09:11:51 +0200 Subject: [PATCH 042/293] Add TODO to rename `TeeWorkflowConfiguration` --- .../main/java/com/iexec/sms/api/TeeWorkflowConfiguration.java | 1 + 1 file changed, 1 insertion(+) diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/TeeWorkflowConfiguration.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/TeeWorkflowConfiguration.java index f56a7de5..00056c3c 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/TeeWorkflowConfiguration.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/TeeWorkflowConfiguration.java @@ -30,6 +30,7 @@ @Getter @AllArgsConstructor @NoArgsConstructor +// TODO: rename into `TeeServicesConfiguration` (or better) public class TeeWorkflowConfiguration { private String lasImage; private String preComputeImage; From 1329de2779d9f6536ec373d30233c1b7a93f3474 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton <87655102+mcornaton@users.noreply.github.com> Date: Thu, 25 Aug 2022 09:12:29 +0200 Subject: [PATCH 043/293] Add comment about `lasImage` (Scone only) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jérémy James Toussaint <33313130+jeremyjams@users.noreply.github.com> --- .../main/java/com/iexec/sms/api/TeeWorkflowConfiguration.java | 1 + 1 file changed, 1 insertion(+) diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/TeeWorkflowConfiguration.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/TeeWorkflowConfiguration.java index 00056c3c..0208eaa0 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/TeeWorkflowConfiguration.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/TeeWorkflowConfiguration.java @@ -32,6 +32,7 @@ @NoArgsConstructor // TODO: rename into `TeeServicesConfiguration` (or better) public class TeeWorkflowConfiguration { + // only required for Scone private String lasImage; private String preComputeImage; private long preComputeHeapSize; From 3bf377fe06c947c815e23336222e64b4f58795cc Mon Sep 17 00:00:00 2001 From: Maxence Cornaton <87655102+mcornaton@users.noreply.github.com> Date: Thu, 25 Aug 2022 09:19:04 +0200 Subject: [PATCH 044/293] Rearrange fields assignment in `TeeWorkflowInternalConfiguration` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jérémy James Toussaint <33313130+jeremyjams@users.noreply.github.com> --- .../sms/tee/workflow/TeeWorkflowInternalConfiguration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/iexec/sms/tee/workflow/TeeWorkflowInternalConfiguration.java b/src/main/java/com/iexec/sms/tee/workflow/TeeWorkflowInternalConfiguration.java index ef5dccf0..0d520060 100644 --- a/src/main/java/com/iexec/sms/tee/workflow/TeeWorkflowInternalConfiguration.java +++ b/src/main/java/com/iexec/sms/tee/workflow/TeeWorkflowInternalConfiguration.java @@ -68,7 +68,6 @@ public TeeWorkflowInternalConfiguration( @Positive(message = "post-compute heap size must be provided") int postComputeHeapSizeGb, Validator validator) { - this.validator = validator; this.preComputeFingerprint = preComputeFingerprint; this.postComputeFingerprint = postComputeFingerprint; this.sharedConfig = TeeWorkflowConfiguration.builder() @@ -80,6 +79,7 @@ public TeeWorkflowInternalConfiguration( .postComputeHeapSize(postComputeHeapSizeGb) .postComputeEntrypoint(postComputeEntrypoint) .build(); + this.validator = validator; } @PostConstruct From 660ac2cbc7e9b8d3f8201dc59ce02fbfc5f43786 Mon Sep 17 00:00:00 2001 From: mcornaton Date: Thu, 25 Aug 2022 10:00:59 +0200 Subject: [PATCH 045/293] Fix `TODO` comment in `application.yml` --- src/main/resources/application.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index e5062261..ee2287d6 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -67,7 +67,7 @@ gramine: login: ${IEXEC_GRAPHENE_SPS_WEB_LOGIN:admin} password: ${IEXEC_GRAPHENE_SPS_WEB_PASSWORD:admin} enclave: - //TODO: Merge shared conf of CAS & SPS (url, port, ..) in a common top parent in yml. Use only secret-provisioner.gramine: and secret-provisioner.scone: for additionnal properties. + # TODO: Merge shared conf of CAS & SPS (url, port, ..) in a common top parent in yml. Use only secret-provisioner.gramine: and secret-provisioner.scone: for additionnal properties. hostname: ${IEXEC_GRAPHENE_SPS_ENCLAVE_HOST_NAME:localhost} port: ${IEXEC_GRAPHENE_SPS_ENCLAVE_PORT:4433} From 2e95031feadb283f80ffbc4356f1ea78cf4db9f0 Mon Sep 17 00:00:00 2001 From: mcornaton Date: Thu, 25 Aug 2022 16:13:41 +0200 Subject: [PATCH 046/293] Get SmsClient from ChainDeal for uninitialized tasks --- .../com/iexec/sms/api/SmsClientProvider.java | 59 +++++-- .../iexec/sms/api/SmsClientProviderTests.java | 146 ++++++++++++++++-- 2 files changed, 177 insertions(+), 28 deletions(-) diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java index 25e5d94e..eac2248d 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java @@ -57,10 +57,7 @@ public SmsClient getOrCreateSmsClientForTask(String chainTaskId) { } /** - * Retrieves the SMS URL defined for this task and caches the result. - *

- * If the task has already been initialized, then gets the URL from the {@link TaskDescription}. - * Otherwise, gets the URL from the {@link ChainDeal}. + * Retrieves the SMS URL from the {@link TaskDescription} defined for this task and caches the result. * * @param chainTaskId ID of the task the specified SMS URL should be retrieved. * @return The SMS URL defined for this task. @@ -70,20 +67,54 @@ Optional getSmsUrlForTask(String chainTaskId) { return taskIdToSmsUrl.get(chainTaskId); } - final Optional smsUrl; - final TaskDescription taskDescription = iexecHubService.getTaskDescription(chainTaskId); - if (taskDescription != null) { - smsUrl = Optional.ofNullable(taskDescription.getSmsUrl()); - } else { - // Fallback: if task is not initialized yet, - // we can still get its SMS url in its deal. - final Optional chainDeal = iexecHubService.getChainDeal(chainTaskId); - smsUrl = chainDeal - .map(deal -> deal.getParams().getIexecSmsUrl()); + final Optional smsUrl = taskDescription != null + ? Optional.ofNullable(taskDescription.getSmsUrl()) + : Optional.empty(); + taskIdToSmsUrl.put(chainTaskId, smsUrl); + return smsUrl; + } + + /** + * Retrieves the specified SMS URL for this task based on its dealId, then: + *
    + *
  • If this SMS has already been accessed, returns the already-constructed {@link SmsClient};
  • + *
  • Otherwise, constructs, stores and returns a new {@link SmsClient}.
  • + *
+ * + * @param chainDealId ID of the task the specified SMS URL should be retrieved. + * @param chainTaskId ID of the task the specified SMS URL should be stored. + * @throws SmsClientCreationException if SMS URL can't be retrieved. + * @return An instance of {@link SmsClient} pointing on the deal's specified SMS. + */ + public SmsClient getOrCreateSmsClientForUninitializedTask(String chainDealId, String chainTaskId) { + final Optional smsUrl = getSmsUrlForUninitializedTask(chainDealId, chainTaskId); + if (smsUrl.isEmpty() || StringUtils.isEmpty(smsUrl.get())) { + throw new SmsClientCreationException("No SMS URL defined for given deal " + + "[chainDealId: " + chainDealId + ", chainTaskId: " + chainTaskId +"]"); } + return urlToSmsClient.computeIfAbsent(smsUrl.get(), url -> SmsClientBuilder.getInstance(loggerLevel, url)); + } + + /** + * Retrieves the SMS URL from the {@link ChainDeal} defined for this task and caches the result. + * + * @param chainDealId ID of the deal the specified SMS URL should be retrieved. + * @param chainTaskId ID of the task the specified SMS URL should be stored. + * @return The SMS URL defined for this deal. + */ + Optional getSmsUrlForUninitializedTask(String chainDealId, String chainTaskId) { + if (taskIdToSmsUrl.containsKey(chainTaskId)) { + return taskIdToSmsUrl.get(chainTaskId); + } + + final Optional chainDeal = iexecHubService.getChainDeal(chainDealId); + final Optional smsUrl = chainDeal + .map(deal -> deal.getParams().getIexecSmsUrl()); + taskIdToSmsUrl.put(chainTaskId, smsUrl); return smsUrl; } + } diff --git a/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientProviderTests.java b/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientProviderTests.java index b00d4674..f9f9fb24 100644 --- a/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientProviderTests.java +++ b/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientProviderTests.java @@ -17,20 +17,29 @@ import static org.mockito.Mockito.*; class SmsClientProviderTests { + private static final String CHAIN_DEAL_ID_1 = "chainDealId1"; private static final String CHAIN_TASK_ID_1 = "chainTaskId1"; private static final String SMS_URL_1 = "smsUrl1"; + private static final ChainDeal CHAIN_DEAL_1 = ChainDeal.builder() + .params(DealParams.builder().iexecSmsUrl(SMS_URL_1).build()) + .build(); private static final TaskDescription TASK_DESCRIPTION_1 = TaskDescription.builder() .chainTaskId(CHAIN_TASK_ID_1) .smsUrl(SMS_URL_1) .build(); + private static final String CHAIN_DEAL_ID_2 = "chainDealId2"; private static final String CHAIN_TASK_ID_2 = "chainTaskId2"; private static final String SMS_URL_2 = "smsUrl2"; + private static final ChainDeal CHAIN_DEAL_2 = ChainDeal.builder() + .params(DealParams.builder().iexecSmsUrl(SMS_URL_2).build()) + .build(); private static final TaskDescription TASK_DESCRIPTION_2 = TaskDescription.builder() .chainTaskId(CHAIN_TASK_ID_2) .smsUrl(SMS_URL_2) .build(); + private static final String CHAIN_DEAL_ID_3 = "chainDealId3"; private static final String CHAIN_TASK_ID_3 = "chainTaskId3"; @Mock @@ -155,32 +164,141 @@ void shouldGetSmsUrlTwiceForDifferentTasks() { verify(iexecHubService, times(0)).getChainDeal(any()); } - @Test - void shouldGetSmsUrlForTaskWhenTaskNotFoundButDealFound() { + void shouldNotGetSmsUrlForTaskWhenTaskNotFound() { Mockito.when(iexecHubService.getTaskDescription(CHAIN_TASK_ID_1)).thenReturn(null); - Mockito.when(iexecHubService.getChainDeal(CHAIN_TASK_ID_1)).thenReturn(Optional.of( - ChainDeal.builder().params(DealParams.builder().iexecSmsUrl(SMS_URL_1).build()).build() - )); Optional smsUrl = smsClientProvider.getSmsUrlForTask(CHAIN_TASK_ID_1); + assertTrue(smsUrl.isEmpty()); + + verify(iexecHubService, times(1)).getTaskDescription(any()); + verify(iexecHubService, times(0)).getChainDeal(any()); + } + // endregion + + // region getOrCreateSmsClientForUninitializedTask + @Test + void shouldGetSmsClientForUninitializedTask() { + Mockito.when(smsClientProvider.getSmsUrlForUninitializedTask(CHAIN_DEAL_ID_1, CHAIN_TASK_ID_1)).thenReturn(Optional.of(SMS_URL_1)); + + final SmsClient smsClient = assertDoesNotThrow(() -> smsClientProvider.getOrCreateSmsClientForUninitializedTask(CHAIN_DEAL_ID_1, CHAIN_TASK_ID_1)); + assertNotNull(smsClient); + } + + @Test + void shouldNotRebuildSmsClientForSameDeal() { + Mockito.when(smsClientProvider.getSmsUrlForUninitializedTask(CHAIN_DEAL_ID_1, CHAIN_TASK_ID_1)).thenReturn(Optional.of(SMS_URL_1)); + + final SmsClient smsClient1 = assertDoesNotThrow(() -> smsClientProvider.getOrCreateSmsClientForUninitializedTask(CHAIN_DEAL_ID_1, CHAIN_TASK_ID_1)); + assertNotNull(smsClient1); + + final SmsClient smsClient2 = assertDoesNotThrow(() -> smsClientProvider.getOrCreateSmsClientForUninitializedTask(CHAIN_DEAL_ID_1, CHAIN_TASK_ID_1)); + assertNotNull(smsClient2); + + assertEquals(smsClient1, smsClient2); + } + + @Test + void shouldNotRebuildSmsClientForSameSmsUrlOnAnotherDeal() { + Mockito.when(smsClientProvider.getSmsUrlForUninitializedTask(CHAIN_DEAL_ID_1, CHAIN_TASK_ID_1)).thenReturn(Optional.of(SMS_URL_1)); + final SmsClient smsClient1 = assertDoesNotThrow(() -> smsClientProvider.getOrCreateSmsClientForUninitializedTask(CHAIN_DEAL_ID_1, CHAIN_TASK_ID_1)); + assertNotNull(smsClient1); + + Mockito.when(smsClientProvider.getSmsUrlForUninitializedTask(CHAIN_DEAL_ID_3, CHAIN_TASK_ID_3)).thenReturn(Optional.of(SMS_URL_1)); + final SmsClient smsClient2 = assertDoesNotThrow(() -> smsClientProvider.getOrCreateSmsClientForUninitializedTask(CHAIN_DEAL_ID_3, CHAIN_TASK_ID_3)); + assertNotNull(smsClient2); + + assertEquals(smsClient1, smsClient2); + } + + @Test + void shouldBuildAnotherSmsClientForUninitializedTaskOnSecondCallForAnotherSms() { + Mockito.when(smsClientProvider.getSmsUrlForUninitializedTask(CHAIN_DEAL_ID_1, CHAIN_TASK_ID_1)).thenReturn(Optional.of(SMS_URL_1)); + Mockito.when(smsClientProvider.getSmsUrlForUninitializedTask(CHAIN_DEAL_ID_2, CHAIN_TASK_ID_2)).thenReturn(Optional.of(SMS_URL_2)); + + final SmsClient smsClientForUninitializedTask1 = assertDoesNotThrow(() -> smsClientProvider.getOrCreateSmsClientForUninitializedTask(CHAIN_DEAL_ID_1, CHAIN_TASK_ID_1)); + assertNotNull(smsClientForUninitializedTask1); + + final SmsClient smsClientForUninitializedTask2 = assertDoesNotThrow(() -> smsClientProvider.getOrCreateSmsClientForUninitializedTask(CHAIN_DEAL_ID_2, CHAIN_TASK_ID_2)); + assertNotNull(smsClientForUninitializedTask2); + + assertNotEquals(smsClientForUninitializedTask1, smsClientForUninitializedTask2); + } + + @Test + void shouldNotGetSmsClientForUninitializedTaskWhenNoSmsUrl() { + Mockito.when(smsClientProvider.getSmsUrlForUninitializedTask(CHAIN_DEAL_ID_1, CHAIN_TASK_ID_1)).thenReturn(Optional.empty()); + + SmsClientCreationException e = assertThrows(SmsClientCreationException.class, + () -> smsClientProvider.getOrCreateSmsClientForUninitializedTask(CHAIN_DEAL_ID_1, CHAIN_TASK_ID_1)); + assertEquals( + "No SMS URL defined for given deal" + + " [chainDealId: " + CHAIN_DEAL_ID_1 + ", chainTaskId: " + CHAIN_TASK_ID_1 +"]", + e.getMessage()); + } + // endregion + + // region getSmsUrlForUninitializedTask + @Test + void shouldGetSmsUrlForUninitializedTaskWhenTaskFound() { + Mockito.when(iexecHubService.getChainDeal(CHAIN_DEAL_ID_1)).thenReturn(Optional.of(CHAIN_DEAL_1)); + + Optional smsUrl = smsClientProvider.getSmsUrlForUninitializedTask(CHAIN_DEAL_ID_1, CHAIN_TASK_ID_1); assertTrue(smsUrl.isPresent()); assertEquals(SMS_URL_1, smsUrl.get()); - verify(iexecHubService, times(1)).getTaskDescription(any()); - verify(iexecHubService, times(1)).getChainDeal(any()); + verify(iexecHubService, times(1)).getChainDeal(CHAIN_DEAL_ID_1); + verify(iexecHubService, times(0)).getTaskDescription(any()); } @Test - void shouldNotGetSmsUrlForTaskWhenTaskAndDealNotFound() { - Mockito.when(iexecHubService.getTaskDescription(CHAIN_TASK_ID_1)).thenReturn(null); - Mockito.when(iexecHubService.getChainDeal(CHAIN_TASK_ID_1)).thenReturn(Optional.empty()); + void shouldGetSmsUrlOnlyOnceForSameUninitializedTask() { + Mockito.when(iexecHubService.getChainDeal(CHAIN_DEAL_ID_1)).thenReturn(Optional.of(CHAIN_DEAL_1)); - Optional smsUrl = smsClientProvider.getSmsUrlForTask(CHAIN_TASK_ID_1); + Optional smsUrlFirstCall = smsClientProvider.getSmsUrlForUninitializedTask(CHAIN_DEAL_ID_1, CHAIN_TASK_ID_1); + assertTrue(smsUrlFirstCall.isPresent()); + assertEquals(SMS_URL_1, smsUrlFirstCall.get()); + + verify(iexecHubService, times(1)).getChainDeal(CHAIN_DEAL_ID_1); + verify(iexecHubService, times(0)).getTaskDescription(any()); + + Optional smsUrlSecondCall = smsClientProvider.getSmsUrlForUninitializedTask(CHAIN_DEAL_ID_1, CHAIN_TASK_ID_1); + assertTrue(smsUrlSecondCall.isPresent()); + assertEquals(SMS_URL_1, smsUrlSecondCall.get()); + + verify(iexecHubService, times(1)).getChainDeal(CHAIN_DEAL_ID_1); + verify(iexecHubService, times(0)).getTaskDescription(any()); + } + + @Test + void shouldGetSmsUrlTwiceForDifferentUninitializedTasks() { + Mockito.when(iexecHubService.getChainDeal(CHAIN_DEAL_ID_1)).thenReturn(Optional.of(CHAIN_DEAL_1)); + Mockito.when(iexecHubService.getChainDeal(CHAIN_DEAL_ID_2)).thenReturn(Optional.of(CHAIN_DEAL_2)); + + Optional smsUrlFirstCall = smsClientProvider.getSmsUrlForUninitializedTask(CHAIN_DEAL_ID_1, CHAIN_TASK_ID_1); + assertTrue(smsUrlFirstCall.isPresent()); + assertEquals(SMS_URL_1, smsUrlFirstCall.get()); + + verify(iexecHubService, times(1)).getChainDeal(CHAIN_DEAL_ID_1); + verify(iexecHubService, times(0)).getTaskDescription(any()); + + Optional smsUrlSecondCall = smsClientProvider.getSmsUrlForUninitializedTask(CHAIN_DEAL_ID_2, CHAIN_TASK_ID_2); + assertTrue(smsUrlSecondCall.isPresent()); + assertEquals(SMS_URL_2, smsUrlSecondCall.get()); + + verify(iexecHubService, times(1)).getChainDeal(CHAIN_DEAL_ID_2); + verify(iexecHubService, times(0)).getTaskDescription(any()); + } + + @Test + void shouldNotGetSmsUrlForTaskWhenDealNotFound() { + Mockito.when(iexecHubService.getChainDeal(CHAIN_DEAL_ID_1)).thenReturn(Optional.of(CHAIN_DEAL_1)); + + Optional smsUrl = smsClientProvider.getSmsUrlForUninitializedTask(CHAIN_DEAL_ID_1, CHAIN_TASK_ID_1); assertTrue(smsUrl.isEmpty()); - verify(iexecHubService, times(1)).getTaskDescription(any()); - verify(iexecHubService, times(1)).getChainDeal(any()); + verify(iexecHubService, times(1)).getChainDeal(CHAIN_DEAL_ID_1); + verify(iexecHubService, times(0)).getTaskDescription(any()); } - // region + // endregion } \ No newline at end of file From 6f2da4d351e291f2a9b3714784b1d0e44728b060 Mon Sep 17 00:00:00 2001 From: mcornaton Date: Thu, 25 Aug 2022 17:30:53 +0200 Subject: [PATCH 047/293] Fix `shouldNotGetSmsUrlForTaskWhenDealNotFound` --- .../src/test/java/com/iexec/sms/api/SmsClientProviderTests.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientProviderTests.java b/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientProviderTests.java index f9f9fb24..a78d36aa 100644 --- a/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientProviderTests.java +++ b/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientProviderTests.java @@ -292,7 +292,7 @@ void shouldGetSmsUrlTwiceForDifferentUninitializedTasks() { @Test void shouldNotGetSmsUrlForTaskWhenDealNotFound() { - Mockito.when(iexecHubService.getChainDeal(CHAIN_DEAL_ID_1)).thenReturn(Optional.of(CHAIN_DEAL_1)); + Mockito.when(iexecHubService.getChainDeal(CHAIN_DEAL_ID_1)).thenReturn(Optional.empty()); Optional smsUrl = smsClientProvider.getSmsUrlForUninitializedTask(CHAIN_DEAL_ID_1, CHAIN_TASK_ID_1); assertTrue(smsUrl.isEmpty()); From 0c8649de12a2fbd72f03cc56b34c7ed63c1752f0 Mon Sep 17 00:00:00 2001 From: mcornaton Date: Fri, 26 Aug 2022 11:15:29 +0200 Subject: [PATCH 048/293] Fix `shouldNotGetSmsUrlForTaskWhenDealNotFound` --- .../src/test/java/com/iexec/sms/api/SmsClientProviderTests.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientProviderTests.java b/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientProviderTests.java index a78d36aa..f9f9fb24 100644 --- a/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientProviderTests.java +++ b/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientProviderTests.java @@ -292,7 +292,7 @@ void shouldGetSmsUrlTwiceForDifferentUninitializedTasks() { @Test void shouldNotGetSmsUrlForTaskWhenDealNotFound() { - Mockito.when(iexecHubService.getChainDeal(CHAIN_DEAL_ID_1)).thenReturn(Optional.empty()); + Mockito.when(iexecHubService.getChainDeal(CHAIN_DEAL_ID_1)).thenReturn(Optional.of(CHAIN_DEAL_1)); Optional smsUrl = smsClientProvider.getSmsUrlForUninitializedTask(CHAIN_DEAL_ID_1, CHAIN_TASK_ID_1); assertTrue(smsUrl.isEmpty()); From 5af727e6c02c60b154b16af4bed8525d0630e391 Mon Sep 17 00:00:00 2001 From: mcornaton Date: Fri, 26 Aug 2022 11:59:50 +0200 Subject: [PATCH 049/293] Fix `shouldNotGetSmsUrlForTaskWhenDealNotFound` --- .../src/test/java/com/iexec/sms/api/SmsClientProviderTests.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientProviderTests.java b/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientProviderTests.java index f9f9fb24..a78d36aa 100644 --- a/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientProviderTests.java +++ b/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientProviderTests.java @@ -292,7 +292,7 @@ void shouldGetSmsUrlTwiceForDifferentUninitializedTasks() { @Test void shouldNotGetSmsUrlForTaskWhenDealNotFound() { - Mockito.when(iexecHubService.getChainDeal(CHAIN_DEAL_ID_1)).thenReturn(Optional.of(CHAIN_DEAL_1)); + Mockito.when(iexecHubService.getChainDeal(CHAIN_DEAL_ID_1)).thenReturn(Optional.empty()); Optional smsUrl = smsClientProvider.getSmsUrlForUninitializedTask(CHAIN_DEAL_ID_1, CHAIN_TASK_ID_1); assertTrue(smsUrl.isEmpty()); From 7fc445e18f2aaad1c99e3919820f5fc580b73c30 Mon Sep 17 00:00:00 2001 From: mcornaton Date: Mon, 29 Aug 2022 10:10:15 +0200 Subject: [PATCH 050/293] Remove `NO_SMS_FOR_TASK` error code --- .../main/java/com/iexec/sms/api/TeeSessionGenerationError.java | 1 - 1 file changed, 1 deletion(-) diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/TeeSessionGenerationError.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/TeeSessionGenerationError.java index ffdd6360..61c6a57e 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/TeeSessionGenerationError.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/TeeSessionGenerationError.java @@ -58,7 +58,6 @@ public enum TeeSessionGenerationError { NO_SESSION_REQUEST, NO_TASK_DESCRIPTION, GET_SESSION_FAILED, - NO_SMS_FOR_TASK, UNKNOWN_ISSUE // endregion From 2e6e9f8ee1f856a50c4573da3f8fd64e67df2dc6 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Wed, 31 Aug 2022 10:02:37 +0200 Subject: [PATCH 051/293] Add support for bean conditional loading --- .../iexec/sms/tee/EnableIfTeeProvider.java | 66 +++++++++++++++++++ .../tee/EnableIfTeeProviderDefinition.java | 11 ++++ 2 files changed, 77 insertions(+) create mode 100644 src/main/java/com/iexec/sms/tee/EnableIfTeeProvider.java create mode 100644 src/main/java/com/iexec/sms/tee/EnableIfTeeProviderDefinition.java diff --git a/src/main/java/com/iexec/sms/tee/EnableIfTeeProvider.java b/src/main/java/com/iexec/sms/tee/EnableIfTeeProvider.java new file mode 100644 index 00000000..dff27698 --- /dev/null +++ b/src/main/java/com/iexec/sms/tee/EnableIfTeeProvider.java @@ -0,0 +1,66 @@ +package com.iexec.sms.tee; + +import com.iexec.common.tee.TeeEnclaveProvider; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Condition; +import org.springframework.context.annotation.ConditionContext; +import org.springframework.core.type.AnnotatedTypeMetadata; +import org.springframework.core.type.StandardMethodMetadata; + +/** + * Define a way to include beans only if a profile is enabled + *

+ * Usage: + * Annotate any bean with the following: + * {@code + * @Conditional(EnableIfTeeProvider.class) + * @EnableIfTeeProviderDefinition(TeeEnclaveProvider.) + * } + *

+ * If bean is not annotated with {@link EnableIfTeeProviderDefinition} + * or {@link EnableIfTeeProviderDefinition#providers()} is null or empty, + * the bean won't be loaded. + */ +@Slf4j +public class EnableIfTeeProvider implements Condition { + @Override + public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { + final String[] activeProfiles = context.getEnvironment().getActiveProfiles(); + final String beanClassName = ((StandardMethodMetadata) metadata).getReturnTypeName(); + final Class clazz; + try { + clazz = Class.forName(beanClassName); + } catch (ClassNotFoundException e) { + log.error("Bean does not exist " + + "[bean: {}]", beanClassName); + return false; + } + + final EnableIfTeeProviderDefinition condition = + clazz.getAnnotation(EnableIfTeeProviderDefinition.class); + if (condition == null) { + log.error("@EnableIfTeeProviderDefinition annotation is required to use EnableIfTeeProvider condition " + + "[bean: {}]", beanClassName); + return false; + } + + final TeeEnclaveProvider[] teeProviders = condition.providers(); + if (teeProviders == null || teeProviders.length == 0) { + log.warn("No TEE provider defined for bean, won't be loaded " + + "[bean: {}]", beanClassName); + return false; + } + + for (String activeProfile : activeProfiles) { + for (TeeEnclaveProvider teeProvider : teeProviders) { + if (activeProfile.equalsIgnoreCase(teeProvider.name())) { + return true; + } + } + } + + log.debug("Active profiles and condition don't match, bean won't be loaded" + + "[bean: {}]", beanClassName); + return false; + } +} diff --git a/src/main/java/com/iexec/sms/tee/EnableIfTeeProviderDefinition.java b/src/main/java/com/iexec/sms/tee/EnableIfTeeProviderDefinition.java new file mode 100644 index 00000000..690cdcb7 --- /dev/null +++ b/src/main/java/com/iexec/sms/tee/EnableIfTeeProviderDefinition.java @@ -0,0 +1,11 @@ +package com.iexec.sms.tee; + +import com.iexec.common.tee.TeeEnclaveProvider; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) +public @interface EnableIfTeeProviderDefinition { + TeeEnclaveProvider[] providers(); +} From b7e0c1e4be223588cfe903e8b98783195a99e715 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Wed, 31 Aug 2022 16:33:18 +0200 Subject: [PATCH 052/293] Split Gramine & Scone SMS clients --- .../java/com/iexec/sms/api/SmsClient.java | 22 ++++- .../sms/api/TeeWorkflowConfiguration.java | 43 -------- .../config/GramineServicesConfiguration.java | 11 +++ .../config/SconeServicesConfiguration.java | 17 ++++ .../sms/api/config/TeeAppConfiguration.java | 18 ++++ .../api/config/TeeServicesConfiguration.java | 20 ++++ src/itest/resources/application-test.yml | 18 ++-- .../iexec/sms/tee/EnableIfTeeProvider.java | 2 +- .../java/com/iexec/sms/tee/TeeController.java | 28 +++--- .../sms/tee/TeeEnclaveProviderConverter.java | 17 ++++ .../GramineInternalServicesConfiguration.java | 22 +++++ .../SconeInternalServicesConfiguration.java | 23 +++++ .../SideComputeInternalConfiguration.java | 57 +++++++++++ .../base/SecretSessionBaseService.java | 12 +-- .../gramine/GramineSessionHandlerService.java | 6 ++ .../gramine/GramineSessionMakerService.java | 16 ++- .../session/gramine/sps/SpsConfiguration.java | 18 ++-- .../scone/SconeSessionHandlerService.java | 6 ++ .../scone/SconeSessionMakerService.java | 18 ++-- .../scone/SconeSessionSecurityConfig.java | 6 ++ .../sms/tee/session/scone/cas/CasClient.java | 6 ++ .../session/scone/cas/CasConfiguration.java | 14 ++- .../TeeWorkflowInternalConfiguration.java | 98 ------------------- src/main/resources/application-gramine.yml | 13 +++ src/main/resources/application-scone.yml | 14 +++ src/main/resources/application.yml | 50 ++++------ .../com/iexec/sms/tee/TeeControllerTests.java | 4 +- .../base/SecretSessionBaseServiceTests.java | 21 ++-- .../GramineSessionMakerServiceTests.java | 15 ++- .../scone/SconeSessionMakerServiceTests.java | 15 ++- 30 files changed, 390 insertions(+), 240 deletions(-) delete mode 100644 iexec-sms-library/src/main/java/com/iexec/sms/api/TeeWorkflowConfiguration.java create mode 100644 iexec-sms-library/src/main/java/com/iexec/sms/api/config/GramineServicesConfiguration.java create mode 100644 iexec-sms-library/src/main/java/com/iexec/sms/api/config/SconeServicesConfiguration.java create mode 100644 iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeAppConfiguration.java create mode 100644 iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeServicesConfiguration.java create mode 100644 src/main/java/com/iexec/sms/tee/TeeEnclaveProviderConverter.java create mode 100644 src/main/java/com/iexec/sms/tee/config/GramineInternalServicesConfiguration.java create mode 100644 src/main/java/com/iexec/sms/tee/config/SconeInternalServicesConfiguration.java create mode 100644 src/main/java/com/iexec/sms/tee/config/SideComputeInternalConfiguration.java delete mode 100644 src/main/java/com/iexec/sms/tee/workflow/TeeWorkflowInternalConfiguration.java create mode 100644 src/main/resources/application-gramine.yml create mode 100644 src/main/resources/application-scone.yml diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java index 9e7091dd..798717c3 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java @@ -18,7 +18,11 @@ import com.iexec.common.chain.WorkerpoolAuthorization; import com.iexec.common.sms.secret.SmsSecretResponse; +import com.iexec.common.tee.TeeEnclaveProvider; import com.iexec.common.web.ApiResponseBody; +import com.iexec.sms.api.config.GramineServicesConfiguration; +import com.iexec.sms.api.config.SconeServicesConfiguration; +import com.iexec.sms.api.config.TeeServicesConfiguration; import feign.Headers; import feign.Param; import feign.RequestLine; @@ -90,9 +94,6 @@ ApiResponseBody generat WorkerpoolAuthorization workerpoolAuthorization ); - @RequestLine("GET /tee/workflow/config") - TeeWorkflowConfiguration getTeeWorkflowConfiguration(); - @RequestLine("POST /untee/secrets") @Headers("Authorization: {authorization}") SmsSecretResponse getUnTeeSecrets( @@ -100,4 +101,19 @@ SmsSecretResponse getUnTeeSecrets( WorkerpoolAuthorization workerpoolAuthorization ); + @RequestLine("GET /tee/config/scone") + SconeServicesConfiguration getSconeServicesConfiguration(); + + @RequestLine("GET /tee/config/gramine") + GramineServicesConfiguration getGramineServicesConfiguration(); + + default TeeServicesConfiguration getServicesConfiguration(TeeEnclaveProvider teeEnclaveProvider) { + if (teeEnclaveProvider == TeeEnclaveProvider.SCONE) { + return getSconeServicesConfiguration(); + } else if (teeEnclaveProvider == TeeEnclaveProvider.GRAMINE) { + return getGramineServicesConfiguration(); + } + + return null; // FIXME: throw + } } diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/TeeWorkflowConfiguration.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/TeeWorkflowConfiguration.java deleted file mode 100644 index 0208eaa0..00000000 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/TeeWorkflowConfiguration.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2020 IEXEC BLOCKCHAIN TECH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.iexec.sms.api; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; - -/** - * Configuration of tee workflow. It contains: - * pre-compute image, pre-compute heap size, pre compute entrypoint, - * post-compute image, post-compute heap size, post compute entrypoint. - */ -@Builder -@Getter -@AllArgsConstructor -@NoArgsConstructor -// TODO: rename into `TeeServicesConfiguration` (or better) -public class TeeWorkflowConfiguration { - // only required for Scone - private String lasImage; - private String preComputeImage; - private long preComputeHeapSize; - private String preComputeEntrypoint; - private String postComputeImage; - private long postComputeHeapSize; - private String postComputeEntrypoint; -} diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/GramineServicesConfiguration.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/GramineServicesConfiguration.java new file mode 100644 index 00000000..c49a79f9 --- /dev/null +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/GramineServicesConfiguration.java @@ -0,0 +1,11 @@ +package com.iexec.sms.api.config; + +import com.iexec.common.tee.TeeEnclaveProvider; + +public class GramineServicesConfiguration extends TeeServicesConfiguration { + + public GramineServicesConfiguration(TeeAppConfiguration preComputeConfiguration, + TeeAppConfiguration postComputeConfiguration) { + super(TeeEnclaveProvider.GRAMINE, preComputeConfiguration, postComputeConfiguration); + } +} diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/SconeServicesConfiguration.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/SconeServicesConfiguration.java new file mode 100644 index 00000000..ca4c5b10 --- /dev/null +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/SconeServicesConfiguration.java @@ -0,0 +1,17 @@ +package com.iexec.sms.api.config; + +import com.iexec.common.tee.TeeEnclaveProvider; +import lombok.Getter; + +@Getter +public class SconeServicesConfiguration extends TeeServicesConfiguration { + private final String lasImage; + + public SconeServicesConfiguration( + TeeAppConfiguration preComputeConfiguration, + TeeAppConfiguration postComputeConfiguration, + String lasImage) { + super(TeeEnclaveProvider.SCONE, preComputeConfiguration, postComputeConfiguration); + this.lasImage = lasImage; + } +} diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeAppConfiguration.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeAppConfiguration.java new file mode 100644 index 00000000..044b54c6 --- /dev/null +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeAppConfiguration.java @@ -0,0 +1,18 @@ +package com.iexec.sms.api.config; + +import lombok.Getter; + +@Getter +public class TeeAppConfiguration { + private final String image; + private final String fingerprint; + private final String entrypoint; + private final long heapSize; + + public TeeAppConfiguration(String image, String fingerprint, String entrypoint, long heapSize) { + this.image = image; + this.fingerprint = fingerprint; + this.entrypoint = entrypoint; + this.heapSize = heapSize; + } +} diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeServicesConfiguration.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeServicesConfiguration.java new file mode 100644 index 00000000..8c4fdd95 --- /dev/null +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeServicesConfiguration.java @@ -0,0 +1,20 @@ +package com.iexec.sms.api.config; + +import com.iexec.common.tee.TeeEnclaveProvider; +import lombok.Getter; + +@Getter +public abstract class TeeServicesConfiguration { + + private final TeeEnclaveProvider teeEnclaveProvider; + private final TeeAppConfiguration preComputeConfiguration; + private final TeeAppConfiguration postComputeConfiguration; + + protected TeeServicesConfiguration(TeeEnclaveProvider teeEnclaveProvider, + TeeAppConfiguration preComputeConfiguration, + TeeAppConfiguration postComputeConfiguration) { + this.teeEnclaveProvider = teeEnclaveProvider; + this.preComputeConfiguration = preComputeConfiguration; + this.postComputeConfiguration = postComputeConfiguration; + } +} diff --git a/src/itest/resources/application-test.yml b/src/itest/resources/application-test.yml index 775bcdc0..530fded3 100644 --- a/src/itest/resources/application-test.yml +++ b/src/itest/resources/application-test.yml @@ -11,11 +11,13 @@ spring: url: jdbc:h2:mem:db # `TeeWorkflowConfiguration` needs some dummy value to be instantiated -tee.workflow: - las-image: "none" - pre-compute: - image: "none" - fingerprint: "none" - post-compute: - image: "none" - fingerprint: "none" +tee: + scone: + las-image: "none" + workflow: + pre-compute: + image: "none" + fingerprint: "none" + post-compute: + image: "none" + fingerprint: "none" diff --git a/src/main/java/com/iexec/sms/tee/EnableIfTeeProvider.java b/src/main/java/com/iexec/sms/tee/EnableIfTeeProvider.java index dff27698..5674205f 100644 --- a/src/main/java/com/iexec/sms/tee/EnableIfTeeProvider.java +++ b/src/main/java/com/iexec/sms/tee/EnableIfTeeProvider.java @@ -14,7 +14,7 @@ * Annotate any bean with the following: * {@code * @Conditional(EnableIfTeeProvider.class) - * @EnableIfTeeProviderDefinition(TeeEnclaveProvider.) + * @EnableIfTeeProviderDefinition(providers = TeeEnclaveProvider.) * } *

* If bean is not annotated with {@link EnableIfTeeProviderDefinition} diff --git a/src/main/java/com/iexec/sms/tee/TeeController.java b/src/main/java/com/iexec/sms/tee/TeeController.java index ee076155..9259cc1b 100644 --- a/src/main/java/com/iexec/sms/tee/TeeController.java +++ b/src/main/java/com/iexec/sms/tee/TeeController.java @@ -18,17 +18,17 @@ import com.iexec.common.chain.WorkerpoolAuthorization; +import com.iexec.common.tee.TeeEnclaveProvider; import com.iexec.common.web.ApiResponseBody; import com.iexec.sms.api.TeeSessionGenerationError; import com.iexec.sms.api.TeeSessionGenerationResponse; -import com.iexec.sms.api.TeeWorkflowConfiguration; +import com.iexec.sms.api.config.TeeServicesConfiguration; import com.iexec.sms.authorization.AuthorizationError; import com.iexec.sms.authorization.AuthorizationService; import com.iexec.sms.tee.challenge.TeeChallenge; import com.iexec.sms.tee.challenge.TeeChallengeService; import com.iexec.sms.tee.session.TeeSessionService; import com.iexec.sms.tee.session.generic.TeeSessionGenerationException; -import com.iexec.sms.tee.workflow.TeeWorkflowInternalConfiguration; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -58,29 +58,35 @@ public class TeeController { private final AuthorizationService authorizationService; private final TeeChallengeService teeChallengeService; private final TeeSessionService teeSessionService; - private final TeeWorkflowInternalConfiguration teeWorkflowConfig; + private final TeeServicesConfiguration teeServicesConfig; public TeeController( AuthorizationService authorizationService, TeeChallengeService teeChallengeService, TeeSessionService teeSessionService, - TeeWorkflowInternalConfiguration teeWorkflowConfig) { + TeeServicesConfiguration teeServicesConfig) { this.authorizationService = authorizationService; this.teeChallengeService = teeChallengeService; this.teeSessionService = teeSessionService; - this.teeWorkflowConfig = teeWorkflowConfig; + this.teeServicesConfig = teeServicesConfig; } /** - * Retrieve configuration for tee workflow. This includes configuration - * for pre-compute and post-compute stages. + * Retrieve configuration for TEE services. This includes configuration + * for pre-compute and post-compute stages + * and potential TEE provider's specific data. * - * @return tee workflow config (pre-compute image uri, post-compute image uri, + * @return TEE services config (pre-compute image uri, post-compute image uri, * heap size, ...) */ - @GetMapping("/workflow/config") - public ResponseEntity getTeeWorkflowSharedConfig() { - return ResponseEntity.ok(teeWorkflowConfig.getSharedConfig()); + @GetMapping("/config/{teeEnclaveProvider}") + public ResponseEntity getTeeServicesConfig(TeeEnclaveProvider teeEnclaveProvider) { + if (teeEnclaveProvider != teeServicesConfig.getTeeEnclaveProvider()) { + log.error("SMS configured to use another TeeEnclaveProvider " + + "[required: {}, actual: {}]", teeEnclaveProvider, teeServicesConfig.getTeeEnclaveProvider()); + return ResponseEntity.status(HttpStatus.CONFLICT).build(); + } + return ResponseEntity.ok(teeServicesConfig); } /** diff --git a/src/main/java/com/iexec/sms/tee/TeeEnclaveProviderConverter.java b/src/main/java/com/iexec/sms/tee/TeeEnclaveProviderConverter.java new file mode 100644 index 00000000..dc3c8bb5 --- /dev/null +++ b/src/main/java/com/iexec/sms/tee/TeeEnclaveProviderConverter.java @@ -0,0 +1,17 @@ +package com.iexec.sms.tee; + +import com.iexec.common.tee.TeeEnclaveProvider; +import org.springframework.core.convert.converter.Converter; +import org.springframework.stereotype.Component; + +/** + * This class is needed to have a case-insensitive `teeEnclaveProvider` path variable in + * {@link TeeController#getTeeServicesConfig(TeeEnclaveProvider)}. + */ +@Component +public class TeeEnclaveProviderConverter implements Converter { + @Override + public TeeEnclaveProvider convert(String value) { + return TeeEnclaveProvider.valueOf(value.toUpperCase()); + } +} diff --git a/src/main/java/com/iexec/sms/tee/config/GramineInternalServicesConfiguration.java b/src/main/java/com/iexec/sms/tee/config/GramineInternalServicesConfiguration.java new file mode 100644 index 00000000..0bcc0191 --- /dev/null +++ b/src/main/java/com/iexec/sms/tee/config/GramineInternalServicesConfiguration.java @@ -0,0 +1,22 @@ +package com.iexec.sms.tee.config; + +import com.iexec.common.tee.TeeEnclaveProvider; +import com.iexec.sms.api.config.GramineServicesConfiguration; +import com.iexec.sms.api.config.TeeAppConfiguration; +import com.iexec.sms.tee.EnableIfTeeProvider; +import com.iexec.sms.tee.EnableIfTeeProviderDefinition; +import lombok.Getter; +import org.springframework.context.annotation.Conditional; +import org.springframework.context.annotation.Configuration; + +@Configuration +@Conditional(EnableIfTeeProvider.class) +@EnableIfTeeProviderDefinition(providers = TeeEnclaveProvider.GRAMINE) +@Getter +public class GramineInternalServicesConfiguration extends GramineServicesConfiguration { + protected GramineInternalServicesConfiguration( + TeeAppConfiguration preComputeConfiguration, + TeeAppConfiguration postComputeConfiguration) { + super(preComputeConfiguration, postComputeConfiguration); + } +} diff --git a/src/main/java/com/iexec/sms/tee/config/SconeInternalServicesConfiguration.java b/src/main/java/com/iexec/sms/tee/config/SconeInternalServicesConfiguration.java new file mode 100644 index 00000000..f8b9f177 --- /dev/null +++ b/src/main/java/com/iexec/sms/tee/config/SconeInternalServicesConfiguration.java @@ -0,0 +1,23 @@ +package com.iexec.sms.tee.config; + +import com.iexec.common.tee.TeeEnclaveProvider; +import com.iexec.sms.api.config.SconeServicesConfiguration; +import com.iexec.sms.api.config.TeeAppConfiguration; +import com.iexec.sms.tee.EnableIfTeeProvider; +import com.iexec.sms.tee.EnableIfTeeProviderDefinition; +import lombok.Getter; +import org.springframework.context.annotation.Conditional; +import org.springframework.context.annotation.Configuration; + +@Configuration +@Conditional(EnableIfTeeProvider.class) +@EnableIfTeeProviderDefinition(providers = TeeEnclaveProvider.SCONE) +@Getter +public class SconeInternalServicesConfiguration extends SconeServicesConfiguration { + protected SconeInternalServicesConfiguration( + TeeAppConfiguration preComputeConfiguration, + TeeAppConfiguration postComputeConfiguration, + String lasImage) { + super(preComputeConfiguration, postComputeConfiguration, lasImage); + } +} diff --git a/src/main/java/com/iexec/sms/tee/config/SideComputeInternalConfiguration.java b/src/main/java/com/iexec/sms/tee/config/SideComputeInternalConfiguration.java new file mode 100644 index 00000000..bcdc7ef5 --- /dev/null +++ b/src/main/java/com/iexec/sms/tee/config/SideComputeInternalConfiguration.java @@ -0,0 +1,57 @@ +package com.iexec.sms.tee.config; + +import com.iexec.sms.api.config.TeeAppConfiguration; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Positive; + +@Configuration +public class SideComputeInternalConfiguration { + @Bean + TeeAppConfiguration preComputeConfiguration( + @Value("${tee.workflow.pre-compute.image}") + @NotBlank(message = "pre-compute image must be provided") + String preComputeImage, + @Value("${tee.workflow.pre-compute.fingerprint}") + @NotBlank(message = "pre-compute fingerprint must be provided") + String preComputeFingerprint, + @Value("${tee.workflow.pre-compute.entrypoint}") + @NotBlank(message = "pre-compute entrypoint must be provided") + String preComputeEntrypoint, + @Value("${tee.workflow.pre-compute.heap-size-gb}") + @Positive(message = "pre-compute heap size must be provided") + long preComputeHeapSize) { + return new TeeAppConfiguration( + preComputeImage, + preComputeFingerprint, + preComputeEntrypoint, + preComputeHeapSize + ); + } + + @Bean + TeeAppConfiguration postComputeConfiguration( + @Value("${tee.workflow.post-compute.image}") + @NotBlank(message = "post-compute image must be provided") + String postComputeImage, + @Value("${tee.workflow.post-compute.fingerprint}") + @NotBlank(message = "post-compute fingerprint must be provided") + String postComputeFingerprint, + @Value("${tee.workflow.post-compute.entrypoint}") + @NotBlank(message = "post-compute entrypoint must be provided") + String postComputeEntrypoint, + @Value("${tee.workflow.post-compute.heap-size-gb}") + @Positive(message = "post-compute heap size must be provided") + long postComputeHeapSize) { + return new TeeAppConfiguration( + postComputeImage, + postComputeFingerprint, + postComputeEntrypoint, + postComputeHeapSize + ); + } + +} diff --git a/src/main/java/com/iexec/sms/tee/session/base/SecretSessionBaseService.java b/src/main/java/com/iexec/sms/tee/session/base/SecretSessionBaseService.java index e03faef4..faf26f67 100644 --- a/src/main/java/com/iexec/sms/tee/session/base/SecretSessionBaseService.java +++ b/src/main/java/com/iexec/sms/tee/session/base/SecretSessionBaseService.java @@ -20,6 +20,7 @@ import com.iexec.common.tee.TeeEnclaveConfiguration; import com.iexec.common.utils.IexecEnvUtils; import com.iexec.common.utils.IexecFileHelper; +import com.iexec.sms.api.config.TeeServicesConfiguration; import com.iexec.sms.secret.Secret; import com.iexec.sms.secret.compute.OnChainObjectType; import com.iexec.sms.secret.compute.SecretOwnerRole; @@ -33,7 +34,6 @@ import com.iexec.sms.tee.session.base.SecretSessionBase.SecretSessionBaseBuilder; import com.iexec.sms.tee.session.generic.TeeSessionGenerationException; import com.iexec.sms.tee.session.generic.TeeSessionRequest; -import com.iexec.sms.tee.workflow.TeeWorkflowInternalConfiguration; import com.iexec.sms.utils.EthereumCredentials; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; @@ -69,19 +69,19 @@ public class SecretSessionBaseService { private final Web3SecretService web3SecretService; private final Web2SecretsService web2SecretsService; private final TeeChallengeService teeChallengeService; - private final TeeWorkflowInternalConfiguration teeWorkflowConfig; + private final TeeServicesConfiguration teeServicesConfig; private final TeeTaskComputeSecretService teeTaskComputeSecretService; public SecretSessionBaseService( Web3SecretService web3SecretService, Web2SecretsService web2SecretsService, TeeChallengeService teeChallengeService, - TeeWorkflowInternalConfiguration teeWorkflowConfig, + TeeServicesConfiguration teeServicesConfig, TeeTaskComputeSecretService teeTaskComputeSecretService) { this.web3SecretService = web3SecretService; this.web2SecretsService = web2SecretsService; this.teeChallengeService = teeChallengeService; - this.teeWorkflowConfig = teeWorkflowConfig; + this.teeServicesConfig = teeServicesConfig; this.teeTaskComputeSecretService = teeTaskComputeSecretService; } @@ -130,7 +130,7 @@ public SecretEnclaveBase getPreComputeTokens(TeeSessionRequest request) Map tokens = new HashMap<>(); TaskDescription taskDescription = request.getTaskDescription(); String taskId = taskDescription.getChainTaskId(); - enclaveBase.mrenclave(teeWorkflowConfig.getPreComputeFingerprint()); + enclaveBase.mrenclave(teeServicesConfig.getPreComputeConfiguration().getFingerprint()); tokens.put(IEXEC_PRE_COMPUTE_OUT, IexecFileHelper.SLASH_IEXEC_IN); // `IS_DATASET_REQUIRED` still meaningful? tokens.put(IS_DATASET_REQUIRED, taskDescription.containsDataset()); @@ -274,7 +274,7 @@ public SecretEnclaveBase getPostComputeTokens(TeeSessionRequest request) throws TeeSessionGenerationException { SecretEnclaveBaseBuilder enclaveBase = SecretEnclaveBase.builder() .name("post-compute") - .mrenclave(teeWorkflowConfig.getPostComputeFingerprint()); + .mrenclave(teeServicesConfig.getPostComputeConfiguration().getFingerprint()); Map tokens = new HashMap<>(); TaskDescription taskDescription = request.getTaskDescription(); if (taskDescription == null) { diff --git a/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerService.java b/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerService.java index 058a2c3d..ca4d28f7 100644 --- a/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerService.java +++ b/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerService.java @@ -16,7 +16,10 @@ package com.iexec.sms.tee.session.gramine; +import com.iexec.common.tee.TeeEnclaveProvider; import com.iexec.sms.api.TeeSessionGenerationError; +import com.iexec.sms.tee.EnableIfTeeProvider; +import com.iexec.sms.tee.EnableIfTeeProviderDefinition; import com.iexec.sms.tee.session.TeeSessionLogConfiguration; import com.iexec.sms.tee.session.generic.TeeSessionGenerationException; import com.iexec.sms.tee.session.generic.TeeSessionHandler; @@ -24,10 +27,13 @@ import com.iexec.sms.tee.session.gramine.sps.GramineSession; import com.iexec.sms.tee.session.gramine.sps.SpsConfiguration; import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Conditional; import org.springframework.stereotype.Component; @Slf4j @Component +@Conditional(EnableIfTeeProvider.class) +@EnableIfTeeProviderDefinition(providers = TeeEnclaveProvider.GRAMINE) public class GramineSessionHandlerService implements TeeSessionHandler { private GramineSessionMakerService sessionService; private SpsConfiguration spsConfiguration; diff --git a/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerService.java b/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerService.java index 2486a4ae..97294793 100644 --- a/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerService.java +++ b/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerService.java @@ -16,6 +16,10 @@ package com.iexec.sms.tee.session.gramine; +import com.iexec.common.tee.TeeEnclaveProvider; +import com.iexec.sms.api.config.TeeServicesConfiguration; +import com.iexec.sms.tee.EnableIfTeeProvider; +import com.iexec.sms.tee.EnableIfTeeProviderDefinition; import com.iexec.sms.tee.session.base.SecretEnclaveBase; import com.iexec.sms.tee.session.base.SecretSessionBase; import com.iexec.sms.tee.session.base.SecretSessionBaseService; @@ -24,21 +28,23 @@ import com.iexec.sms.tee.session.gramine.sps.GramineEnclave; import com.iexec.sms.tee.session.gramine.sps.GramineSession; import com.iexec.sms.tee.session.gramine.sps.GramineSession.GramineSessionBuilder; -import com.iexec.sms.tee.workflow.TeeWorkflowInternalConfiguration; +import org.springframework.context.annotation.Conditional; import org.springframework.stereotype.Service; import java.util.List; @Service +@Conditional(EnableIfTeeProvider.class) +@EnableIfTeeProviderDefinition(providers = TeeEnclaveProvider.GRAMINE) public class GramineSessionMakerService { private final SecretSessionBaseService secretSessionBaseService; - private TeeWorkflowInternalConfiguration teeWorkflowConfiguration; + private final TeeServicesConfiguration teeServicesConfig; public GramineSessionMakerService(SecretSessionBaseService secretSessionBaseService, - TeeWorkflowInternalConfiguration teeWorkflowConfiguration) { + TeeServicesConfiguration teeServicesConfig) { this.secretSessionBaseService = secretSessionBaseService; - this.teeWorkflowConfiguration = teeWorkflowConfiguration; + this.teeServicesConfig = teeServicesConfig; } /** @@ -55,7 +61,7 @@ public GramineSession generateSession(TeeSessionRequest request) throws TeeSessi GramineEnclave gramineAppEnclave = toGramineEnclave(baseSession.getAppCompute()); gramineAppEnclave.setCommand(request.getTaskDescription().getAppCommand()); GramineEnclave graminePostEnclave = toGramineEnclave(baseSession.getPostCompute()); - graminePostEnclave.setCommand(teeWorkflowConfiguration.getPostComputeEntrypoint()); + graminePostEnclave.setCommand(teeServicesConfig.getPostComputeConfiguration().getEntrypoint()); // TODO: Remove useless volumes when SPS is ready gramineAppEnclave.setVolumes(List.of()); diff --git a/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsConfiguration.java b/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsConfiguration.java index 80c19adb..64e0c830 100644 --- a/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsConfiguration.java +++ b/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsConfiguration.java @@ -16,31 +16,37 @@ package com.iexec.sms.tee.session.gramine.sps; +import com.iexec.common.tee.TeeEnclaveProvider; import com.iexec.common.utils.FeignBuilder; +import com.iexec.sms.tee.EnableIfTeeProvider; +import com.iexec.sms.tee.EnableIfTeeProviderDefinition; import feign.Logger.Level; import lombok.Getter; import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; @Configuration +@Conditional(EnableIfTeeProvider.class) +@EnableIfTeeProviderDefinition(providers = TeeEnclaveProvider.GRAMINE) @Getter public class SpsConfiguration { - @Value("${gramine.sps.web.host}") + @Value("${tee.secret-provisioner.web.hostname}") private String webHost; - @Value("${gramine.sps.web.port}") + @Value("${tee.secret-provisioner.web.port}") private String webPort; - @Value("${gramine.sps.web.login}") + @Value("${tee.gramine.sps.web.login}") private String webLogin; - @Value("${gramine.sps.web.password}") + @Value("${tee.gramine.sps.web.password}") private String webPassword; - @Value("${gramine.sps.enclave.hostname}") + @Value("${tee.secret-provisioner.enclave.hostname}") private String enclaveHostName; - @Value("${gramine.sps.enclave.port}") + @Value("${tee.secret-provisioner.enclave.port}") private String enclavePort; private SpsApiClient spsApiClient; diff --git a/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerService.java b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerService.java index e023d4ea..201e84b8 100644 --- a/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerService.java +++ b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerService.java @@ -16,7 +16,10 @@ package com.iexec.sms.tee.session.scone; +import com.iexec.common.tee.TeeEnclaveProvider; import com.iexec.sms.api.TeeSessionGenerationError; +import com.iexec.sms.tee.EnableIfTeeProvider; +import com.iexec.sms.tee.EnableIfTeeProviderDefinition; import com.iexec.sms.tee.session.TeeSessionLogConfiguration; import com.iexec.sms.tee.session.generic.TeeSessionGenerationException; import com.iexec.sms.tee.session.generic.TeeSessionHandler; @@ -25,11 +28,14 @@ import com.iexec.sms.tee.session.scone.cas.CasConfiguration; import com.iexec.sms.tee.session.scone.cas.SconeSession; import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Conditional; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; @Slf4j @Component +@Conditional(EnableIfTeeProvider.class) +@EnableIfTeeProviderDefinition(providers = TeeEnclaveProvider.SCONE) public class SconeSessionHandlerService implements TeeSessionHandler { private SconeSessionMakerService sessionService; private CasClient apiClient; diff --git a/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionMakerService.java b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionMakerService.java index bd7382bf..25d95562 100644 --- a/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionMakerService.java +++ b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionMakerService.java @@ -16,6 +16,10 @@ package com.iexec.sms.tee.session.scone; +import com.iexec.common.tee.TeeEnclaveProvider; +import com.iexec.sms.api.config.TeeServicesConfiguration; +import com.iexec.sms.tee.EnableIfTeeProvider; +import com.iexec.sms.tee.EnableIfTeeProviderDefinition; import com.iexec.sms.tee.session.base.SecretEnclaveBase; import com.iexec.sms.tee.session.base.SecretSessionBase; import com.iexec.sms.tee.session.base.SecretSessionBaseService; @@ -28,8 +32,8 @@ import com.iexec.sms.tee.session.scone.cas.SconeSession.Image.Volume; import com.iexec.sms.tee.session.scone.cas.SconeSession.Security; import com.iexec.sms.tee.session.scone.cas.SconeSession.Volumes; -import com.iexec.sms.tee.workflow.TeeWorkflowInternalConfiguration; import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Conditional; import org.springframework.stereotype.Service; import java.util.*; @@ -37,6 +41,8 @@ //TODO Rename and move @Slf4j @Service +@Conditional(EnableIfTeeProvider.class) +@EnableIfTeeProviderDefinition(providers = TeeEnclaveProvider.SCONE) public class SconeSessionMakerService { // Internal values required for setting up a palaemon session @@ -51,15 +57,15 @@ public class SconeSessionMakerService { static final String POST_COMPUTE_ENTRYPOINT = "POST_COMPUTE_ENTRYPOINT"; private final SecretSessionBaseService secretSessionBaseService; - private final TeeWorkflowInternalConfiguration teeWorkflowConfig; + private final TeeServicesConfiguration teeServicesConfig; private final SconeSessionSecurityConfig attestationSecurityConfig; public SconeSessionMakerService( SecretSessionBaseService secretSessionBaseService, - TeeWorkflowInternalConfiguration teeWorkflowConfig, + TeeServicesConfiguration teeServicesConfig, SconeSessionSecurityConfig attestationSecurityConfig) { this.secretSessionBaseService = secretSessionBaseService; - this.teeWorkflowConfig = teeWorkflowConfig; + this.teeServicesConfig = teeServicesConfig; this.attestationSecurityConfig = attestationSecurityConfig; } @@ -92,7 +98,7 @@ public SconeSession generateSession(TeeSessionRequest request) SconeEnclave sconePreEnclave = toSconeEnclave( baseSession.getPreCompute()); sconePreEnclave - .setCommand(teeWorkflowConfig.getPreComputeEntrypoint()); + .setCommand(teeServicesConfig.getPreComputeConfiguration().getEntrypoint()); addJavaEnvVars(sconePreEnclave); services.add(sconePreEnclave); images.add(new SconeSession.Image(sconePreEnclave.getImageName(), @@ -110,7 +116,7 @@ public SconeSession generateSession(TeeSessionRequest request) SconeEnclave sconePostEnclave = toSconeEnclave( baseSession.getPostCompute()); sconePostEnclave - .setCommand(teeWorkflowConfig.getPostComputeEntrypoint()); + .setCommand(teeServicesConfig.getPostComputeConfiguration().getEntrypoint()); addJavaEnvVars(sconePostEnclave); services.add(sconePostEnclave); images.add(new SconeSession.Image(sconePostEnclave.getImageName(), diff --git a/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionSecurityConfig.java b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionSecurityConfig.java index 9e0c6eab..e4909ba4 100644 --- a/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionSecurityConfig.java +++ b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionSecurityConfig.java @@ -16,13 +16,19 @@ package com.iexec.sms.tee.session.scone; +import com.iexec.common.tee.TeeEnclaveProvider; +import com.iexec.sms.tee.EnableIfTeeProvider; +import com.iexec.sms.tee.EnableIfTeeProviderDefinition; import lombok.Getter; import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; import java.util.List; @Configuration +@Conditional(EnableIfTeeProvider.class) +@EnableIfTeeProviderDefinition(providers = TeeEnclaveProvider.SCONE) public class SconeSessionSecurityConfig { @Value("${scone.attestation.tolerated-insecure-options}") diff --git a/src/main/java/com/iexec/sms/tee/session/scone/cas/CasClient.java b/src/main/java/com/iexec/sms/tee/session/scone/cas/CasClient.java index ef5e85e6..87c30898 100644 --- a/src/main/java/com/iexec/sms/tee/session/scone/cas/CasClient.java +++ b/src/main/java/com/iexec/sms/tee/session/scone/cas/CasClient.java @@ -16,7 +16,11 @@ package com.iexec.sms.tee.session.scone.cas; +import com.iexec.common.tee.TeeEnclaveProvider; import com.iexec.sms.ssl.TwoWaySslClient; +import com.iexec.sms.tee.EnableIfTeeProvider; +import com.iexec.sms.tee.EnableIfTeeProviderDefinition; +import org.springframework.context.annotation.Conditional; import org.springframework.http.HttpEntity; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; @@ -24,6 +28,8 @@ import java.nio.charset.StandardCharsets; @Service +@Conditional(EnableIfTeeProvider.class) +@EnableIfTeeProviderDefinition(providers = TeeEnclaveProvider.SCONE) public class CasClient { private final CasConfiguration casConfiguration; diff --git a/src/main/java/com/iexec/sms/tee/session/scone/cas/CasConfiguration.java b/src/main/java/com/iexec/sms/tee/session/scone/cas/CasConfiguration.java index e968f81f..98f42e4e 100644 --- a/src/main/java/com/iexec/sms/tee/session/scone/cas/CasConfiguration.java +++ b/src/main/java/com/iexec/sms/tee/session/scone/cas/CasConfiguration.java @@ -16,10 +16,14 @@ package com.iexec.sms.tee.session.scone.cas; +import com.iexec.common.tee.TeeEnclaveProvider; +import com.iexec.sms.tee.EnableIfTeeProvider; +import com.iexec.sms.tee.EnableIfTeeProviderDefinition; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Conditional; import org.springframework.stereotype.Component; /** @@ -34,21 +38,23 @@ * code. It guarantees that a code behaves exactly as expected. */ @Component +@Conditional(EnableIfTeeProvider.class) +@EnableIfTeeProviderDefinition(providers = TeeEnclaveProvider.SCONE) @Getter @NoArgsConstructor @AllArgsConstructor public class CasConfiguration { - @Value("${scone.cas.host}") + @Value("${tee.secret-provisioner.web.hostname}") private String host; - @Value("${scone.cas.port}") + @Value("${tee.secret-provisioner.web.port}") private String port; - @Value("${scone.cas.public-host}") + @Value("${tee.secret-provisioner.enclave.hostname}") private String publicHost; - @Value("${scone.cas.enclave-port}") + @Value("${tee.secret-provisioner.enclave.port}") private String enclavePort; public String getUrl() { diff --git a/src/main/java/com/iexec/sms/tee/workflow/TeeWorkflowInternalConfiguration.java b/src/main/java/com/iexec/sms/tee/workflow/TeeWorkflowInternalConfiguration.java deleted file mode 100644 index 0d520060..00000000 --- a/src/main/java/com/iexec/sms/tee/workflow/TeeWorkflowInternalConfiguration.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright 2020 IEXEC BLOCKCHAIN TECH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.iexec.sms.tee.workflow; - -import com.iexec.sms.api.TeeWorkflowConfiguration; -import lombok.AccessLevel; -import lombok.Getter; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Configuration; - -import javax.annotation.PostConstruct; -import javax.validation.ConstraintViolationException; -import javax.validation.Validator; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.Positive; - -@Configuration -@Getter -public class TeeWorkflowInternalConfiguration { - - private final TeeWorkflowConfiguration sharedConfig; - private final String preComputeFingerprint; - private final String postComputeFingerprint; - - @Getter(AccessLevel.NONE) // no getter - private final Validator validator; - - public TeeWorkflowInternalConfiguration( - @Value("${tee.workflow.las-image}") - @NotBlank(message = "las image must be provided") - String lasImage, - @Value("${tee.workflow.pre-compute.image}") - @NotBlank(message = "pre-compute image must be provided") - String preComputeImage, - @Value("${tee.workflow.pre-compute.fingerprint}") - @NotBlank(message = "pre-compute fingerprint must be provided") - String preComputeFingerprint, - @Value("${tee.workflow.pre-compute.entrypoint}") - @NotBlank(message = "pre-compute entrypoint must be provided") - String preComputeEntrypoint, - @Value("${tee.workflow.pre-compute.heap-size-gb}") - @Positive(message = "pre-compute heap size must be provided") - int preComputeHeapSizeGb, - @Value("${tee.workflow.post-compute.image}") - @NotBlank(message = "post-compute image must be provided") - String postComputeImage, - @Value("${tee.workflow.post-compute.fingerprint}") - @NotBlank(message = "post-compute fingerprint must be provided") - String postComputeFingerprint, - @Value("${tee.workflow.post-compute.entrypoint}") - @NotBlank(message = "post-compute entrypoint must be provided") - String postComputeEntrypoint, - @Value("${tee.workflow.post-compute.heap-size-gb}") - @Positive(message = "post-compute heap size must be provided") - int postComputeHeapSizeGb, - Validator validator) { - this.preComputeFingerprint = preComputeFingerprint; - this.postComputeFingerprint = postComputeFingerprint; - this.sharedConfig = TeeWorkflowConfiguration.builder() - .lasImage(lasImage) - .preComputeImage(preComputeImage) - .preComputeHeapSize(preComputeHeapSizeGb) - .preComputeEntrypoint(preComputeEntrypoint) - .postComputeImage(postComputeImage) - .postComputeHeapSize(postComputeHeapSizeGb) - .postComputeEntrypoint(postComputeEntrypoint) - .build(); - this.validator = validator; - } - - @PostConstruct - private void validate() { - if (!validator.validate(this).isEmpty()) { - throw new ConstraintViolationException(validator.validate(this)); - } - } - - public String getPreComputeEntrypoint() { - return sharedConfig.getPreComputeEntrypoint(); - } - public String getPostComputeEntrypoint() { - return sharedConfig.getPostComputeEntrypoint(); - } -} diff --git a/src/main/resources/application-gramine.yml b/src/main/resources/application-gramine.yml new file mode 100644 index 00000000..1bf08058 --- /dev/null +++ b/src/main/resources/application-gramine.yml @@ -0,0 +1,13 @@ +tee: + secret-provisioner: + web: + hostname: ${IEXEC_SECRET_PROVISIONER_WEB_HOSTNAME:localhost} + port: ${IEXEC_SECRET_PROVISIONER_WEB_PORT:8080} + enclave: + hostname: ${IEXEC_SECRET_PROVISIONER_ENCLAVE_HOSTNAME:localhost} + port: ${IEXEC_SECRET_PROVISIONER_ENCLAVE_PORT:4433} + + gramine: + sps: + login: ${IEXEC_GRAPHENE_SPS_WEB_LOGIN:admin} + password: ${IEXEC_GRAPHENE_SPS_WEB_PASSWORD:admin} \ No newline at end of file diff --git a/src/main/resources/application-scone.yml b/src/main/resources/application-scone.yml new file mode 100644 index 00000000..63cb8a59 --- /dev/null +++ b/src/main/resources/application-scone.yml @@ -0,0 +1,14 @@ +tee: + secret-provisioner: + web: + hostname: ${IEXEC_SECRET_PROVISIONER_WEB_HOSTNAME:localhost} + port: ${IEXEC_SECRET_PROVISIONER_WEB_PORT:8081} + enclave: + hostname: ${IEXEC_SECRET_PROVISIONER_ENCLAVE_HOSTNAME:localhost} + port: ${IEXEC_SECRET_PROVISIONER_ENCLAVE_PORT:18765} + + scone: + las-image: ${IEXEC_SMS_IMAGE_LAS_IMAGE:} # e.g.: registry.scontain.com:5050/scone-production/iexec-las:x.y.z + attestation: + tolerated-insecure-options: ${IEXEC_SCONE_TOLERATED_INSECURE_OPTIONS:} # e.g.: hyperthreading,software-hardening-needed,insecure-igpu,outdated-tcb,debug-mode + ignored-sgx-advisories: ${IEXEC_IGNORED_SGX_ADVISORIES:} # e.g.: INTEL-SA-00220,INTEL-SA-00270 diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index ee2287d6..d2dbe754 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -49,41 +49,27 @@ blockchain: gas-price-cap: ${IEXEC_GAS_PRICE_CAP:22000000000} #in Wei, will be used for txs if networkGasPrice*gasPriceMultiplier > gasPriceCap is-sidechain: ${IEXEC_IS_SIDECHAIN:false} -scone: - cas: - host: ${IEXEC_SCONE_CAS_HOST:localhost} - port: ${IEXEC_SCONE_CAS_PORT:8081} - public-host: ${IEXEC_SCONE_CAS_PUBLIC_HOST:localhost} - enclave-port: ${IEXEC_SCONE_CAS_ENCLAVE_PORT:18765} - attestation: - tolerated-insecure-options: ${IEXEC_SCONE_TOLERATED_INSECURE_OPTIONS:} # e.g.: hyperthreading,software-hardening-needed,insecure-igpu,outdated-tcb,debug-mode - ignored-sgx-advisories: ${IEXEC_IGNORED_SGX_ADVISORIES:} # e.g.: INTEL-SA-00220,INTEL-SA-00270 - -gramine: - sps: +# TODO /!\ remove the option of env variable for releases. +tee: + secret-provisioner: web: - host: ${IEXEC_GRAPHENE_SPS_WEB_HOST:localhost} - port: ${IEXEC_GRAPHENE_SPS_WEB_POST:8080} - login: ${IEXEC_GRAPHENE_SPS_WEB_LOGIN:admin} - password: ${IEXEC_GRAPHENE_SPS_WEB_PASSWORD:admin} + hostname: ${IEXEC_SECRET_PROVISIONER_WEB_HOSTNAME:localhost} + port: ${IEXEC_SECRET_PROVISIONER_WEB_PORT} enclave: - # TODO: Merge shared conf of CAS & SPS (url, port, ..) in a common top parent in yml. Use only secret-provisioner.gramine: and secret-provisioner.scone: for additionnal properties. - hostname: ${IEXEC_GRAPHENE_SPS_ENCLAVE_HOST_NAME:localhost} - port: ${IEXEC_GRAPHENE_SPS_ENCLAVE_PORT:4433} + hostname: ${IEXEC_SECRET_PROVISIONER_ENCLAVE_HOSTNAME:localhost} + port: ${IEXEC_SECRET_PROVISIONER_ENCLAVE_PORT} -# TODO /!\ remove the option of env variable for releases. -tee.workflow: - las-image: ${IEXEC_SMS_IMAGE_LAS_IMAGE:} # e.g.: registry.scontain.com:5050/scone-production/iexec-las:x.y.z - pre-compute: - image: ${IEXEC_TEE_WORKER_PRE_COMPUTE_IMAGE:} # e.g.: docker.io/iexechub/tee-worker-pre-compute:x.y.z-production - fingerprint: ${IEXEC_TEE_WORKER_PRE_COMPUTE_FINGERPRINT:} - heap-size-gb: ${IEXEC_TEE_WORKER_PRE_COMPUTE_HEAP_SIZE_GB:4} - entrypoint: ${IEXEC_TEE_WORKER_PRE_COMPUTE_ENTRYPOINT:java -jar /app/app.jar} - post-compute: - image: ${IEXEC_TEE_WORKER_POST_COMPUTE_IMAGE:} # e.g.: docker.io/iexechub/tee-worker-post-compute:x.y.z-production - fingerprint: ${IEXEC_TEE_WORKER_POST_COMPUTE_FINGERPRINT:} - heap-size-gb: ${IEXEC_TEE_WORKER_POST_COMPUTE_HEAP_SIZE_GB:4} - entrypoint: ${IEXEC_TEE_WORKER_POST_COMPUTE_ENTRYPOINT:java -jar /app/app.jar} + workflow: + pre-compute: + image: ${IEXEC_TEE_WORKER_PRE_COMPUTE_IMAGE:} # e.g.: docker.io/iexechub/tee-worker-pre-compute:x.y.z-production + fingerprint: ${IEXEC_TEE_WORKER_PRE_COMPUTE_FINGERPRINT:} + heap-size-gb: ${IEXEC_TEE_WORKER_PRE_COMPUTE_HEAP_SIZE_GB:4} + entrypoint: ${IEXEC_TEE_WORKER_PRE_COMPUTE_ENTRYPOINT:java -jar /app/app.jar} + post-compute: + image: ${IEXEC_TEE_WORKER_POST_COMPUTE_IMAGE:} # e.g.: docker.io/iexechub/tee-worker-post-compute:x.y.z-production + fingerprint: ${IEXEC_TEE_WORKER_POST_COMPUTE_FINGERPRINT:} + heap-size-gb: ${IEXEC_TEE_WORKER_POST_COMPUTE_HEAP_SIZE_GB:4} + entrypoint: ${IEXEC_TEE_WORKER_POST_COMPUTE_ENTRYPOINT:java -jar /app/app.jar} logging: tee.display-debug-session: ${IEXEC_SMS_DISPLAY_DEBUG_SESSION:false} diff --git a/src/test/java/com/iexec/sms/tee/TeeControllerTests.java b/src/test/java/com/iexec/sms/tee/TeeControllerTests.java index 97e66dcf..36a000cf 100644 --- a/src/test/java/com/iexec/sms/tee/TeeControllerTests.java +++ b/src/test/java/com/iexec/sms/tee/TeeControllerTests.java @@ -4,12 +4,12 @@ import com.iexec.common.web.ApiResponseBody; import com.iexec.sms.api.TeeSessionGenerationError; import com.iexec.sms.api.TeeSessionGenerationResponse; +import com.iexec.sms.api.config.TeeServicesConfiguration; import com.iexec.sms.authorization.AuthorizationError; import com.iexec.sms.authorization.AuthorizationService; import com.iexec.sms.tee.challenge.TeeChallengeService; import com.iexec.sms.tee.session.TeeSessionService; import com.iexec.sms.tee.session.generic.TeeSessionGenerationException; -import com.iexec.sms.tee.workflow.TeeWorkflowInternalConfiguration; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; @@ -46,7 +46,7 @@ class TeeControllerTests { @Mock TeeSessionService teeSessionService; @Mock - TeeWorkflowInternalConfiguration teeWorkflowConfig; + TeeServicesConfiguration teeServicesConfig; @InjectMocks TeeController teeController; diff --git a/src/test/java/com/iexec/sms/tee/session/base/SecretSessionBaseServiceTests.java b/src/test/java/com/iexec/sms/tee/session/base/SecretSessionBaseServiceTests.java index 6e32238d..f2d78bdd 100644 --- a/src/test/java/com/iexec/sms/tee/session/base/SecretSessionBaseServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/base/SecretSessionBaseServiceTests.java @@ -7,6 +7,8 @@ import com.iexec.common.tee.TeeEnclaveProvider; import com.iexec.common.utils.IexecEnvUtils; import com.iexec.sms.api.TeeSessionGenerationError; +import com.iexec.sms.api.config.TeeAppConfiguration; +import com.iexec.sms.api.config.TeeServicesConfiguration; import com.iexec.sms.secret.Secret; import com.iexec.sms.secret.compute.OnChainObjectType; import com.iexec.sms.secret.compute.SecretOwnerRole; @@ -19,7 +21,6 @@ import com.iexec.sms.tee.challenge.TeeChallengeService; import com.iexec.sms.tee.session.generic.TeeSessionGenerationException; import com.iexec.sms.tee.session.generic.TeeSessionRequest; -import com.iexec.sms.tee.workflow.TeeWorkflowInternalConfiguration; import com.iexec.sms.utils.EthereumCredentials; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; @@ -62,7 +63,11 @@ class SecretSessionBaseServiceTests { @Mock private TeeChallengeService teeChallengeService; @Mock - private TeeWorkflowInternalConfiguration teeWorkflowConfig; + private TeeAppConfiguration preComputeConfiguration; + @Mock + private TeeAppConfiguration postComputeConfiguration; + @Mock + private TeeServicesConfiguration teeServicesConfig; @Mock private TeeTaskComputeSecretService teeTaskComputeSecretService; @@ -72,6 +77,8 @@ class SecretSessionBaseServiceTests { @BeforeEach void beforeEach() { MockitoAnnotations.openMocks(this); + when(teeServicesConfig.getPreComputeConfiguration()).thenReturn(preComputeConfiguration); + when(teeServicesConfig.getPostComputeConfiguration()).thenReturn(postComputeConfiguration); } // region getSecretsTokens @@ -81,14 +88,14 @@ void shouldGetSecretsTokens() throws Exception { TeeSessionRequest request = createSessionRequest(taskDescription); // pre - when(teeWorkflowConfig.getPreComputeFingerprint()) + when(preComputeConfiguration.getFingerprint()) .thenReturn(PRE_COMPUTE_FINGERPRINT); Web3Secret secret = new Web3Secret(DATASET_ADDRESS, DATASET_KEY); when(web3SecretService.getSecret(DATASET_ADDRESS, true)) .thenReturn(Optional.of(secret)); // post Secret publicKeySecret = new Secret("address", ENCRYPTION_PUBLIC_KEY); - when(teeWorkflowConfig.getPostComputeFingerprint()) + when(postComputeConfiguration.getFingerprint()) .thenReturn(POST_COMPUTE_FINGERPRINT); when(web2SecretsService.getSecret( request.getTaskDescription().getBeneficiary(), @@ -155,7 +162,7 @@ void shouldNotGetSecretsTokensSinceTaskDescriptionIsMissing() { void shouldGetPreComputeTokens() throws Exception { TaskDescription taskDescription = createTaskDescription(enclaveConfig); TeeSessionRequest request = createSessionRequest(taskDescription); - when(teeWorkflowConfig.getPreComputeFingerprint()) + when(preComputeConfiguration.getFingerprint()) .thenReturn(PRE_COMPUTE_FINGERPRINT); Web3Secret secret = new Web3Secret(DATASET_ADDRESS, DATASET_KEY); when(web3SecretService.getSecret(DATASET_ADDRESS, true)) @@ -190,7 +197,7 @@ void shouldGetPreComputeTokensWithoutDataset() throws Exception { .inputFiles(List.of(INPUT_FILE_URL_1, INPUT_FILE_URL_2)) .build()) .build(); - when(teeWorkflowConfig.getPreComputeFingerprint()) + when(preComputeConfiguration.getFingerprint()) .thenReturn(PRE_COMPUTE_FINGERPRINT); SecretEnclaveBase enclaveBase = teeSecretsService.getPreComputeTokens(request); @@ -385,7 +392,7 @@ void shouldGetPostComputeTokens() throws Exception { String requesterAddress = request.getTaskDescription().getRequester(); Secret publicKeySecret = new Secret("address", ENCRYPTION_PUBLIC_KEY); - when(teeWorkflowConfig.getPostComputeFingerprint()) + when(postComputeConfiguration.getFingerprint()) .thenReturn(POST_COMPUTE_FINGERPRINT); when(web2SecretsService.getSecret( request.getTaskDescription().getBeneficiary(), diff --git a/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerServiceTests.java b/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerServiceTests.java index d4d0964a..1a7faa65 100644 --- a/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerServiceTests.java @@ -2,12 +2,13 @@ import com.iexec.common.tee.TeeEnclaveConfiguration; import com.iexec.common.utils.FileHelper; +import com.iexec.sms.api.config.TeeAppConfiguration; +import com.iexec.sms.tee.config.GramineInternalServicesConfiguration; import com.iexec.sms.tee.session.base.SecretEnclaveBase; import com.iexec.sms.tee.session.base.SecretSessionBase; import com.iexec.sms.tee.session.base.SecretSessionBaseService; import com.iexec.sms.tee.session.generic.TeeSessionRequest; import com.iexec.sms.tee.session.gramine.sps.GramineSession; -import com.iexec.sms.tee.workflow.TeeWorkflowInternalConfiguration; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -25,7 +26,11 @@ @Slf4j class GramineSessionMakerServiceTests { @Mock - private TeeWorkflowInternalConfiguration teeWorkflowConfig; + private TeeAppConfiguration preComputeConfiguration; + @Mock + private TeeAppConfiguration postComputeConfiguration; + @Mock + private GramineInternalServicesConfiguration teeServicesConfig; @Mock private SecretSessionBaseService teeSecretsService; @InjectMocks @@ -34,6 +39,8 @@ class GramineSessionMakerServiceTests { @BeforeEach void beforeEach() { MockitoAnnotations.openMocks(this); + when(teeServicesConfig.getPreComputeConfiguration()).thenReturn(preComputeConfiguration); + when(teeServicesConfig.getPostComputeConfiguration()).thenReturn(postComputeConfiguration); } // region getSessionYml @@ -42,8 +49,8 @@ void shouldGetSessionJson() throws Exception { TeeEnclaveConfiguration enclaveConfig = mock(TeeEnclaveConfiguration.class); TeeSessionRequest request = createSessionRequest(createTaskDescription(enclaveConfig)); - when(teeWorkflowConfig.getPostComputeFingerprint()).thenReturn(POST_COMPUTE_FINGERPRINT); - when(teeWorkflowConfig.getPostComputeEntrypoint()).thenReturn(POST_COMPUTE_ENTRYPOINT); + when(postComputeConfiguration.getFingerprint()).thenReturn(POST_COMPUTE_FINGERPRINT); + when(postComputeConfiguration.getEntrypoint()).thenReturn(POST_COMPUTE_ENTRYPOINT); when(enclaveConfig.getFingerprint()).thenReturn(APP_FINGERPRINT); when(enclaveConfig.getEntrypoint()).thenReturn("/apploader.sh"); diff --git a/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionMakerServiceTests.java b/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionMakerServiceTests.java index 81e8f6e1..c70fa197 100644 --- a/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionMakerServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionMakerServiceTests.java @@ -18,12 +18,13 @@ import com.iexec.common.tee.TeeEnclaveConfiguration; import com.iexec.common.utils.FileHelper; +import com.iexec.sms.api.config.TeeAppConfiguration; +import com.iexec.sms.tee.config.SconeInternalServicesConfiguration; import com.iexec.sms.tee.session.base.SecretEnclaveBase; import com.iexec.sms.tee.session.base.SecretSessionBase; import com.iexec.sms.tee.session.base.SecretSessionBaseService; import com.iexec.sms.tee.session.generic.TeeSessionRequest; import com.iexec.sms.tee.session.scone.cas.SconeSession; -import com.iexec.sms.tee.workflow.TeeWorkflowInternalConfiguration; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -48,7 +49,11 @@ class SconeSessionMakerServiceTests { private static final String POST_COMPUTE_ENTRYPOINT = "entrypoint3"; @Mock - private TeeWorkflowInternalConfiguration teeWorkflowConfig; + private TeeAppConfiguration preComputeConfiguration; + @Mock + private TeeAppConfiguration postComputeConfiguration; + @Mock + private SconeInternalServicesConfiguration teeServicesConfig; @Mock private SecretSessionBaseService teeSecretsService; @Mock @@ -60,6 +65,8 @@ class SconeSessionMakerServiceTests { @BeforeEach void beforeEach() { MockitoAnnotations.openMocks(this); + when(teeServicesConfig.getPreComputeConfiguration()).thenReturn(preComputeConfiguration); + when(teeServicesConfig.getPostComputeConfiguration()).thenReturn(postComputeConfiguration); } // region getSessionYml @@ -68,8 +75,8 @@ void shouldGetSessionYml() throws Exception { TeeEnclaveConfiguration enclaveConfig = mock(TeeEnclaveConfiguration.class); TeeSessionRequest request = createSessionRequest(createTaskDescription(enclaveConfig)); - when(teeWorkflowConfig.getPreComputeEntrypoint()).thenReturn(PRE_COMPUTE_ENTRYPOINT); - when(teeWorkflowConfig.getPostComputeEntrypoint()).thenReturn(POST_COMPUTE_ENTRYPOINT); + when(preComputeConfiguration.getEntrypoint()).thenReturn(PRE_COMPUTE_ENTRYPOINT); + when(postComputeConfiguration.getEntrypoint()).thenReturn(POST_COMPUTE_ENTRYPOINT); when(enclaveConfig.getFingerprint()).thenReturn(APP_FINGERPRINT); when(enclaveConfig.getEntrypoint()).thenReturn(APP_ENTRYPOINT); From ca0e7a5b6ed630dc65ba2912278cb0373e9617b3 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Wed, 31 Aug 2022 18:01:42 +0200 Subject: [PATCH 053/293] Update `SmsClientProvider` to avoid calling the chain too often --- .../java/com/iexec/sms/api/SmsClient.java | 2 +- .../com/iexec/sms/api/SmsClientProvider.java | 76 ++---- .../iexec/sms/api/SmsClientProviderTests.java | 220 +++--------------- 3 files changed, 54 insertions(+), 244 deletions(-) diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java index 798717c3..81e88f3a 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java @@ -107,7 +107,7 @@ SmsSecretResponse getUnTeeSecrets( @RequestLine("GET /tee/config/gramine") GramineServicesConfiguration getGramineServicesConfiguration(); - default TeeServicesConfiguration getServicesConfiguration(TeeEnclaveProvider teeEnclaveProvider) { + default TeeServicesConfiguration getTeeServicesConfiguration(TeeEnclaveProvider teeEnclaveProvider) { if (teeEnclaveProvider == TeeEnclaveProvider.SCONE) { return getSconeServicesConfiguration(); } else if (teeEnclaveProvider == TeeEnclaveProvider.GRAMINE) { diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java index eac2248d..c7361bd7 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java @@ -1,7 +1,6 @@ package com.iexec.sms.api; import com.iexec.common.chain.ChainDeal; -import com.iexec.common.chain.IexecHubAbstractService; import com.iexec.common.task.TaskDescription; import feign.Logger; import lombok.extern.slf4j.Slf4j; @@ -21,21 +20,12 @@ public class SmsClientProvider { private final Map> taskIdToSmsUrl = new HashMap<>(); private final Map urlToSmsClient = new HashMap<>(); - private final IexecHubAbstractService iexecHubService; private final Logger.Level loggerLevel; - public SmsClientProvider(IexecHubAbstractService iexecHubService) { - this.iexecHubService = iexecHubService; - this.loggerLevel = Logger.Level.NONE; - } - - public SmsClientProvider(IexecHubAbstractService iexecHubService, - Logger.Level loggerLevel) { - this.iexecHubService = iexecHubService; + public SmsClientProvider(Logger.Level loggerLevel) { this.loggerLevel = loggerLevel; } - /** * Retrieves the specified SMS URL for this task, then: *

    @@ -43,12 +33,18 @@ public SmsClientProvider(IexecHubAbstractService iexecHubService, *
  • Otherwise, constructs, stores and returns a new {@link SmsClient}.
  • *
* - * @param chainTaskId ID of the task the specified SMS URL should be retrieved. + * @param taskDescription Task the specified SMS URL should be retrieved for. * @throws SmsClientCreationException if SMS URL can't be retrieved. * @return An instance of {@link SmsClient} pointing on the task's specified SMS. */ - public SmsClient getOrCreateSmsClientForTask(String chainTaskId) { - final Optional smsUrl = getSmsUrlForTask(chainTaskId); + public SmsClient getOrCreateSmsClientForTask(TaskDescription taskDescription) { + final String chainTaskId = taskDescription.getChainTaskId(); + + final Optional smsUrl = taskIdToSmsUrl.computeIfAbsent( + chainTaskId, + id -> Optional.ofNullable(taskDescription.getSmsUrl()) + ); + if (smsUrl.isEmpty() || StringUtils.isEmpty(smsUrl.get())) { throw new SmsClientCreationException("No SMS URL defined for given task [chainTaskId: " + chainTaskId +"]"); } @@ -56,25 +52,6 @@ public SmsClient getOrCreateSmsClientForTask(String chainTaskId) { return urlToSmsClient.computeIfAbsent(smsUrl.get(), url -> SmsClientBuilder.getInstance(loggerLevel, url)); } - /** - * Retrieves the SMS URL from the {@link TaskDescription} defined for this task and caches the result. - * - * @param chainTaskId ID of the task the specified SMS URL should be retrieved. - * @return The SMS URL defined for this task. - */ - Optional getSmsUrlForTask(String chainTaskId) { - if (taskIdToSmsUrl.containsKey(chainTaskId)) { - return taskIdToSmsUrl.get(chainTaskId); - } - - final TaskDescription taskDescription = iexecHubService.getTaskDescription(chainTaskId); - final Optional smsUrl = taskDescription != null - ? Optional.ofNullable(taskDescription.getSmsUrl()) - : Optional.empty(); - taskIdToSmsUrl.put(chainTaskId, smsUrl); - return smsUrl; - } - /** * Retrieves the specified SMS URL for this task based on its dealId, then: *
    @@ -82,39 +59,22 @@ Optional getSmsUrlForTask(String chainTaskId) { *
  • Otherwise, constructs, stores and returns a new {@link SmsClient}.
  • *
* - * @param chainDealId ID of the task the specified SMS URL should be retrieved. + * @param deal Deal of the task the specified SMS URL should be retrieved. * @param chainTaskId ID of the task the specified SMS URL should be stored. * @throws SmsClientCreationException if SMS URL can't be retrieved. * @return An instance of {@link SmsClient} pointing on the deal's specified SMS. */ - public SmsClient getOrCreateSmsClientForUninitializedTask(String chainDealId, String chainTaskId) { - final Optional smsUrl = getSmsUrlForUninitializedTask(chainDealId, chainTaskId); + public SmsClient getOrCreateSmsClientForUninitializedTask(ChainDeal deal, String chainTaskId) { + final Optional smsUrl = taskIdToSmsUrl.computeIfAbsent( + chainTaskId, + id -> Optional.ofNullable(deal.getParams().getIexecSmsUrl()) + ); + if (smsUrl.isEmpty() || StringUtils.isEmpty(smsUrl.get())) { throw new SmsClientCreationException("No SMS URL defined for given deal " + - "[chainDealId: " + chainDealId + ", chainTaskId: " + chainTaskId +"]"); + "[chainDealId: " + deal.getChainDealId() + ", chainTaskId: " + chainTaskId +"]"); } return urlToSmsClient.computeIfAbsent(smsUrl.get(), url -> SmsClientBuilder.getInstance(loggerLevel, url)); } - - /** - * Retrieves the SMS URL from the {@link ChainDeal} defined for this task and caches the result. - * - * @param chainDealId ID of the deal the specified SMS URL should be retrieved. - * @param chainTaskId ID of the task the specified SMS URL should be stored. - * @return The SMS URL defined for this deal. - */ - Optional getSmsUrlForUninitializedTask(String chainDealId, String chainTaskId) { - if (taskIdToSmsUrl.containsKey(chainTaskId)) { - return taskIdToSmsUrl.get(chainTaskId); - } - - final Optional chainDeal = iexecHubService.getChainDeal(chainDealId); - final Optional smsUrl = chainDeal - .map(deal -> deal.getParams().getIexecSmsUrl()); - - taskIdToSmsUrl.put(chainTaskId, smsUrl); - return smsUrl; - } - } diff --git a/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientProviderTests.java b/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientProviderTests.java index a78d36aa..d2c9e97c 100644 --- a/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientProviderTests.java +++ b/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientProviderTests.java @@ -2,19 +2,14 @@ import com.iexec.common.chain.ChainDeal; import com.iexec.common.chain.DealParams; -import com.iexec.common.chain.IexecHubAbstractService; import com.iexec.common.task.TaskDescription; import feign.Logger; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.mockito.Mock; -import org.mockito.Mockito; import org.mockito.MockitoAnnotations; -import java.util.Optional; - import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.spy; class SmsClientProviderTests { private static final String CHAIN_DEAL_ID_1 = "chainDealId1"; @@ -32,6 +27,7 @@ class SmsClientProviderTests { private static final String CHAIN_TASK_ID_2 = "chainTaskId2"; private static final String SMS_URL_2 = "smsUrl2"; private static final ChainDeal CHAIN_DEAL_2 = ChainDeal.builder() + .chainDealId(CHAIN_DEAL_ID_2) .params(DealParams.builder().iexecSmsUrl(SMS_URL_2).build()) .build(); private static final TaskDescription TASK_DESCRIPTION_2 = TaskDescription.builder() @@ -41,185 +37,105 @@ class SmsClientProviderTests { private static final String CHAIN_DEAL_ID_3 = "chainDealId3"; private static final String CHAIN_TASK_ID_3 = "chainTaskId3"; - - @Mock - IexecHubAbstractService iexecHubService; + private static final ChainDeal CHAIN_DEAL_3 = ChainDeal.builder() + .params(DealParams.builder().iexecSmsUrl(SMS_URL_1).build()) + .build(); + private static final TaskDescription TASK_DESCRIPTION_3 = TaskDescription.builder() + .chainTaskId(CHAIN_TASK_ID_3) + .smsUrl(SMS_URL_1) + .build(); SmsClientProvider smsClientProvider; @BeforeEach - void init() { + void init() { MockitoAnnotations.openMocks(this); - smsClientProvider = spy(new SmsClientProvider(iexecHubService, Logger.Level.NONE)); + smsClientProvider = spy(new SmsClientProvider(Logger.Level.NONE)); } // region getOrCreateSmsClientForTask @Test - void shouldGetSmsClientForTask() { - Mockito.when(smsClientProvider.getSmsUrlForTask(CHAIN_TASK_ID_1)).thenReturn(Optional.of(SMS_URL_1)); - - final SmsClient smsClient = assertDoesNotThrow(() -> smsClientProvider.getOrCreateSmsClientForTask(CHAIN_TASK_ID_1)); + void shouldGetSmsClientForTaskDescription() { + final SmsClient smsClient = assertDoesNotThrow(() -> smsClientProvider.getOrCreateSmsClientForTask(TASK_DESCRIPTION_1)); assertNotNull(smsClient); } @Test - void shouldNotRebuildSmsClientForSameTask() { - Mockito.when(smsClientProvider.getSmsUrlForTask(CHAIN_TASK_ID_1)).thenReturn(Optional.of(SMS_URL_1)); - - final SmsClient smsClient1 = assertDoesNotThrow(() -> smsClientProvider.getOrCreateSmsClientForTask(CHAIN_TASK_ID_1)); + void shouldNotRetrieveAgainSmsClientForSameTaskDescription() { + final SmsClient smsClient1 = assertDoesNotThrow(() -> smsClientProvider.getOrCreateSmsClientForTask(TASK_DESCRIPTION_1)); assertNotNull(smsClient1); - final SmsClient smsClient2 = assertDoesNotThrow(() -> smsClientProvider.getOrCreateSmsClientForTask(CHAIN_TASK_ID_1)); + final SmsClient smsClient2 = assertDoesNotThrow(() -> smsClientProvider.getOrCreateSmsClientForTask(TASK_DESCRIPTION_1)); assertNotNull(smsClient2); assertEquals(smsClient1, smsClient2); } @Test - void shouldNotRebuildSmsClientForSameSmsUrlOnAnotherTask() { - Mockito.when(smsClientProvider.getSmsUrlForTask(CHAIN_TASK_ID_1)).thenReturn(Optional.of(SMS_URL_1)); - final SmsClient smsClient1 = assertDoesNotThrow(() -> smsClientProvider.getOrCreateSmsClientForTask(CHAIN_TASK_ID_1)); + void shouldNotRetrieveAgainSmsClientForSameSmsUrlOnAnotherTaskDescription() { + final SmsClient smsClient1 = assertDoesNotThrow(() -> smsClientProvider.getOrCreateSmsClientForTask(TASK_DESCRIPTION_1)); assertNotNull(smsClient1); - Mockito.when(smsClientProvider.getSmsUrlForTask(CHAIN_TASK_ID_3)).thenReturn(Optional.of(SMS_URL_1)); - final SmsClient smsClient2 = assertDoesNotThrow(() -> smsClientProvider.getOrCreateSmsClientForTask(CHAIN_TASK_ID_3)); + final SmsClient smsClient2 = assertDoesNotThrow(() -> smsClientProvider.getOrCreateSmsClientForTask(TASK_DESCRIPTION_3)); assertNotNull(smsClient2); assertEquals(smsClient1, smsClient2); } @Test - void shouldBuildAnotherSmsClientForTaskOnSecondCallForAnotherSms() { - Mockito.when(smsClientProvider.getSmsUrlForTask(CHAIN_TASK_ID_1)).thenReturn(Optional.of(SMS_URL_1)); - Mockito.when(smsClientProvider.getSmsUrlForTask(CHAIN_TASK_ID_2)).thenReturn(Optional.of(SMS_URL_2)); - - final SmsClient smsClientForTask1 = assertDoesNotThrow(() -> smsClientProvider.getOrCreateSmsClientForTask(CHAIN_TASK_ID_1)); + void shouldRetrieveAnotherSmsClientForTaskDescriptionOnSecondCallForAnotherSms() { + final SmsClient smsClientForTask1 = assertDoesNotThrow(() -> smsClientProvider.getOrCreateSmsClientForTask(TASK_DESCRIPTION_1)); assertNotNull(smsClientForTask1); - final SmsClient smsClientForTask2 = assertDoesNotThrow(() -> smsClientProvider.getOrCreateSmsClientForTask(CHAIN_TASK_ID_2)); + final SmsClient smsClientForTask2 = assertDoesNotThrow(() -> smsClientProvider.getOrCreateSmsClientForTask(TASK_DESCRIPTION_2)); assertNotNull(smsClientForTask2); assertNotEquals(smsClientForTask1, smsClientForTask2); } @Test - void shouldNotGetSmsClientForTaskWhenNoSmsUrl() { - Mockito.when(smsClientProvider.getSmsUrlForTask(CHAIN_TASK_ID_1)).thenReturn(Optional.empty()); - + void shouldNotGetSmsClientForTaskDescriptionWhenNoSmsUrl() { SmsClientCreationException e = assertThrows(SmsClientCreationException.class, - () -> smsClientProvider.getOrCreateSmsClientForTask(CHAIN_TASK_ID_1)); + () -> smsClientProvider.getOrCreateSmsClientForTask(TaskDescription.builder().chainTaskId(CHAIN_TASK_ID_1).build())); assertEquals("No SMS URL defined for given task [chainTaskId: " + CHAIN_TASK_ID_1 +"]", e.getMessage()); } // endregion - // region getSmsUrlForTask - @Test - void shouldGetSmsUrlForTaskWhenTaskFound() { - Mockito.when(iexecHubService.getTaskDescription(CHAIN_TASK_ID_1)).thenReturn(TASK_DESCRIPTION_1); - - Optional smsUrl = smsClientProvider.getSmsUrlForTask(CHAIN_TASK_ID_1); - assertTrue(smsUrl.isPresent()); - assertEquals(SMS_URL_1, smsUrl.get()); - - verify(iexecHubService, times(1)).getTaskDescription(any()); - verify(iexecHubService, times(0)).getChainDeal(any()); - } - - @Test - void shouldGetSmsUrlOnlyOnceForSameTask() { - Mockito.when(iexecHubService.getTaskDescription(CHAIN_TASK_ID_1)).thenReturn(TASK_DESCRIPTION_1); - - Optional smsUrlFirstCall = smsClientProvider.getSmsUrlForTask(CHAIN_TASK_ID_1); - assertTrue(smsUrlFirstCall.isPresent()); - assertEquals(SMS_URL_1, smsUrlFirstCall.get()); - - verify(iexecHubService, times(1)).getTaskDescription(any()); - verify(iexecHubService, times(0)).getChainDeal(any()); - - Optional smsUrlSecondCall = smsClientProvider.getSmsUrlForTask(CHAIN_TASK_ID_1); - assertTrue(smsUrlSecondCall.isPresent()); - assertEquals(SMS_URL_1, smsUrlSecondCall.get()); - - verify(iexecHubService, times(1)).getTaskDescription(any()); - verify(iexecHubService, times(0)).getChainDeal(any()); - } - - @Test - void shouldGetSmsUrlTwiceForDifferentTasks() { - Mockito.when(iexecHubService.getTaskDescription(CHAIN_TASK_ID_1)).thenReturn(TASK_DESCRIPTION_1); - Mockito.when(iexecHubService.getTaskDescription(CHAIN_TASK_ID_2)).thenReturn(TASK_DESCRIPTION_2); - - Optional smsUrlFirstCall = smsClientProvider.getSmsUrlForTask(CHAIN_TASK_ID_1); - assertTrue(smsUrlFirstCall.isPresent()); - assertEquals(SMS_URL_1, smsUrlFirstCall.get()); - - verify(iexecHubService, times(1)).getTaskDescription(any()); - verify(iexecHubService, times(0)).getChainDeal(any()); - - Optional smsUrlSecondCall = smsClientProvider.getSmsUrlForTask(CHAIN_TASK_ID_2); - assertTrue(smsUrlSecondCall.isPresent()); - assertEquals(SMS_URL_2, smsUrlSecondCall.get()); - - verify(iexecHubService, times(2)).getTaskDescription(any()); - verify(iexecHubService, times(0)).getChainDeal(any()); - } - - @Test - void shouldNotGetSmsUrlForTaskWhenTaskNotFound() { - Mockito.when(iexecHubService.getTaskDescription(CHAIN_TASK_ID_1)).thenReturn(null); - - Optional smsUrl = smsClientProvider.getSmsUrlForTask(CHAIN_TASK_ID_1); - assertTrue(smsUrl.isEmpty()); - - verify(iexecHubService, times(1)).getTaskDescription(any()); - verify(iexecHubService, times(0)).getChainDeal(any()); - } - // endregion - // region getOrCreateSmsClientForUninitializedTask @Test void shouldGetSmsClientForUninitializedTask() { - Mockito.when(smsClientProvider.getSmsUrlForUninitializedTask(CHAIN_DEAL_ID_1, CHAIN_TASK_ID_1)).thenReturn(Optional.of(SMS_URL_1)); - - final SmsClient smsClient = assertDoesNotThrow(() -> smsClientProvider.getOrCreateSmsClientForUninitializedTask(CHAIN_DEAL_ID_1, CHAIN_TASK_ID_1)); + final SmsClient smsClient = assertDoesNotThrow(() -> smsClientProvider.getOrCreateSmsClientForUninitializedTask(CHAIN_DEAL_1, CHAIN_TASK_ID_1)); assertNotNull(smsClient); } @Test - void shouldNotRebuildSmsClientForSameDeal() { - Mockito.when(smsClientProvider.getSmsUrlForUninitializedTask(CHAIN_DEAL_ID_1, CHAIN_TASK_ID_1)).thenReturn(Optional.of(SMS_URL_1)); - - final SmsClient smsClient1 = assertDoesNotThrow(() -> smsClientProvider.getOrCreateSmsClientForUninitializedTask(CHAIN_DEAL_ID_1, CHAIN_TASK_ID_1)); + void shouldNotRetrieveAgainSmsClientForSameDeal() { + final SmsClient smsClient1 = assertDoesNotThrow(() -> smsClientProvider.getOrCreateSmsClientForUninitializedTask(CHAIN_DEAL_1, CHAIN_TASK_ID_1)); assertNotNull(smsClient1); - final SmsClient smsClient2 = assertDoesNotThrow(() -> smsClientProvider.getOrCreateSmsClientForUninitializedTask(CHAIN_DEAL_ID_1, CHAIN_TASK_ID_1)); + final SmsClient smsClient2 = assertDoesNotThrow(() -> smsClientProvider.getOrCreateSmsClientForUninitializedTask(CHAIN_DEAL_1, CHAIN_TASK_ID_1)); assertNotNull(smsClient2); assertEquals(smsClient1, smsClient2); } @Test - void shouldNotRebuildSmsClientForSameSmsUrlOnAnotherDeal() { - Mockito.when(smsClientProvider.getSmsUrlForUninitializedTask(CHAIN_DEAL_ID_1, CHAIN_TASK_ID_1)).thenReturn(Optional.of(SMS_URL_1)); - final SmsClient smsClient1 = assertDoesNotThrow(() -> smsClientProvider.getOrCreateSmsClientForUninitializedTask(CHAIN_DEAL_ID_1, CHAIN_TASK_ID_1)); + void shouldNotRetrieveAgainSmsClientForSameSmsUrlOnAnotherDeal() { + final SmsClient smsClient1 = assertDoesNotThrow(() -> smsClientProvider.getOrCreateSmsClientForUninitializedTask(CHAIN_DEAL_1, CHAIN_TASK_ID_1)); assertNotNull(smsClient1); - Mockito.when(smsClientProvider.getSmsUrlForUninitializedTask(CHAIN_DEAL_ID_3, CHAIN_TASK_ID_3)).thenReturn(Optional.of(SMS_URL_1)); - final SmsClient smsClient2 = assertDoesNotThrow(() -> smsClientProvider.getOrCreateSmsClientForUninitializedTask(CHAIN_DEAL_ID_3, CHAIN_TASK_ID_3)); + final SmsClient smsClient2 = assertDoesNotThrow(() -> smsClientProvider.getOrCreateSmsClientForUninitializedTask(CHAIN_DEAL_3, CHAIN_TASK_ID_3)); assertNotNull(smsClient2); assertEquals(smsClient1, smsClient2); } @Test - void shouldBuildAnotherSmsClientForUninitializedTaskOnSecondCallForAnotherSms() { - Mockito.when(smsClientProvider.getSmsUrlForUninitializedTask(CHAIN_DEAL_ID_1, CHAIN_TASK_ID_1)).thenReturn(Optional.of(SMS_URL_1)); - Mockito.when(smsClientProvider.getSmsUrlForUninitializedTask(CHAIN_DEAL_ID_2, CHAIN_TASK_ID_2)).thenReturn(Optional.of(SMS_URL_2)); - - final SmsClient smsClientForUninitializedTask1 = assertDoesNotThrow(() -> smsClientProvider.getOrCreateSmsClientForUninitializedTask(CHAIN_DEAL_ID_1, CHAIN_TASK_ID_1)); + void shouldRetrieveAnotherSmsClientForUninitializedTaskOnSecondCallForAnotherSms() { + final SmsClient smsClientForUninitializedTask1 = assertDoesNotThrow(() -> smsClientProvider.getOrCreateSmsClientForUninitializedTask(CHAIN_DEAL_1, CHAIN_TASK_ID_1)); assertNotNull(smsClientForUninitializedTask1); - final SmsClient smsClientForUninitializedTask2 = assertDoesNotThrow(() -> smsClientProvider.getOrCreateSmsClientForUninitializedTask(CHAIN_DEAL_ID_2, CHAIN_TASK_ID_2)); + final SmsClient smsClientForUninitializedTask2 = assertDoesNotThrow(() -> smsClientProvider.getOrCreateSmsClientForUninitializedTask(CHAIN_DEAL_2, CHAIN_TASK_ID_2)); assertNotNull(smsClientForUninitializedTask2); assertNotEquals(smsClientForUninitializedTask1, smsClientForUninitializedTask2); @@ -227,78 +143,12 @@ void shouldBuildAnotherSmsClientForUninitializedTaskOnSecondCallForAnotherSms() @Test void shouldNotGetSmsClientForUninitializedTaskWhenNoSmsUrl() { - Mockito.when(smsClientProvider.getSmsUrlForUninitializedTask(CHAIN_DEAL_ID_1, CHAIN_TASK_ID_1)).thenReturn(Optional.empty()); - SmsClientCreationException e = assertThrows(SmsClientCreationException.class, - () -> smsClientProvider.getOrCreateSmsClientForUninitializedTask(CHAIN_DEAL_ID_1, CHAIN_TASK_ID_1)); + () -> smsClientProvider.getOrCreateSmsClientForUninitializedTask(ChainDeal.builder().chainDealId(CHAIN_DEAL_ID_1).params(DealParams.builder().build()).build(), CHAIN_TASK_ID_1)); assertEquals( "No SMS URL defined for given deal" + " [chainDealId: " + CHAIN_DEAL_ID_1 + ", chainTaskId: " + CHAIN_TASK_ID_1 +"]", e.getMessage()); } // endregion - - // region getSmsUrlForUninitializedTask - @Test - void shouldGetSmsUrlForUninitializedTaskWhenTaskFound() { - Mockito.when(iexecHubService.getChainDeal(CHAIN_DEAL_ID_1)).thenReturn(Optional.of(CHAIN_DEAL_1)); - - Optional smsUrl = smsClientProvider.getSmsUrlForUninitializedTask(CHAIN_DEAL_ID_1, CHAIN_TASK_ID_1); - assertTrue(smsUrl.isPresent()); - assertEquals(SMS_URL_1, smsUrl.get()); - - verify(iexecHubService, times(1)).getChainDeal(CHAIN_DEAL_ID_1); - verify(iexecHubService, times(0)).getTaskDescription(any()); - } - - @Test - void shouldGetSmsUrlOnlyOnceForSameUninitializedTask() { - Mockito.when(iexecHubService.getChainDeal(CHAIN_DEAL_ID_1)).thenReturn(Optional.of(CHAIN_DEAL_1)); - - Optional smsUrlFirstCall = smsClientProvider.getSmsUrlForUninitializedTask(CHAIN_DEAL_ID_1, CHAIN_TASK_ID_1); - assertTrue(smsUrlFirstCall.isPresent()); - assertEquals(SMS_URL_1, smsUrlFirstCall.get()); - - verify(iexecHubService, times(1)).getChainDeal(CHAIN_DEAL_ID_1); - verify(iexecHubService, times(0)).getTaskDescription(any()); - - Optional smsUrlSecondCall = smsClientProvider.getSmsUrlForUninitializedTask(CHAIN_DEAL_ID_1, CHAIN_TASK_ID_1); - assertTrue(smsUrlSecondCall.isPresent()); - assertEquals(SMS_URL_1, smsUrlSecondCall.get()); - - verify(iexecHubService, times(1)).getChainDeal(CHAIN_DEAL_ID_1); - verify(iexecHubService, times(0)).getTaskDescription(any()); - } - - @Test - void shouldGetSmsUrlTwiceForDifferentUninitializedTasks() { - Mockito.when(iexecHubService.getChainDeal(CHAIN_DEAL_ID_1)).thenReturn(Optional.of(CHAIN_DEAL_1)); - Mockito.when(iexecHubService.getChainDeal(CHAIN_DEAL_ID_2)).thenReturn(Optional.of(CHAIN_DEAL_2)); - - Optional smsUrlFirstCall = smsClientProvider.getSmsUrlForUninitializedTask(CHAIN_DEAL_ID_1, CHAIN_TASK_ID_1); - assertTrue(smsUrlFirstCall.isPresent()); - assertEquals(SMS_URL_1, smsUrlFirstCall.get()); - - verify(iexecHubService, times(1)).getChainDeal(CHAIN_DEAL_ID_1); - verify(iexecHubService, times(0)).getTaskDescription(any()); - - Optional smsUrlSecondCall = smsClientProvider.getSmsUrlForUninitializedTask(CHAIN_DEAL_ID_2, CHAIN_TASK_ID_2); - assertTrue(smsUrlSecondCall.isPresent()); - assertEquals(SMS_URL_2, smsUrlSecondCall.get()); - - verify(iexecHubService, times(1)).getChainDeal(CHAIN_DEAL_ID_2); - verify(iexecHubService, times(0)).getTaskDescription(any()); - } - - @Test - void shouldNotGetSmsUrlForTaskWhenDealNotFound() { - Mockito.when(iexecHubService.getChainDeal(CHAIN_DEAL_ID_1)).thenReturn(Optional.empty()); - - Optional smsUrl = smsClientProvider.getSmsUrlForUninitializedTask(CHAIN_DEAL_ID_1, CHAIN_TASK_ID_1); - assertTrue(smsUrl.isEmpty()); - - verify(iexecHubService, times(1)).getChainDeal(CHAIN_DEAL_ID_1); - verify(iexecHubService, times(0)).getTaskDescription(any()); - } - // endregion } \ No newline at end of file From fcd7ef5d7ba1eeb34b21a8bcfb5b1098a7a35a58 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Thu, 1 Sep 2022 09:14:03 +0200 Subject: [PATCH 054/293] Fix code smells --- .../iexec/sms/api/SmsClientProviderTests.java | 14 +++++++++---- .../iexec/sms/tee/EnableIfTeeProvider.java | 20 +++++++++++-------- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientProviderTests.java b/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientProviderTests.java index d2c9e97c..420451bc 100644 --- a/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientProviderTests.java +++ b/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientProviderTests.java @@ -95,8 +95,9 @@ void shouldRetrieveAnotherSmsClientForTaskDescriptionOnSecondCallForAnotherSms() @Test void shouldNotGetSmsClientForTaskDescriptionWhenNoSmsUrl() { - SmsClientCreationException e = assertThrows(SmsClientCreationException.class, - () -> smsClientProvider.getOrCreateSmsClientForTask(TaskDescription.builder().chainTaskId(CHAIN_TASK_ID_1).build())); + final TaskDescription taskDescription = TaskDescription.builder().chainTaskId(CHAIN_TASK_ID_1).build(); + final SmsClientCreationException e = assertThrows(SmsClientCreationException.class, + () -> smsClientProvider.getOrCreateSmsClientForTask(taskDescription)); assertEquals("No SMS URL defined for given task [chainTaskId: " + CHAIN_TASK_ID_1 +"]", e.getMessage()); } // endregion @@ -143,8 +144,13 @@ void shouldRetrieveAnotherSmsClientForUninitializedTaskOnSecondCallForAnotherSms @Test void shouldNotGetSmsClientForUninitializedTaskWhenNoSmsUrl() { - SmsClientCreationException e = assertThrows(SmsClientCreationException.class, - () -> smsClientProvider.getOrCreateSmsClientForUninitializedTask(ChainDeal.builder().chainDealId(CHAIN_DEAL_ID_1).params(DealParams.builder().build()).build(), CHAIN_TASK_ID_1)); + final ChainDeal chainDeal = ChainDeal + .builder() + .chainDealId(CHAIN_DEAL_ID_1) + .params(DealParams.builder().build()) + .build(); + final SmsClientCreationException e = assertThrows(SmsClientCreationException.class, + () -> smsClientProvider.getOrCreateSmsClientForUninitializedTask(chainDeal, CHAIN_TASK_ID_1)); assertEquals( "No SMS URL defined for given deal" + " [chainDealId: " + CHAIN_DEAL_ID_1 + ", chainTaskId: " + CHAIN_TASK_ID_1 +"]", diff --git a/src/main/java/com/iexec/sms/tee/EnableIfTeeProvider.java b/src/main/java/com/iexec/sms/tee/EnableIfTeeProvider.java index 5674205f..1f998ca4 100644 --- a/src/main/java/com/iexec/sms/tee/EnableIfTeeProvider.java +++ b/src/main/java/com/iexec/sms/tee/EnableIfTeeProvider.java @@ -31,23 +31,26 @@ public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) try { clazz = Class.forName(beanClassName); } catch (ClassNotFoundException e) { - log.error("Bean does not exist " + - "[bean: {}]", beanClassName); + log.error( + "Bean does not exist [bean: {}]", + beanClassName); return false; } final EnableIfTeeProviderDefinition condition = clazz.getAnnotation(EnableIfTeeProviderDefinition.class); if (condition == null) { - log.error("@EnableIfTeeProviderDefinition annotation is required to use EnableIfTeeProvider condition " + - "[bean: {}]", beanClassName); + log.error( + "@EnableIfTeeProviderDefinition annotation is required to use EnableIfTeeProvider condition [bean: {}]", + beanClassName); return false; } final TeeEnclaveProvider[] teeProviders = condition.providers(); if (teeProviders == null || teeProviders.length == 0) { - log.warn("No TEE provider defined for bean, won't be loaded " + - "[bean: {}]", beanClassName); + log.warn( + "No TEE provider defined for bean, won't be loaded [bean: {}]", + beanClassName); return false; } @@ -59,8 +62,9 @@ public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) } } - log.debug("Active profiles and condition don't match, bean won't be loaded" + - "[bean: {}]", beanClassName); + log.debug( + "Active profiles and condition don't match, bean won't be loaded [bean: {}]", + beanClassName); return false; } } From 14e1f9c33cf6acfcb47d4eab559439ba90734db3 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Thu, 1 Sep 2022 10:42:17 +0200 Subject: [PATCH 055/293] Simplify `SmslClient#getTeeServicesConfiguration` calls --- .../java/com/iexec/sms/api/SmsClient.java | 19 ++----------------- .../com/iexec/sms/api/SmsClientProvider.java | 4 ++++ 2 files changed, 6 insertions(+), 17 deletions(-) diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java index 81e88f3a..134b9a62 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java @@ -20,8 +20,6 @@ import com.iexec.common.sms.secret.SmsSecretResponse; import com.iexec.common.tee.TeeEnclaveProvider; import com.iexec.common.web.ApiResponseBody; -import com.iexec.sms.api.config.GramineServicesConfiguration; -import com.iexec.sms.api.config.SconeServicesConfiguration; import com.iexec.sms.api.config.TeeServicesConfiguration; import feign.Headers; import feign.Param; @@ -101,19 +99,6 @@ SmsSecretResponse getUnTeeSecrets( WorkerpoolAuthorization workerpoolAuthorization ); - @RequestLine("GET /tee/config/scone") - SconeServicesConfiguration getSconeServicesConfiguration(); - - @RequestLine("GET /tee/config/gramine") - GramineServicesConfiguration getGramineServicesConfiguration(); - - default TeeServicesConfiguration getTeeServicesConfiguration(TeeEnclaveProvider teeEnclaveProvider) { - if (teeEnclaveProvider == TeeEnclaveProvider.SCONE) { - return getSconeServicesConfiguration(); - } else if (teeEnclaveProvider == TeeEnclaveProvider.GRAMINE) { - return getGramineServicesConfiguration(); - } - - return null; // FIXME: throw - } + @RequestLine("GET /tee/config/{teeEnclaveProvider}") + T getTeeServicesConfiguration(@Param("teeEnclaveProvider") TeeEnclaveProvider teeEnclaveProvider); } diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java index c7361bd7..a83a3859 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java @@ -22,6 +22,10 @@ public class SmsClientProvider { private final Logger.Level loggerLevel; + public SmsClientProvider() { + this(Logger.Level.BASIC); + } + public SmsClientProvider(Logger.Level loggerLevel) { this.loggerLevel = loggerLevel; } From ca072825bf249854f2d7ab892e8587e4f2e8fc94 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Thu, 1 Sep 2022 11:35:42 +0200 Subject: [PATCH 056/293] Fix `TeeSessionService` loading --- .../iexec/sms/tee/EnableIfTeeProvider.java | 3 +- .../sms/tee/session/TeeSessionService.java | 23 ++---- .../tee/session/TeeSessionServiceTests.java | 71 ++++++++----------- 3 files changed, 36 insertions(+), 61 deletions(-) diff --git a/src/main/java/com/iexec/sms/tee/EnableIfTeeProvider.java b/src/main/java/com/iexec/sms/tee/EnableIfTeeProvider.java index 1f998ca4..4de77fed 100644 --- a/src/main/java/com/iexec/sms/tee/EnableIfTeeProvider.java +++ b/src/main/java/com/iexec/sms/tee/EnableIfTeeProvider.java @@ -5,6 +5,7 @@ import org.springframework.context.annotation.Condition; import org.springframework.context.annotation.ConditionContext; import org.springframework.core.type.AnnotatedTypeMetadata; +import org.springframework.core.type.AnnotationMetadata; import org.springframework.core.type.StandardMethodMetadata; /** @@ -26,7 +27,7 @@ public class EnableIfTeeProvider implements Condition { @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { final String[] activeProfiles = context.getEnvironment().getActiveProfiles(); - final String beanClassName = ((StandardMethodMetadata) metadata).getReturnTypeName(); + final String beanClassName = ((AnnotationMetadata) metadata).getClassName(); final Class clazz; try { clazz = Class.forName(beanClassName); diff --git a/src/main/java/com/iexec/sms/tee/session/TeeSessionService.java b/src/main/java/com/iexec/sms/tee/session/TeeSessionService.java index 0f571441..bd0b13ec 100644 --- a/src/main/java/com/iexec/sms/tee/session/TeeSessionService.java +++ b/src/main/java/com/iexec/sms/tee/session/TeeSessionService.java @@ -23,32 +23,26 @@ import com.iexec.sms.tee.session.generic.TeeSessionGenerationException; import com.iexec.sms.tee.session.generic.TeeSessionHandler; import com.iexec.sms.tee.session.generic.TeeSessionRequest; -import com.iexec.sms.tee.session.gramine.GramineSessionHandlerService; -import com.iexec.sms.tee.session.scone.SconeSessionHandlerService; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.RandomStringUtils; import org.springframework.stereotype.Service; -import java.util.Map; - -import static com.iexec.sms.api.TeeSessionGenerationError.*; +import static com.iexec.sms.api.TeeSessionGenerationError.GET_TASK_DESCRIPTION_FAILED; +import static com.iexec.sms.api.TeeSessionGenerationError.SECURE_SESSION_NO_TEE_PROVIDER; @Slf4j @Service public class TeeSessionService { private final IexecHubService iexecHubService; + private final TeeSessionHandler teeSessionHandler; - private final Map teeSessionConfigurations; public TeeSessionService( IexecHubService iexecService, - SconeSessionHandlerService sconeService, - GramineSessionHandlerService gramineService) { + TeeSessionHandler teeSessionHandler) { this.iexecHubService = iexecService; - this.teeSessionConfigurations = Map.of( - TeeEnclaveProvider.SCONE, sconeService, - TeeEnclaveProvider.GRAMINE, gramineService); + this.teeSessionHandler = teeSessionHandler; } public TeeSessionGenerationResponse generateTeeSession( @@ -76,13 +70,6 @@ public TeeSessionGenerationResponse generateTeeSession( String.format("TEE provider can't be null [taskId:%s]", taskId)); } - final TeeSessionHandler teeSessionHandler = teeSessionConfigurations.get(teeEnclaveProvider); - if (teeSessionHandler == null) { - throw new TeeSessionGenerationException( - SECURE_SESSION_UNKNOWN_TEE_PROVIDER, - String.format("Unknown TEE provider [taskId:%s, teeProvider:%s]", taskId, teeEnclaveProvider)); - } - // /!\ TODO clean expired tasks sessions String secretProvisioningUrl = teeSessionHandler.buildAndPostSession(request); return new TeeSessionGenerationResponse(sessionId, secretProvisioningUrl); diff --git a/src/test/java/com/iexec/sms/tee/session/TeeSessionServiceTests.java b/src/test/java/com/iexec/sms/tee/session/TeeSessionServiceTests.java index 16300808..0b71b03d 100644 --- a/src/test/java/com/iexec/sms/tee/session/TeeSessionServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/TeeSessionServiceTests.java @@ -35,39 +35,47 @@ class TeeSessionServiceTests { private GramineSessionHandlerService gramineService; @Mock private IexecHubService iexecHubService; - @InjectMocks - private TeeSessionService teeSessionService; - private Map providerToSessionService; @BeforeEach void setUp() { MockitoAnnotations.openMocks(this); - providerToSessionService = Map.of( - TeeEnclaveProvider.SCONE, sconeService, - TeeEnclaveProvider.GRAMINE, gramineService); } - static Stream teeProviders() { - return Stream.of( - TeeEnclaveProvider.SCONE, - TeeEnclaveProvider.GRAMINE); + @Test + void shouldGenerateSconeSession() + throws TeeSessionGenerationException { + final TeeSessionService teeSessionService = new TeeSessionService(iexecHubService, sconeService); + + final TaskDescription taskDescription = TaskDescription.builder() + .chainTaskId(TASK_ID) + .teeEnclaveProvider(TeeEnclaveProvider.SCONE) + .build(); + when(iexecHubService.getTaskDescription(TASK_ID)).thenReturn(taskDescription); + when(sconeService.buildAndPostSession(any())).thenReturn(SECRET_PROVISIONING_URL); + + final TeeSessionGenerationResponse teeSessionReponse = assertDoesNotThrow( + () -> teeSessionService.generateTeeSession(TASK_ID, WORKER_ADDRESS, TEE_CHALLENGE)); + verify(sconeService, times(1)) + .buildAndPostSession(any()); + assertFalse(teeSessionReponse.getSessionId().isEmpty()); + assertEquals(SECRET_PROVISIONING_URL, teeSessionReponse.getSecretProvisioningUrl()); } - @ParameterizedTest - @MethodSource("teeProviders") - void shouldGenerateTeeSession(TeeEnclaveProvider teeEnclaveProvider) + @Test + void shouldGenerateGramineSession() throws TeeSessionGenerationException { + final TeeSessionService teeSessionService = new TeeSessionService(iexecHubService, gramineService); + final TaskDescription taskDescription = TaskDescription.builder() .chainTaskId(TASK_ID) - .teeEnclaveProvider(teeEnclaveProvider) + .teeEnclaveProvider(TeeEnclaveProvider.GRAMINE) .build(); when(iexecHubService.getTaskDescription(TASK_ID)).thenReturn(taskDescription); - TeeSessionHandler teeProviderSessionHandler = getTeeSessionHandler(teeEnclaveProvider); - when(teeProviderSessionHandler.buildAndPostSession(any())).thenReturn(SECRET_PROVISIONING_URL); + when(gramineService.buildAndPostSession(any())).thenReturn(SECRET_PROVISIONING_URL); final TeeSessionGenerationResponse teeSessionReponse = assertDoesNotThrow( () -> teeSessionService.generateTeeSession(TASK_ID, WORKER_ADDRESS, TEE_CHALLENGE)); - verify(teeProviderSessionHandler, times(1)) + verify(gramineService, times(1)) .buildAndPostSession(any()); assertFalse(teeSessionReponse.getSessionId().isEmpty()); assertEquals(SECRET_PROVISIONING_URL, teeSessionReponse.getSecretProvisioningUrl()); @@ -75,6 +83,8 @@ void shouldGenerateTeeSession(TeeEnclaveProvider teeEnclaveProvider) @Test void shouldNotGenerateTeeSessionSinceCantGetTaskDescription() { + final TeeSessionService teeSessionService = new TeeSessionService(iexecHubService, sconeService); + when(iexecHubService.getTaskDescription(TASK_ID)).thenReturn(null); final TeeSessionGenerationException teeSessionGenerationException = assertThrows( @@ -88,6 +98,8 @@ void shouldNotGenerateTeeSessionSinceCantGetTaskDescription() { @Test void shouldNotGenerateTeeSessionSinceNoTeeEnclaveProvider() { + final TeeSessionService teeSessionService = new TeeSessionService(iexecHubService, sconeService); + final TaskDescription taskDescription = TaskDescription.builder() .chainTaskId(TASK_ID) .teeEnclaveProvider(null) @@ -105,29 +117,4 @@ void shouldNotGenerateTeeSessionSinceNoTeeEnclaveProvider() { teeSessionGenerationException.getMessage()); } - @ParameterizedTest - @MethodSource("teeProviders") - void shouldNotGenerateTeeSessionSinceCantBuildAndPostSession(TeeEnclaveProvider teeEnclaveProvider) - throws TeeSessionGenerationException { - final TaskDescription taskDescription = TaskDescription.builder() - .chainTaskId(TASK_ID) - .teeEnclaveProvider(teeEnclaveProvider) - .build(); - TeeSessionGenerationError error = TeeSessionGenerationError.SECURE_SESSION_GENERATION_FAILED; - TeeSessionGenerationException exception = new TeeSessionGenerationException( - error, "some error"); - when(iexecHubService.getTaskDescription(TASK_ID)).thenReturn(taskDescription); - doThrow(exception) - .when(getTeeSessionHandler(teeEnclaveProvider)).buildAndPostSession(any()); - - final TeeSessionGenerationException teeSessionGenerationException = assertThrows( - exception.getClass(), - () -> teeSessionService.generateTeeSession(TASK_ID, WORKER_ADDRESS, TEE_CHALLENGE)); - assertEquals(error, teeSessionGenerationException.getError()); - } - - private TeeSessionHandler getTeeSessionHandler(TeeEnclaveProvider teeEnclaveProvider) { - return providerToSessionService.get(teeEnclaveProvider); - } - } \ No newline at end of file From 855599a6e08cb0983937ee702cd980c2f3adfce6 Mon Sep 17 00:00:00 2001 From: mcornaton Date: Thu, 1 Sep 2022 11:40:28 +0200 Subject: [PATCH 057/293] Fix `SpsConfiguration` login/password vars --- .../iexec/sms/tee/session/gramine/sps/SpsConfiguration.java | 4 ++-- src/main/resources/application-gramine.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsConfiguration.java b/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsConfiguration.java index 64e0c830..6d1d4ac8 100644 --- a/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsConfiguration.java +++ b/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsConfiguration.java @@ -37,10 +37,10 @@ public class SpsConfiguration { @Value("${tee.secret-provisioner.web.port}") private String webPort; - @Value("${tee.gramine.sps.web.login}") + @Value("${tee.gramine.sps.login}") private String webLogin; - @Value("${tee.gramine.sps.web.password}") + @Value("${tee.gramine.sps.password}") private String webPassword; @Value("${tee.secret-provisioner.enclave.hostname}") diff --git a/src/main/resources/application-gramine.yml b/src/main/resources/application-gramine.yml index 1bf08058..5a16f4f7 100644 --- a/src/main/resources/application-gramine.yml +++ b/src/main/resources/application-gramine.yml @@ -10,4 +10,4 @@ tee: gramine: sps: login: ${IEXEC_GRAPHENE_SPS_WEB_LOGIN:admin} - password: ${IEXEC_GRAPHENE_SPS_WEB_PASSWORD:admin} \ No newline at end of file + password: ${IEXEC_GRAPHENE_SPS_WEB_PASSWORD:admin} From fb9623177a6ac2e0b7bc1d433368091fe80b7857 Mon Sep 17 00:00:00 2001 From: mcornaton Date: Thu, 1 Sep 2022 11:51:16 +0200 Subject: [PATCH 058/293] Fix `TeeController#getTeeServicesConfig` path variable --- src/main/java/com/iexec/sms/tee/TeeController.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/iexec/sms/tee/TeeController.java b/src/main/java/com/iexec/sms/tee/TeeController.java index 9259cc1b..e7a249df 100644 --- a/src/main/java/com/iexec/sms/tee/TeeController.java +++ b/src/main/java/com/iexec/sms/tee/TeeController.java @@ -80,7 +80,8 @@ public TeeController( * heap size, ...) */ @GetMapping("/config/{teeEnclaveProvider}") - public ResponseEntity getTeeServicesConfig(TeeEnclaveProvider teeEnclaveProvider) { + public ResponseEntity getTeeServicesConfig( + @PathVariable TeeEnclaveProvider teeEnclaveProvider) { if (teeEnclaveProvider != teeServicesConfig.getTeeEnclaveProvider()) { log.error("SMS configured to use another TeeEnclaveProvider " + "[required: {}, actual: {}]", teeEnclaveProvider, teeServicesConfig.getTeeEnclaveProvider()); From 5ab7c6e3a369a42d2d8cd400e9cfb79a136ad277 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Thu, 1 Sep 2022 12:08:06 +0200 Subject: [PATCH 059/293] Fix `SconeInternalServicesConfiguration` loading --- .../sms/tee/config/SconeInternalServicesConfiguration.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/com/iexec/sms/tee/config/SconeInternalServicesConfiguration.java b/src/main/java/com/iexec/sms/tee/config/SconeInternalServicesConfiguration.java index f8b9f177..59aab60a 100644 --- a/src/main/java/com/iexec/sms/tee/config/SconeInternalServicesConfiguration.java +++ b/src/main/java/com/iexec/sms/tee/config/SconeInternalServicesConfiguration.java @@ -6,9 +6,12 @@ import com.iexec.sms.tee.EnableIfTeeProvider; import com.iexec.sms.tee.EnableIfTeeProviderDefinition; import lombok.Getter; +import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; +import javax.validation.constraints.NotBlank; + @Configuration @Conditional(EnableIfTeeProvider.class) @EnableIfTeeProviderDefinition(providers = TeeEnclaveProvider.SCONE) @@ -17,6 +20,8 @@ public class SconeInternalServicesConfiguration extends SconeServicesConfigurati protected SconeInternalServicesConfiguration( TeeAppConfiguration preComputeConfiguration, TeeAppConfiguration postComputeConfiguration, + @Value("${tee.scone.las-image}") + @NotBlank(message = "las image must be provided") String lasImage) { super(preComputeConfiguration, postComputeConfiguration, lasImage); } From e2fbc38971e226a60524316f512c05d528f67507 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Thu, 1 Sep 2022 12:28:38 +0200 Subject: [PATCH 060/293] Fix `SconeSessionSecurityConfig` loading --- .../sms/tee/session/scone/SconeSessionSecurityConfig.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionSecurityConfig.java b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionSecurityConfig.java index e4909ba4..86e6aa48 100644 --- a/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionSecurityConfig.java +++ b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionSecurityConfig.java @@ -31,11 +31,11 @@ @EnableIfTeeProviderDefinition(providers = TeeEnclaveProvider.SCONE) public class SconeSessionSecurityConfig { - @Value("${scone.attestation.tolerated-insecure-options}") + @Value("${tee.scone.attestation.tolerated-insecure-options}") @Getter private List toleratedInsecureOptions; - @Value("${scone.attestation.ignored-sgx-advisories}") + @Value("${tee.scone.attestation.ignored-sgx-advisories}") @Getter private List ignoredSgxAdvisories; } From 14b938a9ed7a477d099187988a7182e3653e3a26 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Thu, 1 Sep 2022 15:05:23 +0200 Subject: [PATCH 061/293] Fix `TeeServicesConfiguration` de/serialization --- .../java/com/iexec/sms/api/SmsClient.java | 19 +++++++++++++++-- .../config/GramineServicesConfiguration.java | 8 +++++++ .../config/SconeServicesConfiguration.java | 15 ++++++++----- .../sms/api/config/TeeAppConfiguration.java | 21 +++++++++---------- .../api/config/TeeServicesConfiguration.java | 19 +++++++++-------- .../java/com/iexec/sms/tee/TeeController.java | 7 ++++--- .../GramineInternalServicesConfiguration.java | 10 ++++++++- .../SconeInternalServicesConfiguration.java | 10 ++++++++- .../TeeInternalServicesConfiguration.java | 9 ++++++++ 9 files changed, 86 insertions(+), 32 deletions(-) create mode 100644 src/main/java/com/iexec/sms/tee/config/TeeInternalServicesConfiguration.java diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java index 134b9a62..3938194e 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java @@ -20,6 +20,8 @@ import com.iexec.common.sms.secret.SmsSecretResponse; import com.iexec.common.tee.TeeEnclaveProvider; import com.iexec.common.web.ApiResponseBody; +import com.iexec.sms.api.config.GramineServicesConfiguration; +import com.iexec.sms.api.config.SconeServicesConfiguration; import com.iexec.sms.api.config.TeeServicesConfiguration; import feign.Headers; import feign.Param; @@ -99,6 +101,19 @@ SmsSecretResponse getUnTeeSecrets( WorkerpoolAuthorization workerpoolAuthorization ); - @RequestLine("GET /tee/config/{teeEnclaveProvider}") - T getTeeServicesConfiguration(@Param("teeEnclaveProvider") TeeEnclaveProvider teeEnclaveProvider); + @RequestLine("GET /tee/config/scone") + SconeServicesConfiguration getSconeServicesConfiguration(); + + @RequestLine("GET /tee/config/gramine") + GramineServicesConfiguration getGramineServicesConfiguration(); + + default T getTeeServicesConfiguration(TeeEnclaveProvider teeEnclaveProvider) { + if (teeEnclaveProvider == TeeEnclaveProvider.SCONE) { + return (T) getSconeServicesConfiguration(); + } else if (teeEnclaveProvider == TeeEnclaveProvider.GRAMINE) { + return (T) getGramineServicesConfiguration(); + } + + return null; + } } diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/GramineServicesConfiguration.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/GramineServicesConfiguration.java index c49a79f9..b428142e 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/GramineServicesConfiguration.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/GramineServicesConfiguration.java @@ -1,9 +1,17 @@ package com.iexec.sms.api.config; import com.iexec.common.tee.TeeEnclaveProvider; +import lombok.Getter; +import lombok.Setter; +@Getter +@Setter public class GramineServicesConfiguration extends TeeServicesConfiguration { + public GramineServicesConfiguration() { + super(TeeEnclaveProvider.GRAMINE); + } + public GramineServicesConfiguration(TeeAppConfiguration preComputeConfiguration, TeeAppConfiguration postComputeConfiguration) { super(TeeEnclaveProvider.GRAMINE, preComputeConfiguration, postComputeConfiguration); diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/SconeServicesConfiguration.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/SconeServicesConfiguration.java index ca4c5b10..8adc2b57 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/SconeServicesConfiguration.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/SconeServicesConfiguration.java @@ -2,15 +2,20 @@ import com.iexec.common.tee.TeeEnclaveProvider; import lombok.Getter; +import lombok.Setter; @Getter +@Setter public class SconeServicesConfiguration extends TeeServicesConfiguration { - private final String lasImage; + private String lasImage; - public SconeServicesConfiguration( - TeeAppConfiguration preComputeConfiguration, - TeeAppConfiguration postComputeConfiguration, - String lasImage) { + public SconeServicesConfiguration() { + super(TeeEnclaveProvider.SCONE); + } + + public SconeServicesConfiguration(TeeAppConfiguration preComputeConfiguration, + TeeAppConfiguration postComputeConfiguration, + String lasImage) { super(TeeEnclaveProvider.SCONE, preComputeConfiguration, postComputeConfiguration); this.lasImage = lasImage; } diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeAppConfiguration.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeAppConfiguration.java index 044b54c6..8aab15e7 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeAppConfiguration.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeAppConfiguration.java @@ -1,18 +1,17 @@ package com.iexec.sms.api.config; +import lombok.AllArgsConstructor; import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +@NoArgsConstructor +@AllArgsConstructor @Getter +@Setter public class TeeAppConfiguration { - private final String image; - private final String fingerprint; - private final String entrypoint; - private final long heapSize; - - public TeeAppConfiguration(String image, String fingerprint, String entrypoint, long heapSize) { - this.image = image; - this.fingerprint = fingerprint; - this.entrypoint = entrypoint; - this.heapSize = heapSize; - } + private String image; + private String fingerprint; + private String entrypoint; + private long heapSize; } diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeServicesConfiguration.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeServicesConfiguration.java index 8c4fdd95..cdf154b5 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeServicesConfiguration.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeServicesConfiguration.java @@ -1,20 +1,21 @@ package com.iexec.sms.api.config; import com.iexec.common.tee.TeeEnclaveProvider; +import lombok.AllArgsConstructor; import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +@NoArgsConstructor +@AllArgsConstructor @Getter +@Setter public abstract class TeeServicesConfiguration { + private TeeEnclaveProvider teeEnclaveProvider; + private TeeAppConfiguration preComputeConfiguration; + private TeeAppConfiguration postComputeConfiguration; - private final TeeEnclaveProvider teeEnclaveProvider; - private final TeeAppConfiguration preComputeConfiguration; - private final TeeAppConfiguration postComputeConfiguration; - - protected TeeServicesConfiguration(TeeEnclaveProvider teeEnclaveProvider, - TeeAppConfiguration preComputeConfiguration, - TeeAppConfiguration postComputeConfiguration) { + TeeServicesConfiguration(TeeEnclaveProvider teeEnclaveProvider) { this.teeEnclaveProvider = teeEnclaveProvider; - this.preComputeConfiguration = preComputeConfiguration; - this.postComputeConfiguration = postComputeConfiguration; } } diff --git a/src/main/java/com/iexec/sms/tee/TeeController.java b/src/main/java/com/iexec/sms/tee/TeeController.java index e7a249df..bd0e1af8 100644 --- a/src/main/java/com/iexec/sms/tee/TeeController.java +++ b/src/main/java/com/iexec/sms/tee/TeeController.java @@ -27,6 +27,7 @@ import com.iexec.sms.authorization.AuthorizationService; import com.iexec.sms.tee.challenge.TeeChallenge; import com.iexec.sms.tee.challenge.TeeChallengeService; +import com.iexec.sms.tee.config.TeeInternalServicesConfiguration; import com.iexec.sms.tee.session.TeeSessionService; import com.iexec.sms.tee.session.generic.TeeSessionGenerationException; import lombok.extern.slf4j.Slf4j; @@ -58,13 +59,13 @@ public class TeeController { private final AuthorizationService authorizationService; private final TeeChallengeService teeChallengeService; private final TeeSessionService teeSessionService; - private final TeeServicesConfiguration teeServicesConfig; + private final TeeInternalServicesConfiguration teeServicesConfig; public TeeController( AuthorizationService authorizationService, TeeChallengeService teeChallengeService, TeeSessionService teeSessionService, - TeeServicesConfiguration teeServicesConfig) { + TeeInternalServicesConfiguration teeServicesConfig) { this.authorizationService = authorizationService; this.teeChallengeService = teeChallengeService; this.teeSessionService = teeSessionService; @@ -87,7 +88,7 @@ public ResponseEntity getTeeServicesConfig( "[required: {}, actual: {}]", teeEnclaveProvider, teeServicesConfig.getTeeEnclaveProvider()); return ResponseEntity.status(HttpStatus.CONFLICT).build(); } - return ResponseEntity.ok(teeServicesConfig); + return ResponseEntity.ok(teeServicesConfig.getShareableConfiguration()); } /** diff --git a/src/main/java/com/iexec/sms/tee/config/GramineInternalServicesConfiguration.java b/src/main/java/com/iexec/sms/tee/config/GramineInternalServicesConfiguration.java index 0bcc0191..49c1f755 100644 --- a/src/main/java/com/iexec/sms/tee/config/GramineInternalServicesConfiguration.java +++ b/src/main/java/com/iexec/sms/tee/config/GramineInternalServicesConfiguration.java @@ -3,6 +3,7 @@ import com.iexec.common.tee.TeeEnclaveProvider; import com.iexec.sms.api.config.GramineServicesConfiguration; import com.iexec.sms.api.config.TeeAppConfiguration; +import com.iexec.sms.api.config.TeeServicesConfiguration; import com.iexec.sms.tee.EnableIfTeeProvider; import com.iexec.sms.tee.EnableIfTeeProviderDefinition; import lombok.Getter; @@ -13,10 +14,17 @@ @Conditional(EnableIfTeeProvider.class) @EnableIfTeeProviderDefinition(providers = TeeEnclaveProvider.GRAMINE) @Getter -public class GramineInternalServicesConfiguration extends GramineServicesConfiguration { +public class GramineInternalServicesConfiguration + extends GramineServicesConfiguration + implements TeeInternalServicesConfiguration { protected GramineInternalServicesConfiguration( TeeAppConfiguration preComputeConfiguration, TeeAppConfiguration postComputeConfiguration) { super(preComputeConfiguration, postComputeConfiguration); } + + @Override + public TeeServicesConfiguration getShareableConfiguration() { + return new GramineServicesConfiguration(getPreComputeConfiguration(), getPostComputeConfiguration()); + } } diff --git a/src/main/java/com/iexec/sms/tee/config/SconeInternalServicesConfiguration.java b/src/main/java/com/iexec/sms/tee/config/SconeInternalServicesConfiguration.java index 59aab60a..b963b418 100644 --- a/src/main/java/com/iexec/sms/tee/config/SconeInternalServicesConfiguration.java +++ b/src/main/java/com/iexec/sms/tee/config/SconeInternalServicesConfiguration.java @@ -3,6 +3,7 @@ import com.iexec.common.tee.TeeEnclaveProvider; import com.iexec.sms.api.config.SconeServicesConfiguration; import com.iexec.sms.api.config.TeeAppConfiguration; +import com.iexec.sms.api.config.TeeServicesConfiguration; import com.iexec.sms.tee.EnableIfTeeProvider; import com.iexec.sms.tee.EnableIfTeeProviderDefinition; import lombok.Getter; @@ -16,7 +17,9 @@ @Conditional(EnableIfTeeProvider.class) @EnableIfTeeProviderDefinition(providers = TeeEnclaveProvider.SCONE) @Getter -public class SconeInternalServicesConfiguration extends SconeServicesConfiguration { +public class SconeInternalServicesConfiguration + extends SconeServicesConfiguration + implements TeeInternalServicesConfiguration{ protected SconeInternalServicesConfiguration( TeeAppConfiguration preComputeConfiguration, TeeAppConfiguration postComputeConfiguration, @@ -25,4 +28,9 @@ protected SconeInternalServicesConfiguration( String lasImage) { super(preComputeConfiguration, postComputeConfiguration, lasImage); } + + @Override + public TeeServicesConfiguration getShareableConfiguration() { + return new SconeServicesConfiguration(getPreComputeConfiguration(), getPostComputeConfiguration(), getLasImage()); + } } diff --git a/src/main/java/com/iexec/sms/tee/config/TeeInternalServicesConfiguration.java b/src/main/java/com/iexec/sms/tee/config/TeeInternalServicesConfiguration.java new file mode 100644 index 00000000..35bb8702 --- /dev/null +++ b/src/main/java/com/iexec/sms/tee/config/TeeInternalServicesConfiguration.java @@ -0,0 +1,9 @@ +package com.iexec.sms.tee.config; + +import com.iexec.common.tee.TeeEnclaveProvider; +import com.iexec.sms.api.config.TeeServicesConfiguration; + +public interface TeeInternalServicesConfiguration { + TeeEnclaveProvider getTeeEnclaveProvider(); + TeeServicesConfiguration getShareableConfiguration(); +} From 83c55fcb7667590ffc30c2d252dea7e65523de02 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Thu, 1 Sep 2022 15:45:43 +0200 Subject: [PATCH 062/293] Fix `TeeAppConfiguration` heap size --- .../java/com/iexec/sms/api/config/TeeAppConfiguration.java | 2 +- .../sms/tee/config/SideComputeInternalConfiguration.java | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeAppConfiguration.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeAppConfiguration.java index 8aab15e7..1b9a3fac 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeAppConfiguration.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeAppConfiguration.java @@ -13,5 +13,5 @@ public class TeeAppConfiguration { private String image; private String fingerprint; private String entrypoint; - private long heapSize; + private long heapSize; // In GB } diff --git a/src/main/java/com/iexec/sms/tee/config/SideComputeInternalConfiguration.java b/src/main/java/com/iexec/sms/tee/config/SideComputeInternalConfiguration.java index bcdc7ef5..3edc5881 100644 --- a/src/main/java/com/iexec/sms/tee/config/SideComputeInternalConfiguration.java +++ b/src/main/java/com/iexec/sms/tee/config/SideComputeInternalConfiguration.java @@ -4,6 +4,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.util.unit.DataSize; import javax.validation.constraints.NotBlank; import javax.validation.constraints.Positive; @@ -28,7 +29,7 @@ TeeAppConfiguration preComputeConfiguration( preComputeImage, preComputeFingerprint, preComputeEntrypoint, - preComputeHeapSize + DataSize.ofGigabytes(preComputeHeapSize).toBytes() ); } @@ -50,7 +51,7 @@ TeeAppConfiguration postComputeConfiguration( postComputeImage, postComputeFingerprint, postComputeEntrypoint, - postComputeHeapSize + DataSize.ofGigabytes(postComputeHeapSize).toBytes() ); } From 36efa127a5918da35136c9be4e530a105e3b8bce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20James=20Toussaint?= Date: Thu, 1 Sep 2022 16:19:27 +0200 Subject: [PATCH 063/293] Scone regression testing --- .../tee/workflow/TeeWorkflowInternalConfiguration.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/iexec/sms/tee/workflow/TeeWorkflowInternalConfiguration.java b/src/main/java/com/iexec/sms/tee/workflow/TeeWorkflowInternalConfiguration.java index 0d520060..4cbf7773 100644 --- a/src/main/java/com/iexec/sms/tee/workflow/TeeWorkflowInternalConfiguration.java +++ b/src/main/java/com/iexec/sms/tee/workflow/TeeWorkflowInternalConfiguration.java @@ -21,6 +21,7 @@ import lombok.Getter; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; +import org.springframework.util.unit.DataSize; import javax.annotation.PostConstruct; import javax.validation.ConstraintViolationException; @@ -73,10 +74,14 @@ public TeeWorkflowInternalConfiguration( this.sharedConfig = TeeWorkflowConfiguration.builder() .lasImage(lasImage) .preComputeImage(preComputeImage) - .preComputeHeapSize(preComputeHeapSizeGb) + .preComputeHeapSize(DataSize + .ofGigabytes(preComputeHeapSizeGb) + .toBytes()) .preComputeEntrypoint(preComputeEntrypoint) .postComputeImage(postComputeImage) - .postComputeHeapSize(postComputeHeapSizeGb) + .postComputeHeapSize(DataSize + .ofGigabytes(postComputeHeapSizeGb) + .toBytes()) .postComputeEntrypoint(postComputeEntrypoint) .build(); this.validator = validator; From e8d0354d1b83e03fe42bcf935d3696eca01b11e6 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Fri, 2 Sep 2022 09:53:06 +0200 Subject: [PATCH 064/293] Add `EnableIfTeeProviderTests` --- .../sms/tee/EnableIfTeeProviderTests.java | 167 ++++++++++++++++++ 1 file changed, 167 insertions(+) create mode 100644 src/test/java/com/iexec/sms/tee/EnableIfTeeProviderTests.java diff --git a/src/test/java/com/iexec/sms/tee/EnableIfTeeProviderTests.java b/src/test/java/com/iexec/sms/tee/EnableIfTeeProviderTests.java new file mode 100644 index 00000000..2fe67c15 --- /dev/null +++ b/src/test/java/com/iexec/sms/tee/EnableIfTeeProviderTests.java @@ -0,0 +1,167 @@ +package com.iexec.sms.tee; + +import com.iexec.sms.tee.config.GramineInternalServicesConfiguration; +import com.iexec.sms.tee.config.SconeInternalServicesConfiguration; +import com.iexec.sms.tee.config.TeeInternalServicesConfiguration; +import com.iexec.sms.tee.session.generic.TeeSessionHandler; +import com.iexec.sms.tee.session.gramine.GramineSessionHandlerService; +import com.iexec.sms.tee.session.gramine.GramineSessionMakerService; +import com.iexec.sms.tee.session.gramine.sps.SpsConfiguration; +import com.iexec.sms.tee.session.scone.SconeSessionHandlerService; +import com.iexec.sms.tee.session.scone.SconeSessionMakerService; +import com.iexec.sms.tee.session.scone.SconeSessionSecurityConfig; +import com.iexec.sms.tee.session.scone.cas.CasClient; +import com.iexec.sms.tee.session.scone.cas.CasConfiguration; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.springframework.context.annotation.ConditionContext; +import org.springframework.core.env.Environment; +import org.springframework.core.type.AnnotationMetadata; + +import java.util.function.Function; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.when; + +class EnableIfTeeProviderTests { + @Mock + Environment environment; + @Mock + ConditionContext context; + @Mock + AnnotationMetadata metadata; + EnableIfTeeProvider condition = new EnableIfTeeProvider(); + + @BeforeEach + void init() { + MockitoAnnotations.openMocks(this); + } + + static Stream sconeBeansClasses() { + return Stream.of( + Arguments.of(SconeInternalServicesConfiguration.class), + Arguments.of(SconeSessionHandlerService.class), + Arguments.of(SconeSessionMakerService.class), + Arguments.of(SconeSessionSecurityConfig.class), + Arguments.of(CasClient.class), + Arguments.of(CasConfiguration.class) + ); + } + + static Stream gramineBeansClasses() { + return Stream.of( + Arguments.of(GramineInternalServicesConfiguration.class), + Arguments.of(GramineSessionHandlerService.class), + Arguments.of(GramineSessionMakerService.class), + Arguments.of(SpsConfiguration.class), + Arguments.of(GramineInternalServicesConfiguration.class) + ); + } + + static Stream sconeAndGramineBeansClasses() { + return Stream.of(sconeBeansClasses(), gramineBeansClasses()) + .flatMap(Function.identity()); + } + + static Stream nonAnnotatedClasses() { + return Stream.of( + Arguments.of(TeeInternalServicesConfiguration.class), + Arguments.of(TeeSessionHandler.class) + ); + } + + // region shouldMatch + @ParameterizedTest + @MethodSource("sconeBeansClasses") + void shouldMatchScone(Class clazz) { + when(context.getEnvironment()).thenReturn(environment); + when(environment.getActiveProfiles()).thenReturn(new String[]{"scone"}); + when(metadata.getClassName()).thenReturn(clazz.getName()); + + assertTrue(condition.matches(context, metadata)); + } + + @ParameterizedTest + @MethodSource("gramineBeansClasses") + void shouldMatchGramine(Class clazz) { + when(context.getEnvironment()).thenReturn(environment); + when(environment.getActiveProfiles()).thenReturn(new String[]{"gramine"}); + when(metadata.getClassName()).thenReturn(clazz.getName()); + + assertTrue(condition.matches(context, metadata)); + } + + @ParameterizedTest + @MethodSource("sconeAndGramineBeansClasses") + void shouldMatchSconeAndGramine(Class clazz) { + when(context.getEnvironment()).thenReturn(environment); + when(environment.getActiveProfiles()).thenReturn(new String[]{"scone", "gramine"}); + when(metadata.getClassName()).thenReturn(clazz.getName()); + + assertTrue(condition.matches(context, metadata)); + } + // endregion + + // region shouldNotMatch + @ParameterizedTest + @MethodSource("sconeBeansClasses") + void shouldNotMatchSconeSinceGramineProfile(Class clazz) { + when(context.getEnvironment()).thenReturn(environment); + when(environment.getActiveProfiles()).thenReturn(new String[]{"gramine"}); + when(metadata.getClassName()).thenReturn(clazz.getName()); + + assertFalse(condition.matches(context, metadata)); + } + + @ParameterizedTest + @MethodSource("gramineBeansClasses") + void shouldNotMatchGramineSinceSconeProfile(Class clazz) { + when(context.getEnvironment()).thenReturn(environment); + when(environment.getActiveProfiles()).thenReturn(new String[]{"scone"}); + when(metadata.getClassName()).thenReturn(clazz.getName()); + + assertFalse(condition.matches(context, metadata)); + } + + @ParameterizedTest + @MethodSource("gramineBeansClasses") + void shouldNotMatchAnySinceNoProfile(Class clazz) { + when(context.getEnvironment()).thenReturn(environment); + when(environment.getActiveProfiles()).thenReturn(new String[]{}); + when(metadata.getClassName()).thenReturn(clazz.getName()); + + assertFalse(condition.matches(context, metadata)); + } + + @ParameterizedTest + @MethodSource("nonAnnotatedClasses") + void shouldNotMatchAnySinceNoAnnotation(Class clazz) { + when(context.getEnvironment()).thenReturn(environment); + when(environment.getActiveProfiles()).thenReturn(new String[]{}); + when(metadata.getClassName()).thenReturn(clazz.getName()); + + assertFalse(condition.matches(context, metadata)); + } + + + @Test + void shouldNotMatchAnySinceClassDoesNotExist() { + final String className = "Not an existing class"; + + when(context.getEnvironment()).thenReturn(environment); + when(environment.getActiveProfiles()).thenReturn(new String[]{"scone", "gramine"}); + when(metadata.getClassName()).thenReturn(className); + + assertFalse(condition.matches(context, metadata)); + } + + + // endregion +} From c6390489b003c4c6fc7e5882441a57499b1c12ec Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Fri, 2 Sep 2022 10:05:56 +0200 Subject: [PATCH 065/293] Cover more cases in `EnableIfTeeProviderTests` --- .../com/iexec/sms/tee/EnableIfTeeProvider.java | 1 - .../sms/tee/EnableIfTeeProviderTests.java | 18 +++++++++++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/iexec/sms/tee/EnableIfTeeProvider.java b/src/main/java/com/iexec/sms/tee/EnableIfTeeProvider.java index 4de77fed..686d8846 100644 --- a/src/main/java/com/iexec/sms/tee/EnableIfTeeProvider.java +++ b/src/main/java/com/iexec/sms/tee/EnableIfTeeProvider.java @@ -6,7 +6,6 @@ import org.springframework.context.annotation.ConditionContext; import org.springframework.core.type.AnnotatedTypeMetadata; import org.springframework.core.type.AnnotationMetadata; -import org.springframework.core.type.StandardMethodMetadata; /** * Define a way to include beans only if a profile is enabled diff --git a/src/test/java/com/iexec/sms/tee/EnableIfTeeProviderTests.java b/src/test/java/com/iexec/sms/tee/EnableIfTeeProviderTests.java index 2fe67c15..e8e1075d 100644 --- a/src/test/java/com/iexec/sms/tee/EnableIfTeeProviderTests.java +++ b/src/test/java/com/iexec/sms/tee/EnableIfTeeProviderTests.java @@ -20,6 +20,7 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.springframework.context.annotation.ConditionContext; +import org.springframework.context.annotation.Conditional; import org.springframework.core.env.Environment; import org.springframework.core.type.AnnotationMetadata; @@ -31,6 +32,11 @@ import static org.mockito.Mockito.when; class EnableIfTeeProviderTests { + @Conditional(EnableIfTeeProvider.class) + @EnableIfTeeProviderDefinition(providers = {}) + static class NoProvidersSet { + + } @Mock Environment environment; @Mock @@ -131,7 +137,7 @@ void shouldNotMatchGramineSinceSconeProfile(Class clazz) { } @ParameterizedTest - @MethodSource("gramineBeansClasses") + @MethodSource("sconeAndGramineBeansClasses") void shouldNotMatchAnySinceNoProfile(Class clazz) { when(context.getEnvironment()).thenReturn(environment); when(environment.getActiveProfiles()).thenReturn(new String[]{}); @@ -150,6 +156,16 @@ void shouldNotMatchAnySinceNoAnnotation(Class clazz) { assertFalse(condition.matches(context, metadata)); } + @Test + void shouldNotMatchAnySinceNoProviderDefined() { + final Class clazz = NoProvidersSet.class; + + when(context.getEnvironment()).thenReturn(environment); + when(environment.getActiveProfiles()).thenReturn(new String[]{"scone", "gramine"}); + when(metadata.getClassName()).thenReturn(clazz.getName()); + + assertFalse(condition.matches(context, metadata)); + } @Test void shouldNotMatchAnySinceClassDoesNotExist() { From 65a11d748c056fc84984c089f393ce321a6ccb36 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Fri, 2 Sep 2022 10:22:01 +0200 Subject: [PATCH 066/293] Add tests for `TeeController` --- .../java/com/iexec/sms/api/SmsClient.java | 3 + .../java/com/iexec/sms/tee/TeeController.java | 9 ++ .../GramineInternalServicesConfiguration.java | 2 +- .../SconeInternalServicesConfiguration.java | 2 +- .../com/iexec/sms/tee/TeeControllerTests.java | 145 ++++++++++++++++++ 5 files changed, 159 insertions(+), 2 deletions(-) diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java index 3938194e..9e40e730 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java @@ -101,6 +101,9 @@ SmsSecretResponse getUnTeeSecrets( WorkerpoolAuthorization workerpoolAuthorization ); + @RequestLine("GET /tee/provider") + TeeEnclaveProvider getTeeEnclaveProvider(); + @RequestLine("GET /tee/config/scone") SconeServicesConfiguration getSconeServicesConfiguration(); diff --git a/src/main/java/com/iexec/sms/tee/TeeController.java b/src/main/java/com/iexec/sms/tee/TeeController.java index bd0e1af8..9a561c7c 100644 --- a/src/main/java/com/iexec/sms/tee/TeeController.java +++ b/src/main/java/com/iexec/sms/tee/TeeController.java @@ -72,6 +72,15 @@ public TeeController( this.teeServicesConfig = teeServicesConfig; } + /** + * Return which TEE enclave provider this SMS is configured to use. + * @return TEE enclave provider this SMS is configured to use. + */ + @GetMapping("/provider") + public ResponseEntity getTeeEnclaveProvider() { + return ResponseEntity.ok(teeServicesConfig.getTeeEnclaveProvider()); + } + /** * Retrieve configuration for TEE services. This includes configuration * for pre-compute and post-compute stages diff --git a/src/main/java/com/iexec/sms/tee/config/GramineInternalServicesConfiguration.java b/src/main/java/com/iexec/sms/tee/config/GramineInternalServicesConfiguration.java index 49c1f755..dd6e21d5 100644 --- a/src/main/java/com/iexec/sms/tee/config/GramineInternalServicesConfiguration.java +++ b/src/main/java/com/iexec/sms/tee/config/GramineInternalServicesConfiguration.java @@ -17,7 +17,7 @@ public class GramineInternalServicesConfiguration extends GramineServicesConfiguration implements TeeInternalServicesConfiguration { - protected GramineInternalServicesConfiguration( + public GramineInternalServicesConfiguration( TeeAppConfiguration preComputeConfiguration, TeeAppConfiguration postComputeConfiguration) { super(preComputeConfiguration, postComputeConfiguration); diff --git a/src/main/java/com/iexec/sms/tee/config/SconeInternalServicesConfiguration.java b/src/main/java/com/iexec/sms/tee/config/SconeInternalServicesConfiguration.java index b963b418..065c91b0 100644 --- a/src/main/java/com/iexec/sms/tee/config/SconeInternalServicesConfiguration.java +++ b/src/main/java/com/iexec/sms/tee/config/SconeInternalServicesConfiguration.java @@ -20,7 +20,7 @@ public class SconeInternalServicesConfiguration extends SconeServicesConfiguration implements TeeInternalServicesConfiguration{ - protected SconeInternalServicesConfiguration( + public SconeInternalServicesConfiguration( TeeAppConfiguration preComputeConfiguration, TeeAppConfiguration postComputeConfiguration, @Value("${tee.scone.las-image}") diff --git a/src/test/java/com/iexec/sms/tee/TeeControllerTests.java b/src/test/java/com/iexec/sms/tee/TeeControllerTests.java index 36a000cf..6c509fc2 100644 --- a/src/test/java/com/iexec/sms/tee/TeeControllerTests.java +++ b/src/test/java/com/iexec/sms/tee/TeeControllerTests.java @@ -1,13 +1,20 @@ package com.iexec.sms.tee; import com.iexec.common.chain.WorkerpoolAuthorization; +import com.iexec.common.tee.TeeEnclaveProvider; import com.iexec.common.web.ApiResponseBody; import com.iexec.sms.api.TeeSessionGenerationError; import com.iexec.sms.api.TeeSessionGenerationResponse; +import com.iexec.sms.api.config.GramineServicesConfiguration; +import com.iexec.sms.api.config.SconeServicesConfiguration; +import com.iexec.sms.api.config.TeeAppConfiguration; import com.iexec.sms.api.config.TeeServicesConfiguration; import com.iexec.sms.authorization.AuthorizationError; import com.iexec.sms.authorization.AuthorizationService; import com.iexec.sms.tee.challenge.TeeChallengeService; +import com.iexec.sms.tee.config.GramineInternalServicesConfiguration; +import com.iexec.sms.tee.config.SconeInternalServicesConfiguration; +import com.iexec.sms.tee.config.TeeInternalServicesConfiguration; import com.iexec.sms.tee.session.TeeSessionService; import com.iexec.sms.tee.session.generic.TeeSessionGenerationException; import org.junit.jupiter.api.BeforeEach; @@ -38,6 +45,8 @@ class TeeControllerTests { private final static String CHALLENGE = "CHALLENGE"; private final static String SESSION_ID = "SESSION_ID"; private static final String SECRET_PROVISIONING_URL = "https://secretProvisioningUrl"; + private static final String LAS_IMAGE = "lasImage"; + @Mock AuthorizationService authorizationService; @@ -48,6 +57,11 @@ class TeeControllerTests { @Mock TeeServicesConfiguration teeServicesConfig; + @Mock + TeeAppConfiguration preComputeConfig; + @Mock + TeeAppConfiguration postComputeConfig; + @InjectMocks TeeController teeController; @@ -56,6 +70,137 @@ void setUp() { MockitoAnnotations.openMocks(this); } + // region getTeeEnclaveProvider + @Test + void shouldGetSconeProvider() { + final TeeInternalServicesConfiguration config = new SconeInternalServicesConfiguration( + preComputeConfig, + postComputeConfig, + LAS_IMAGE + ); + + final TeeController teeController = new TeeController( + authorizationService, teeChallengeService, teeSessionService, config + ); + + final ResponseEntity response = + teeController.getTeeEnclaveProvider(); + + assertEquals(HttpStatus.OK, response.getStatusCode()); + + final TeeEnclaveProvider result = response.getBody(); + assertEquals(TeeEnclaveProvider.SCONE, result); + } + + @Test + void shouldGetGramineProvider() { + final TeeInternalServicesConfiguration config = new GramineInternalServicesConfiguration( + preComputeConfig, + postComputeConfig + ); + + final TeeController teeController = new TeeController( + authorizationService, teeChallengeService, teeSessionService, config + ); + + final ResponseEntity response = + teeController.getTeeEnclaveProvider(); + + assertEquals(HttpStatus.OK, response.getStatusCode()); + + final TeeEnclaveProvider result = response.getBody(); + assertEquals(TeeEnclaveProvider.GRAMINE, result); + } + // endregion + + // region getTeeServicesConfig + @Test + void shouldGetSconeConfig() { + final TeeInternalServicesConfiguration config = new SconeInternalServicesConfiguration( + preComputeConfig, + postComputeConfig, + LAS_IMAGE + ); + + final TeeController teeController = new TeeController( + authorizationService, teeChallengeService, teeSessionService, config + ); + + final ResponseEntity response = + teeController.getTeeServicesConfig(TeeEnclaveProvider.SCONE); + + assertEquals(HttpStatus.OK, response.getStatusCode()); + + final TeeServicesConfiguration result = response.getBody(); + assertNotNull(result); + assertInstanceOf(SconeServicesConfiguration.class, result); + assertEquals(TeeEnclaveProvider.SCONE, result.getTeeEnclaveProvider()); + assertEquals(preComputeConfig, result.getPreComputeConfiguration()); + assertEquals(postComputeConfig, result.getPostComputeConfiguration()); + assertEquals(postComputeConfig, result.getPostComputeConfiguration()); + assertEquals(LAS_IMAGE, ((SconeServicesConfiguration) result).getLasImage()); + } + + @Test + void shouldGetGramineConfig() { + final TeeInternalServicesConfiguration config = new GramineInternalServicesConfiguration( + preComputeConfig, + postComputeConfig + ); + + final TeeController teeController = new TeeController( + authorizationService, teeChallengeService, teeSessionService, config + ); + + final ResponseEntity response = + teeController.getTeeServicesConfig(TeeEnclaveProvider.GRAMINE); + + assertEquals(HttpStatus.OK, response.getStatusCode()); + + final TeeServicesConfiguration result = response.getBody(); + assertNotNull(result); + assertInstanceOf(GramineServicesConfiguration.class, result); + assertEquals(TeeEnclaveProvider.GRAMINE, result.getTeeEnclaveProvider()); + assertEquals(preComputeConfig, result.getPreComputeConfiguration()); + assertEquals(postComputeConfig, result.getPostComputeConfiguration()); + } + + @Test + void shouldNotGetSconeConfigSinceGramineSms() { + final TeeInternalServicesConfiguration config = new SconeInternalServicesConfiguration( + preComputeConfig, + postComputeConfig, + LAS_IMAGE + ); + + final TeeController teeController = new TeeController( + authorizationService, teeChallengeService, teeSessionService, config + ); + + final ResponseEntity response = + teeController.getTeeServicesConfig(TeeEnclaveProvider.GRAMINE); + + assertEquals(HttpStatus.CONFLICT, response.getStatusCode()); + } + + @Test + void shouldNotGetGramineConfigSinceSconeSms() { + final TeeInternalServicesConfiguration config = new GramineInternalServicesConfiguration( + preComputeConfig, + postComputeConfig + ); + + final TeeController teeController = new TeeController( + authorizationService, teeChallengeService, teeSessionService, config + ); + + final ResponseEntity response = + teeController.getTeeServicesConfig(TeeEnclaveProvider.SCONE); + + assertEquals(HttpStatus.CONFLICT, response.getStatusCode()); + } + // endregion + // region generateTeeSession @Test void shouldGenerateTeeSession() throws TeeSessionGenerationException { From b0ca9f97d733c7868d19f16dde8a705bd4eccc9e Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Fri, 2 Sep 2022 11:04:25 +0200 Subject: [PATCH 067/293] Add tests for `TeeEnclaveProviderConverter` and `SmsClientProviderTests` --- .../iexec/sms/api/SmsClientProviderTests.java | 9 ++++- .../tee/TeeEnclaveProviderConverterTests.java | 37 +++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 src/test/java/com/iexec/sms/tee/TeeEnclaveProviderConverterTests.java diff --git a/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientProviderTests.java b/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientProviderTests.java index 420451bc..0c948c60 100644 --- a/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientProviderTests.java +++ b/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientProviderTests.java @@ -35,7 +35,6 @@ class SmsClientProviderTests { .smsUrl(SMS_URL_2) .build(); - private static final String CHAIN_DEAL_ID_3 = "chainDealId3"; private static final String CHAIN_TASK_ID_3 = "chainTaskId3"; private static final ChainDeal CHAIN_DEAL_3 = ChainDeal.builder() .params(DealParams.builder().iexecSmsUrl(SMS_URL_1).build()) @@ -100,6 +99,14 @@ void shouldNotGetSmsClientForTaskDescriptionWhenNoSmsUrl() { () -> smsClientProvider.getOrCreateSmsClientForTask(taskDescription)); assertEquals("No SMS URL defined for given task [chainTaskId: " + CHAIN_TASK_ID_1 +"]", e.getMessage()); } + + @Test + void shouldNotGetSmsClientForTaskDescriptionWhenEmptySmsUrl() { + final TaskDescription taskDescription = TaskDescription.builder().chainTaskId(CHAIN_TASK_ID_1).smsUrl("").build(); + final SmsClientCreationException e = assertThrows(SmsClientCreationException.class, + () -> smsClientProvider.getOrCreateSmsClientForTask(taskDescription)); + assertEquals("No SMS URL defined for given task [chainTaskId: " + CHAIN_TASK_ID_1 + "]", e.getMessage()); + } // endregion // region getOrCreateSmsClientForUninitializedTask diff --git a/src/test/java/com/iexec/sms/tee/TeeEnclaveProviderConverterTests.java b/src/test/java/com/iexec/sms/tee/TeeEnclaveProviderConverterTests.java new file mode 100644 index 00000000..3c21e100 --- /dev/null +++ b/src/test/java/com/iexec/sms/tee/TeeEnclaveProviderConverterTests.java @@ -0,0 +1,37 @@ +package com.iexec.sms.tee; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import static com.iexec.common.tee.TeeEnclaveProvider.GRAMINE; +import static com.iexec.common.tee.TeeEnclaveProvider.SCONE; +import static org.junit.jupiter.api.Assertions.*; + +class TeeEnclaveProviderConverterTests { + private final TeeEnclaveProviderConverter converter = new TeeEnclaveProviderConverter(); + + // region convert + @Test + void shouldConvertScone() { + assertEquals(SCONE, converter.convert("scone")); + assertEquals(SCONE, converter.convert("Scone")); + assertEquals(SCONE, converter.convert("SCONE")); + assertEquals(SCONE, converter.convert("sCoNe")); + } + + @Test + void shouldConvertGramine() { + assertEquals(GRAMINE, converter.convert("gramine")); + assertEquals(GRAMINE, converter.convert("Gramine")); + assertEquals(GRAMINE, converter.convert("GRAMINE")); + assertEquals(GRAMINE, converter.convert("gRaMiNe")); + } + + @ParameterizedTest + @ValueSource(strings = {"", "azer"}) + void shouldNotConvertBadValue(String value) { + assertThrows(IllegalArgumentException.class, () -> converter.convert(value)); + } + // endregion +} From bb9c19276e2f66e69be873fa02c76c3ffefd0e29 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Fri, 2 Sep 2022 11:33:11 +0200 Subject: [PATCH 068/293] Add tests for `SmsClientTests` --- .../iexec/sms/api/SmsClientBuilderTests.java | 16 ++++ .../java/com/iexec/sms/api/SmsClientTest.java | 30 ------- .../com/iexec/sms/api/SmsClientTests.java | 86 +++++++++++++++++++ 3 files changed, 102 insertions(+), 30 deletions(-) create mode 100644 iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientBuilderTests.java delete mode 100644 iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientTest.java create mode 100644 iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientTests.java diff --git a/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientBuilderTests.java b/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientBuilderTests.java new file mode 100644 index 00000000..d0a2969f --- /dev/null +++ b/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientBuilderTests.java @@ -0,0 +1,16 @@ +package com.iexec.sms.api; + +import feign.Logger; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class SmsClientBuilderTests { + + // region getInstance + @Test + void instantiationTest() { + assertNotNull(SmsClientBuilder.getInstance(Logger.Level.FULL, "localhost")); + } + // endregion +} \ No newline at end of file diff --git a/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientTest.java b/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientTest.java deleted file mode 100644 index 3cd6a2e2..00000000 --- a/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientTest.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2022 IEXEC BLOCKCHAIN TECH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.iexec.sms.api; - -import feign.Logger; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -public class SmsClientTest { - - @Test - void instantiationTest() { - Assertions.assertNotNull(SmsClientBuilder.getInstance(Logger.Level.FULL, "localhost")); - } - -} diff --git a/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientTests.java b/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientTests.java new file mode 100644 index 00000000..3050f62a --- /dev/null +++ b/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientTests.java @@ -0,0 +1,86 @@ +/* + * Copyright 2022 IEXEC BLOCKCHAIN TECH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.iexec.sms.api; + +import com.iexec.common.tee.TeeEnclaveProvider; +import com.iexec.sms.api.config.GramineServicesConfiguration; +import com.iexec.sms.api.config.SconeServicesConfiguration; +import com.iexec.sms.api.config.TeeAppConfiguration; +import com.iexec.sms.api.config.TeeServicesConfiguration; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +class SmsClientTests { + private static final String LAS_IMAGE = "lasImage"; + + @Mock + TeeAppConfiguration preComputeConfig; + @Mock + TeeAppConfiguration postComputeConfig; + + // region getTeeServicesConfiguration + @Test + void shouldGetSconeServicesConfiguration() { + final SmsClient smsClient = spy(SmsClient.class); + final SconeServicesConfiguration config = new SconeServicesConfiguration( + preComputeConfig, + postComputeConfig, + LAS_IMAGE + ); + + when(smsClient.getSconeServicesConfiguration()).thenReturn(config); + + final TeeServicesConfiguration teeServicesConfiguration = + smsClient.getTeeServicesConfiguration(TeeEnclaveProvider.SCONE); + + assertEquals(config, teeServicesConfiguration); + } + + @Test + void shouldGetGramineServicesConfiguration() { + final SmsClient smsClient = spy(SmsClient.class); + final GramineServicesConfiguration config = new GramineServicesConfiguration( + preComputeConfig, + postComputeConfig + ); + + when(smsClient.getGramineServicesConfiguration()).thenReturn(config); + + final TeeServicesConfiguration teeServicesConfiguration = + smsClient.getTeeServicesConfiguration(TeeEnclaveProvider.GRAMINE); + + assertEquals(config, teeServicesConfiguration); + } + + @Test + void shouldNotGetTeeServicesConfigurationSinceUnknownProvider() { + final SmsClient smsClient = spy(SmsClient.class); + + when(smsClient.getGramineServicesConfiguration()).thenReturn(null); + + final TeeServicesConfiguration teeServicesConfiguration = + smsClient.getTeeServicesConfiguration(TeeEnclaveProvider.GRAMINE); + + assertNull(teeServicesConfiguration); + } + // endregion +} From 6b207e6f89d865c1580ceeb29e558446b370c8c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20James=20Toussaint?= Date: Fri, 2 Sep 2022 17:16:39 +0200 Subject: [PATCH 069/293] Add test on exposed heap size values --- ...TeeWorkflowInternalConfigurationTests.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src/test/java/com/iexec/sms/tee/workflow/TeeWorkflowInternalConfigurationTests.java diff --git a/src/test/java/com/iexec/sms/tee/workflow/TeeWorkflowInternalConfigurationTests.java b/src/test/java/com/iexec/sms/tee/workflow/TeeWorkflowInternalConfigurationTests.java new file mode 100644 index 00000000..4e27eb04 --- /dev/null +++ b/src/test/java/com/iexec/sms/tee/workflow/TeeWorkflowInternalConfigurationTests.java @@ -0,0 +1,20 @@ +package com.iexec.sms.tee.workflow; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; + +public class TeeWorkflowInternalConfigurationTests { + + @Test + void testGetSharedConfigWithHeapSizeValues() { + var teeWorkflowInternalConfiguration = new TeeWorkflowInternalConfiguration( + "lasImage", "preImage", + "preFingerprint", "preEntrypoint", 1, "postImage", + "postFingerprint", "postEntrypoint", 2, null); + Assertions.assertThat(teeWorkflowInternalConfiguration.getSharedConfig() + .getPreComputeHeapSize()).isEqualTo(1073741824L); + Assertions.assertThat(teeWorkflowInternalConfiguration.getSharedConfig() + .getPostComputeHeapSize()).isEqualTo(2147483648L); + } + +} From 6e9212a53734931cd4de4e1a7365dd8079c33535 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Mon, 5 Sep 2022 10:29:00 +0200 Subject: [PATCH 070/293] Purge maps storing task after completion or failure --- .../com/iexec/sms/api/SmsClientProvider.java | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java index a83a3859..c9a8d1c2 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java @@ -2,6 +2,7 @@ import com.iexec.common.chain.ChainDeal; import com.iexec.common.task.TaskDescription; +import com.iexec.common.utils.purge.Purgeable; import feign.Logger; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; @@ -15,8 +16,7 @@ * and avoiding the need to create a new {@link SmsClient} instance each time. */ @Slf4j -public class SmsClientProvider { - // TODO: purge once task has been completed +public class SmsClientProvider implements Purgeable { private final Map> taskIdToSmsUrl = new HashMap<>(); private final Map urlToSmsClient = new HashMap<>(); @@ -81,4 +81,17 @@ public SmsClient getOrCreateSmsClientForUninitializedTask(ChainDeal deal, String return urlToSmsClient.computeIfAbsent(smsUrl.get(), url -> SmsClientBuilder.getInstance(loggerLevel, url)); } + + @Override + public boolean purgeTask(String chainTaskId) { + // Returning `taskIdToSmsUrl.remove(chainTaskId) != null` throws a warning: + // don't compare an `Optional` with null. + // So let's use a longer form. + + if (!taskIdToSmsUrl.containsKey(chainTaskId)) { + return false; + } + taskIdToSmsUrl.remove(chainTaskId); + return true; + } } From 86b80df08b93bee82345549429135a52d85289fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20James=20Toussaint?= Date: Mon, 5 Sep 2022 10:52:00 +0200 Subject: [PATCH 071/293] Remove useless public visibility in test class --- .../sms/tee/workflow/TeeWorkflowInternalConfigurationTests.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/iexec/sms/tee/workflow/TeeWorkflowInternalConfigurationTests.java b/src/test/java/com/iexec/sms/tee/workflow/TeeWorkflowInternalConfigurationTests.java index 4e27eb04..b96ff3ea 100644 --- a/src/test/java/com/iexec/sms/tee/workflow/TeeWorkflowInternalConfigurationTests.java +++ b/src/test/java/com/iexec/sms/tee/workflow/TeeWorkflowInternalConfigurationTests.java @@ -3,7 +3,7 @@ import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; -public class TeeWorkflowInternalConfigurationTests { +class TeeWorkflowInternalConfigurationTests { @Test void testGetSharedConfigWithHeapSizeValues() { From 816fc3e0bc6adef778567129d8f769898026b2af Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Mon, 5 Sep 2022 15:46:58 +0200 Subject: [PATCH 072/293] Reformat `GramineServicesConfiguration` --- .../com/iexec/sms/api/config/GramineServicesConfiguration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/GramineServicesConfiguration.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/GramineServicesConfiguration.java index b428142e..404f124f 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/GramineServicesConfiguration.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/GramineServicesConfiguration.java @@ -13,7 +13,7 @@ public GramineServicesConfiguration() { } public GramineServicesConfiguration(TeeAppConfiguration preComputeConfiguration, - TeeAppConfiguration postComputeConfiguration) { + TeeAppConfiguration postComputeConfiguration) { super(TeeEnclaveProvider.GRAMINE, preComputeConfiguration, postComputeConfiguration); } } From e3f9605e7b592b75f894132dace04a40356f3ff8 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Mon, 5 Sep 2022 15:53:57 +0200 Subject: [PATCH 073/293] Rename `TeeAppConfiguration#heapSize` into `heapSizeInBytes` --- .../com/iexec/sms/api/config/TeeAppConfiguration.java | 5 ++++- .../sms/tee/config/SideComputeInternalConfiguration.java | 8 ++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeAppConfiguration.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeAppConfiguration.java index 1b9a3fac..ac1e4117 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeAppConfiguration.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeAppConfiguration.java @@ -13,5 +13,8 @@ public class TeeAppConfiguration { private String image; private String fingerprint; private String entrypoint; - private long heapSize; // In GB + /** + * Represents the app heap size, in bytes. + */ + private long heapSizeInBytes; } diff --git a/src/main/java/com/iexec/sms/tee/config/SideComputeInternalConfiguration.java b/src/main/java/com/iexec/sms/tee/config/SideComputeInternalConfiguration.java index 3edc5881..de84c98b 100644 --- a/src/main/java/com/iexec/sms/tee/config/SideComputeInternalConfiguration.java +++ b/src/main/java/com/iexec/sms/tee/config/SideComputeInternalConfiguration.java @@ -24,12 +24,12 @@ TeeAppConfiguration preComputeConfiguration( String preComputeEntrypoint, @Value("${tee.workflow.pre-compute.heap-size-gb}") @Positive(message = "pre-compute heap size must be provided") - long preComputeHeapSize) { + long preComputeHeapSizeInGB) { return new TeeAppConfiguration( preComputeImage, preComputeFingerprint, preComputeEntrypoint, - DataSize.ofGigabytes(preComputeHeapSize).toBytes() + DataSize.ofGigabytes(preComputeHeapSizeInGB).toBytes() ); } @@ -46,12 +46,12 @@ TeeAppConfiguration postComputeConfiguration( String postComputeEntrypoint, @Value("${tee.workflow.post-compute.heap-size-gb}") @Positive(message = "post-compute heap size must be provided") - long postComputeHeapSize) { + long postComputeHeapSizeInGB) { return new TeeAppConfiguration( postComputeImage, postComputeFingerprint, postComputeEntrypoint, - DataSize.ofGigabytes(postComputeHeapSize).toBytes() + DataSize.ofGigabytes(postComputeHeapSizeInGB).toBytes() ); } From 7a1c5d207d00be368a83c878dbef9e67a83b20af Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Mon, 5 Sep 2022 16:23:10 +0200 Subject: [PATCH 074/293] Reorder `SmsClient` methods --- .../main/java/com/iexec/sms/api/SmsClient.java | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java index 9e40e730..8f8e813c 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java @@ -37,6 +37,7 @@ */ public interface SmsClient { + // region Secrets @RequestLine("POST /apps/{appAddress}/secrets/1") @Headers("Authorization: {authorization}") ApiResponseBody> addAppDeveloperAppComputeSecret( @@ -84,19 +85,21 @@ String setWeb3Secret( String secretValue ); - @RequestLine("POST /tee/challenges/{chainTaskId}") - String generateTeeChallenge(@Param("chainTaskId") String chainTaskId); - - @RequestLine("POST /tee/sessions") + @RequestLine("POST /untee/secrets") @Headers("Authorization: {authorization}") - ApiResponseBody generateTeeSession( + SmsSecretResponse getUnTeeSecrets( @Param("authorization") String authorization, WorkerpoolAuthorization workerpoolAuthorization ); + // endregion - @RequestLine("POST /untee/secrets") + // region TEE + @RequestLine("POST /tee/challenges/{chainTaskId}") + String generateTeeChallenge(@Param("chainTaskId") String chainTaskId); + + @RequestLine("POST /tee/sessions") @Headers("Authorization: {authorization}") - SmsSecretResponse getUnTeeSecrets( + ApiResponseBody generateTeeSession( @Param("authorization") String authorization, WorkerpoolAuthorization workerpoolAuthorization ); @@ -119,4 +122,5 @@ default T getTeeServicesConfiguration(TeeEn return null; } + // endregion } From 40876587f75a9032d7707dcf9cfb28406f0968f7 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Mon, 5 Sep 2022 16:37:47 +0200 Subject: [PATCH 075/293] Remove empty line --- src/test/java/com/iexec/sms/tee/EnableIfTeeProviderTests.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/test/java/com/iexec/sms/tee/EnableIfTeeProviderTests.java b/src/test/java/com/iexec/sms/tee/EnableIfTeeProviderTests.java index e8e1075d..a883ae11 100644 --- a/src/test/java/com/iexec/sms/tee/EnableIfTeeProviderTests.java +++ b/src/test/java/com/iexec/sms/tee/EnableIfTeeProviderTests.java @@ -34,9 +34,8 @@ class EnableIfTeeProviderTests { @Conditional(EnableIfTeeProvider.class) @EnableIfTeeProviderDefinition(providers = {}) - static class NoProvidersSet { + static class NoProvidersSet {} - } @Mock Environment environment; @Mock From 81514e02980a0a69a9d9973cafdf35ae78807cae Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Tue, 6 Sep 2022 08:50:48 +0200 Subject: [PATCH 076/293] Add missing web2/web3 endpoints in iexec-sms-library --- .../java/com/iexec/sms/api/SmsClient.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java index d4c8f147..e6f3f294 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java @@ -67,6 +67,12 @@ ApiResponseBody> isRequesterAppComputeSecretPresent( @Param("secretKey") String secretKey ); + @RequestLine("HEAD /secrets/web2?ownerAddress={ownerAddress}&secretName={secretName}") + void isWeb2SecretSet( + @Param("ownerAddress") String ownerAddress, + @Param("secretName") String secretName + ); + @RequestLine("POST /secrets/web2?ownerAddress={ownerAddress}&secretName={secretName}") @Headers("Authorization: {authorization}") String setWeb2Secret( @@ -76,6 +82,20 @@ String setWeb2Secret( String secretValue ); + @RequestLine("PUT /secrets/web2?ownerAddress={ownerAddress}&secretName={secretName}") + @Headers("Authorization: {authorization}") + String updateWeb2Secret( + @Param("authorization") String authorization, + @Param("ownerAddress") String ownerAddress, + @Param("secretName") String secretName, + String secretValue + ); + + @RequestLine("HEAD /secrets/web3?secretAddress={secretAddress}") + void isWeb3SecretSet( + @Param("secretAddress") String secretAddress + ); + @RequestLine("POST /secrets/web3?secretAddress={secretAddress}") @Headers("Authorization: {authorization}") String setWeb3Secret( From 285cd5b3fb2984b7a1f2463a60e8113c73ec27dd Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Tue, 6 Sep 2022 08:52:56 +0200 Subject: [PATCH 077/293] Remove signature endpoint from SecretController --- .../com/iexec/sms/secret/SecretController.java | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/src/main/java/com/iexec/sms/secret/SecretController.java b/src/main/java/com/iexec/sms/secret/SecretController.java index f61af5b0..15a8226d 100644 --- a/src/main/java/com/iexec/sms/secret/SecretController.java +++ b/src/main/java/com/iexec/sms/secret/SecretController.java @@ -17,7 +17,6 @@ package com.iexec.sms.secret; -import com.iexec.common.security.Signature; import com.iexec.sms.authorization.AuthorizationService; import com.iexec.sms.secret.web2.Web2SecretsService; import com.iexec.sms.secret.web3.Web3Secret; @@ -29,8 +28,6 @@ import java.util.Optional; -import static com.iexec.common.utils.SignatureUtils.signMessageHashAndGetSignature; - @Slf4j @CrossOrigin @RestController @@ -165,19 +162,5 @@ public ResponseEntity updateWeb2Secret(@RequestHeader("Authorization") S return ResponseEntity.noContent().build(); } - /* - * Server-side signature of a messageHash - * */ - @PostMapping("/delegate/signature") - public ResponseEntity signMessageHashOnServerSide(@RequestParam String messageHash, - @RequestBody String privateKey) { - Signature signature = signMessageHashAndGetSignature(messageHash, privateKey); - - if (signature.getValue() == null || signature.getValue().isEmpty()) { - return ResponseEntity.notFound().build(); - } - - return ResponseEntity.ok(signature.getValue()); - } } From c84ef7a1b5c9596f4daf4e5495e8d4863fccb4c2 Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Tue, 6 Sep 2022 08:56:43 +0200 Subject: [PATCH 078/293] Update method signatures in SecretController --- .../com/iexec/sms/secret/SecretController.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/iexec/sms/secret/SecretController.java b/src/main/java/com/iexec/sms/secret/SecretController.java index 15a8226d..51f4ab10 100644 --- a/src/main/java/com/iexec/sms/secret/SecretController.java +++ b/src/main/java/com/iexec/sms/secret/SecretController.java @@ -49,13 +49,13 @@ public SecretController(AuthorizationService authorizationService, // Web3 @RequestMapping(path = "/web3", method = RequestMethod.HEAD) - public ResponseEntity isWeb3SecretSet(@RequestParam String secretAddress) { + public ResponseEntity isWeb3SecretSet(@RequestParam String secretAddress) { Optional secret = web3SecretService.getSecret(secretAddress); return secret.map(body -> ResponseEntity.noContent().build()).orElseGet(() -> ResponseEntity.notFound().build()); } @GetMapping("/web3") - public ResponseEntity getWeb3Secret(@RequestHeader("Authorization") String authorization, + public ResponseEntity getWeb3Secret(@RequestHeader String authorization, @RequestParam String secretAddress, @RequestParam(required = false, defaultValue = "false") boolean shouldDecryptSecret) { String challenge = authorizationService.getChallengeForGetWeb3Secret(secretAddress); @@ -71,7 +71,7 @@ public ResponseEntity getWeb3Secret(@RequestHeader("Authorization") } @PostMapping("/web3") - public ResponseEntity addWeb3Secret(@RequestHeader("Authorization") String authorization, + public ResponseEntity addWeb3Secret(@RequestHeader String authorization, @RequestParam String secretAddress, @RequestBody String secretValue) { if (!SecretUtils.isSecretSizeValid(secretValue)) { @@ -96,14 +96,14 @@ public ResponseEntity addWeb3Secret(@RequestHeader("Authorization") Stri // Web2 @RequestMapping(path = "/web2", method = RequestMethod.HEAD) - public ResponseEntity isWeb2SecretSet(@RequestParam String ownerAddress, - @RequestParam String secretName) { + public ResponseEntity isWeb2SecretSet(@RequestParam String ownerAddress, + @RequestParam String secretName) { Optional secret = web2SecretsService.getSecret(ownerAddress, secretName, false); return secret.map(body -> ResponseEntity.noContent().build()).orElseGet(() -> ResponseEntity.notFound().build()); } @GetMapping("/web2") - public ResponseEntity getWeb2Secret(@RequestHeader("Authorization") String authorization, + public ResponseEntity getWeb2Secret(@RequestHeader String authorization, @RequestParam String ownerAddress, @RequestParam String secretName, @RequestParam(required = false, defaultValue = "false") boolean shouldDecryptSecret) { @@ -119,7 +119,7 @@ public ResponseEntity getWeb2Secret(@RequestHeader("Authorization") Stri } @PostMapping("/web2") - public ResponseEntity addWeb2Secret(@RequestHeader("Authorization") String authorization, + public ResponseEntity addWeb2Secret(@RequestHeader String authorization, @RequestParam String ownerAddress, @RequestParam String secretName, @RequestBody String secretValue) { @@ -143,7 +143,7 @@ public ResponseEntity addWeb2Secret(@RequestHeader("Authorization") Stri } @PutMapping("/web2") - public ResponseEntity updateWeb2Secret(@RequestHeader("Authorization") String authorization, + public ResponseEntity updateWeb2Secret(@RequestHeader String authorization, @RequestParam String ownerAddress, @RequestParam String secretName, @RequestBody String newSecretValue) { From 57709771f53bd012f8ef923a45955832d8c56315 Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Tue, 6 Sep 2022 09:10:07 +0200 Subject: [PATCH 079/293] Fix return statements in methods checking web2/web3 secrets existence --- src/main/java/com/iexec/sms/secret/SecretController.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/iexec/sms/secret/SecretController.java b/src/main/java/com/iexec/sms/secret/SecretController.java index 51f4ab10..4348e356 100644 --- a/src/main/java/com/iexec/sms/secret/SecretController.java +++ b/src/main/java/com/iexec/sms/secret/SecretController.java @@ -51,7 +51,7 @@ public SecretController(AuthorizationService authorizationService, @RequestMapping(path = "/web3", method = RequestMethod.HEAD) public ResponseEntity isWeb3SecretSet(@RequestParam String secretAddress) { Optional secret = web3SecretService.getSecret(secretAddress); - return secret.map(body -> ResponseEntity.noContent().build()).orElseGet(() -> ResponseEntity.notFound().build()); + return secret.isPresent() ? ResponseEntity.noContent().build() : ResponseEntity.notFound().build(); } @GetMapping("/web3") @@ -99,7 +99,7 @@ public ResponseEntity addWeb3Secret(@RequestHeader String authorization, public ResponseEntity isWeb2SecretSet(@RequestParam String ownerAddress, @RequestParam String secretName) { Optional secret = web2SecretsService.getSecret(ownerAddress, secretName, false); - return secret.map(body -> ResponseEntity.noContent().build()).orElseGet(() -> ResponseEntity.notFound().build()); + return secret.isPresent() ? ResponseEntity.noContent().build() : ResponseEntity.notFound().build(); } @GetMapping("/web2") From 7c3d3e1f49df037c41303b5aef48b13dc4418a64 Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Tue, 6 Sep 2022 09:11:35 +0200 Subject: [PATCH 080/293] Check web2 secret size is valid when updating its value --- src/main/java/com/iexec/sms/secret/SecretController.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/com/iexec/sms/secret/SecretController.java b/src/main/java/com/iexec/sms/secret/SecretController.java index 4348e356..24f642d8 100644 --- a/src/main/java/com/iexec/sms/secret/SecretController.java +++ b/src/main/java/com/iexec/sms/secret/SecretController.java @@ -147,6 +147,10 @@ public ResponseEntity updateWeb2Secret(@RequestHeader String authorizati @RequestParam String ownerAddress, @RequestParam String secretName, @RequestBody String newSecretValue) { + if (!SecretUtils.isSecretSizeValid(newSecretValue)) { + return ResponseEntity.status(HttpStatus.PAYLOAD_TOO_LARGE).build(); + } + String challenge = authorizationService.getChallengeForSetWeb2Secret(ownerAddress, secretName, newSecretValue); if (!authorizationService.isSignedByHimself(challenge, authorization, ownerAddress)) { From e9f6b7921b9d18204a10ce718fa11b08457a95a2 Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Tue, 6 Sep 2022 09:14:39 +0200 Subject: [PATCH 081/293] Use ReponseEntity#of when possible in SecretController --- src/main/java/com/iexec/sms/secret/SecretController.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/iexec/sms/secret/SecretController.java b/src/main/java/com/iexec/sms/secret/SecretController.java index 24f642d8..37f129f9 100644 --- a/src/main/java/com/iexec/sms/secret/SecretController.java +++ b/src/main/java/com/iexec/sms/secret/SecretController.java @@ -67,7 +67,7 @@ public ResponseEntity getWeb3Secret(@RequestHeader String authorizat } Optional secret = web3SecretService.getSecret(secretAddress, shouldDecryptSecret); - return secret.map(ResponseEntity::ok).orElseGet(() -> ResponseEntity.notFound().build()); + return ResponseEntity.of(secret); } @PostMapping("/web3") @@ -115,7 +115,7 @@ public ResponseEntity getWeb2Secret(@RequestHeader String authorization, } Optional secret = web2SecretsService.getSecret(ownerAddress, secretName, shouldDecryptSecret); - return secret.map(ResponseEntity::ok).orElseGet(() -> ResponseEntity.notFound().build()); + return ResponseEntity.of(secret); } @PostMapping("/web2") From 9655fa78de0ef4f15c0045b4a4e4747780b694e4 Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Tue, 6 Sep 2022 09:19:24 +0200 Subject: [PATCH 082/293] Rework web2 secret update to read database once and remove Optional#get warnings --- .../iexec/sms/secret/SecretController.java | 11 ++++---- .../iexec/sms/secret/web2/Web2Secrets.java | 12 ++++---- .../sms/secret/web2/Web2SecretsService.java | 28 ++++++------------- .../secret/web2/Web2SecretsServiceTests.java | 1 + 4 files changed, 20 insertions(+), 32 deletions(-) diff --git a/src/main/java/com/iexec/sms/secret/SecretController.java b/src/main/java/com/iexec/sms/secret/SecretController.java index 37f129f9..44153379 100644 --- a/src/main/java/com/iexec/sms/secret/SecretController.java +++ b/src/main/java/com/iexec/sms/secret/SecretController.java @@ -26,6 +26,7 @@ import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; +import java.util.NoSuchElementException; import java.util.Optional; @Slf4j @@ -98,7 +99,7 @@ public ResponseEntity addWeb3Secret(@RequestHeader String authorization, @RequestMapping(path = "/web2", method = RequestMethod.HEAD) public ResponseEntity isWeb2SecretSet(@RequestParam String ownerAddress, @RequestParam String secretName) { - Optional secret = web2SecretsService.getSecret(ownerAddress, secretName, false); + Optional secret = web2SecretsService.getSecret(ownerAddress, secretName); return secret.isPresent() ? ResponseEntity.noContent().build() : ResponseEntity.notFound().build(); } @@ -158,12 +159,12 @@ public ResponseEntity updateWeb2Secret(@RequestHeader String authorizati return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build(); } - if (web2SecretsService.getSecret(ownerAddress, secretName).isEmpty()) { + try { + web2SecretsService.updateSecret(ownerAddress, secretName, newSecretValue); + return ResponseEntity.noContent().build(); + } catch (NoSuchElementException e) { return ResponseEntity.notFound().build(); } - - web2SecretsService.updateSecret(ownerAddress, secretName, newSecretValue); - return ResponseEntity.noContent().build(); } } diff --git a/src/main/java/com/iexec/sms/secret/web2/Web2Secrets.java b/src/main/java/com/iexec/sms/secret/web2/Web2Secrets.java index dccdebd9..e884d0fb 100644 --- a/src/main/java/com/iexec/sms/secret/web2/Web2Secrets.java +++ b/src/main/java/com/iexec/sms/secret/web2/Web2Secrets.java @@ -25,6 +25,7 @@ import javax.persistence.*; import java.util.ArrayList; import java.util.List; +import java.util.Optional; @Data @Getter @@ -46,12 +47,9 @@ public class Web2Secrets { this.secrets = new ArrayList<>(); } - public Secret getSecret(String secretAddress) { - for (Secret secret : secrets) { - if (secret.getAddress().equals(secretAddress)) { - return secret; - } - } - return null; + public Optional getSecret(String secretAddress) { + return secrets.stream() + .filter(secret -> secret.getAddress().equals(secretAddress)) + .findFirst(); } } diff --git a/src/main/java/com/iexec/sms/secret/web2/Web2SecretsService.java b/src/main/java/com/iexec/sms/secret/web2/Web2SecretsService.java index 4122451f..baffb935 100644 --- a/src/main/java/com/iexec/sms/secret/web2/Web2SecretsService.java +++ b/src/main/java/com/iexec/sms/secret/web2/Web2SecretsService.java @@ -48,27 +48,15 @@ public Optional getSecret(String ownerAddress, String secretAddress) { public Optional getSecret(String ownerAddress, String secretAddress, boolean shouldDecryptValue) { ownerAddress = ownerAddress.toLowerCase(); - Optional web2Secrets = getWeb2Secrets(ownerAddress); - if (web2Secrets.isEmpty()) { - return Optional.empty(); - } - Secret secret = web2Secrets.get().getSecret(secretAddress); - if (secret == null) { - return Optional.empty(); - } - if (shouldDecryptValue) { - decryptSecret(secret); - } - return Optional.of(secret); + Optional oSecret = getWeb2Secrets(ownerAddress) + .flatMap(web2Secrets -> web2Secrets.getSecret(secretAddress)); + return shouldDecryptValue ? oSecret.map(this::decryptSecret) : oSecret; } public void addSecret(String ownerAddress, String secretAddress, String secretValue) { ownerAddress = ownerAddress.toLowerCase(); - Web2Secrets web2Secrets = new Web2Secrets(ownerAddress); - Optional existingWeb2Secrets = getWeb2Secrets(ownerAddress); - if (existingWeb2Secrets.isPresent()) { - web2Secrets = existingWeb2Secrets.get(); - } + Web2Secrets web2Secrets = getWeb2Secrets(ownerAddress) + .orElse(new Web2Secrets(ownerAddress)); Secret secret = new Secret(secretAddress, secretValue); encryptSecret(secret); @@ -82,8 +70,8 @@ public void updateSecret(String ownerAddress, String secretAddress, String newSe ownerAddress = ownerAddress.toLowerCase(); Secret newSecret = new Secret(secretAddress, newSecretValue); encryptSecret(newSecret); - Optional web2Secrets = getWeb2Secrets(ownerAddress); - Secret existingSecret = web2Secrets.get().getSecret(secretAddress); + Web2Secrets web2Secrets = getWeb2Secrets(ownerAddress).orElseThrow(); + Secret existingSecret = web2Secrets.getSecret(secretAddress).orElseThrow(); if (existingSecret.getValue().equals(newSecret.getValue())) { log.info("No need to update secret [ownerAddress:{}, secretAddress:{}]", ownerAddress, secretAddress); @@ -93,6 +81,6 @@ public void updateSecret(String ownerAddress, String secretAddress, String newSe log.info("Updating secret [ownerAddress:{}, secretAddress:{}, oldEncryptedSecretValue:{}, newEncryptedSecretValue:{}]", ownerAddress, secretAddress, existingSecret.getValue(), newSecret.getValue()); existingSecret.setValue(newSecret.getValue(), true); - web2SecretsRepository.save(web2Secrets.get()); + web2SecretsRepository.save(web2Secrets); } } diff --git a/src/test/java/com/iexec/sms/secret/web2/Web2SecretsServiceTests.java b/src/test/java/com/iexec/sms/secret/web2/Web2SecretsServiceTests.java index 1d17bec1..a2dfc280 100644 --- a/src/test/java/com/iexec/sms/secret/web2/Web2SecretsServiceTests.java +++ b/src/test/java/com/iexec/sms/secret/web2/Web2SecretsServiceTests.java @@ -65,6 +65,7 @@ void shouldGetAndDecryptWeb2Secrets() { .thenReturn(plainSecretValue); Optional result = web2SecretsService.getSecret(ownerAddress, secretAddress, true); + assertThat(result).isNotEmpty(); assertThat(result.get().getAddress()).isEqualTo(secretAddress); assertThat(result.get().getValue()).isEqualTo(plainSecretValue); } From e44918eb116c74c56118d864652e4b0637b4b70a Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Tue, 6 Sep 2022 09:20:07 +0200 Subject: [PATCH 083/293] Set AbstractSecretService constructor visibility to protected --- src/main/java/com/iexec/sms/secret/AbstractSecretService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/iexec/sms/secret/AbstractSecretService.java b/src/main/java/com/iexec/sms/secret/AbstractSecretService.java index 2a1271ee..48978428 100644 --- a/src/main/java/com/iexec/sms/secret/AbstractSecretService.java +++ b/src/main/java/com/iexec/sms/secret/AbstractSecretService.java @@ -22,7 +22,7 @@ public abstract class AbstractSecretService { private final EncryptionService encryptionService; - public AbstractSecretService(EncryptionService encryptionService) { + protected AbstractSecretService(EncryptionService encryptionService) { this.encryptionService = encryptionService; } From af8c7128d98459d924c14ef8d3e85dd7cc3a0702 Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Tue, 6 Sep 2022 09:36:08 +0200 Subject: [PATCH 084/293] Add SecretController tests --- .../sms/secret/SecretControllerTests.java | 318 ++++++++++++++++++ 1 file changed, 318 insertions(+) create mode 100644 src/test/java/com/iexec/sms/secret/SecretControllerTests.java diff --git a/src/test/java/com/iexec/sms/secret/SecretControllerTests.java b/src/test/java/com/iexec/sms/secret/SecretControllerTests.java new file mode 100644 index 00000000..2ee6b09d --- /dev/null +++ b/src/test/java/com/iexec/sms/secret/SecretControllerTests.java @@ -0,0 +1,318 @@ +/* + * Copyright 2022 IEXEC BLOCKCHAIN TECH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.iexec.sms.secret; + +import com.iexec.sms.authorization.AuthorizationService; +import com.iexec.sms.secret.web2.Web2SecretsService; +import com.iexec.sms.secret.web3.Web3Secret; +import com.iexec.sms.secret.web3.Web3SecretService; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; + +import java.nio.charset.StandardCharsets; +import java.security.SecureRandom; +import java.util.NoSuchElementException; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.*; + +class SecretControllerTests { + + private static final String AUTHORIZATION = "AUTHORIZATION"; + private static final String CHALLENGE = "CHALLENGE"; + private static final String WEB2_OWNER_ADDRESS = "WEB2_OWNER_ADDRESS"; + private static final String WEB2_SECRET_NAME = "WEB2_SECRET_NAME"; + private static final String WEB2_SECRET_VALUE = "WEB2_SECRET_VALUE"; + private static final String WEB3_SECRET_ADDRESS = "WEB3_SECRET_ADDRESS"; + private static final String WEB3_SECRET_VALUE = "WEB3_SECRET_VALUE"; + + @Mock + private AuthorizationService authorizationService; + + @Mock + private Web2SecretsService web2SecretsService; + + @Mock + private Web3SecretService web3SecretService; + + @InjectMocks + private SecretController secretController; + + private static final SecureRandom seed = new SecureRandom(); + + @BeforeEach + public void init() { + MockitoAnnotations.openMocks(this); + } + + //region isWeb3SecretSet + @Test + void shouldReturnNoContentWhenWeb3SecretExists() { + when(web3SecretService.getSecret(WEB3_SECRET_ADDRESS)) + .thenReturn(Optional.of(new Web3Secret())); + assertThat(secretController.isWeb3SecretSet(WEB3_SECRET_ADDRESS)) + .isEqualTo(ResponseEntity.noContent().build()); + verifyNoInteractions(authorizationService, web2SecretsService); + } + + @Test + void shouldReturnNotFoundWhenWeb3SecretDoesNotExist() { + when(web3SecretService.getSecret(WEB3_SECRET_ADDRESS)) + .thenReturn(Optional.empty()); + assertThat(secretController.isWeb3SecretSet(WEB3_SECRET_ADDRESS)) + .isEqualTo(ResponseEntity.notFound().build()); + verifyNoInteractions(authorizationService, web2SecretsService); + } + //endregion + + //region getWeb3Secret + @Test + void failToGetWeb3SecretWhenBadAuthorization() { + when(authorizationService.getChallengeForGetWeb3Secret(WEB3_SECRET_ADDRESS)) + .thenReturn(CHALLENGE); + when(authorizationService.isSignedByOwner(CHALLENGE, AUTHORIZATION, WEB3_SECRET_ADDRESS)) + .thenReturn(false); + assertThat(secretController.getWeb3Secret(AUTHORIZATION, WEB3_SECRET_ADDRESS, false)) + .isEqualTo(ResponseEntity.status(HttpStatus.UNAUTHORIZED).build()); + verifyNoInteractions(web2SecretsService, web3SecretService); + } + + @Test + void failToGetWeb3SecretWhenSecretDoesNotExist() { + when(authorizationService.getChallengeForGetWeb3Secret(WEB3_SECRET_ADDRESS)) + .thenReturn(CHALLENGE); + when(authorizationService.isSignedByOwner(CHALLENGE, AUTHORIZATION, WEB3_SECRET_ADDRESS)) + .thenReturn(true); + when(web3SecretService.getSecret(WEB3_SECRET_ADDRESS)).thenReturn(Optional.empty()); + assertThat(secretController.getWeb3Secret(AUTHORIZATION, WEB3_SECRET_ADDRESS, false)) + .isEqualTo(ResponseEntity.notFound().build()); + verifyNoInteractions(web2SecretsService); + } + + @Test + void getWeb3Secret() { + when(authorizationService.getChallengeForGetWeb3Secret(WEB3_SECRET_ADDRESS)) + .thenReturn(CHALLENGE); + when(authorizationService.isSignedByOwner(CHALLENGE, AUTHORIZATION, WEB3_SECRET_ADDRESS)) + .thenReturn(true); + when(web3SecretService.getSecret(WEB3_SECRET_ADDRESS)).thenReturn(Optional.of(new Web3Secret())); + assertThat(secretController.getWeb3Secret(AUTHORIZATION, WEB3_SECRET_ADDRESS, false)) + .isEqualTo(ResponseEntity.notFound().build()); + verifyNoInteractions(web2SecretsService); + } + //endregion + + //region addWeb3Secret + @Test + void failToAddWeb3SecretWhenPayloadTooLarge() { + assertThat(secretController.addWeb3Secret(AUTHORIZATION, WEB3_SECRET_ADDRESS, getRandomString(4097))) + .isEqualTo(ResponseEntity.status(HttpStatus.PAYLOAD_TOO_LARGE).build()); + verifyNoInteractions(web2SecretsService, web3SecretService); + } + + @Test + void failToAddWeb3SecretWhenBadAuthorization() { + when(authorizationService.getChallengeForSetWeb3Secret(WEB3_SECRET_ADDRESS, WEB3_SECRET_VALUE)) + .thenReturn(CHALLENGE); + when(authorizationService.isSignedByOwner(CHALLENGE, AUTHORIZATION, WEB3_SECRET_ADDRESS)) + .thenReturn(false); + assertThat(secretController.addWeb3Secret(AUTHORIZATION, WEB3_SECRET_ADDRESS, WEB3_SECRET_VALUE)) + .isEqualTo(ResponseEntity.status(HttpStatus.UNAUTHORIZED).build()); + verifyNoInteractions(web2SecretsService, web3SecretService); + } + + @Test + void failToAddWeb3SecretWhenSecretAlreadyExists() { + when(authorizationService.getChallengeForSetWeb3Secret(WEB3_SECRET_ADDRESS, WEB3_SECRET_VALUE)) + .thenReturn(CHALLENGE); + when(authorizationService.isSignedByOwner(CHALLENGE, AUTHORIZATION, WEB3_SECRET_ADDRESS)) + .thenReturn(true); + when(web3SecretService.getSecret(WEB3_SECRET_ADDRESS)) + .thenReturn(Optional.of(new Web3Secret())); + assertThat(secretController.addWeb3Secret(AUTHORIZATION, WEB3_SECRET_ADDRESS, WEB3_SECRET_VALUE)) + .isEqualTo(ResponseEntity.status(HttpStatus.CONFLICT).build()); + } + + @Test + void addWeb3Secret() { + when(authorizationService.getChallengeForSetWeb3Secret(WEB3_SECRET_ADDRESS, WEB3_SECRET_VALUE)) + .thenReturn(CHALLENGE); + when(authorizationService.isSignedByOwner(CHALLENGE, AUTHORIZATION, WEB3_SECRET_ADDRESS)) + .thenReturn(true); + when(web3SecretService.getSecret(WEB3_SECRET_ADDRESS)) + .thenReturn(Optional.empty()); + assertThat(secretController.addWeb3Secret(AUTHORIZATION, WEB3_SECRET_ADDRESS, WEB3_SECRET_VALUE)) + .isEqualTo(ResponseEntity.noContent().build()); + } + //endregion + + //region isWeb2SecretSet + @Test + void shouldReturnNoContentWhenWeb2SecretExists() { + when(web2SecretsService.getSecret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME)) + .thenReturn(Optional.of(new Secret())); + assertThat(secretController.isWeb2SecretSet(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME)) + .isEqualTo(ResponseEntity.noContent().build()); + verifyNoInteractions(authorizationService, web3SecretService); + } + + @Test + void shouldReturnNotFoundWhenWeb2SecretDoesNotExist() { + when(web2SecretsService.getSecret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME)) + .thenReturn(Optional.empty()); + assertThat(secretController.isWeb2SecretSet(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME)) + .isEqualTo(ResponseEntity.notFound().build()); + verifyNoInteractions(authorizationService, web3SecretService); + } + //endregion + + //region getWeb2Secret + @Test + void failToGetWeb2SecretWhenBadAuthorization() { + when(authorizationService.getChallengeForGetWeb2Secret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME)) + .thenReturn(CHALLENGE); + when(authorizationService.isSignedByHimself(CHALLENGE, AUTHORIZATION, WEB2_OWNER_ADDRESS)) + .thenReturn(false); + assertThat(secretController.getWeb2Secret(AUTHORIZATION, WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, false)) + .isEqualTo(ResponseEntity.status(HttpStatus.UNAUTHORIZED).build()); + verifyNoInteractions(web2SecretsService, web3SecretService); + } + + @Test + void failToGetWeb2SecretWhenSecretDoesNotExist() { + when(authorizationService.getChallengeForGetWeb2Secret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME)) + .thenReturn(CHALLENGE); + when(authorizationService.isSignedByHimself(CHALLENGE, AUTHORIZATION, WEB2_OWNER_ADDRESS)) + .thenReturn(true); + when(web2SecretsService.getSecret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME)).thenReturn(Optional.empty()); + assertThat(secretController.getWeb2Secret(AUTHORIZATION, WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, false)) + .isEqualTo(ResponseEntity.notFound().build()); + verifyNoInteractions(web3SecretService); + } + + @Test + void getWeb2Secret() { + when(authorizationService.getChallengeForGetWeb2Secret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME)) + .thenReturn(CHALLENGE); + when(authorizationService.isSignedByHimself(CHALLENGE, AUTHORIZATION, WEB2_OWNER_ADDRESS)) + .thenReturn(true); + when(web2SecretsService.getSecret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME)).thenReturn(Optional.of(new Secret())); + assertThat(secretController.getWeb2Secret(AUTHORIZATION, WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, false)) + .isEqualTo(ResponseEntity.notFound().build()); + verifyNoInteractions(web3SecretService); + } + //endregion + + //region addWeb2Secret + @Test + void failToAddWeb2SecretWhenPayloadTooLarge() { + assertThat(secretController.addWeb2Secret(AUTHORIZATION, WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, getRandomString(4097))) + .isEqualTo(ResponseEntity.status(HttpStatus.PAYLOAD_TOO_LARGE).build()); + verifyNoInteractions(web2SecretsService, web3SecretService); + } + + @Test + void failToAddWeb2SecretWhenBadAuthorization() { + when(authorizationService.getChallengeForSetWeb2Secret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, WEB2_SECRET_VALUE)) + .thenReturn(CHALLENGE); + when(authorizationService.isSignedByHimself(CHALLENGE, AUTHORIZATION, WEB2_OWNER_ADDRESS)) + .thenReturn(false); + assertThat(secretController.addWeb2Secret(AUTHORIZATION, WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, WEB2_SECRET_VALUE)) + .isEqualTo(ResponseEntity.status(HttpStatus.UNAUTHORIZED).build()); + verifyNoInteractions(web2SecretsService, web3SecretService); + } + + @Test + void failToAddWeb2SecretWhenSecretAlreadyExists() { + when(authorizationService.getChallengeForSetWeb2Secret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, WEB2_SECRET_VALUE)) + .thenReturn(CHALLENGE); + when(authorizationService.isSignedByHimself(CHALLENGE, AUTHORIZATION, WEB2_OWNER_ADDRESS)) + .thenReturn(true); + when(web2SecretsService.getSecret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME)) + .thenReturn(Optional.of(new Secret())); + assertThat(secretController.addWeb2Secret(AUTHORIZATION, WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, WEB2_SECRET_VALUE)) + .isEqualTo(ResponseEntity.status(HttpStatus.CONFLICT).build()); + } + + @Test + void addWeb2Secret() { + when(authorizationService.getChallengeForSetWeb2Secret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, WEB2_SECRET_VALUE)) + .thenReturn(CHALLENGE); + when(authorizationService.isSignedByHimself(CHALLENGE, AUTHORIZATION, WEB2_OWNER_ADDRESS)) + .thenReturn(true); + when(web2SecretsService.getSecret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME)) + .thenReturn(Optional.empty()); + assertThat(secretController.addWeb2Secret(AUTHORIZATION, WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, WEB2_SECRET_VALUE)) + .isEqualTo(ResponseEntity.noContent().build()); + } + //endregion + + //region updateWeb2Secret + @Test + void failToUpdateWeb2SecretWhenPayloadTooLarge() { + assertThat(secretController.updateWeb2Secret(AUTHORIZATION, WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, getRandomString(4097))) + .isEqualTo(ResponseEntity.status(HttpStatus.PAYLOAD_TOO_LARGE).build()); + verifyNoInteractions(web2SecretsService, web3SecretService); + } + + @Test + void failToUpdateWeb2SecretWhenBadAuthorization() { + when(authorizationService.getChallengeForSetWeb2Secret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, WEB2_SECRET_VALUE)) + .thenReturn(CHALLENGE); + when(authorizationService.isSignedByHimself(CHALLENGE, AUTHORIZATION, WEB2_OWNER_ADDRESS)) + .thenReturn(false); + assertThat(secretController.updateWeb2Secret(AUTHORIZATION, WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, WEB2_SECRET_VALUE)) + .isEqualTo(ResponseEntity.status(HttpStatus.UNAUTHORIZED).build()); + verifyNoInteractions(web2SecretsService, web3SecretService); + } + + @Test + void failToUpdateWeb2SecretWhenSecretIsMissing() { + when(authorizationService.getChallengeForSetWeb2Secret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, WEB2_SECRET_VALUE)) + .thenReturn(CHALLENGE); + when(authorizationService.isSignedByHimself(CHALLENGE, AUTHORIZATION, WEB2_OWNER_ADDRESS)) + .thenReturn(true); + doThrow(NoSuchElementException.class).when(web2SecretsService) + .updateSecret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, WEB2_SECRET_VALUE); + assertThat(secretController.updateWeb2Secret(AUTHORIZATION, WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, WEB2_SECRET_VALUE)) + .isEqualTo(ResponseEntity.notFound().build()); + } + + @Test + void updateWeb2Secret() { + when(authorizationService.getChallengeForSetWeb2Secret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, WEB2_SECRET_VALUE)) + .thenReturn(CHALLENGE); + when(authorizationService.isSignedByHimself(CHALLENGE, AUTHORIZATION, WEB2_OWNER_ADDRESS)) + .thenReturn(true); + assertThat(secretController.updateWeb2Secret(AUTHORIZATION, WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, WEB2_SECRET_VALUE)) + .isEqualTo(ResponseEntity.noContent().build()); + } + //endregion + + String getRandomString(int size) { + byte[] bytes = new byte[size]; + seed.nextBytes(bytes); + return new String(bytes, StandardCharsets.UTF_8); + } + +} From 4a641a68960de4981e7cb44bca9a3453194e09f7 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Tue, 6 Sep 2022 09:44:00 +0200 Subject: [PATCH 085/293] Move `tee.workflow` to TEE provider's specific properties file --- src/main/resources/application-gramine.yml | 10 ++++++++++ src/main/resources/application-scone.yml | 12 ++++++++++++ src/main/resources/application.yml | 12 ------------ 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/src/main/resources/application-gramine.yml b/src/main/resources/application-gramine.yml index 5a16f4f7..938a5610 100644 --- a/src/main/resources/application-gramine.yml +++ b/src/main/resources/application-gramine.yml @@ -7,6 +7,16 @@ tee: hostname: ${IEXEC_SECRET_PROVISIONER_ENCLAVE_HOSTNAME:localhost} port: ${IEXEC_SECRET_PROVISIONER_ENCLAVE_PORT:4433} + workflow: + pre-compute: + image: ${IEXEC_TEE_WORKER_PRE_COMPUTE_IMAGE:} # e.g.: docker.io/iexechub/tee-worker-pre-compute:x.y.z-production + fingerprint: ${IEXEC_TEE_WORKER_PRE_COMPUTE_FINGERPRINT:} + entrypoint: ${IEXEC_TEE_WORKER_PRE_COMPUTE_ENTRYPOINT:/bin/bash /apploader.sh} + post-compute: + image: ${IEXEC_TEE_WORKER_POST_COMPUTE_IMAGE:} # e.g.: docker.io/iexechub/tee-worker-post-compute:x.y.z-production + fingerprint: ${IEXEC_TEE_WORKER_POST_COMPUTE_FINGERPRINT:} + entrypoint: ${IEXEC_TEE_WORKER_POST_COMPUTE_ENTRYPOINT:/bin/bash /apploader.sh} + gramine: sps: login: ${IEXEC_GRAPHENE_SPS_WEB_LOGIN:admin} diff --git a/src/main/resources/application-scone.yml b/src/main/resources/application-scone.yml index 63cb8a59..73c3eeae 100644 --- a/src/main/resources/application-scone.yml +++ b/src/main/resources/application-scone.yml @@ -7,6 +7,18 @@ tee: hostname: ${IEXEC_SECRET_PROVISIONER_ENCLAVE_HOSTNAME:localhost} port: ${IEXEC_SECRET_PROVISIONER_ENCLAVE_PORT:18765} + workflow: + pre-compute: + image: ${IEXEC_TEE_WORKER_PRE_COMPUTE_IMAGE:} # e.g.: docker.io/iexechub/tee-worker-pre-compute:x.y.z-production + fingerprint: ${IEXEC_TEE_WORKER_PRE_COMPUTE_FINGERPRINT:} + heap-size-gb: ${IEXEC_TEE_WORKER_PRE_COMPUTE_HEAP_SIZE_GB:3} + entrypoint: ${IEXEC_TEE_WORKER_PRE_COMPUTE_ENTRYPOINT:java -jar /app/app.jar} + post-compute: + image: ${IEXEC_TEE_WORKER_POST_COMPUTE_IMAGE:} # e.g.: docker.io/iexechub/tee-worker-post-compute:x.y.z-production + fingerprint: ${IEXEC_TEE_WORKER_POST_COMPUTE_FINGERPRINT:} + heap-size-gb: ${IEXEC_TEE_WORKER_POST_COMPUTE_HEAP_SIZE_GB:3} + entrypoint: ${IEXEC_TEE_WORKER_POST_COMPUTE_ENTRYPOINT:java -jar /app/app.jar} + scone: las-image: ${IEXEC_SMS_IMAGE_LAS_IMAGE:} # e.g.: registry.scontain.com:5050/scone-production/iexec-las:x.y.z attestation: diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index d2dbe754..01734c7d 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -59,18 +59,6 @@ tee: hostname: ${IEXEC_SECRET_PROVISIONER_ENCLAVE_HOSTNAME:localhost} port: ${IEXEC_SECRET_PROVISIONER_ENCLAVE_PORT} - workflow: - pre-compute: - image: ${IEXEC_TEE_WORKER_PRE_COMPUTE_IMAGE:} # e.g.: docker.io/iexechub/tee-worker-pre-compute:x.y.z-production - fingerprint: ${IEXEC_TEE_WORKER_PRE_COMPUTE_FINGERPRINT:} - heap-size-gb: ${IEXEC_TEE_WORKER_PRE_COMPUTE_HEAP_SIZE_GB:4} - entrypoint: ${IEXEC_TEE_WORKER_PRE_COMPUTE_ENTRYPOINT:java -jar /app/app.jar} - post-compute: - image: ${IEXEC_TEE_WORKER_POST_COMPUTE_IMAGE:} # e.g.: docker.io/iexechub/tee-worker-post-compute:x.y.z-production - fingerprint: ${IEXEC_TEE_WORKER_POST_COMPUTE_FINGERPRINT:} - heap-size-gb: ${IEXEC_TEE_WORKER_POST_COMPUTE_HEAP_SIZE_GB:4} - entrypoint: ${IEXEC_TEE_WORKER_POST_COMPUTE_ENTRYPOINT:java -jar /app/app.jar} - logging: tee.display-debug-session: ${IEXEC_SMS_DISPLAY_DEBUG_SESSION:false} # level: From 0fddcd75a6ee3bc92731a70785583fa55f809985 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Tue, 6 Sep 2022 10:02:07 +0200 Subject: [PATCH 086/293] Restore `heap-size-gb` property --- src/main/resources/application-gramine.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/resources/application-gramine.yml b/src/main/resources/application-gramine.yml index 938a5610..b68bb005 100644 --- a/src/main/resources/application-gramine.yml +++ b/src/main/resources/application-gramine.yml @@ -11,10 +11,12 @@ tee: pre-compute: image: ${IEXEC_TEE_WORKER_PRE_COMPUTE_IMAGE:} # e.g.: docker.io/iexechub/tee-worker-pre-compute:x.y.z-production fingerprint: ${IEXEC_TEE_WORKER_PRE_COMPUTE_FINGERPRINT:} + heap-size-gb: ${IEXEC_TEE_WORKER_PRE_COMPUTE_HEAP_SIZE_GB:3} entrypoint: ${IEXEC_TEE_WORKER_PRE_COMPUTE_ENTRYPOINT:/bin/bash /apploader.sh} post-compute: image: ${IEXEC_TEE_WORKER_POST_COMPUTE_IMAGE:} # e.g.: docker.io/iexechub/tee-worker-post-compute:x.y.z-production fingerprint: ${IEXEC_TEE_WORKER_POST_COMPUTE_FINGERPRINT:} + heap-size-gb: ${IEXEC_TEE_WORKER_POST_COMPUTE_HEAP_SIZE_GB:3} entrypoint: ${IEXEC_TEE_WORKER_POST_COMPUTE_ENTRYPOINT:/bin/bash /apploader.sh} gramine: From 41a06cd3457e0e7f0f86924a5ac0429d6c60baeb Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Tue, 6 Sep 2022 11:01:22 +0200 Subject: [PATCH 087/293] Remove spaces in `log.xxx` --- .../java/com/iexec/sms/tee/EnableIfTeeProvider.java | 10 ++++++---- src/main/java/com/iexec/sms/tee/TeeController.java | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/iexec/sms/tee/EnableIfTeeProvider.java b/src/main/java/com/iexec/sms/tee/EnableIfTeeProvider.java index 686d8846..e2285df8 100644 --- a/src/main/java/com/iexec/sms/tee/EnableIfTeeProvider.java +++ b/src/main/java/com/iexec/sms/tee/EnableIfTeeProvider.java @@ -7,6 +7,8 @@ import org.springframework.core.type.AnnotatedTypeMetadata; import org.springframework.core.type.AnnotationMetadata; +import java.util.Arrays; + /** * Define a way to include beans only if a profile is enabled *

@@ -32,7 +34,7 @@ public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) clazz = Class.forName(beanClassName); } catch (ClassNotFoundException e) { log.error( - "Bean does not exist [bean: {}]", + "Bean does not exist [bean:{}]", beanClassName); return false; } @@ -41,7 +43,7 @@ public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) clazz.getAnnotation(EnableIfTeeProviderDefinition.class); if (condition == null) { log.error( - "@EnableIfTeeProviderDefinition annotation is required to use EnableIfTeeProvider condition [bean: {}]", + "@EnableIfTeeProviderDefinition annotation is required to use EnableIfTeeProvider condition [bean:{}]", beanClassName); return false; } @@ -49,7 +51,7 @@ public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) final TeeEnclaveProvider[] teeProviders = condition.providers(); if (teeProviders == null || teeProviders.length == 0) { log.warn( - "No TEE provider defined for bean, won't be loaded [bean: {}]", + "No TEE provider defined for bean, won't be loaded [bean:{}]", beanClassName); return false; } @@ -63,7 +65,7 @@ public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) } log.debug( - "Active profiles and condition don't match, bean won't be loaded [bean: {}]", + "Active profiles and condition don't match, bean won't be loaded [bean:{}]", beanClassName); return false; } diff --git a/src/main/java/com/iexec/sms/tee/TeeController.java b/src/main/java/com/iexec/sms/tee/TeeController.java index 9a561c7c..a887a965 100644 --- a/src/main/java/com/iexec/sms/tee/TeeController.java +++ b/src/main/java/com/iexec/sms/tee/TeeController.java @@ -94,7 +94,7 @@ public ResponseEntity getTeeServicesConfig( @PathVariable TeeEnclaveProvider teeEnclaveProvider) { if (teeEnclaveProvider != teeServicesConfig.getTeeEnclaveProvider()) { log.error("SMS configured to use another TeeEnclaveProvider " + - "[required: {}, actual: {}]", teeEnclaveProvider, teeServicesConfig.getTeeEnclaveProvider()); + "[required:{}, actual:{}]", teeEnclaveProvider, teeServicesConfig.getTeeEnclaveProvider()); return ResponseEntity.status(HttpStatus.CONFLICT).build(); } return ResponseEntity.ok(teeServicesConfig.getShareableConfiguration()); From 60a85757fcd610969c816c9f21cdf5ee2467af97 Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Tue, 6 Sep 2022 11:25:12 +0200 Subject: [PATCH 088/293] Fix getWeb2Secret and getWeb3Secret tests --- .../sms/secret/SecretControllerTests.java | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/test/java/com/iexec/sms/secret/SecretControllerTests.java b/src/test/java/com/iexec/sms/secret/SecretControllerTests.java index 2ee6b09d..44d2c9c5 100644 --- a/src/test/java/com/iexec/sms/secret/SecretControllerTests.java +++ b/src/test/java/com/iexec/sms/secret/SecretControllerTests.java @@ -22,6 +22,8 @@ import com.iexec.sms.secret.web3.Web3SecretService; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -109,15 +111,18 @@ void failToGetWeb3SecretWhenSecretDoesNotExist() { verifyNoInteractions(web2SecretsService); } - @Test - void getWeb3Secret() { + @ParameterizedTest + @ValueSource(strings = {"true", "false"}) + void getWeb3Secret(boolean shouldDecryptSecret) { + Web3Secret expectedSecret = new Web3Secret(); when(authorizationService.getChallengeForGetWeb3Secret(WEB3_SECRET_ADDRESS)) .thenReturn(CHALLENGE); when(authorizationService.isSignedByOwner(CHALLENGE, AUTHORIZATION, WEB3_SECRET_ADDRESS)) .thenReturn(true); - when(web3SecretService.getSecret(WEB3_SECRET_ADDRESS)).thenReturn(Optional.of(new Web3Secret())); - assertThat(secretController.getWeb3Secret(AUTHORIZATION, WEB3_SECRET_ADDRESS, false)) - .isEqualTo(ResponseEntity.notFound().build()); + when(web3SecretService.getSecret(WEB3_SECRET_ADDRESS, shouldDecryptSecret)) + .thenReturn(Optional.of(expectedSecret)); + assertThat(secretController.getWeb3Secret(AUTHORIZATION, WEB3_SECRET_ADDRESS, shouldDecryptSecret)) + .isEqualTo(ResponseEntity.ok(expectedSecret)); verifyNoInteractions(web2SecretsService); } //endregion @@ -210,15 +215,18 @@ void failToGetWeb2SecretWhenSecretDoesNotExist() { verifyNoInteractions(web3SecretService); } - @Test - void getWeb2Secret() { + @ParameterizedTest + @ValueSource(strings = {"true", "false"}) + void getWeb2Secret(boolean shouldDecryptSecret) { + Secret expectedSecret = new Secret(); when(authorizationService.getChallengeForGetWeb2Secret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME)) .thenReturn(CHALLENGE); when(authorizationService.isSignedByHimself(CHALLENGE, AUTHORIZATION, WEB2_OWNER_ADDRESS)) .thenReturn(true); - when(web2SecretsService.getSecret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME)).thenReturn(Optional.of(new Secret())); - assertThat(secretController.getWeb2Secret(AUTHORIZATION, WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, false)) - .isEqualTo(ResponseEntity.notFound().build()); + when(web2SecretsService.getSecret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, shouldDecryptSecret)) + .thenReturn(Optional.of(expectedSecret)); + assertThat(secretController.getWeb2Secret(AUTHORIZATION, WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, shouldDecryptSecret)) + .isEqualTo(ResponseEntity.ok(expectedSecret)); verifyNoInteractions(web3SecretService); } //endregion From 5a1d5f61e392cb3b9b652cea35ec3b0c4aed7694 Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Tue, 6 Sep 2022 11:33:26 +0200 Subject: [PATCH 089/293] Parameterized all tests related to getWeb2Secret and getWeb3Secret methods --- .../sms/secret/SecretControllerTests.java | 34 +++++++++++-------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/src/test/java/com/iexec/sms/secret/SecretControllerTests.java b/src/test/java/com/iexec/sms/secret/SecretControllerTests.java index 44d2c9c5..edb0e03a 100644 --- a/src/test/java/com/iexec/sms/secret/SecretControllerTests.java +++ b/src/test/java/com/iexec/sms/secret/SecretControllerTests.java @@ -88,25 +88,28 @@ void shouldReturnNotFoundWhenWeb3SecretDoesNotExist() { //endregion //region getWeb3Secret - @Test - void failToGetWeb3SecretWhenBadAuthorization() { + @ParameterizedTest + @ValueSource(strings = {"true", "false"}) + void failToGetWeb3SecretWhenBadAuthorization(boolean shouldDecryptValue) { when(authorizationService.getChallengeForGetWeb3Secret(WEB3_SECRET_ADDRESS)) .thenReturn(CHALLENGE); when(authorizationService.isSignedByOwner(CHALLENGE, AUTHORIZATION, WEB3_SECRET_ADDRESS)) .thenReturn(false); - assertThat(secretController.getWeb3Secret(AUTHORIZATION, WEB3_SECRET_ADDRESS, false)) + assertThat(secretController.getWeb3Secret(AUTHORIZATION, WEB3_SECRET_ADDRESS, shouldDecryptValue)) .isEqualTo(ResponseEntity.status(HttpStatus.UNAUTHORIZED).build()); verifyNoInteractions(web2SecretsService, web3SecretService); } - @Test - void failToGetWeb3SecretWhenSecretDoesNotExist() { + @ParameterizedTest + @ValueSource(strings = {"true", "false"}) + void failToGetWeb3SecretWhenSecretDoesNotExist(boolean shouldDecryptValue) { when(authorizationService.getChallengeForGetWeb3Secret(WEB3_SECRET_ADDRESS)) .thenReturn(CHALLENGE); when(authorizationService.isSignedByOwner(CHALLENGE, AUTHORIZATION, WEB3_SECRET_ADDRESS)) .thenReturn(true); - when(web3SecretService.getSecret(WEB3_SECRET_ADDRESS)).thenReturn(Optional.empty()); - assertThat(secretController.getWeb3Secret(AUTHORIZATION, WEB3_SECRET_ADDRESS, false)) + when(web3SecretService.getSecret(WEB3_SECRET_ADDRESS, shouldDecryptValue)) + .thenReturn(Optional.empty()); + assertThat(secretController.getWeb3Secret(AUTHORIZATION, WEB3_SECRET_ADDRESS, shouldDecryptValue)) .isEqualTo(ResponseEntity.notFound().build()); verifyNoInteractions(web2SecretsService); } @@ -192,25 +195,28 @@ void shouldReturnNotFoundWhenWeb2SecretDoesNotExist() { //endregion //region getWeb2Secret - @Test - void failToGetWeb2SecretWhenBadAuthorization() { + @ParameterizedTest + @ValueSource(strings = {"true", "false"}) + void failToGetWeb2SecretWhenBadAuthorization(boolean shouldDecryptValue) { when(authorizationService.getChallengeForGetWeb2Secret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME)) .thenReturn(CHALLENGE); when(authorizationService.isSignedByHimself(CHALLENGE, AUTHORIZATION, WEB2_OWNER_ADDRESS)) .thenReturn(false); - assertThat(secretController.getWeb2Secret(AUTHORIZATION, WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, false)) + assertThat(secretController.getWeb2Secret(AUTHORIZATION, WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, shouldDecryptValue)) .isEqualTo(ResponseEntity.status(HttpStatus.UNAUTHORIZED).build()); verifyNoInteractions(web2SecretsService, web3SecretService); } - @Test - void failToGetWeb2SecretWhenSecretDoesNotExist() { + @ParameterizedTest + @ValueSource(strings = {"true", "false"}) + void failToGetWeb2SecretWhenSecretDoesNotExist(boolean shouldDecryptValue) { when(authorizationService.getChallengeForGetWeb2Secret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME)) .thenReturn(CHALLENGE); when(authorizationService.isSignedByHimself(CHALLENGE, AUTHORIZATION, WEB2_OWNER_ADDRESS)) .thenReturn(true); - when(web2SecretsService.getSecret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME)).thenReturn(Optional.empty()); - assertThat(secretController.getWeb2Secret(AUTHORIZATION, WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, false)) + when(web2SecretsService.getSecret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, shouldDecryptValue)) + .thenReturn(Optional.empty()); + assertThat(secretController.getWeb2Secret(AUTHORIZATION, WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, shouldDecryptValue)) .isEqualTo(ResponseEntity.notFound().build()); verifyNoInteractions(web3SecretService); } From ad5993043a9ec970a34b86a075b18991716048cf Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Wed, 7 Sep 2022 10:33:44 +0200 Subject: [PATCH 090/293] Refactor beans TEE providers conditional loading --- .../sms/tee/ConditionalOnTeeProvider.java | 27 +++++++ .../iexec/sms/tee/EnableIfTeeProvider.java | 72 ------------------- .../tee/EnableIfTeeProviderDefinition.java | 11 --- .../iexec/sms/tee/OnTeeProviderCondition.java | 57 +++++++++++++++ .../GramineInternalServicesConfiguration.java | 7 +- .../SconeInternalServicesConfiguration.java | 7 +- .../gramine/GramineSessionHandlerService.java | 7 +- .../gramine/GramineSessionMakerService.java | 7 +- .../session/gramine/sps/SpsConfiguration.java | 7 +- .../scone/SconeSessionHandlerService.java | 7 +- .../scone/SconeSessionMakerService.java | 7 +- .../scone/SconeSessionSecurityConfig.java | 7 +- .../sms/tee/session/scone/cas/CasClient.java | 7 +- .../session/scone/cas/CasConfiguration.java | 7 +- ...ava => ConditionalOnTeeProviderTests.java} | 24 +++++-- 15 files changed, 123 insertions(+), 138 deletions(-) create mode 100644 src/main/java/com/iexec/sms/tee/ConditionalOnTeeProvider.java delete mode 100644 src/main/java/com/iexec/sms/tee/EnableIfTeeProvider.java delete mode 100644 src/main/java/com/iexec/sms/tee/EnableIfTeeProviderDefinition.java create mode 100644 src/main/java/com/iexec/sms/tee/OnTeeProviderCondition.java rename src/test/java/com/iexec/sms/tee/{EnableIfTeeProviderTests.java => ConditionalOnTeeProviderTests.java} (88%) diff --git a/src/main/java/com/iexec/sms/tee/ConditionalOnTeeProvider.java b/src/main/java/com/iexec/sms/tee/ConditionalOnTeeProvider.java new file mode 100644 index 00000000..90bc0b8d --- /dev/null +++ b/src/main/java/com/iexec/sms/tee/ConditionalOnTeeProvider.java @@ -0,0 +1,27 @@ +package com.iexec.sms.tee; + +import com.iexec.common.tee.TeeEnclaveProvider; +import org.springframework.context.annotation.Conditional; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Defines a way to include beans based on active profiles. + *

+ * E.g.: + *

    + *
  • a {@code SconeConfig} bean annotated with {@code ConditionalOnTeeProvider(teeProviders = SCONE)} + * will be loaded only if a {@code scone} profile is active.
  • + *
  • a {@code TeeConfig} bean annotated with {@code ConditionalOnTeeProvider(teeProviders = {SCONE, GRAMINE})} + * will be loaded only if any of {@code scone} or {@code gramine} profile is active.
  • + *
+ */ +@Target({ ElementType.TYPE, ElementType.METHOD }) +@Retention(RetentionPolicy.RUNTIME) +@Conditional(OnTeeProviderCondition.class) +public @interface ConditionalOnTeeProvider { + TeeEnclaveProvider[] providers() default {}; +} diff --git a/src/main/java/com/iexec/sms/tee/EnableIfTeeProvider.java b/src/main/java/com/iexec/sms/tee/EnableIfTeeProvider.java deleted file mode 100644 index e2285df8..00000000 --- a/src/main/java/com/iexec/sms/tee/EnableIfTeeProvider.java +++ /dev/null @@ -1,72 +0,0 @@ -package com.iexec.sms.tee; - -import com.iexec.common.tee.TeeEnclaveProvider; -import lombok.extern.slf4j.Slf4j; -import org.springframework.context.annotation.Condition; -import org.springframework.context.annotation.ConditionContext; -import org.springframework.core.type.AnnotatedTypeMetadata; -import org.springframework.core.type.AnnotationMetadata; - -import java.util.Arrays; - -/** - * Define a way to include beans only if a profile is enabled - *

- * Usage: - * Annotate any bean with the following: - * {@code - * @Conditional(EnableIfTeeProvider.class) - * @EnableIfTeeProviderDefinition(providers = TeeEnclaveProvider.) - * } - *

- * If bean is not annotated with {@link EnableIfTeeProviderDefinition} - * or {@link EnableIfTeeProviderDefinition#providers()} is null or empty, - * the bean won't be loaded. - */ -@Slf4j -public class EnableIfTeeProvider implements Condition { - @Override - public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { - final String[] activeProfiles = context.getEnvironment().getActiveProfiles(); - final String beanClassName = ((AnnotationMetadata) metadata).getClassName(); - final Class clazz; - try { - clazz = Class.forName(beanClassName); - } catch (ClassNotFoundException e) { - log.error( - "Bean does not exist [bean:{}]", - beanClassName); - return false; - } - - final EnableIfTeeProviderDefinition condition = - clazz.getAnnotation(EnableIfTeeProviderDefinition.class); - if (condition == null) { - log.error( - "@EnableIfTeeProviderDefinition annotation is required to use EnableIfTeeProvider condition [bean:{}]", - beanClassName); - return false; - } - - final TeeEnclaveProvider[] teeProviders = condition.providers(); - if (teeProviders == null || teeProviders.length == 0) { - log.warn( - "No TEE provider defined for bean, won't be loaded [bean:{}]", - beanClassName); - return false; - } - - for (String activeProfile : activeProfiles) { - for (TeeEnclaveProvider teeProvider : teeProviders) { - if (activeProfile.equalsIgnoreCase(teeProvider.name())) { - return true; - } - } - } - - log.debug( - "Active profiles and condition don't match, bean won't be loaded [bean:{}]", - beanClassName); - return false; - } -} diff --git a/src/main/java/com/iexec/sms/tee/EnableIfTeeProviderDefinition.java b/src/main/java/com/iexec/sms/tee/EnableIfTeeProviderDefinition.java deleted file mode 100644 index 690cdcb7..00000000 --- a/src/main/java/com/iexec/sms/tee/EnableIfTeeProviderDefinition.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.iexec.sms.tee; - -import com.iexec.common.tee.TeeEnclaveProvider; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -@Retention(RetentionPolicy.RUNTIME) -public @interface EnableIfTeeProviderDefinition { - TeeEnclaveProvider[] providers(); -} diff --git a/src/main/java/com/iexec/sms/tee/OnTeeProviderCondition.java b/src/main/java/com/iexec/sms/tee/OnTeeProviderCondition.java new file mode 100644 index 00000000..5d08266a --- /dev/null +++ b/src/main/java/com/iexec/sms/tee/OnTeeProviderCondition.java @@ -0,0 +1,57 @@ +package com.iexec.sms.tee; + +import com.iexec.common.tee.TeeEnclaveProvider; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.autoconfigure.condition.ConditionMessage; +import org.springframework.boot.autoconfigure.condition.ConditionOutcome; +import org.springframework.boot.autoconfigure.condition.SpringBootCondition; +import org.springframework.context.annotation.Condition; +import org.springframework.context.annotation.ConditionContext; +import org.springframework.core.type.AnnotatedTypeMetadata; +import org.springframework.core.type.AnnotationMetadata; + +import java.util.Arrays; +import java.util.Map; + +/** + * {@link Condition} that checks for a specific profile to be enabled. + * To be used with {@link ConditionalOnTeeProvider}. + */ +@Slf4j +public class OnTeeProviderCondition extends SpringBootCondition { + @Override + public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) { + final Map attributes = metadata.getAnnotationAttributes(ConditionalOnTeeProvider.class.getName()); + final String[] activeProfiles = context.getEnvironment().getActiveProfiles(); + + final String beanClassName = ((AnnotationMetadata) metadata).getClassName(); + + final TeeEnclaveProvider[] providers = (TeeEnclaveProvider[]) attributes.get("providers"); + if (providers == null || providers.length == 0) { + log.warn( + "No TEE provider defined for bean, won't be loaded [bean:{}]", + beanClassName); + return new ConditionOutcome( + false, + ConditionMessage.forCondition(ConditionalOnTeeProvider.class).didNotFind("any TEE enclave providers").atAll()); + } + + for (String activeProfile : activeProfiles) { + for (TeeEnclaveProvider teeProvider : providers) { + if (activeProfile.equalsIgnoreCase(teeProvider.name())) { + return new ConditionOutcome( + true, + ConditionMessage.forCondition(ConditionalOnTeeProvider.class).foundExactly(teeProvider)); + } + } + } + + log.debug( + "Active profiles and condition don't match, bean won't be loaded [bean:{}]", + beanClassName); + + return new ConditionOutcome( + false, + ConditionMessage.forCondition(ConditionalOnTeeProvider.class).didNotFind("profile", "profiles").items(Arrays.asList(providers))); + } +} diff --git a/src/main/java/com/iexec/sms/tee/config/GramineInternalServicesConfiguration.java b/src/main/java/com/iexec/sms/tee/config/GramineInternalServicesConfiguration.java index dd6e21d5..81bead1b 100644 --- a/src/main/java/com/iexec/sms/tee/config/GramineInternalServicesConfiguration.java +++ b/src/main/java/com/iexec/sms/tee/config/GramineInternalServicesConfiguration.java @@ -4,15 +4,12 @@ import com.iexec.sms.api.config.GramineServicesConfiguration; import com.iexec.sms.api.config.TeeAppConfiguration; import com.iexec.sms.api.config.TeeServicesConfiguration; -import com.iexec.sms.tee.EnableIfTeeProvider; -import com.iexec.sms.tee.EnableIfTeeProviderDefinition; +import com.iexec.sms.tee.ConditionalOnTeeProvider; import lombok.Getter; -import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; @Configuration -@Conditional(EnableIfTeeProvider.class) -@EnableIfTeeProviderDefinition(providers = TeeEnclaveProvider.GRAMINE) +@ConditionalOnTeeProvider(providers = TeeEnclaveProvider.GRAMINE) @Getter public class GramineInternalServicesConfiguration extends GramineServicesConfiguration diff --git a/src/main/java/com/iexec/sms/tee/config/SconeInternalServicesConfiguration.java b/src/main/java/com/iexec/sms/tee/config/SconeInternalServicesConfiguration.java index 065c91b0..db8e5550 100644 --- a/src/main/java/com/iexec/sms/tee/config/SconeInternalServicesConfiguration.java +++ b/src/main/java/com/iexec/sms/tee/config/SconeInternalServicesConfiguration.java @@ -4,18 +4,15 @@ import com.iexec.sms.api.config.SconeServicesConfiguration; import com.iexec.sms.api.config.TeeAppConfiguration; import com.iexec.sms.api.config.TeeServicesConfiguration; -import com.iexec.sms.tee.EnableIfTeeProvider; -import com.iexec.sms.tee.EnableIfTeeProviderDefinition; +import com.iexec.sms.tee.ConditionalOnTeeProvider; import lombok.Getter; import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; import javax.validation.constraints.NotBlank; @Configuration -@Conditional(EnableIfTeeProvider.class) -@EnableIfTeeProviderDefinition(providers = TeeEnclaveProvider.SCONE) +@ConditionalOnTeeProvider(providers = TeeEnclaveProvider.SCONE) @Getter public class SconeInternalServicesConfiguration extends SconeServicesConfiguration diff --git a/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerService.java b/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerService.java index ca4d28f7..052cb14a 100644 --- a/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerService.java +++ b/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerService.java @@ -18,8 +18,7 @@ import com.iexec.common.tee.TeeEnclaveProvider; import com.iexec.sms.api.TeeSessionGenerationError; -import com.iexec.sms.tee.EnableIfTeeProvider; -import com.iexec.sms.tee.EnableIfTeeProviderDefinition; +import com.iexec.sms.tee.ConditionalOnTeeProvider; import com.iexec.sms.tee.session.TeeSessionLogConfiguration; import com.iexec.sms.tee.session.generic.TeeSessionGenerationException; import com.iexec.sms.tee.session.generic.TeeSessionHandler; @@ -27,13 +26,11 @@ import com.iexec.sms.tee.session.gramine.sps.GramineSession; import com.iexec.sms.tee.session.gramine.sps.SpsConfiguration; import lombok.extern.slf4j.Slf4j; -import org.springframework.context.annotation.Conditional; import org.springframework.stereotype.Component; @Slf4j @Component -@Conditional(EnableIfTeeProvider.class) -@EnableIfTeeProviderDefinition(providers = TeeEnclaveProvider.GRAMINE) +@ConditionalOnTeeProvider(providers = TeeEnclaveProvider.GRAMINE) public class GramineSessionHandlerService implements TeeSessionHandler { private GramineSessionMakerService sessionService; private SpsConfiguration spsConfiguration; diff --git a/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerService.java b/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerService.java index 97294793..5f2b1754 100644 --- a/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerService.java +++ b/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerService.java @@ -18,8 +18,7 @@ import com.iexec.common.tee.TeeEnclaveProvider; import com.iexec.sms.api.config.TeeServicesConfiguration; -import com.iexec.sms.tee.EnableIfTeeProvider; -import com.iexec.sms.tee.EnableIfTeeProviderDefinition; +import com.iexec.sms.tee.ConditionalOnTeeProvider; import com.iexec.sms.tee.session.base.SecretEnclaveBase; import com.iexec.sms.tee.session.base.SecretSessionBase; import com.iexec.sms.tee.session.base.SecretSessionBaseService; @@ -28,14 +27,12 @@ import com.iexec.sms.tee.session.gramine.sps.GramineEnclave; import com.iexec.sms.tee.session.gramine.sps.GramineSession; import com.iexec.sms.tee.session.gramine.sps.GramineSession.GramineSessionBuilder; -import org.springframework.context.annotation.Conditional; import org.springframework.stereotype.Service; import java.util.List; @Service -@Conditional(EnableIfTeeProvider.class) -@EnableIfTeeProviderDefinition(providers = TeeEnclaveProvider.GRAMINE) +@ConditionalOnTeeProvider(providers = TeeEnclaveProvider.GRAMINE) public class GramineSessionMakerService { private final SecretSessionBaseService secretSessionBaseService; diff --git a/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsConfiguration.java b/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsConfiguration.java index 6d1d4ac8..7e893fa5 100644 --- a/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsConfiguration.java +++ b/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsConfiguration.java @@ -18,17 +18,14 @@ import com.iexec.common.tee.TeeEnclaveProvider; import com.iexec.common.utils.FeignBuilder; -import com.iexec.sms.tee.EnableIfTeeProvider; -import com.iexec.sms.tee.EnableIfTeeProviderDefinition; +import com.iexec.sms.tee.ConditionalOnTeeProvider; import feign.Logger.Level; import lombok.Getter; import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; @Configuration -@Conditional(EnableIfTeeProvider.class) -@EnableIfTeeProviderDefinition(providers = TeeEnclaveProvider.GRAMINE) +@ConditionalOnTeeProvider(providers = TeeEnclaveProvider.GRAMINE) @Getter public class SpsConfiguration { @Value("${tee.secret-provisioner.web.hostname}") diff --git a/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerService.java b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerService.java index 201e84b8..beaa1178 100644 --- a/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerService.java +++ b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerService.java @@ -18,8 +18,7 @@ import com.iexec.common.tee.TeeEnclaveProvider; import com.iexec.sms.api.TeeSessionGenerationError; -import com.iexec.sms.tee.EnableIfTeeProvider; -import com.iexec.sms.tee.EnableIfTeeProviderDefinition; +import com.iexec.sms.tee.ConditionalOnTeeProvider; import com.iexec.sms.tee.session.TeeSessionLogConfiguration; import com.iexec.sms.tee.session.generic.TeeSessionGenerationException; import com.iexec.sms.tee.session.generic.TeeSessionHandler; @@ -28,14 +27,12 @@ import com.iexec.sms.tee.session.scone.cas.CasConfiguration; import com.iexec.sms.tee.session.scone.cas.SconeSession; import lombok.extern.slf4j.Slf4j; -import org.springframework.context.annotation.Conditional; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; @Slf4j @Component -@Conditional(EnableIfTeeProvider.class) -@EnableIfTeeProviderDefinition(providers = TeeEnclaveProvider.SCONE) +@ConditionalOnTeeProvider(providers = TeeEnclaveProvider.SCONE) public class SconeSessionHandlerService implements TeeSessionHandler { private SconeSessionMakerService sessionService; private CasClient apiClient; diff --git a/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionMakerService.java b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionMakerService.java index 25d95562..2d8d31d3 100644 --- a/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionMakerService.java +++ b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionMakerService.java @@ -18,8 +18,7 @@ import com.iexec.common.tee.TeeEnclaveProvider; import com.iexec.sms.api.config.TeeServicesConfiguration; -import com.iexec.sms.tee.EnableIfTeeProvider; -import com.iexec.sms.tee.EnableIfTeeProviderDefinition; +import com.iexec.sms.tee.ConditionalOnTeeProvider; import com.iexec.sms.tee.session.base.SecretEnclaveBase; import com.iexec.sms.tee.session.base.SecretSessionBase; import com.iexec.sms.tee.session.base.SecretSessionBaseService; @@ -33,7 +32,6 @@ import com.iexec.sms.tee.session.scone.cas.SconeSession.Security; import com.iexec.sms.tee.session.scone.cas.SconeSession.Volumes; import lombok.extern.slf4j.Slf4j; -import org.springframework.context.annotation.Conditional; import org.springframework.stereotype.Service; import java.util.*; @@ -41,8 +39,7 @@ //TODO Rename and move @Slf4j @Service -@Conditional(EnableIfTeeProvider.class) -@EnableIfTeeProviderDefinition(providers = TeeEnclaveProvider.SCONE) +@ConditionalOnTeeProvider(providers = TeeEnclaveProvider.SCONE) public class SconeSessionMakerService { // Internal values required for setting up a palaemon session diff --git a/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionSecurityConfig.java b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionSecurityConfig.java index 86e6aa48..974870f6 100644 --- a/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionSecurityConfig.java +++ b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionSecurityConfig.java @@ -17,18 +17,15 @@ package com.iexec.sms.tee.session.scone; import com.iexec.common.tee.TeeEnclaveProvider; -import com.iexec.sms.tee.EnableIfTeeProvider; -import com.iexec.sms.tee.EnableIfTeeProviderDefinition; +import com.iexec.sms.tee.ConditionalOnTeeProvider; import lombok.Getter; import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; import java.util.List; @Configuration -@Conditional(EnableIfTeeProvider.class) -@EnableIfTeeProviderDefinition(providers = TeeEnclaveProvider.SCONE) +@ConditionalOnTeeProvider(providers = TeeEnclaveProvider.SCONE) public class SconeSessionSecurityConfig { @Value("${tee.scone.attestation.tolerated-insecure-options}") diff --git a/src/main/java/com/iexec/sms/tee/session/scone/cas/CasClient.java b/src/main/java/com/iexec/sms/tee/session/scone/cas/CasClient.java index 87c30898..7832ff94 100644 --- a/src/main/java/com/iexec/sms/tee/session/scone/cas/CasClient.java +++ b/src/main/java/com/iexec/sms/tee/session/scone/cas/CasClient.java @@ -18,9 +18,7 @@ import com.iexec.common.tee.TeeEnclaveProvider; import com.iexec.sms.ssl.TwoWaySslClient; -import com.iexec.sms.tee.EnableIfTeeProvider; -import com.iexec.sms.tee.EnableIfTeeProviderDefinition; -import org.springframework.context.annotation.Conditional; +import com.iexec.sms.tee.ConditionalOnTeeProvider; import org.springframework.http.HttpEntity; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; @@ -28,8 +26,7 @@ import java.nio.charset.StandardCharsets; @Service -@Conditional(EnableIfTeeProvider.class) -@EnableIfTeeProviderDefinition(providers = TeeEnclaveProvider.SCONE) +@ConditionalOnTeeProvider(providers = TeeEnclaveProvider.SCONE) public class CasClient { private final CasConfiguration casConfiguration; diff --git a/src/main/java/com/iexec/sms/tee/session/scone/cas/CasConfiguration.java b/src/main/java/com/iexec/sms/tee/session/scone/cas/CasConfiguration.java index 98f42e4e..efe28130 100644 --- a/src/main/java/com/iexec/sms/tee/session/scone/cas/CasConfiguration.java +++ b/src/main/java/com/iexec/sms/tee/session/scone/cas/CasConfiguration.java @@ -17,13 +17,11 @@ package com.iexec.sms.tee.session.scone.cas; import com.iexec.common.tee.TeeEnclaveProvider; -import com.iexec.sms.tee.EnableIfTeeProvider; -import com.iexec.sms.tee.EnableIfTeeProviderDefinition; +import com.iexec.sms.tee.ConditionalOnTeeProvider; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Conditional; import org.springframework.stereotype.Component; /** @@ -38,8 +36,7 @@ * code. It guarantees that a code behaves exactly as expected. */ @Component -@Conditional(EnableIfTeeProvider.class) -@EnableIfTeeProviderDefinition(providers = TeeEnclaveProvider.SCONE) +@ConditionalOnTeeProvider(providers = TeeEnclaveProvider.SCONE) @Getter @NoArgsConstructor @AllArgsConstructor diff --git a/src/test/java/com/iexec/sms/tee/EnableIfTeeProviderTests.java b/src/test/java/com/iexec/sms/tee/ConditionalOnTeeProviderTests.java similarity index 88% rename from src/test/java/com/iexec/sms/tee/EnableIfTeeProviderTests.java rename to src/test/java/com/iexec/sms/tee/ConditionalOnTeeProviderTests.java index a883ae11..f79668f2 100644 --- a/src/test/java/com/iexec/sms/tee/EnableIfTeeProviderTests.java +++ b/src/test/java/com/iexec/sms/tee/ConditionalOnTeeProviderTests.java @@ -1,5 +1,6 @@ package com.iexec.sms.tee; +import com.iexec.common.tee.TeeEnclaveProvider; import com.iexec.sms.tee.config.GramineInternalServicesConfiguration; import com.iexec.sms.tee.config.SconeInternalServicesConfiguration; import com.iexec.sms.tee.config.TeeInternalServicesConfiguration; @@ -20,10 +21,10 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.springframework.context.annotation.ConditionContext; -import org.springframework.context.annotation.Conditional; import org.springframework.core.env.Environment; import org.springframework.core.type.AnnotationMetadata; +import java.util.Map; import java.util.function.Function; import java.util.stream.Stream; @@ -31,9 +32,8 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.when; -class EnableIfTeeProviderTests { - @Conditional(EnableIfTeeProvider.class) - @EnableIfTeeProviderDefinition(providers = {}) +class ConditionalOnTeeProviderTests { + @ConditionalOnTeeProvider(providers = {}) static class NoProvidersSet {} @Mock @@ -42,7 +42,7 @@ static class NoProvidersSet {} ConditionContext context; @Mock AnnotationMetadata metadata; - EnableIfTeeProvider condition = new EnableIfTeeProvider(); + OnTeeProviderCondition condition = new OnTeeProviderCondition(); @BeforeEach void init() { @@ -89,6 +89,7 @@ void shouldMatchScone(Class clazz) { when(context.getEnvironment()).thenReturn(environment); when(environment.getActiveProfiles()).thenReturn(new String[]{"scone"}); when(metadata.getClassName()).thenReturn(clazz.getName()); + setAttributesForMetadataMock(clazz); assertTrue(condition.matches(context, metadata)); } @@ -99,6 +100,7 @@ void shouldMatchGramine(Class clazz) { when(context.getEnvironment()).thenReturn(environment); when(environment.getActiveProfiles()).thenReturn(new String[]{"gramine"}); when(metadata.getClassName()).thenReturn(clazz.getName()); + setAttributesForMetadataMock(clazz); assertTrue(condition.matches(context, metadata)); } @@ -109,6 +111,7 @@ void shouldMatchSconeAndGramine(Class clazz) { when(context.getEnvironment()).thenReturn(environment); when(environment.getActiveProfiles()).thenReturn(new String[]{"scone", "gramine"}); when(metadata.getClassName()).thenReturn(clazz.getName()); + setAttributesForMetadataMock(clazz); assertTrue(condition.matches(context, metadata)); } @@ -121,6 +124,7 @@ void shouldNotMatchSconeSinceGramineProfile(Class clazz) { when(context.getEnvironment()).thenReturn(environment); when(environment.getActiveProfiles()).thenReturn(new String[]{"gramine"}); when(metadata.getClassName()).thenReturn(clazz.getName()); + setAttributesForMetadataMock(clazz); assertFalse(condition.matches(context, metadata)); } @@ -131,6 +135,7 @@ void shouldNotMatchGramineSinceSconeProfile(Class clazz) { when(context.getEnvironment()).thenReturn(environment); when(environment.getActiveProfiles()).thenReturn(new String[]{"scone"}); when(metadata.getClassName()).thenReturn(clazz.getName()); + setAttributesForMetadataMock(clazz); assertFalse(condition.matches(context, metadata)); } @@ -141,6 +146,7 @@ void shouldNotMatchAnySinceNoProfile(Class clazz) { when(context.getEnvironment()).thenReturn(environment); when(environment.getActiveProfiles()).thenReturn(new String[]{}); when(metadata.getClassName()).thenReturn(clazz.getName()); + setAttributesForMetadataMock(clazz); assertFalse(condition.matches(context, metadata)); } @@ -162,6 +168,7 @@ void shouldNotMatchAnySinceNoProviderDefined() { when(context.getEnvironment()).thenReturn(environment); when(environment.getActiveProfiles()).thenReturn(new String[]{"scone", "gramine"}); when(metadata.getClassName()).thenReturn(clazz.getName()); + setAttributesForMetadataMock(clazz); assertFalse(condition.matches(context, metadata)); } @@ -179,4 +186,11 @@ void shouldNotMatchAnySinceClassDoesNotExist() { // endregion + + void setAttributesForMetadataMock(Class clazz) { + ConditionalOnTeeProvider annotation = clazz.getAnnotation(ConditionalOnTeeProvider.class); + TeeEnclaveProvider[] providers = annotation.providers(); + when(metadata.getAnnotationAttributes(ConditionalOnTeeProvider.class.getName())) + .thenReturn(Map.of("providers", providers)); + } } From 08d3764231b96a97f4e3ff9d3dd1feacce9d8764 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Wed, 7 Sep 2022 15:25:24 +0200 Subject: [PATCH 091/293] Add tests to check TEE beans are correctly loaded --- .../sms/tee/GramineBeansLoadingTests.java | 37 +++++++++++ .../iexec/sms/tee/SconeBeansLoadingTests.java | 45 +++++++++++++ .../iexec/sms/tee/TeeBeansLoadingTests.java | 63 +++++++++++++++++++ .../tee/ConditionalOnTeeProviderTests.java | 3 +- 4 files changed, 146 insertions(+), 2 deletions(-) create mode 100644 src/itest/java/com/iexec/sms/tee/GramineBeansLoadingTests.java create mode 100644 src/itest/java/com/iexec/sms/tee/SconeBeansLoadingTests.java create mode 100644 src/itest/java/com/iexec/sms/tee/TeeBeansLoadingTests.java diff --git a/src/itest/java/com/iexec/sms/tee/GramineBeansLoadingTests.java b/src/itest/java/com/iexec/sms/tee/GramineBeansLoadingTests.java new file mode 100644 index 00000000..045d174c --- /dev/null +++ b/src/itest/java/com/iexec/sms/tee/GramineBeansLoadingTests.java @@ -0,0 +1,37 @@ +package com.iexec.sms.tee; + +import com.iexec.sms.tee.config.GramineInternalServicesConfiguration; +import com.iexec.sms.tee.session.gramine.GramineSessionHandlerService; +import com.iexec.sms.tee.session.gramine.GramineSessionMakerService; +import com.iexec.sms.tee.session.gramine.sps.SpsConfiguration; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.test.context.ActiveProfiles; + + +@ActiveProfiles(profiles = "gramine") +public class GramineBeansLoadingTests extends TeeBeansLoadingTests { + @Autowired + GramineInternalServicesConfiguration gramineInternalServicesConfiguration; + @Autowired + GramineSessionHandlerService gramineSessionHandlerService; + @Autowired + GramineSessionMakerService gramineSessionMakerService; + @Autowired + SpsConfiguration spsConfiguration; + + GramineBeansLoadingTests(@Autowired Environment environment) { + super(environment); + } + + @Test + @Override + void checkTeeBeansAreLoaded() { + Assertions.assertNotNull(gramineInternalServicesConfiguration); + Assertions.assertNotNull(gramineSessionHandlerService); + Assertions.assertNotNull(gramineSessionMakerService); + Assertions.assertNotNull(spsConfiguration); + } +} diff --git a/src/itest/java/com/iexec/sms/tee/SconeBeansLoadingTests.java b/src/itest/java/com/iexec/sms/tee/SconeBeansLoadingTests.java new file mode 100644 index 00000000..c41eb40d --- /dev/null +++ b/src/itest/java/com/iexec/sms/tee/SconeBeansLoadingTests.java @@ -0,0 +1,45 @@ +package com.iexec.sms.tee; + +import com.iexec.sms.tee.config.SconeInternalServicesConfiguration; +import com.iexec.sms.tee.session.scone.SconeSessionHandlerService; +import com.iexec.sms.tee.session.scone.SconeSessionMakerService; +import com.iexec.sms.tee.session.scone.SconeSessionSecurityConfig; +import com.iexec.sms.tee.session.scone.cas.CasClient; +import com.iexec.sms.tee.session.scone.cas.CasConfiguration; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.test.context.ActiveProfiles; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + +@ActiveProfiles(profiles = "scone") +public class SconeBeansLoadingTests extends TeeBeansLoadingTests { + @Autowired + SconeInternalServicesConfiguration sconeInternalServicesConfiguration; + @Autowired + SconeSessionHandlerService sconeSessionHandlerService; + @Autowired + SconeSessionMakerService sconeSessionMakerService; + @Autowired + SconeSessionSecurityConfig sconeSessionSecurityConfig; + @Autowired + CasClient casClient; + @Autowired + CasConfiguration casConfiguration; + + SconeBeansLoadingTests(@Autowired Environment environment) { + super(environment); + } + + @Test + @Override + void checkTeeBeansAreLoaded() { + assertNotNull(sconeInternalServicesConfiguration); + assertNotNull(sconeSessionHandlerService); + assertNotNull(sconeSessionMakerService); + assertNotNull(sconeSessionSecurityConfig); + assertNotNull(casClient); + assertNotNull(casConfiguration); + } +} diff --git a/src/itest/java/com/iexec/sms/tee/TeeBeansLoadingTests.java b/src/itest/java/com/iexec/sms/tee/TeeBeansLoadingTests.java new file mode 100644 index 00000000..c832c8e2 --- /dev/null +++ b/src/itest/java/com/iexec/sms/tee/TeeBeansLoadingTests.java @@ -0,0 +1,63 @@ +package com.iexec.sms.tee; + +import com.iexec.common.tee.TeeEnclaveProvider; +import com.iexec.sms.CommonTestSetup; +import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.data.util.AnnotatedTypeScanner; + +import java.util.Arrays; +import java.util.Set; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * Subclass this class to test whether some TEE beans are correctly loaded. + */ +@Slf4j +public abstract class TeeBeansLoadingTests extends CommonTestSetup { + + final AnnotatedTypeScanner annotatedTypeScanner; + final String[] activeProfiles; + + TeeBeansLoadingTests(@Autowired Environment environment) { + this.annotatedTypeScanner = new AnnotatedTypeScanner(true, ConditionalOnTeeProvider.class); + this.annotatedTypeScanner.setEnvironment(environment); + this.activeProfiles = environment.getActiveProfiles(); + } + + /** + * This will check that, for given active profiles, + * we don't load beans that should be disabled. + */ + @Test + void checkNoUnwantedBeanIsLoaded() { + final Set> sconeClasses = annotatedTypeScanner.findTypes("com", "iexec", "sms"); + for (Class clazz : sconeClasses) { + log.info("{} is loaded", clazz); + final TeeEnclaveProvider[] providers = clazz.getAnnotation(ConditionalOnTeeProvider.class).providers(); + assertTrue( + areProfilesAndProvidersMatching(providers), + clazz.getName() + " should not have been loaded [profiles:" + Arrays.toString(activeProfiles) + "]" + ); + } + } + + private boolean areProfilesAndProvidersMatching(TeeEnclaveProvider[] providers) { + for (TeeEnclaveProvider provider : providers) { + for (String activeProfile : activeProfiles) { + if (provider.name().equalsIgnoreCase(activeProfile)) { + return true; + } + } + } + return false; + } + + /** + * Implement this method to check all beans of given TEE enclave provider are loaded (= not null). + */ + abstract void checkTeeBeansAreLoaded(); +} diff --git a/src/test/java/com/iexec/sms/tee/ConditionalOnTeeProviderTests.java b/src/test/java/com/iexec/sms/tee/ConditionalOnTeeProviderTests.java index f79668f2..a9969099 100644 --- a/src/test/java/com/iexec/sms/tee/ConditionalOnTeeProviderTests.java +++ b/src/test/java/com/iexec/sms/tee/ConditionalOnTeeProviderTests.java @@ -65,8 +65,7 @@ static Stream gramineBeansClasses() { Arguments.of(GramineInternalServicesConfiguration.class), Arguments.of(GramineSessionHandlerService.class), Arguments.of(GramineSessionMakerService.class), - Arguments.of(SpsConfiguration.class), - Arguments.of(GramineInternalServicesConfiguration.class) + Arguments.of(SpsConfiguration.class) ); } From 3f1c62433a06c194c07df11e2f67e6344224ddd7 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Wed, 7 Sep 2022 15:26:11 +0200 Subject: [PATCH 092/293] Fix `TeeTaskComputeSecretIntegrationTests` --- .../secret/compute/TeeTaskComputeSecretIntegrationTests.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/itest/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretIntegrationTests.java b/src/itest/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretIntegrationTests.java index 92a806c6..808a698f 100644 --- a/src/itest/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretIntegrationTests.java +++ b/src/itest/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretIntegrationTests.java @@ -35,6 +35,7 @@ import org.springframework.data.domain.Example; import org.springframework.data.domain.ExampleMatcher; import org.springframework.http.HttpStatus; +import org.springframework.test.context.ActiveProfiles; import org.web3j.crypto.Hash; import java.util.Date; @@ -48,6 +49,7 @@ import static org.mockito.Mockito.when; @Slf4j +@ActiveProfiles("scone") public class TeeTaskComputeSecretIntegrationTests extends CommonTestSetup { private static final String APP_ADDRESS = "0xabcd1339ec7e762e639f4887e2bfe5ee8023e23e"; private static final String UPPER_CASE_APP_ADDRESS = "0xABCD1339EC7E762E639F4887E2BFE5EE8023E23E"; From 317c261926364347a19e903d51ccd4a312d78056 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Wed, 7 Sep 2022 15:33:42 +0200 Subject: [PATCH 093/293] Fix `OnTeeProviderCondition` NPE warning --- .../java/com/iexec/sms/tee/ConditionalOnTeeProvider.java | 2 +- .../java/com/iexec/sms/tee/OnTeeProviderCondition.java | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/iexec/sms/tee/ConditionalOnTeeProvider.java b/src/main/java/com/iexec/sms/tee/ConditionalOnTeeProvider.java index 90bc0b8d..f0d2aa56 100644 --- a/src/main/java/com/iexec/sms/tee/ConditionalOnTeeProvider.java +++ b/src/main/java/com/iexec/sms/tee/ConditionalOnTeeProvider.java @@ -23,5 +23,5 @@ @Retention(RetentionPolicy.RUNTIME) @Conditional(OnTeeProviderCondition.class) public @interface ConditionalOnTeeProvider { - TeeEnclaveProvider[] providers() default {}; + TeeEnclaveProvider[] providers(); } diff --git a/src/main/java/com/iexec/sms/tee/OnTeeProviderCondition.java b/src/main/java/com/iexec/sms/tee/OnTeeProviderCondition.java index 5d08266a..07c38757 100644 --- a/src/main/java/com/iexec/sms/tee/OnTeeProviderCondition.java +++ b/src/main/java/com/iexec/sms/tee/OnTeeProviderCondition.java @@ -25,6 +25,13 @@ public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeM final String[] activeProfiles = context.getEnvironment().getActiveProfiles(); final String beanClassName = ((AnnotationMetadata) metadata).getClassName(); + if (attributes == null) { + log.warn("No attribute for bean annotation, won't be loaded [bean:{}", + beanClassName); + return new ConditionOutcome( + false, + ConditionMessage.forCondition(ConditionalOnTeeProvider.class).didNotFind("any TEE enclave providers").atAll()); + } final TeeEnclaveProvider[] providers = (TeeEnclaveProvider[]) attributes.get("providers"); if (providers == null || providers.length == 0) { From 1da85963a200908925fd26e686ecbce29cbbbe70 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Wed, 7 Sep 2022 16:45:50 +0200 Subject: [PATCH 094/293] Improve test coverage --- .../iexec/sms/api/SmsClientProviderTests.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientProviderTests.java b/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientProviderTests.java index 0c948c60..44b37863 100644 --- a/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientProviderTests.java +++ b/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientProviderTests.java @@ -164,4 +164,22 @@ void shouldNotGetSmsClientForUninitializedTaskWhenNoSmsUrl() { e.getMessage()); } // endregion + + // region purgeTask + @Test + void shouldPurgeTask() { + // Adding a task + smsClientProvider.getOrCreateSmsClientForTask(TASK_DESCRIPTION_1); + + // Purging the task + boolean purged = smsClientProvider.purgeTask(CHAIN_TASK_ID_1); + assertTrue(purged); + } + + @Test + void shouldNotPurgeTaskSinceTaskNeverAccessed() { + boolean purged = smsClientProvider.purgeTask(CHAIN_TASK_ID_1); + assertFalse(purged); + } + // endregion } \ No newline at end of file From 737f0350185fb4f06765505b5d8246dd382b83c5 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Thu, 8 Sep 2022 08:52:04 +0200 Subject: [PATCH 095/293] Rename `SideComputeInternalConfiguration` into `TeeWorkerInternalConfiguration` + update properties name --- ...ava => TeeWorkerInternalConfiguration.java} | 18 +++++++++--------- src/main/resources/application-gramine.yml | 2 +- src/main/resources/application-scone.yml | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) rename src/main/java/com/iexec/sms/tee/config/{SideComputeInternalConfiguration.java => TeeWorkerInternalConfiguration.java} (78%) diff --git a/src/main/java/com/iexec/sms/tee/config/SideComputeInternalConfiguration.java b/src/main/java/com/iexec/sms/tee/config/TeeWorkerInternalConfiguration.java similarity index 78% rename from src/main/java/com/iexec/sms/tee/config/SideComputeInternalConfiguration.java rename to src/main/java/com/iexec/sms/tee/config/TeeWorkerInternalConfiguration.java index de84c98b..753938c1 100644 --- a/src/main/java/com/iexec/sms/tee/config/SideComputeInternalConfiguration.java +++ b/src/main/java/com/iexec/sms/tee/config/TeeWorkerInternalConfiguration.java @@ -10,19 +10,19 @@ import javax.validation.constraints.Positive; @Configuration -public class SideComputeInternalConfiguration { +public class TeeWorkerInternalConfiguration { @Bean TeeAppConfiguration preComputeConfiguration( - @Value("${tee.workflow.pre-compute.image}") + @Value("${tee.worker.pre-compute.image}") @NotBlank(message = "pre-compute image must be provided") String preComputeImage, - @Value("${tee.workflow.pre-compute.fingerprint}") + @Value("${tee.worker.pre-compute.fingerprint}") @NotBlank(message = "pre-compute fingerprint must be provided") String preComputeFingerprint, - @Value("${tee.workflow.pre-compute.entrypoint}") + @Value("${tee.worker.pre-compute.entrypoint}") @NotBlank(message = "pre-compute entrypoint must be provided") String preComputeEntrypoint, - @Value("${tee.workflow.pre-compute.heap-size-gb}") + @Value("${tee.worker.pre-compute.heap-size-gb}") @Positive(message = "pre-compute heap size must be provided") long preComputeHeapSizeInGB) { return new TeeAppConfiguration( @@ -35,16 +35,16 @@ TeeAppConfiguration preComputeConfiguration( @Bean TeeAppConfiguration postComputeConfiguration( - @Value("${tee.workflow.post-compute.image}") + @Value("${tee.worker.post-compute.image}") @NotBlank(message = "post-compute image must be provided") String postComputeImage, - @Value("${tee.workflow.post-compute.fingerprint}") + @Value("${tee.worker.post-compute.fingerprint}") @NotBlank(message = "post-compute fingerprint must be provided") String postComputeFingerprint, - @Value("${tee.workflow.post-compute.entrypoint}") + @Value("${tee.worker.post-compute.entrypoint}") @NotBlank(message = "post-compute entrypoint must be provided") String postComputeEntrypoint, - @Value("${tee.workflow.post-compute.heap-size-gb}") + @Value("${tee.worker.post-compute.heap-size-gb}") @Positive(message = "post-compute heap size must be provided") long postComputeHeapSizeInGB) { return new TeeAppConfiguration( diff --git a/src/main/resources/application-gramine.yml b/src/main/resources/application-gramine.yml index b68bb005..7601c07b 100644 --- a/src/main/resources/application-gramine.yml +++ b/src/main/resources/application-gramine.yml @@ -7,7 +7,7 @@ tee: hostname: ${IEXEC_SECRET_PROVISIONER_ENCLAVE_HOSTNAME:localhost} port: ${IEXEC_SECRET_PROVISIONER_ENCLAVE_PORT:4433} - workflow: + worker: pre-compute: image: ${IEXEC_TEE_WORKER_PRE_COMPUTE_IMAGE:} # e.g.: docker.io/iexechub/tee-worker-pre-compute:x.y.z-production fingerprint: ${IEXEC_TEE_WORKER_PRE_COMPUTE_FINGERPRINT:} diff --git a/src/main/resources/application-scone.yml b/src/main/resources/application-scone.yml index 73c3eeae..a5f2fa05 100644 --- a/src/main/resources/application-scone.yml +++ b/src/main/resources/application-scone.yml @@ -7,7 +7,7 @@ tee: hostname: ${IEXEC_SECRET_PROVISIONER_ENCLAVE_HOSTNAME:localhost} port: ${IEXEC_SECRET_PROVISIONER_ENCLAVE_PORT:18765} - workflow: + worker: pre-compute: image: ${IEXEC_TEE_WORKER_PRE_COMPUTE_IMAGE:} # e.g.: docker.io/iexechub/tee-worker-pre-compute:x.y.z-production fingerprint: ${IEXEC_TEE_WORKER_PRE_COMPUTE_FINGERPRINT:} From a305d6436fcd58eae4590abba97f1d9e560eab5b Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Thu, 8 Sep 2022 08:52:04 +0200 Subject: [PATCH 096/293] Rename `SideComputeInternalConfiguration` into `TeeWorkerInternalConfiguration` + update properties name --- ...ava => TeeWorkerInternalConfiguration.java} | 18 +++++++++--------- src/main/resources/application-gramine.yml | 2 +- src/main/resources/application-scone.yml | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) rename src/main/java/com/iexec/sms/tee/config/{SideComputeInternalConfiguration.java => TeeWorkerInternalConfiguration.java} (78%) diff --git a/src/main/java/com/iexec/sms/tee/config/SideComputeInternalConfiguration.java b/src/main/java/com/iexec/sms/tee/config/TeeWorkerInternalConfiguration.java similarity index 78% rename from src/main/java/com/iexec/sms/tee/config/SideComputeInternalConfiguration.java rename to src/main/java/com/iexec/sms/tee/config/TeeWorkerInternalConfiguration.java index de84c98b..753938c1 100644 --- a/src/main/java/com/iexec/sms/tee/config/SideComputeInternalConfiguration.java +++ b/src/main/java/com/iexec/sms/tee/config/TeeWorkerInternalConfiguration.java @@ -10,19 +10,19 @@ import javax.validation.constraints.Positive; @Configuration -public class SideComputeInternalConfiguration { +public class TeeWorkerInternalConfiguration { @Bean TeeAppConfiguration preComputeConfiguration( - @Value("${tee.workflow.pre-compute.image}") + @Value("${tee.worker.pre-compute.image}") @NotBlank(message = "pre-compute image must be provided") String preComputeImage, - @Value("${tee.workflow.pre-compute.fingerprint}") + @Value("${tee.worker.pre-compute.fingerprint}") @NotBlank(message = "pre-compute fingerprint must be provided") String preComputeFingerprint, - @Value("${tee.workflow.pre-compute.entrypoint}") + @Value("${tee.worker.pre-compute.entrypoint}") @NotBlank(message = "pre-compute entrypoint must be provided") String preComputeEntrypoint, - @Value("${tee.workflow.pre-compute.heap-size-gb}") + @Value("${tee.worker.pre-compute.heap-size-gb}") @Positive(message = "pre-compute heap size must be provided") long preComputeHeapSizeInGB) { return new TeeAppConfiguration( @@ -35,16 +35,16 @@ TeeAppConfiguration preComputeConfiguration( @Bean TeeAppConfiguration postComputeConfiguration( - @Value("${tee.workflow.post-compute.image}") + @Value("${tee.worker.post-compute.image}") @NotBlank(message = "post-compute image must be provided") String postComputeImage, - @Value("${tee.workflow.post-compute.fingerprint}") + @Value("${tee.worker.post-compute.fingerprint}") @NotBlank(message = "post-compute fingerprint must be provided") String postComputeFingerprint, - @Value("${tee.workflow.post-compute.entrypoint}") + @Value("${tee.worker.post-compute.entrypoint}") @NotBlank(message = "post-compute entrypoint must be provided") String postComputeEntrypoint, - @Value("${tee.workflow.post-compute.heap-size-gb}") + @Value("${tee.worker.post-compute.heap-size-gb}") @Positive(message = "post-compute heap size must be provided") long postComputeHeapSizeInGB) { return new TeeAppConfiguration( diff --git a/src/main/resources/application-gramine.yml b/src/main/resources/application-gramine.yml index b68bb005..7601c07b 100644 --- a/src/main/resources/application-gramine.yml +++ b/src/main/resources/application-gramine.yml @@ -7,7 +7,7 @@ tee: hostname: ${IEXEC_SECRET_PROVISIONER_ENCLAVE_HOSTNAME:localhost} port: ${IEXEC_SECRET_PROVISIONER_ENCLAVE_PORT:4433} - workflow: + worker: pre-compute: image: ${IEXEC_TEE_WORKER_PRE_COMPUTE_IMAGE:} # e.g.: docker.io/iexechub/tee-worker-pre-compute:x.y.z-production fingerprint: ${IEXEC_TEE_WORKER_PRE_COMPUTE_FINGERPRINT:} diff --git a/src/main/resources/application-scone.yml b/src/main/resources/application-scone.yml index 73c3eeae..a5f2fa05 100644 --- a/src/main/resources/application-scone.yml +++ b/src/main/resources/application-scone.yml @@ -7,7 +7,7 @@ tee: hostname: ${IEXEC_SECRET_PROVISIONER_ENCLAVE_HOSTNAME:localhost} port: ${IEXEC_SECRET_PROVISIONER_ENCLAVE_PORT:18765} - workflow: + worker: pre-compute: image: ${IEXEC_TEE_WORKER_PRE_COMPUTE_IMAGE:} # e.g.: docker.io/iexechub/tee-worker-pre-compute:x.y.z-production fingerprint: ${IEXEC_TEE_WORKER_PRE_COMPUTE_FINGERPRINT:} From 488bc010e370f2bcdce39bc5f38371751afa47b9 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Thu, 8 Sep 2022 09:58:07 +0200 Subject: [PATCH 097/293] Clean SMS integration tests --- .../java/com/iexec/sms/CommonTestSetup.java | 11 ------- .../com/iexec/sms/MockChainConfiguration.java | 20 ++++++++++++ .../com/iexec/sms/MockTeeConfiguration.java | 31 +++++++++++++++++++ .../TeeTaskComputeSecretIntegrationTests.java | 8 ++++- .../iexec/sms/tee/TeeBeansLoadingTests.java | 3 ++ src/itest/resources/application-test.yml | 11 ------- 6 files changed, 61 insertions(+), 23 deletions(-) create mode 100644 src/itest/java/com/iexec/sms/MockChainConfiguration.java create mode 100644 src/itest/java/com/iexec/sms/MockTeeConfiguration.java diff --git a/src/itest/java/com/iexec/sms/CommonTestSetup.java b/src/itest/java/com/iexec/sms/CommonTestSetup.java index ea333f8c..0fccb7ba 100644 --- a/src/itest/java/com/iexec/sms/CommonTestSetup.java +++ b/src/itest/java/com/iexec/sms/CommonTestSetup.java @@ -16,10 +16,7 @@ package com.iexec.sms; -import com.iexec.sms.blockchain.IexecHubService; -import com.iexec.sms.blockchain.Web3jService; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.boot.web.server.LocalServerPort; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.TestPropertySource; @@ -31,12 +28,4 @@ public abstract class CommonTestSetup { @LocalServerPort protected int randomServerPort; - - // region Following beans are mocked as they use the blockchain - @MockBean - protected IexecHubService iexecHubService; - - @MockBean - protected Web3jService web3jService; - // endregion } diff --git a/src/itest/java/com/iexec/sms/MockChainConfiguration.java b/src/itest/java/com/iexec/sms/MockChainConfiguration.java new file mode 100644 index 00000000..5467c3fb --- /dev/null +++ b/src/itest/java/com/iexec/sms/MockChainConfiguration.java @@ -0,0 +1,20 @@ +package com.iexec.sms; + +import com.iexec.sms.blockchain.IexecHubService; +import com.iexec.sms.blockchain.Web3jService; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; + +import static com.iexec.sms.MockChainConfiguration.MOCK_CHAIN_PROFILE; + +@Configuration +@Profile(MOCK_CHAIN_PROFILE) +public class MockChainConfiguration { + public static final String MOCK_CHAIN_PROFILE = "mock-chain"; + + @MockBean + protected IexecHubService iexecHubService; + @MockBean + protected Web3jService web3jService; +} diff --git a/src/itest/java/com/iexec/sms/MockTeeConfiguration.java b/src/itest/java/com/iexec/sms/MockTeeConfiguration.java new file mode 100644 index 00000000..feed81f7 --- /dev/null +++ b/src/itest/java/com/iexec/sms/MockTeeConfiguration.java @@ -0,0 +1,31 @@ +package com.iexec.sms; + +import com.iexec.sms.api.config.TeeAppConfiguration; +import com.iexec.sms.api.config.TeeServicesConfiguration; +import com.iexec.sms.tee.config.TeeInternalServicesConfiguration; +import com.iexec.sms.tee.session.generic.TeeSessionHandler; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; + +import static com.iexec.sms.MockTeeConfiguration.MOCK_TEE_PROFILE; + +@Configuration +@Profile(MOCK_TEE_PROFILE) +public class MockTeeConfiguration { + public static final String MOCK_TEE_PROFILE = "mock-tee"; + + @MockBean + private TeeSessionHandler teeSessionHandler; + @MockBean + private TeeInternalServicesConfiguration teeInternalServicesConfiguration; + @MockBean + private TeeServicesConfiguration teeServicesConfiguration; + @MockBean + @Qualifier("preComputeConfiguration") + private TeeAppConfiguration preComputeConfiguration; + @MockBean + @Qualifier("postComputeConfiguration") + private TeeAppConfiguration postComputeConfiguration; +} diff --git a/src/itest/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretIntegrationTests.java b/src/itest/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretIntegrationTests.java index 808a698f..d1742e7c 100644 --- a/src/itest/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretIntegrationTests.java +++ b/src/itest/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretIntegrationTests.java @@ -21,6 +21,7 @@ import com.iexec.sms.CommonTestSetup; import com.iexec.sms.api.SmsClient; import com.iexec.sms.api.SmsClientBuilder; +import com.iexec.sms.blockchain.IexecHubService; import com.iexec.sms.encryption.EncryptionService; import feign.FeignException; import feign.Logger; @@ -45,11 +46,13 @@ import java.util.stream.Collectors; import static com.iexec.common.utils.SignatureUtils.signMessageHashAndGetSignature; +import static com.iexec.sms.MockChainConfiguration.MOCK_CHAIN_PROFILE; +import static com.iexec.sms.MockTeeConfiguration.MOCK_TEE_PROFILE; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @Slf4j -@ActiveProfiles("scone") +@ActiveProfiles({MOCK_TEE_PROFILE, MOCK_CHAIN_PROFILE}) public class TeeTaskComputeSecretIntegrationTests extends CommonTestSetup { private static final String APP_ADDRESS = "0xabcd1339ec7e762e639f4887e2bfe5ee8023e23e"; private static final String UPPER_CASE_APP_ADDRESS = "0xABCD1339EC7E762E639F4887E2BFE5EE8023E23E"; @@ -68,6 +71,9 @@ public class TeeTaskComputeSecretIntegrationTests extends CommonTestSetup { @Autowired private TeeTaskComputeSecretRepository repository; + @Autowired + private IexecHubService iexecHubService; + /* * Generate random ASCII from seed for re-testability. * See also {@link org.apache.commons.lang3.RandomStringUtils#randomAscii(int)} diff --git a/src/itest/java/com/iexec/sms/tee/TeeBeansLoadingTests.java b/src/itest/java/com/iexec/sms/tee/TeeBeansLoadingTests.java index c832c8e2..42d7b8f2 100644 --- a/src/itest/java/com/iexec/sms/tee/TeeBeansLoadingTests.java +++ b/src/itest/java/com/iexec/sms/tee/TeeBeansLoadingTests.java @@ -7,16 +7,19 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.env.Environment; import org.springframework.data.util.AnnotatedTypeScanner; +import org.springframework.test.context.ActiveProfiles; import java.util.Arrays; import java.util.Set; +import static com.iexec.sms.MockChainConfiguration.MOCK_CHAIN_PROFILE; import static org.junit.jupiter.api.Assertions.assertTrue; /** * Subclass this class to test whether some TEE beans are correctly loaded. */ @Slf4j +@ActiveProfiles(MOCK_CHAIN_PROFILE) public abstract class TeeBeansLoadingTests extends CommonTestSetup { final AnnotatedTypeScanner annotatedTypeScanner; diff --git a/src/itest/resources/application-test.yml b/src/itest/resources/application-test.yml index 530fded3..71470e34 100644 --- a/src/itest/resources/application-test.yml +++ b/src/itest/resources/application-test.yml @@ -10,14 +10,3 @@ spring: datasource: url: jdbc:h2:mem:db -# `TeeWorkflowConfiguration` needs some dummy value to be instantiated -tee: - scone: - las-image: "none" - workflow: - pre-compute: - image: "none" - fingerprint: "none" - post-compute: - image: "none" - fingerprint: "none" From 0fdff7593fbfe8cc4dda152e6c956a41a76818ba Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Thu, 8 Sep 2022 14:01:25 +0200 Subject: [PATCH 098/293] Rename `TeeServicesConfiguration` into `TeeServicesProperties` Same for all inherited POJO classes --- .../java/com/iexec/sms/api/SmsClient.java | 12 +++--- ...on.java => GramineServicesProperties.java} | 8 ++-- .../config/SconeServicesConfiguration.java | 22 ---------- .../api/config/SconeServicesProperties.java | 22 ++++++++++ ...nfiguration.java => TeeAppProperties.java} | 2 +- ...ration.java => TeeServicesProperties.java} | 8 ++-- .../com/iexec/sms/api/SmsClientTests.java | 28 ++++++------- .../com/iexec/sms/MockTeeConfiguration.java | 10 ++--- .../java/com/iexec/sms/tee/TeeController.java | 6 +-- .../GramineInternalServicesConfiguration.java | 16 +++---- .../SconeInternalServicesConfiguration.java | 16 +++---- .../TeeInternalServicesConfiguration.java | 4 +- .../TeeWorkerInternalConfiguration.java | 10 ++--- .../base/SecretSessionBaseService.java | 10 ++--- .../gramine/GramineSessionMakerService.java | 8 ++-- .../scone/SconeSessionMakerService.java | 10 ++--- .../com/iexec/sms/tee/TeeControllerTests.java | 42 +++++++++---------- .../base/SecretSessionBaseServiceTests.java | 14 +++---- .../GramineSessionMakerServiceTests.java | 10 ++--- .../scone/SconeSessionMakerServiceTests.java | 10 ++--- 20 files changed, 134 insertions(+), 134 deletions(-) rename iexec-sms-library/src/main/java/com/iexec/sms/api/config/{GramineServicesConfiguration.java => GramineServicesProperties.java} (50%) delete mode 100644 iexec-sms-library/src/main/java/com/iexec/sms/api/config/SconeServicesConfiguration.java create mode 100644 iexec-sms-library/src/main/java/com/iexec/sms/api/config/SconeServicesProperties.java rename iexec-sms-library/src/main/java/com/iexec/sms/api/config/{TeeAppConfiguration.java => TeeAppProperties.java} (91%) rename iexec-sms-library/src/main/java/com/iexec/sms/api/config/{TeeServicesConfiguration.java => TeeServicesProperties.java} (60%) diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java index 8f8e813c..f563f821 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java @@ -20,9 +20,9 @@ import com.iexec.common.sms.secret.SmsSecretResponse; import com.iexec.common.tee.TeeEnclaveProvider; import com.iexec.common.web.ApiResponseBody; -import com.iexec.sms.api.config.GramineServicesConfiguration; -import com.iexec.sms.api.config.SconeServicesConfiguration; -import com.iexec.sms.api.config.TeeServicesConfiguration; +import com.iexec.sms.api.config.GramineServicesProperties; +import com.iexec.sms.api.config.SconeServicesProperties; +import com.iexec.sms.api.config.TeeServicesProperties; import feign.Headers; import feign.Param; import feign.RequestLine; @@ -108,12 +108,12 @@ ApiResponseBody generat TeeEnclaveProvider getTeeEnclaveProvider(); @RequestLine("GET /tee/config/scone") - SconeServicesConfiguration getSconeServicesConfiguration(); + SconeServicesProperties getSconeServicesConfiguration(); @RequestLine("GET /tee/config/gramine") - GramineServicesConfiguration getGramineServicesConfiguration(); + GramineServicesProperties getGramineServicesConfiguration(); - default T getTeeServicesConfiguration(TeeEnclaveProvider teeEnclaveProvider) { + default T getTeeServicesConfiguration(TeeEnclaveProvider teeEnclaveProvider) { if (teeEnclaveProvider == TeeEnclaveProvider.SCONE) { return (T) getSconeServicesConfiguration(); } else if (teeEnclaveProvider == TeeEnclaveProvider.GRAMINE) { diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/GramineServicesConfiguration.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/GramineServicesProperties.java similarity index 50% rename from iexec-sms-library/src/main/java/com/iexec/sms/api/config/GramineServicesConfiguration.java rename to iexec-sms-library/src/main/java/com/iexec/sms/api/config/GramineServicesProperties.java index 404f124f..1e344905 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/GramineServicesConfiguration.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/GramineServicesProperties.java @@ -6,14 +6,14 @@ @Getter @Setter -public class GramineServicesConfiguration extends TeeServicesConfiguration { +public class GramineServicesProperties extends TeeServicesProperties { - public GramineServicesConfiguration() { + public GramineServicesProperties() { super(TeeEnclaveProvider.GRAMINE); } - public GramineServicesConfiguration(TeeAppConfiguration preComputeConfiguration, - TeeAppConfiguration postComputeConfiguration) { + public GramineServicesProperties(TeeAppProperties preComputeConfiguration, + TeeAppProperties postComputeConfiguration) { super(TeeEnclaveProvider.GRAMINE, preComputeConfiguration, postComputeConfiguration); } } diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/SconeServicesConfiguration.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/SconeServicesConfiguration.java deleted file mode 100644 index 8adc2b57..00000000 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/SconeServicesConfiguration.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.iexec.sms.api.config; - -import com.iexec.common.tee.TeeEnclaveProvider; -import lombok.Getter; -import lombok.Setter; - -@Getter -@Setter -public class SconeServicesConfiguration extends TeeServicesConfiguration { - private String lasImage; - - public SconeServicesConfiguration() { - super(TeeEnclaveProvider.SCONE); - } - - public SconeServicesConfiguration(TeeAppConfiguration preComputeConfiguration, - TeeAppConfiguration postComputeConfiguration, - String lasImage) { - super(TeeEnclaveProvider.SCONE, preComputeConfiguration, postComputeConfiguration); - this.lasImage = lasImage; - } -} diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/SconeServicesProperties.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/SconeServicesProperties.java new file mode 100644 index 00000000..1a305d7f --- /dev/null +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/SconeServicesProperties.java @@ -0,0 +1,22 @@ +package com.iexec.sms.api.config; + +import com.iexec.common.tee.TeeEnclaveProvider; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class SconeServicesProperties extends TeeServicesProperties { + private String lasImage; + + public SconeServicesProperties() { + super(TeeEnclaveProvider.SCONE); + } + + public SconeServicesProperties(TeeAppProperties preComputeProperties, + TeeAppProperties postComputeProperties, + String lasImage) { + super(TeeEnclaveProvider.SCONE, preComputeProperties, postComputeProperties); + this.lasImage = lasImage; + } +} diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeAppConfiguration.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeAppProperties.java similarity index 91% rename from iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeAppConfiguration.java rename to iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeAppProperties.java index ac1e4117..62e6c4f9 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeAppConfiguration.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeAppProperties.java @@ -9,7 +9,7 @@ @AllArgsConstructor @Getter @Setter -public class TeeAppConfiguration { +public class TeeAppProperties { private String image; private String fingerprint; private String entrypoint; diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeServicesConfiguration.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeServicesProperties.java similarity index 60% rename from iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeServicesConfiguration.java rename to iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeServicesProperties.java index cdf154b5..72e4279d 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeServicesConfiguration.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeServicesProperties.java @@ -10,12 +10,12 @@ @AllArgsConstructor @Getter @Setter -public abstract class TeeServicesConfiguration { +public abstract class TeeServicesProperties { private TeeEnclaveProvider teeEnclaveProvider; - private TeeAppConfiguration preComputeConfiguration; - private TeeAppConfiguration postComputeConfiguration; + private TeeAppProperties preComputeProperties; + private TeeAppProperties postComputeProperties; - TeeServicesConfiguration(TeeEnclaveProvider teeEnclaveProvider) { + TeeServicesProperties(TeeEnclaveProvider teeEnclaveProvider) { this.teeEnclaveProvider = teeEnclaveProvider; } } diff --git a/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientTests.java b/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientTests.java index 3050f62a..79d62535 100644 --- a/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientTests.java +++ b/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientTests.java @@ -17,10 +17,10 @@ package com.iexec.sms.api; import com.iexec.common.tee.TeeEnclaveProvider; -import com.iexec.sms.api.config.GramineServicesConfiguration; -import com.iexec.sms.api.config.SconeServicesConfiguration; -import com.iexec.sms.api.config.TeeAppConfiguration; -import com.iexec.sms.api.config.TeeServicesConfiguration; +import com.iexec.sms.api.config.GramineServicesProperties; +import com.iexec.sms.api.config.SconeServicesProperties; +import com.iexec.sms.api.config.TeeAppProperties; +import com.iexec.sms.api.config.TeeServicesProperties; import org.junit.jupiter.api.Test; import org.mockito.Mock; @@ -33,15 +33,15 @@ class SmsClientTests { private static final String LAS_IMAGE = "lasImage"; @Mock - TeeAppConfiguration preComputeConfig; + TeeAppProperties preComputeConfig; @Mock - TeeAppConfiguration postComputeConfig; + TeeAppProperties postComputeConfig; // region getTeeServicesConfiguration @Test void shouldGetSconeServicesConfiguration() { final SmsClient smsClient = spy(SmsClient.class); - final SconeServicesConfiguration config = new SconeServicesConfiguration( + final SconeServicesProperties config = new SconeServicesProperties( preComputeConfig, postComputeConfig, LAS_IMAGE @@ -49,26 +49,26 @@ void shouldGetSconeServicesConfiguration() { when(smsClient.getSconeServicesConfiguration()).thenReturn(config); - final TeeServicesConfiguration teeServicesConfiguration = + final TeeServicesProperties teeServicesProperties = smsClient.getTeeServicesConfiguration(TeeEnclaveProvider.SCONE); - assertEquals(config, teeServicesConfiguration); + assertEquals(config, teeServicesProperties); } @Test void shouldGetGramineServicesConfiguration() { final SmsClient smsClient = spy(SmsClient.class); - final GramineServicesConfiguration config = new GramineServicesConfiguration( + final GramineServicesProperties config = new GramineServicesProperties( preComputeConfig, postComputeConfig ); when(smsClient.getGramineServicesConfiguration()).thenReturn(config); - final TeeServicesConfiguration teeServicesConfiguration = + final TeeServicesProperties teeServicesProperties = smsClient.getTeeServicesConfiguration(TeeEnclaveProvider.GRAMINE); - assertEquals(config, teeServicesConfiguration); + assertEquals(config, teeServicesProperties); } @Test @@ -77,10 +77,10 @@ void shouldNotGetTeeServicesConfigurationSinceUnknownProvider() { when(smsClient.getGramineServicesConfiguration()).thenReturn(null); - final TeeServicesConfiguration teeServicesConfiguration = + final TeeServicesProperties teeServicesProperties = smsClient.getTeeServicesConfiguration(TeeEnclaveProvider.GRAMINE); - assertNull(teeServicesConfiguration); + assertNull(teeServicesProperties); } // endregion } diff --git a/src/itest/java/com/iexec/sms/MockTeeConfiguration.java b/src/itest/java/com/iexec/sms/MockTeeConfiguration.java index feed81f7..9d50d4a6 100644 --- a/src/itest/java/com/iexec/sms/MockTeeConfiguration.java +++ b/src/itest/java/com/iexec/sms/MockTeeConfiguration.java @@ -1,7 +1,7 @@ package com.iexec.sms; -import com.iexec.sms.api.config.TeeAppConfiguration; -import com.iexec.sms.api.config.TeeServicesConfiguration; +import com.iexec.sms.api.config.TeeAppProperties; +import com.iexec.sms.api.config.TeeServicesProperties; import com.iexec.sms.tee.config.TeeInternalServicesConfiguration; import com.iexec.sms.tee.session.generic.TeeSessionHandler; import org.springframework.beans.factory.annotation.Qualifier; @@ -21,11 +21,11 @@ public class MockTeeConfiguration { @MockBean private TeeInternalServicesConfiguration teeInternalServicesConfiguration; @MockBean - private TeeServicesConfiguration teeServicesConfiguration; + private TeeServicesProperties teeServicesProperties; @MockBean @Qualifier("preComputeConfiguration") - private TeeAppConfiguration preComputeConfiguration; + private TeeAppProperties preComputeConfiguration; @MockBean @Qualifier("postComputeConfiguration") - private TeeAppConfiguration postComputeConfiguration; + private TeeAppProperties postComputeConfiguration; } diff --git a/src/main/java/com/iexec/sms/tee/TeeController.java b/src/main/java/com/iexec/sms/tee/TeeController.java index a887a965..15be3fab 100644 --- a/src/main/java/com/iexec/sms/tee/TeeController.java +++ b/src/main/java/com/iexec/sms/tee/TeeController.java @@ -22,7 +22,7 @@ import com.iexec.common.web.ApiResponseBody; import com.iexec.sms.api.TeeSessionGenerationError; import com.iexec.sms.api.TeeSessionGenerationResponse; -import com.iexec.sms.api.config.TeeServicesConfiguration; +import com.iexec.sms.api.config.TeeServicesProperties; import com.iexec.sms.authorization.AuthorizationError; import com.iexec.sms.authorization.AuthorizationService; import com.iexec.sms.tee.challenge.TeeChallenge; @@ -90,14 +90,14 @@ public ResponseEntity getTeeEnclaveProvider() { * heap size, ...) */ @GetMapping("/config/{teeEnclaveProvider}") - public ResponseEntity getTeeServicesConfig( + public ResponseEntity getTeeServicesConfig( @PathVariable TeeEnclaveProvider teeEnclaveProvider) { if (teeEnclaveProvider != teeServicesConfig.getTeeEnclaveProvider()) { log.error("SMS configured to use another TeeEnclaveProvider " + "[required:{}, actual:{}]", teeEnclaveProvider, teeServicesConfig.getTeeEnclaveProvider()); return ResponseEntity.status(HttpStatus.CONFLICT).build(); } - return ResponseEntity.ok(teeServicesConfig.getShareableConfiguration()); + return ResponseEntity.ok(teeServicesConfig.getProperties()); } /** diff --git a/src/main/java/com/iexec/sms/tee/config/GramineInternalServicesConfiguration.java b/src/main/java/com/iexec/sms/tee/config/GramineInternalServicesConfiguration.java index 81bead1b..27d8a9bb 100644 --- a/src/main/java/com/iexec/sms/tee/config/GramineInternalServicesConfiguration.java +++ b/src/main/java/com/iexec/sms/tee/config/GramineInternalServicesConfiguration.java @@ -1,9 +1,9 @@ package com.iexec.sms.tee.config; import com.iexec.common.tee.TeeEnclaveProvider; -import com.iexec.sms.api.config.GramineServicesConfiguration; -import com.iexec.sms.api.config.TeeAppConfiguration; -import com.iexec.sms.api.config.TeeServicesConfiguration; +import com.iexec.sms.api.config.GramineServicesProperties; +import com.iexec.sms.api.config.TeeAppProperties; +import com.iexec.sms.api.config.TeeServicesProperties; import com.iexec.sms.tee.ConditionalOnTeeProvider; import lombok.Getter; import org.springframework.context.annotation.Configuration; @@ -12,16 +12,16 @@ @ConditionalOnTeeProvider(providers = TeeEnclaveProvider.GRAMINE) @Getter public class GramineInternalServicesConfiguration - extends GramineServicesConfiguration + extends GramineServicesProperties implements TeeInternalServicesConfiguration { public GramineInternalServicesConfiguration( - TeeAppConfiguration preComputeConfiguration, - TeeAppConfiguration postComputeConfiguration) { + TeeAppProperties preComputeConfiguration, + TeeAppProperties postComputeConfiguration) { super(preComputeConfiguration, postComputeConfiguration); } @Override - public TeeServicesConfiguration getShareableConfiguration() { - return new GramineServicesConfiguration(getPreComputeConfiguration(), getPostComputeConfiguration()); + public TeeServicesProperties getProperties() { + return new GramineServicesProperties(getPreComputeProperties(), getPostComputeProperties()); } } diff --git a/src/main/java/com/iexec/sms/tee/config/SconeInternalServicesConfiguration.java b/src/main/java/com/iexec/sms/tee/config/SconeInternalServicesConfiguration.java index db8e5550..a388b932 100644 --- a/src/main/java/com/iexec/sms/tee/config/SconeInternalServicesConfiguration.java +++ b/src/main/java/com/iexec/sms/tee/config/SconeInternalServicesConfiguration.java @@ -1,9 +1,9 @@ package com.iexec.sms.tee.config; import com.iexec.common.tee.TeeEnclaveProvider; -import com.iexec.sms.api.config.SconeServicesConfiguration; -import com.iexec.sms.api.config.TeeAppConfiguration; -import com.iexec.sms.api.config.TeeServicesConfiguration; +import com.iexec.sms.api.config.SconeServicesProperties; +import com.iexec.sms.api.config.TeeAppProperties; +import com.iexec.sms.api.config.TeeServicesProperties; import com.iexec.sms.tee.ConditionalOnTeeProvider; import lombok.Getter; import org.springframework.beans.factory.annotation.Value; @@ -15,11 +15,11 @@ @ConditionalOnTeeProvider(providers = TeeEnclaveProvider.SCONE) @Getter public class SconeInternalServicesConfiguration - extends SconeServicesConfiguration + extends SconeServicesProperties implements TeeInternalServicesConfiguration{ public SconeInternalServicesConfiguration( - TeeAppConfiguration preComputeConfiguration, - TeeAppConfiguration postComputeConfiguration, + TeeAppProperties preComputeConfiguration, + TeeAppProperties postComputeConfiguration, @Value("${tee.scone.las-image}") @NotBlank(message = "las image must be provided") String lasImage) { @@ -27,7 +27,7 @@ public SconeInternalServicesConfiguration( } @Override - public TeeServicesConfiguration getShareableConfiguration() { - return new SconeServicesConfiguration(getPreComputeConfiguration(), getPostComputeConfiguration(), getLasImage()); + public TeeServicesProperties getProperties() { + return new SconeServicesProperties(getPreComputeProperties(), getPostComputeProperties(), getLasImage()); } } diff --git a/src/main/java/com/iexec/sms/tee/config/TeeInternalServicesConfiguration.java b/src/main/java/com/iexec/sms/tee/config/TeeInternalServicesConfiguration.java index 35bb8702..e0f1b9ac 100644 --- a/src/main/java/com/iexec/sms/tee/config/TeeInternalServicesConfiguration.java +++ b/src/main/java/com/iexec/sms/tee/config/TeeInternalServicesConfiguration.java @@ -1,9 +1,9 @@ package com.iexec.sms.tee.config; import com.iexec.common.tee.TeeEnclaveProvider; -import com.iexec.sms.api.config.TeeServicesConfiguration; +import com.iexec.sms.api.config.TeeServicesProperties; public interface TeeInternalServicesConfiguration { TeeEnclaveProvider getTeeEnclaveProvider(); - TeeServicesConfiguration getShareableConfiguration(); + TeeServicesProperties getProperties(); } diff --git a/src/main/java/com/iexec/sms/tee/config/TeeWorkerInternalConfiguration.java b/src/main/java/com/iexec/sms/tee/config/TeeWorkerInternalConfiguration.java index 753938c1..ebb18b47 100644 --- a/src/main/java/com/iexec/sms/tee/config/TeeWorkerInternalConfiguration.java +++ b/src/main/java/com/iexec/sms/tee/config/TeeWorkerInternalConfiguration.java @@ -1,6 +1,6 @@ package com.iexec.sms.tee.config; -import com.iexec.sms.api.config.TeeAppConfiguration; +import com.iexec.sms.api.config.TeeAppProperties; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -12,7 +12,7 @@ @Configuration public class TeeWorkerInternalConfiguration { @Bean - TeeAppConfiguration preComputeConfiguration( + TeeAppProperties preComputeConfiguration( @Value("${tee.worker.pre-compute.image}") @NotBlank(message = "pre-compute image must be provided") String preComputeImage, @@ -25,7 +25,7 @@ TeeAppConfiguration preComputeConfiguration( @Value("${tee.worker.pre-compute.heap-size-gb}") @Positive(message = "pre-compute heap size must be provided") long preComputeHeapSizeInGB) { - return new TeeAppConfiguration( + return new TeeAppProperties( preComputeImage, preComputeFingerprint, preComputeEntrypoint, @@ -34,7 +34,7 @@ TeeAppConfiguration preComputeConfiguration( } @Bean - TeeAppConfiguration postComputeConfiguration( + TeeAppProperties postComputeConfiguration( @Value("${tee.worker.post-compute.image}") @NotBlank(message = "post-compute image must be provided") String postComputeImage, @@ -47,7 +47,7 @@ TeeAppConfiguration postComputeConfiguration( @Value("${tee.worker.post-compute.heap-size-gb}") @Positive(message = "post-compute heap size must be provided") long postComputeHeapSizeInGB) { - return new TeeAppConfiguration( + return new TeeAppProperties( postComputeImage, postComputeFingerprint, postComputeEntrypoint, diff --git a/src/main/java/com/iexec/sms/tee/session/base/SecretSessionBaseService.java b/src/main/java/com/iexec/sms/tee/session/base/SecretSessionBaseService.java index faf26f67..b7e9b58a 100644 --- a/src/main/java/com/iexec/sms/tee/session/base/SecretSessionBaseService.java +++ b/src/main/java/com/iexec/sms/tee/session/base/SecretSessionBaseService.java @@ -20,7 +20,7 @@ import com.iexec.common.tee.TeeEnclaveConfiguration; import com.iexec.common.utils.IexecEnvUtils; import com.iexec.common.utils.IexecFileHelper; -import com.iexec.sms.api.config.TeeServicesConfiguration; +import com.iexec.sms.api.config.TeeServicesProperties; import com.iexec.sms.secret.Secret; import com.iexec.sms.secret.compute.OnChainObjectType; import com.iexec.sms.secret.compute.SecretOwnerRole; @@ -69,14 +69,14 @@ public class SecretSessionBaseService { private final Web3SecretService web3SecretService; private final Web2SecretsService web2SecretsService; private final TeeChallengeService teeChallengeService; - private final TeeServicesConfiguration teeServicesConfig; + private final TeeServicesProperties teeServicesConfig; private final TeeTaskComputeSecretService teeTaskComputeSecretService; public SecretSessionBaseService( Web3SecretService web3SecretService, Web2SecretsService web2SecretsService, TeeChallengeService teeChallengeService, - TeeServicesConfiguration teeServicesConfig, + TeeServicesProperties teeServicesConfig, TeeTaskComputeSecretService teeTaskComputeSecretService) { this.web3SecretService = web3SecretService; this.web2SecretsService = web2SecretsService; @@ -130,7 +130,7 @@ public SecretEnclaveBase getPreComputeTokens(TeeSessionRequest request) Map tokens = new HashMap<>(); TaskDescription taskDescription = request.getTaskDescription(); String taskId = taskDescription.getChainTaskId(); - enclaveBase.mrenclave(teeServicesConfig.getPreComputeConfiguration().getFingerprint()); + enclaveBase.mrenclave(teeServicesConfig.getPreComputeProperties().getFingerprint()); tokens.put(IEXEC_PRE_COMPUTE_OUT, IexecFileHelper.SLASH_IEXEC_IN); // `IS_DATASET_REQUIRED` still meaningful? tokens.put(IS_DATASET_REQUIRED, taskDescription.containsDataset()); @@ -274,7 +274,7 @@ public SecretEnclaveBase getPostComputeTokens(TeeSessionRequest request) throws TeeSessionGenerationException { SecretEnclaveBaseBuilder enclaveBase = SecretEnclaveBase.builder() .name("post-compute") - .mrenclave(teeServicesConfig.getPostComputeConfiguration().getFingerprint()); + .mrenclave(teeServicesConfig.getPostComputeProperties().getFingerprint()); Map tokens = new HashMap<>(); TaskDescription taskDescription = request.getTaskDescription(); if (taskDescription == null) { diff --git a/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerService.java b/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerService.java index 5f2b1754..dbad4a69 100644 --- a/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerService.java +++ b/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerService.java @@ -17,7 +17,7 @@ package com.iexec.sms.tee.session.gramine; import com.iexec.common.tee.TeeEnclaveProvider; -import com.iexec.sms.api.config.TeeServicesConfiguration; +import com.iexec.sms.api.config.TeeServicesProperties; import com.iexec.sms.tee.ConditionalOnTeeProvider; import com.iexec.sms.tee.session.base.SecretEnclaveBase; import com.iexec.sms.tee.session.base.SecretSessionBase; @@ -36,10 +36,10 @@ public class GramineSessionMakerService { private final SecretSessionBaseService secretSessionBaseService; - private final TeeServicesConfiguration teeServicesConfig; + private final TeeServicesProperties teeServicesConfig; public GramineSessionMakerService(SecretSessionBaseService secretSessionBaseService, - TeeServicesConfiguration teeServicesConfig) { + TeeServicesProperties teeServicesConfig) { this.secretSessionBaseService = secretSessionBaseService; this.teeServicesConfig = teeServicesConfig; } @@ -58,7 +58,7 @@ public GramineSession generateSession(TeeSessionRequest request) throws TeeSessi GramineEnclave gramineAppEnclave = toGramineEnclave(baseSession.getAppCompute()); gramineAppEnclave.setCommand(request.getTaskDescription().getAppCommand()); GramineEnclave graminePostEnclave = toGramineEnclave(baseSession.getPostCompute()); - graminePostEnclave.setCommand(teeServicesConfig.getPostComputeConfiguration().getEntrypoint()); + graminePostEnclave.setCommand(teeServicesConfig.getPostComputeProperties().getEntrypoint()); // TODO: Remove useless volumes when SPS is ready gramineAppEnclave.setVolumes(List.of()); diff --git a/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionMakerService.java b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionMakerService.java index 2d8d31d3..e8162515 100644 --- a/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionMakerService.java +++ b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionMakerService.java @@ -17,7 +17,7 @@ package com.iexec.sms.tee.session.scone; import com.iexec.common.tee.TeeEnclaveProvider; -import com.iexec.sms.api.config.TeeServicesConfiguration; +import com.iexec.sms.api.config.TeeServicesProperties; import com.iexec.sms.tee.ConditionalOnTeeProvider; import com.iexec.sms.tee.session.base.SecretEnclaveBase; import com.iexec.sms.tee.session.base.SecretSessionBase; @@ -54,12 +54,12 @@ public class SconeSessionMakerService { static final String POST_COMPUTE_ENTRYPOINT = "POST_COMPUTE_ENTRYPOINT"; private final SecretSessionBaseService secretSessionBaseService; - private final TeeServicesConfiguration teeServicesConfig; + private final TeeServicesProperties teeServicesConfig; private final SconeSessionSecurityConfig attestationSecurityConfig; public SconeSessionMakerService( SecretSessionBaseService secretSessionBaseService, - TeeServicesConfiguration teeServicesConfig, + TeeServicesProperties teeServicesConfig, SconeSessionSecurityConfig attestationSecurityConfig) { this.secretSessionBaseService = secretSessionBaseService; this.teeServicesConfig = teeServicesConfig; @@ -95,7 +95,7 @@ public SconeSession generateSession(TeeSessionRequest request) SconeEnclave sconePreEnclave = toSconeEnclave( baseSession.getPreCompute()); sconePreEnclave - .setCommand(teeServicesConfig.getPreComputeConfiguration().getEntrypoint()); + .setCommand(teeServicesConfig.getPreComputeProperties().getEntrypoint()); addJavaEnvVars(sconePreEnclave); services.add(sconePreEnclave); images.add(new SconeSession.Image(sconePreEnclave.getImageName(), @@ -113,7 +113,7 @@ public SconeSession generateSession(TeeSessionRequest request) SconeEnclave sconePostEnclave = toSconeEnclave( baseSession.getPostCompute()); sconePostEnclave - .setCommand(teeServicesConfig.getPostComputeConfiguration().getEntrypoint()); + .setCommand(teeServicesConfig.getPostComputeProperties().getEntrypoint()); addJavaEnvVars(sconePostEnclave); services.add(sconePostEnclave); images.add(new SconeSession.Image(sconePostEnclave.getImageName(), diff --git a/src/test/java/com/iexec/sms/tee/TeeControllerTests.java b/src/test/java/com/iexec/sms/tee/TeeControllerTests.java index 6c509fc2..d6929887 100644 --- a/src/test/java/com/iexec/sms/tee/TeeControllerTests.java +++ b/src/test/java/com/iexec/sms/tee/TeeControllerTests.java @@ -5,10 +5,10 @@ import com.iexec.common.web.ApiResponseBody; import com.iexec.sms.api.TeeSessionGenerationError; import com.iexec.sms.api.TeeSessionGenerationResponse; -import com.iexec.sms.api.config.GramineServicesConfiguration; -import com.iexec.sms.api.config.SconeServicesConfiguration; -import com.iexec.sms.api.config.TeeAppConfiguration; -import com.iexec.sms.api.config.TeeServicesConfiguration; +import com.iexec.sms.api.config.GramineServicesProperties; +import com.iexec.sms.api.config.SconeServicesProperties; +import com.iexec.sms.api.config.TeeAppProperties; +import com.iexec.sms.api.config.TeeServicesProperties; import com.iexec.sms.authorization.AuthorizationError; import com.iexec.sms.authorization.AuthorizationService; import com.iexec.sms.tee.challenge.TeeChallengeService; @@ -55,12 +55,12 @@ class TeeControllerTests { @Mock TeeSessionService teeSessionService; @Mock - TeeServicesConfiguration teeServicesConfig; + TeeServicesProperties teeServicesConfig; @Mock - TeeAppConfiguration preComputeConfig; + TeeAppProperties preComputeConfig; @Mock - TeeAppConfiguration postComputeConfig; + TeeAppProperties postComputeConfig; @InjectMocks TeeController teeController; @@ -126,19 +126,19 @@ void shouldGetSconeConfig() { authorizationService, teeChallengeService, teeSessionService, config ); - final ResponseEntity response = + final ResponseEntity response = teeController.getTeeServicesConfig(TeeEnclaveProvider.SCONE); assertEquals(HttpStatus.OK, response.getStatusCode()); - final TeeServicesConfiguration result = response.getBody(); + final TeeServicesProperties result = response.getBody(); assertNotNull(result); - assertInstanceOf(SconeServicesConfiguration.class, result); + assertInstanceOf(SconeServicesProperties.class, result); assertEquals(TeeEnclaveProvider.SCONE, result.getTeeEnclaveProvider()); - assertEquals(preComputeConfig, result.getPreComputeConfiguration()); - assertEquals(postComputeConfig, result.getPostComputeConfiguration()); - assertEquals(postComputeConfig, result.getPostComputeConfiguration()); - assertEquals(LAS_IMAGE, ((SconeServicesConfiguration) result).getLasImage()); + assertEquals(preComputeConfig, result.getPreComputeProperties()); + assertEquals(postComputeConfig, result.getPostComputeProperties()); + assertEquals(postComputeConfig, result.getPostComputeProperties()); + assertEquals(LAS_IMAGE, ((SconeServicesProperties) result).getLasImage()); } @Test @@ -152,17 +152,17 @@ void shouldGetGramineConfig() { authorizationService, teeChallengeService, teeSessionService, config ); - final ResponseEntity response = + final ResponseEntity response = teeController.getTeeServicesConfig(TeeEnclaveProvider.GRAMINE); assertEquals(HttpStatus.OK, response.getStatusCode()); - final TeeServicesConfiguration result = response.getBody(); + final TeeServicesProperties result = response.getBody(); assertNotNull(result); - assertInstanceOf(GramineServicesConfiguration.class, result); + assertInstanceOf(GramineServicesProperties.class, result); assertEquals(TeeEnclaveProvider.GRAMINE, result.getTeeEnclaveProvider()); - assertEquals(preComputeConfig, result.getPreComputeConfiguration()); - assertEquals(postComputeConfig, result.getPostComputeConfiguration()); + assertEquals(preComputeConfig, result.getPreComputeProperties()); + assertEquals(postComputeConfig, result.getPostComputeProperties()); } @Test @@ -177,7 +177,7 @@ void shouldNotGetSconeConfigSinceGramineSms() { authorizationService, teeChallengeService, teeSessionService, config ); - final ResponseEntity response = + final ResponseEntity response = teeController.getTeeServicesConfig(TeeEnclaveProvider.GRAMINE); assertEquals(HttpStatus.CONFLICT, response.getStatusCode()); @@ -194,7 +194,7 @@ void shouldNotGetGramineConfigSinceSconeSms() { authorizationService, teeChallengeService, teeSessionService, config ); - final ResponseEntity response = + final ResponseEntity response = teeController.getTeeServicesConfig(TeeEnclaveProvider.SCONE); assertEquals(HttpStatus.CONFLICT, response.getStatusCode()); diff --git a/src/test/java/com/iexec/sms/tee/session/base/SecretSessionBaseServiceTests.java b/src/test/java/com/iexec/sms/tee/session/base/SecretSessionBaseServiceTests.java index f2d78bdd..75152f90 100644 --- a/src/test/java/com/iexec/sms/tee/session/base/SecretSessionBaseServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/base/SecretSessionBaseServiceTests.java @@ -7,8 +7,8 @@ import com.iexec.common.tee.TeeEnclaveProvider; import com.iexec.common.utils.IexecEnvUtils; import com.iexec.sms.api.TeeSessionGenerationError; -import com.iexec.sms.api.config.TeeAppConfiguration; -import com.iexec.sms.api.config.TeeServicesConfiguration; +import com.iexec.sms.api.config.TeeAppProperties; +import com.iexec.sms.api.config.TeeServicesProperties; import com.iexec.sms.secret.Secret; import com.iexec.sms.secret.compute.OnChainObjectType; import com.iexec.sms.secret.compute.SecretOwnerRole; @@ -63,11 +63,11 @@ class SecretSessionBaseServiceTests { @Mock private TeeChallengeService teeChallengeService; @Mock - private TeeAppConfiguration preComputeConfiguration; + private TeeAppProperties preComputeConfiguration; @Mock - private TeeAppConfiguration postComputeConfiguration; + private TeeAppProperties postComputeConfiguration; @Mock - private TeeServicesConfiguration teeServicesConfig; + private TeeServicesProperties teeServicesConfig; @Mock private TeeTaskComputeSecretService teeTaskComputeSecretService; @@ -77,8 +77,8 @@ class SecretSessionBaseServiceTests { @BeforeEach void beforeEach() { MockitoAnnotations.openMocks(this); - when(teeServicesConfig.getPreComputeConfiguration()).thenReturn(preComputeConfiguration); - when(teeServicesConfig.getPostComputeConfiguration()).thenReturn(postComputeConfiguration); + when(teeServicesConfig.getPreComputeProperties()).thenReturn(preComputeConfiguration); + when(teeServicesConfig.getPostComputeProperties()).thenReturn(postComputeConfiguration); } // region getSecretsTokens diff --git a/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerServiceTests.java b/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerServiceTests.java index 1a7faa65..bf79ba5a 100644 --- a/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerServiceTests.java @@ -2,7 +2,7 @@ import com.iexec.common.tee.TeeEnclaveConfiguration; import com.iexec.common.utils.FileHelper; -import com.iexec.sms.api.config.TeeAppConfiguration; +import com.iexec.sms.api.config.TeeAppProperties; import com.iexec.sms.tee.config.GramineInternalServicesConfiguration; import com.iexec.sms.tee.session.base.SecretEnclaveBase; import com.iexec.sms.tee.session.base.SecretSessionBase; @@ -26,9 +26,9 @@ @Slf4j class GramineSessionMakerServiceTests { @Mock - private TeeAppConfiguration preComputeConfiguration; + private TeeAppProperties preComputeConfiguration; @Mock - private TeeAppConfiguration postComputeConfiguration; + private TeeAppProperties postComputeConfiguration; @Mock private GramineInternalServicesConfiguration teeServicesConfig; @Mock @@ -39,8 +39,8 @@ class GramineSessionMakerServiceTests { @BeforeEach void beforeEach() { MockitoAnnotations.openMocks(this); - when(teeServicesConfig.getPreComputeConfiguration()).thenReturn(preComputeConfiguration); - when(teeServicesConfig.getPostComputeConfiguration()).thenReturn(postComputeConfiguration); + when(teeServicesConfig.getPreComputeProperties()).thenReturn(preComputeConfiguration); + when(teeServicesConfig.getPostComputeProperties()).thenReturn(postComputeConfiguration); } // region getSessionYml diff --git a/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionMakerServiceTests.java b/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionMakerServiceTests.java index c70fa197..e0a2597d 100644 --- a/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionMakerServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionMakerServiceTests.java @@ -18,7 +18,7 @@ import com.iexec.common.tee.TeeEnclaveConfiguration; import com.iexec.common.utils.FileHelper; -import com.iexec.sms.api.config.TeeAppConfiguration; +import com.iexec.sms.api.config.TeeAppProperties; import com.iexec.sms.tee.config.SconeInternalServicesConfiguration; import com.iexec.sms.tee.session.base.SecretEnclaveBase; import com.iexec.sms.tee.session.base.SecretSessionBase; @@ -49,9 +49,9 @@ class SconeSessionMakerServiceTests { private static final String POST_COMPUTE_ENTRYPOINT = "entrypoint3"; @Mock - private TeeAppConfiguration preComputeConfiguration; + private TeeAppProperties preComputeConfiguration; @Mock - private TeeAppConfiguration postComputeConfiguration; + private TeeAppProperties postComputeConfiguration; @Mock private SconeInternalServicesConfiguration teeServicesConfig; @Mock @@ -65,8 +65,8 @@ class SconeSessionMakerServiceTests { @BeforeEach void beforeEach() { MockitoAnnotations.openMocks(this); - when(teeServicesConfig.getPreComputeConfiguration()).thenReturn(preComputeConfiguration); - when(teeServicesConfig.getPostComputeConfiguration()).thenReturn(postComputeConfiguration); + when(teeServicesConfig.getPreComputeProperties()).thenReturn(preComputeConfiguration); + when(teeServicesConfig.getPostComputeProperties()).thenReturn(postComputeConfiguration); } // region getSessionYml From 1113289c34e83d446d6f8a797e63f5fae063c9fc Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Thu, 8 Sep 2022 14:56:20 +0200 Subject: [PATCH 099/293] Fix pre/post-compute properties validation --- .../iexec/sms/tee/config/TeeWorkerInternalConfiguration.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/com/iexec/sms/tee/config/TeeWorkerInternalConfiguration.java b/src/main/java/com/iexec/sms/tee/config/TeeWorkerInternalConfiguration.java index ebb18b47..9ffe852a 100644 --- a/src/main/java/com/iexec/sms/tee/config/TeeWorkerInternalConfiguration.java +++ b/src/main/java/com/iexec/sms/tee/config/TeeWorkerInternalConfiguration.java @@ -5,11 +5,13 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.util.unit.DataSize; +import org.springframework.validation.annotation.Validated; import javax.validation.constraints.NotBlank; import javax.validation.constraints.Positive; @Configuration +@Validated public class TeeWorkerInternalConfiguration { @Bean TeeAppProperties preComputeConfiguration( From aed4c99082a1f5886383c80b0f914de379eda265 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Thu, 8 Sep 2022 16:05:58 +0200 Subject: [PATCH 100/293] Disambiguate `TeeServicesConfiguration/Properties` naming Rename lots of elements --- .../java/com/iexec/sms/api/SmsClient.java | 14 +++---- .../api/config/GramineServicesProperties.java | 6 +-- .../com/iexec/sms/api/SmsClientTests.java | 40 +++++++++---------- .../com/iexec/sms/MockTeeConfiguration.java | 8 ++-- src/itest/resources/application-test.yml | 14 +++++++ .../java/com/iexec/sms/tee/TeeController.java | 2 +- .../GramineInternalServicesConfiguration.java | 6 +-- .../SconeInternalServicesConfiguration.java | 6 +-- .../TeeWorkerInternalConfiguration.java | 4 +- .../com/iexec/sms/tee/TeeControllerTests.java | 38 +++++++++--------- .../base/SecretSessionBaseServiceTests.java | 18 ++++----- .../GramineSessionMakerServiceTests.java | 12 +++--- .../scone/SconeSessionMakerServiceTests.java | 12 +++--- 13 files changed, 97 insertions(+), 83 deletions(-) diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java index f563f821..13ba3f19 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java @@ -107,17 +107,17 @@ ApiResponseBody generat @RequestLine("GET /tee/provider") TeeEnclaveProvider getTeeEnclaveProvider(); - @RequestLine("GET /tee/config/scone") - SconeServicesProperties getSconeServicesConfiguration(); + @RequestLine("GET /tee/properties/scone") + SconeServicesProperties getSconeServicesProperties(); - @RequestLine("GET /tee/config/gramine") - GramineServicesProperties getGramineServicesConfiguration(); + @RequestLine("GET /tee/properties/gramine") + GramineServicesProperties getGramineServicesProperties(); - default T getTeeServicesConfiguration(TeeEnclaveProvider teeEnclaveProvider) { + default T getTeeServicesProperties(TeeEnclaveProvider teeEnclaveProvider) { if (teeEnclaveProvider == TeeEnclaveProvider.SCONE) { - return (T) getSconeServicesConfiguration(); + return (T) getSconeServicesProperties(); } else if (teeEnclaveProvider == TeeEnclaveProvider.GRAMINE) { - return (T) getGramineServicesConfiguration(); + return (T) getGramineServicesProperties(); } return null; diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/GramineServicesProperties.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/GramineServicesProperties.java index 1e344905..a420b9d7 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/GramineServicesProperties.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/GramineServicesProperties.java @@ -12,8 +12,8 @@ public GramineServicesProperties() { super(TeeEnclaveProvider.GRAMINE); } - public GramineServicesProperties(TeeAppProperties preComputeConfiguration, - TeeAppProperties postComputeConfiguration) { - super(TeeEnclaveProvider.GRAMINE, preComputeConfiguration, postComputeConfiguration); + public GramineServicesProperties(TeeAppProperties preComputeProperties, + TeeAppProperties postComputeProperties) { + super(TeeEnclaveProvider.GRAMINE, preComputeProperties, postComputeProperties); } } diff --git a/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientTests.java b/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientTests.java index 79d62535..31218210 100644 --- a/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientTests.java +++ b/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientTests.java @@ -33,52 +33,52 @@ class SmsClientTests { private static final String LAS_IMAGE = "lasImage"; @Mock - TeeAppProperties preComputeConfig; + TeeAppProperties preComputeProperties; @Mock - TeeAppProperties postComputeConfig; + TeeAppProperties postComputeProperties; - // region getTeeServicesConfiguration + // region getTeeServicesProperties @Test - void shouldGetSconeServicesConfiguration() { + void shouldGetSconeServicesProperties() { final SmsClient smsClient = spy(SmsClient.class); - final SconeServicesProperties config = new SconeServicesProperties( - preComputeConfig, - postComputeConfig, + final SconeServicesProperties properties = new SconeServicesProperties( + preComputeProperties, + postComputeProperties, LAS_IMAGE ); - when(smsClient.getSconeServicesConfiguration()).thenReturn(config); + when(smsClient.getSconeServicesProperties()).thenReturn(properties); final TeeServicesProperties teeServicesProperties = - smsClient.getTeeServicesConfiguration(TeeEnclaveProvider.SCONE); + smsClient.getTeeServicesProperties(TeeEnclaveProvider.SCONE); - assertEquals(config, teeServicesProperties); + assertEquals(properties, teeServicesProperties); } @Test - void shouldGetGramineServicesConfiguration() { + void shouldGetGramineServicesProperties() { final SmsClient smsClient = spy(SmsClient.class); - final GramineServicesProperties config = new GramineServicesProperties( - preComputeConfig, - postComputeConfig + final GramineServicesProperties properties = new GramineServicesProperties( + preComputeProperties, + postComputeProperties ); - when(smsClient.getGramineServicesConfiguration()).thenReturn(config); + when(smsClient.getGramineServicesProperties()).thenReturn(properties); final TeeServicesProperties teeServicesProperties = - smsClient.getTeeServicesConfiguration(TeeEnclaveProvider.GRAMINE); + smsClient.getTeeServicesProperties(TeeEnclaveProvider.GRAMINE); - assertEquals(config, teeServicesProperties); + assertEquals(properties, teeServicesProperties); } @Test - void shouldNotGetTeeServicesConfigurationSinceUnknownProvider() { + void shouldNotGetTeeServicesPropertiesSinceUnknownProvider() { final SmsClient smsClient = spy(SmsClient.class); - when(smsClient.getGramineServicesConfiguration()).thenReturn(null); + when(smsClient.getGramineServicesProperties()).thenReturn(null); final TeeServicesProperties teeServicesProperties = - smsClient.getTeeServicesConfiguration(TeeEnclaveProvider.GRAMINE); + smsClient.getTeeServicesProperties(TeeEnclaveProvider.GRAMINE); assertNull(teeServicesProperties); } diff --git a/src/itest/java/com/iexec/sms/MockTeeConfiguration.java b/src/itest/java/com/iexec/sms/MockTeeConfiguration.java index 9d50d4a6..832779fc 100644 --- a/src/itest/java/com/iexec/sms/MockTeeConfiguration.java +++ b/src/itest/java/com/iexec/sms/MockTeeConfiguration.java @@ -23,9 +23,9 @@ public class MockTeeConfiguration { @MockBean private TeeServicesProperties teeServicesProperties; @MockBean - @Qualifier("preComputeConfiguration") - private TeeAppProperties preComputeConfiguration; + @Qualifier("preComputeProperties") + private TeeAppProperties preComputeProperties; @MockBean - @Qualifier("postComputeConfiguration") - private TeeAppProperties postComputeConfiguration; + @Qualifier("postComputeProperties") + private TeeAppProperties postComputeProperties; } diff --git a/src/itest/resources/application-test.yml b/src/itest/resources/application-test.yml index 71470e34..1f4db232 100644 --- a/src/itest/resources/application-test.yml +++ b/src/itest/resources/application-test.yml @@ -10,3 +10,17 @@ spring: datasource: url: jdbc:h2:mem:db +tee: + worker: + pre-compute: + image: some + fingerprint: some + heap-size-gb: 3 + entrypoint: some + post-compute: + image: some + fingerprint: some + heap-size-gb: 3 + entrypoint: some + scone: + las-image: some diff --git a/src/main/java/com/iexec/sms/tee/TeeController.java b/src/main/java/com/iexec/sms/tee/TeeController.java index 15be3fab..ed41aa2d 100644 --- a/src/main/java/com/iexec/sms/tee/TeeController.java +++ b/src/main/java/com/iexec/sms/tee/TeeController.java @@ -89,7 +89,7 @@ public ResponseEntity getTeeEnclaveProvider() { * @return TEE services config (pre-compute image uri, post-compute image uri, * heap size, ...) */ - @GetMapping("/config/{teeEnclaveProvider}") + @GetMapping("/properties/{teeEnclaveProvider}") public ResponseEntity getTeeServicesConfig( @PathVariable TeeEnclaveProvider teeEnclaveProvider) { if (teeEnclaveProvider != teeServicesConfig.getTeeEnclaveProvider()) { diff --git a/src/main/java/com/iexec/sms/tee/config/GramineInternalServicesConfiguration.java b/src/main/java/com/iexec/sms/tee/config/GramineInternalServicesConfiguration.java index 27d8a9bb..87391383 100644 --- a/src/main/java/com/iexec/sms/tee/config/GramineInternalServicesConfiguration.java +++ b/src/main/java/com/iexec/sms/tee/config/GramineInternalServicesConfiguration.java @@ -15,9 +15,9 @@ public class GramineInternalServicesConfiguration extends GramineServicesProperties implements TeeInternalServicesConfiguration { public GramineInternalServicesConfiguration( - TeeAppProperties preComputeConfiguration, - TeeAppProperties postComputeConfiguration) { - super(preComputeConfiguration, postComputeConfiguration); + TeeAppProperties preComputeProperties, + TeeAppProperties postComputeProperties) { + super(preComputeProperties, postComputeProperties); } @Override diff --git a/src/main/java/com/iexec/sms/tee/config/SconeInternalServicesConfiguration.java b/src/main/java/com/iexec/sms/tee/config/SconeInternalServicesConfiguration.java index a388b932..d864dd62 100644 --- a/src/main/java/com/iexec/sms/tee/config/SconeInternalServicesConfiguration.java +++ b/src/main/java/com/iexec/sms/tee/config/SconeInternalServicesConfiguration.java @@ -18,12 +18,12 @@ public class SconeInternalServicesConfiguration extends SconeServicesProperties implements TeeInternalServicesConfiguration{ public SconeInternalServicesConfiguration( - TeeAppProperties preComputeConfiguration, - TeeAppProperties postComputeConfiguration, + TeeAppProperties preComputeProperties, + TeeAppProperties postComputeProperties, @Value("${tee.scone.las-image}") @NotBlank(message = "las image must be provided") String lasImage) { - super(preComputeConfiguration, postComputeConfiguration, lasImage); + super(preComputeProperties, postComputeProperties, lasImage); } @Override diff --git a/src/main/java/com/iexec/sms/tee/config/TeeWorkerInternalConfiguration.java b/src/main/java/com/iexec/sms/tee/config/TeeWorkerInternalConfiguration.java index 9ffe852a..a0e0614d 100644 --- a/src/main/java/com/iexec/sms/tee/config/TeeWorkerInternalConfiguration.java +++ b/src/main/java/com/iexec/sms/tee/config/TeeWorkerInternalConfiguration.java @@ -14,7 +14,7 @@ @Validated public class TeeWorkerInternalConfiguration { @Bean - TeeAppProperties preComputeConfiguration( + TeeAppProperties preComputeProperties( @Value("${tee.worker.pre-compute.image}") @NotBlank(message = "pre-compute image must be provided") String preComputeImage, @@ -36,7 +36,7 @@ TeeAppProperties preComputeConfiguration( } @Bean - TeeAppProperties postComputeConfiguration( + TeeAppProperties postComputeProperties( @Value("${tee.worker.post-compute.image}") @NotBlank(message = "post-compute image must be provided") String postComputeImage, diff --git a/src/test/java/com/iexec/sms/tee/TeeControllerTests.java b/src/test/java/com/iexec/sms/tee/TeeControllerTests.java index d6929887..b0fa8190 100644 --- a/src/test/java/com/iexec/sms/tee/TeeControllerTests.java +++ b/src/test/java/com/iexec/sms/tee/TeeControllerTests.java @@ -58,9 +58,9 @@ class TeeControllerTests { TeeServicesProperties teeServicesConfig; @Mock - TeeAppProperties preComputeConfig; + TeeAppProperties preComputeProperties; @Mock - TeeAppProperties postComputeConfig; + TeeAppProperties postComputeProperties; @InjectMocks TeeController teeController; @@ -74,8 +74,8 @@ void setUp() { @Test void shouldGetSconeProvider() { final TeeInternalServicesConfiguration config = new SconeInternalServicesConfiguration( - preComputeConfig, - postComputeConfig, + preComputeProperties, + postComputeProperties, LAS_IMAGE ); @@ -95,8 +95,8 @@ void shouldGetSconeProvider() { @Test void shouldGetGramineProvider() { final TeeInternalServicesConfiguration config = new GramineInternalServicesConfiguration( - preComputeConfig, - postComputeConfig + preComputeProperties, + postComputeProperties ); final TeeController teeController = new TeeController( @@ -117,8 +117,8 @@ void shouldGetGramineProvider() { @Test void shouldGetSconeConfig() { final TeeInternalServicesConfiguration config = new SconeInternalServicesConfiguration( - preComputeConfig, - postComputeConfig, + preComputeProperties, + postComputeProperties, LAS_IMAGE ); @@ -135,17 +135,17 @@ void shouldGetSconeConfig() { assertNotNull(result); assertInstanceOf(SconeServicesProperties.class, result); assertEquals(TeeEnclaveProvider.SCONE, result.getTeeEnclaveProvider()); - assertEquals(preComputeConfig, result.getPreComputeProperties()); - assertEquals(postComputeConfig, result.getPostComputeProperties()); - assertEquals(postComputeConfig, result.getPostComputeProperties()); + assertEquals(preComputeProperties, result.getPreComputeProperties()); + assertEquals(postComputeProperties, result.getPostComputeProperties()); + assertEquals(postComputeProperties, result.getPostComputeProperties()); assertEquals(LAS_IMAGE, ((SconeServicesProperties) result).getLasImage()); } @Test void shouldGetGramineConfig() { final TeeInternalServicesConfiguration config = new GramineInternalServicesConfiguration( - preComputeConfig, - postComputeConfig + preComputeProperties, + postComputeProperties ); final TeeController teeController = new TeeController( @@ -161,15 +161,15 @@ void shouldGetGramineConfig() { assertNotNull(result); assertInstanceOf(GramineServicesProperties.class, result); assertEquals(TeeEnclaveProvider.GRAMINE, result.getTeeEnclaveProvider()); - assertEquals(preComputeConfig, result.getPreComputeProperties()); - assertEquals(postComputeConfig, result.getPostComputeProperties()); + assertEquals(preComputeProperties, result.getPreComputeProperties()); + assertEquals(postComputeProperties, result.getPostComputeProperties()); } @Test void shouldNotGetSconeConfigSinceGramineSms() { final TeeInternalServicesConfiguration config = new SconeInternalServicesConfiguration( - preComputeConfig, - postComputeConfig, + preComputeProperties, + postComputeProperties, LAS_IMAGE ); @@ -186,8 +186,8 @@ void shouldNotGetSconeConfigSinceGramineSms() { @Test void shouldNotGetGramineConfigSinceSconeSms() { final TeeInternalServicesConfiguration config = new GramineInternalServicesConfiguration( - preComputeConfig, - postComputeConfig + preComputeProperties, + postComputeProperties ); final TeeController teeController = new TeeController( diff --git a/src/test/java/com/iexec/sms/tee/session/base/SecretSessionBaseServiceTests.java b/src/test/java/com/iexec/sms/tee/session/base/SecretSessionBaseServiceTests.java index 75152f90..fe443fc1 100644 --- a/src/test/java/com/iexec/sms/tee/session/base/SecretSessionBaseServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/base/SecretSessionBaseServiceTests.java @@ -63,9 +63,9 @@ class SecretSessionBaseServiceTests { @Mock private TeeChallengeService teeChallengeService; @Mock - private TeeAppProperties preComputeConfiguration; + private TeeAppProperties preComputeProperties; @Mock - private TeeAppProperties postComputeConfiguration; + private TeeAppProperties postComputeProperties; @Mock private TeeServicesProperties teeServicesConfig; @Mock @@ -77,8 +77,8 @@ class SecretSessionBaseServiceTests { @BeforeEach void beforeEach() { MockitoAnnotations.openMocks(this); - when(teeServicesConfig.getPreComputeProperties()).thenReturn(preComputeConfiguration); - when(teeServicesConfig.getPostComputeProperties()).thenReturn(postComputeConfiguration); + when(teeServicesConfig.getPreComputeProperties()).thenReturn(preComputeProperties); + when(teeServicesConfig.getPostComputeProperties()).thenReturn(postComputeProperties); } // region getSecretsTokens @@ -88,14 +88,14 @@ void shouldGetSecretsTokens() throws Exception { TeeSessionRequest request = createSessionRequest(taskDescription); // pre - when(preComputeConfiguration.getFingerprint()) + when(preComputeProperties.getFingerprint()) .thenReturn(PRE_COMPUTE_FINGERPRINT); Web3Secret secret = new Web3Secret(DATASET_ADDRESS, DATASET_KEY); when(web3SecretService.getSecret(DATASET_ADDRESS, true)) .thenReturn(Optional.of(secret)); // post Secret publicKeySecret = new Secret("address", ENCRYPTION_PUBLIC_KEY); - when(postComputeConfiguration.getFingerprint()) + when(postComputeProperties.getFingerprint()) .thenReturn(POST_COMPUTE_FINGERPRINT); when(web2SecretsService.getSecret( request.getTaskDescription().getBeneficiary(), @@ -162,7 +162,7 @@ void shouldNotGetSecretsTokensSinceTaskDescriptionIsMissing() { void shouldGetPreComputeTokens() throws Exception { TaskDescription taskDescription = createTaskDescription(enclaveConfig); TeeSessionRequest request = createSessionRequest(taskDescription); - when(preComputeConfiguration.getFingerprint()) + when(preComputeProperties.getFingerprint()) .thenReturn(PRE_COMPUTE_FINGERPRINT); Web3Secret secret = new Web3Secret(DATASET_ADDRESS, DATASET_KEY); when(web3SecretService.getSecret(DATASET_ADDRESS, true)) @@ -197,7 +197,7 @@ void shouldGetPreComputeTokensWithoutDataset() throws Exception { .inputFiles(List.of(INPUT_FILE_URL_1, INPUT_FILE_URL_2)) .build()) .build(); - when(preComputeConfiguration.getFingerprint()) + when(preComputeProperties.getFingerprint()) .thenReturn(PRE_COMPUTE_FINGERPRINT); SecretEnclaveBase enclaveBase = teeSecretsService.getPreComputeTokens(request); @@ -392,7 +392,7 @@ void shouldGetPostComputeTokens() throws Exception { String requesterAddress = request.getTaskDescription().getRequester(); Secret publicKeySecret = new Secret("address", ENCRYPTION_PUBLIC_KEY); - when(postComputeConfiguration.getFingerprint()) + when(postComputeProperties.getFingerprint()) .thenReturn(POST_COMPUTE_FINGERPRINT); when(web2SecretsService.getSecret( request.getTaskDescription().getBeneficiary(), diff --git a/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerServiceTests.java b/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerServiceTests.java index bf79ba5a..513031b8 100644 --- a/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerServiceTests.java @@ -26,9 +26,9 @@ @Slf4j class GramineSessionMakerServiceTests { @Mock - private TeeAppProperties preComputeConfiguration; + private TeeAppProperties preComputeProperties; @Mock - private TeeAppProperties postComputeConfiguration; + private TeeAppProperties postComputeProperties; @Mock private GramineInternalServicesConfiguration teeServicesConfig; @Mock @@ -39,8 +39,8 @@ class GramineSessionMakerServiceTests { @BeforeEach void beforeEach() { MockitoAnnotations.openMocks(this); - when(teeServicesConfig.getPreComputeProperties()).thenReturn(preComputeConfiguration); - when(teeServicesConfig.getPostComputeProperties()).thenReturn(postComputeConfiguration); + when(teeServicesConfig.getPreComputeProperties()).thenReturn(preComputeProperties); + when(teeServicesConfig.getPostComputeProperties()).thenReturn(postComputeProperties); } // region getSessionYml @@ -49,8 +49,8 @@ void shouldGetSessionJson() throws Exception { TeeEnclaveConfiguration enclaveConfig = mock(TeeEnclaveConfiguration.class); TeeSessionRequest request = createSessionRequest(createTaskDescription(enclaveConfig)); - when(postComputeConfiguration.getFingerprint()).thenReturn(POST_COMPUTE_FINGERPRINT); - when(postComputeConfiguration.getEntrypoint()).thenReturn(POST_COMPUTE_ENTRYPOINT); + when(postComputeProperties.getFingerprint()).thenReturn(POST_COMPUTE_FINGERPRINT); + when(postComputeProperties.getEntrypoint()).thenReturn(POST_COMPUTE_ENTRYPOINT); when(enclaveConfig.getFingerprint()).thenReturn(APP_FINGERPRINT); when(enclaveConfig.getEntrypoint()).thenReturn("/apploader.sh"); diff --git a/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionMakerServiceTests.java b/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionMakerServiceTests.java index e0a2597d..803f2def 100644 --- a/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionMakerServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionMakerServiceTests.java @@ -49,9 +49,9 @@ class SconeSessionMakerServiceTests { private static final String POST_COMPUTE_ENTRYPOINT = "entrypoint3"; @Mock - private TeeAppProperties preComputeConfiguration; + private TeeAppProperties preComputeProperties; @Mock - private TeeAppProperties postComputeConfiguration; + private TeeAppProperties postComputeProperties; @Mock private SconeInternalServicesConfiguration teeServicesConfig; @Mock @@ -65,8 +65,8 @@ class SconeSessionMakerServiceTests { @BeforeEach void beforeEach() { MockitoAnnotations.openMocks(this); - when(teeServicesConfig.getPreComputeProperties()).thenReturn(preComputeConfiguration); - when(teeServicesConfig.getPostComputeProperties()).thenReturn(postComputeConfiguration); + when(teeServicesConfig.getPreComputeProperties()).thenReturn(preComputeProperties); + when(teeServicesConfig.getPostComputeProperties()).thenReturn(postComputeProperties); } // region getSessionYml @@ -75,8 +75,8 @@ void shouldGetSessionYml() throws Exception { TeeEnclaveConfiguration enclaveConfig = mock(TeeEnclaveConfiguration.class); TeeSessionRequest request = createSessionRequest(createTaskDescription(enclaveConfig)); - when(preComputeConfiguration.getEntrypoint()).thenReturn(PRE_COMPUTE_ENTRYPOINT); - when(postComputeConfiguration.getEntrypoint()).thenReturn(POST_COMPUTE_ENTRYPOINT); + when(preComputeProperties.getEntrypoint()).thenReturn(PRE_COMPUTE_ENTRYPOINT); + when(postComputeProperties.getEntrypoint()).thenReturn(POST_COMPUTE_ENTRYPOINT); when(enclaveConfig.getFingerprint()).thenReturn(APP_FINGERPRINT); when(enclaveConfig.getEntrypoint()).thenReturn(APP_ENTRYPOINT); From 6e22c127314cce864681997f49aab496caa60862 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Thu, 8 Sep 2022 16:06:26 +0200 Subject: [PATCH 101/293] Remove useless properties declaration in `application.yml` --- src/main/resources/application.yml | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 01734c7d..ece1c2fe 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -49,16 +49,6 @@ blockchain: gas-price-cap: ${IEXEC_GAS_PRICE_CAP:22000000000} #in Wei, will be used for txs if networkGasPrice*gasPriceMultiplier > gasPriceCap is-sidechain: ${IEXEC_IS_SIDECHAIN:false} -# TODO /!\ remove the option of env variable for releases. -tee: - secret-provisioner: - web: - hostname: ${IEXEC_SECRET_PROVISIONER_WEB_HOSTNAME:localhost} - port: ${IEXEC_SECRET_PROVISIONER_WEB_PORT} - enclave: - hostname: ${IEXEC_SECRET_PROVISIONER_ENCLAVE_HOSTNAME:localhost} - port: ${IEXEC_SECRET_PROVISIONER_ENCLAVE_PORT} - logging: tee.display-debug-session: ${IEXEC_SMS_DISPLAY_DEBUG_SESSION:false} # level: From dc03cf0fca9a74168ca02549995730050d857aa6 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Thu, 8 Sep 2022 16:18:56 +0200 Subject: [PATCH 102/293] Remove `TeeInternalServicesConfiguration` --- .../api/config/GramineServicesProperties.java | 5 +++ .../api/config/SconeServicesProperties.java | 5 +++ .../sms/api/config/TeeServicesProperties.java | 2 + .../com/iexec/sms/MockTeeConfiguration.java | 3 -- .../java/com/iexec/sms/tee/TeeController.java | 21 +++++----- .../sms/tee/TeeEnclaveProviderConverter.java | 2 +- .../GramineInternalServicesConfiguration.java | 3 +- .../SconeInternalServicesConfiguration.java | 3 +- .../TeeInternalServicesConfiguration.java | 9 ---- .../tee/ConditionalOnTeeProviderTests.java | 2 - .../com/iexec/sms/tee/TeeControllerTests.java | 42 +++++++++---------- 11 files changed, 45 insertions(+), 52 deletions(-) delete mode 100644 src/main/java/com/iexec/sms/tee/config/TeeInternalServicesConfiguration.java diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/GramineServicesProperties.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/GramineServicesProperties.java index a420b9d7..1bf510d0 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/GramineServicesProperties.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/GramineServicesProperties.java @@ -16,4 +16,9 @@ public GramineServicesProperties(TeeAppProperties preComputeProperties, TeeAppProperties postComputeProperties) { super(TeeEnclaveProvider.GRAMINE, preComputeProperties, postComputeProperties); } + + @Override + public TeeServicesProperties getProperties() { + return new GramineServicesProperties(getPreComputeProperties(), getPostComputeProperties()); + } } diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/SconeServicesProperties.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/SconeServicesProperties.java index 1a305d7f..d606bb25 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/SconeServicesProperties.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/SconeServicesProperties.java @@ -19,4 +19,9 @@ public SconeServicesProperties(TeeAppProperties preComputeProperties, super(TeeEnclaveProvider.SCONE, preComputeProperties, postComputeProperties); this.lasImage = lasImage; } + + @Override + public TeeServicesProperties getProperties() { + return new SconeServicesProperties(getPreComputeProperties(), getPostComputeProperties(), getLasImage()); + } } diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeServicesProperties.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeServicesProperties.java index 72e4279d..54cc275a 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeServicesProperties.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeServicesProperties.java @@ -18,4 +18,6 @@ public abstract class TeeServicesProperties { TeeServicesProperties(TeeEnclaveProvider teeEnclaveProvider) { this.teeEnclaveProvider = teeEnclaveProvider; } + + public abstract TeeServicesProperties getProperties(); } diff --git a/src/itest/java/com/iexec/sms/MockTeeConfiguration.java b/src/itest/java/com/iexec/sms/MockTeeConfiguration.java index 832779fc..604eb6a3 100644 --- a/src/itest/java/com/iexec/sms/MockTeeConfiguration.java +++ b/src/itest/java/com/iexec/sms/MockTeeConfiguration.java @@ -2,7 +2,6 @@ import com.iexec.sms.api.config.TeeAppProperties; import com.iexec.sms.api.config.TeeServicesProperties; -import com.iexec.sms.tee.config.TeeInternalServicesConfiguration; import com.iexec.sms.tee.session.generic.TeeSessionHandler; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.test.mock.mockito.MockBean; @@ -19,8 +18,6 @@ public class MockTeeConfiguration { @MockBean private TeeSessionHandler teeSessionHandler; @MockBean - private TeeInternalServicesConfiguration teeInternalServicesConfiguration; - @MockBean private TeeServicesProperties teeServicesProperties; @MockBean @Qualifier("preComputeProperties") diff --git a/src/main/java/com/iexec/sms/tee/TeeController.java b/src/main/java/com/iexec/sms/tee/TeeController.java index ed41aa2d..3c04290d 100644 --- a/src/main/java/com/iexec/sms/tee/TeeController.java +++ b/src/main/java/com/iexec/sms/tee/TeeController.java @@ -27,7 +27,6 @@ import com.iexec.sms.authorization.AuthorizationService; import com.iexec.sms.tee.challenge.TeeChallenge; import com.iexec.sms.tee.challenge.TeeChallengeService; -import com.iexec.sms.tee.config.TeeInternalServicesConfiguration; import com.iexec.sms.tee.session.TeeSessionService; import com.iexec.sms.tee.session.generic.TeeSessionGenerationException; import lombok.extern.slf4j.Slf4j; @@ -59,17 +58,17 @@ public class TeeController { private final AuthorizationService authorizationService; private final TeeChallengeService teeChallengeService; private final TeeSessionService teeSessionService; - private final TeeInternalServicesConfiguration teeServicesConfig; + private final TeeServicesProperties teeServicesProperties; public TeeController( AuthorizationService authorizationService, TeeChallengeService teeChallengeService, TeeSessionService teeSessionService, - TeeInternalServicesConfiguration teeServicesConfig) { + TeeServicesProperties teeServicesProperties) { this.authorizationService = authorizationService; this.teeChallengeService = teeChallengeService; this.teeSessionService = teeSessionService; - this.teeServicesConfig = teeServicesConfig; + this.teeServicesProperties = teeServicesProperties; } /** @@ -78,26 +77,26 @@ public TeeController( */ @GetMapping("/provider") public ResponseEntity getTeeEnclaveProvider() { - return ResponseEntity.ok(teeServicesConfig.getTeeEnclaveProvider()); + return ResponseEntity.ok(teeServicesProperties.getTeeEnclaveProvider()); } /** - * Retrieve configuration for TEE services. This includes configuration + * Retrieve properties for TEE services. This includes properties * for pre-compute and post-compute stages * and potential TEE provider's specific data. * - * @return TEE services config (pre-compute image uri, post-compute image uri, + * @return TEE services properties (pre-compute image uri, post-compute image uri, * heap size, ...) */ @GetMapping("/properties/{teeEnclaveProvider}") - public ResponseEntity getTeeServicesConfig( + public ResponseEntity getTeeServicesProperties( @PathVariable TeeEnclaveProvider teeEnclaveProvider) { - if (teeEnclaveProvider != teeServicesConfig.getTeeEnclaveProvider()) { + if (teeEnclaveProvider != teeServicesProperties.getTeeEnclaveProvider()) { log.error("SMS configured to use another TeeEnclaveProvider " + - "[required:{}, actual:{}]", teeEnclaveProvider, teeServicesConfig.getTeeEnclaveProvider()); + "[required:{}, actual:{}]", teeEnclaveProvider, teeServicesProperties.getTeeEnclaveProvider()); return ResponseEntity.status(HttpStatus.CONFLICT).build(); } - return ResponseEntity.ok(teeServicesConfig.getProperties()); + return ResponseEntity.ok(teeServicesProperties.getProperties()); } /** diff --git a/src/main/java/com/iexec/sms/tee/TeeEnclaveProviderConverter.java b/src/main/java/com/iexec/sms/tee/TeeEnclaveProviderConverter.java index dc3c8bb5..924920b6 100644 --- a/src/main/java/com/iexec/sms/tee/TeeEnclaveProviderConverter.java +++ b/src/main/java/com/iexec/sms/tee/TeeEnclaveProviderConverter.java @@ -6,7 +6,7 @@ /** * This class is needed to have a case-insensitive `teeEnclaveProvider` path variable in - * {@link TeeController#getTeeServicesConfig(TeeEnclaveProvider)}. + * {@link TeeController#getTeeServicesProperties(TeeEnclaveProvider)}. */ @Component public class TeeEnclaveProviderConverter implements Converter { diff --git a/src/main/java/com/iexec/sms/tee/config/GramineInternalServicesConfiguration.java b/src/main/java/com/iexec/sms/tee/config/GramineInternalServicesConfiguration.java index 87391383..b2b8a37a 100644 --- a/src/main/java/com/iexec/sms/tee/config/GramineInternalServicesConfiguration.java +++ b/src/main/java/com/iexec/sms/tee/config/GramineInternalServicesConfiguration.java @@ -12,8 +12,7 @@ @ConditionalOnTeeProvider(providers = TeeEnclaveProvider.GRAMINE) @Getter public class GramineInternalServicesConfiguration - extends GramineServicesProperties - implements TeeInternalServicesConfiguration { + extends GramineServicesProperties { public GramineInternalServicesConfiguration( TeeAppProperties preComputeProperties, TeeAppProperties postComputeProperties) { diff --git a/src/main/java/com/iexec/sms/tee/config/SconeInternalServicesConfiguration.java b/src/main/java/com/iexec/sms/tee/config/SconeInternalServicesConfiguration.java index d864dd62..89d874ea 100644 --- a/src/main/java/com/iexec/sms/tee/config/SconeInternalServicesConfiguration.java +++ b/src/main/java/com/iexec/sms/tee/config/SconeInternalServicesConfiguration.java @@ -15,8 +15,7 @@ @ConditionalOnTeeProvider(providers = TeeEnclaveProvider.SCONE) @Getter public class SconeInternalServicesConfiguration - extends SconeServicesProperties - implements TeeInternalServicesConfiguration{ + extends SconeServicesProperties { public SconeInternalServicesConfiguration( TeeAppProperties preComputeProperties, TeeAppProperties postComputeProperties, diff --git a/src/main/java/com/iexec/sms/tee/config/TeeInternalServicesConfiguration.java b/src/main/java/com/iexec/sms/tee/config/TeeInternalServicesConfiguration.java deleted file mode 100644 index e0f1b9ac..00000000 --- a/src/main/java/com/iexec/sms/tee/config/TeeInternalServicesConfiguration.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.iexec.sms.tee.config; - -import com.iexec.common.tee.TeeEnclaveProvider; -import com.iexec.sms.api.config.TeeServicesProperties; - -public interface TeeInternalServicesConfiguration { - TeeEnclaveProvider getTeeEnclaveProvider(); - TeeServicesProperties getProperties(); -} diff --git a/src/test/java/com/iexec/sms/tee/ConditionalOnTeeProviderTests.java b/src/test/java/com/iexec/sms/tee/ConditionalOnTeeProviderTests.java index a9969099..dd852852 100644 --- a/src/test/java/com/iexec/sms/tee/ConditionalOnTeeProviderTests.java +++ b/src/test/java/com/iexec/sms/tee/ConditionalOnTeeProviderTests.java @@ -3,7 +3,6 @@ import com.iexec.common.tee.TeeEnclaveProvider; import com.iexec.sms.tee.config.GramineInternalServicesConfiguration; import com.iexec.sms.tee.config.SconeInternalServicesConfiguration; -import com.iexec.sms.tee.config.TeeInternalServicesConfiguration; import com.iexec.sms.tee.session.generic.TeeSessionHandler; import com.iexec.sms.tee.session.gramine.GramineSessionHandlerService; import com.iexec.sms.tee.session.gramine.GramineSessionMakerService; @@ -76,7 +75,6 @@ static Stream sconeAndGramineBeansClasses() { static Stream nonAnnotatedClasses() { return Stream.of( - Arguments.of(TeeInternalServicesConfiguration.class), Arguments.of(TeeSessionHandler.class) ); } diff --git a/src/test/java/com/iexec/sms/tee/TeeControllerTests.java b/src/test/java/com/iexec/sms/tee/TeeControllerTests.java index b0fa8190..a2e7598d 100644 --- a/src/test/java/com/iexec/sms/tee/TeeControllerTests.java +++ b/src/test/java/com/iexec/sms/tee/TeeControllerTests.java @@ -12,9 +12,7 @@ import com.iexec.sms.authorization.AuthorizationError; import com.iexec.sms.authorization.AuthorizationService; import com.iexec.sms.tee.challenge.TeeChallengeService; -import com.iexec.sms.tee.config.GramineInternalServicesConfiguration; import com.iexec.sms.tee.config.SconeInternalServicesConfiguration; -import com.iexec.sms.tee.config.TeeInternalServicesConfiguration; import com.iexec.sms.tee.session.TeeSessionService; import com.iexec.sms.tee.session.generic.TeeSessionGenerationException; import org.junit.jupiter.api.BeforeEach; @@ -73,14 +71,14 @@ void setUp() { // region getTeeEnclaveProvider @Test void shouldGetSconeProvider() { - final TeeInternalServicesConfiguration config = new SconeInternalServicesConfiguration( + final TeeServicesProperties properties = new SconeServicesProperties( preComputeProperties, postComputeProperties, LAS_IMAGE ); final TeeController teeController = new TeeController( - authorizationService, teeChallengeService, teeSessionService, config + authorizationService, teeChallengeService, teeSessionService, properties ); final ResponseEntity response = @@ -94,13 +92,13 @@ void shouldGetSconeProvider() { @Test void shouldGetGramineProvider() { - final TeeInternalServicesConfiguration config = new GramineInternalServicesConfiguration( + final TeeServicesProperties properties = new GramineServicesProperties( preComputeProperties, postComputeProperties ); final TeeController teeController = new TeeController( - authorizationService, teeChallengeService, teeSessionService, config + authorizationService, teeChallengeService, teeSessionService, properties ); final ResponseEntity response = @@ -115,19 +113,19 @@ void shouldGetGramineProvider() { // region getTeeServicesConfig @Test - void shouldGetSconeConfig() { - final TeeInternalServicesConfiguration config = new SconeInternalServicesConfiguration( + void shouldGetSconeProperties() { + final TeeServicesProperties properties = new SconeInternalServicesConfiguration( preComputeProperties, postComputeProperties, LAS_IMAGE ); final TeeController teeController = new TeeController( - authorizationService, teeChallengeService, teeSessionService, config + authorizationService, teeChallengeService, teeSessionService, properties ); final ResponseEntity response = - teeController.getTeeServicesConfig(TeeEnclaveProvider.SCONE); + teeController.getTeeServicesProperties(TeeEnclaveProvider.SCONE); assertEquals(HttpStatus.OK, response.getStatusCode()); @@ -142,18 +140,18 @@ void shouldGetSconeConfig() { } @Test - void shouldGetGramineConfig() { - final TeeInternalServicesConfiguration config = new GramineInternalServicesConfiguration( + void shouldGetGramineProperties() { + final TeeServicesProperties properties = new GramineServicesProperties( preComputeProperties, postComputeProperties ); final TeeController teeController = new TeeController( - authorizationService, teeChallengeService, teeSessionService, config + authorizationService, teeChallengeService, teeSessionService, properties ); final ResponseEntity response = - teeController.getTeeServicesConfig(TeeEnclaveProvider.GRAMINE); + teeController.getTeeServicesProperties(TeeEnclaveProvider.GRAMINE); assertEquals(HttpStatus.OK, response.getStatusCode()); @@ -166,36 +164,36 @@ void shouldGetGramineConfig() { } @Test - void shouldNotGetSconeConfigSinceGramineSms() { - final TeeInternalServicesConfiguration config = new SconeInternalServicesConfiguration( + void shouldNotGetSconePropertiesSinceGramineSms() { + final TeeServicesProperties properties = new SconeInternalServicesConfiguration( preComputeProperties, postComputeProperties, LAS_IMAGE ); final TeeController teeController = new TeeController( - authorizationService, teeChallengeService, teeSessionService, config + authorizationService, teeChallengeService, teeSessionService, properties ); final ResponseEntity response = - teeController.getTeeServicesConfig(TeeEnclaveProvider.GRAMINE); + teeController.getTeeServicesProperties(TeeEnclaveProvider.GRAMINE); assertEquals(HttpStatus.CONFLICT, response.getStatusCode()); } @Test - void shouldNotGetGramineConfigSinceSconeSms() { - final TeeInternalServicesConfiguration config = new GramineInternalServicesConfiguration( + void shouldNotGetGraminePropertiesSinceSconeSms() { + final TeeServicesProperties properties = new GramineServicesProperties( preComputeProperties, postComputeProperties ); final TeeController teeController = new TeeController( - authorizationService, teeChallengeService, teeSessionService, config + authorizationService, teeChallengeService, teeSessionService, properties ); final ResponseEntity response = - teeController.getTeeServicesConfig(TeeEnclaveProvider.SCONE); + teeController.getTeeServicesProperties(TeeEnclaveProvider.SCONE); assertEquals(HttpStatus.CONFLICT, response.getStatusCode()); } From 3f921657084454f64ee6a3f425d08863ed72e2ee Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Thu, 8 Sep 2022 16:35:49 +0200 Subject: [PATCH 103/293] Remove `GramineInternalServicesConfiguration` & `SconeInternalServicesConfiguration` --- .../sms/tee/GramineBeansLoadingTests.java | 6 ++-- .../iexec/sms/tee/SconeBeansLoadingTests.java | 6 ++-- .../iexec/sms/tee/OnTeeProviderCondition.java | 10 +++++- .../GramineInternalServicesConfiguration.java | 26 --------------- .../SconeInternalServicesConfiguration.java | 32 ------------------- .../TeeWorkerInternalConfiguration.java | 22 +++++++++++++ 6 files changed, 37 insertions(+), 65 deletions(-) delete mode 100644 src/main/java/com/iexec/sms/tee/config/GramineInternalServicesConfiguration.java delete mode 100644 src/main/java/com/iexec/sms/tee/config/SconeInternalServicesConfiguration.java diff --git a/src/itest/java/com/iexec/sms/tee/GramineBeansLoadingTests.java b/src/itest/java/com/iexec/sms/tee/GramineBeansLoadingTests.java index 045d174c..19b557cc 100644 --- a/src/itest/java/com/iexec/sms/tee/GramineBeansLoadingTests.java +++ b/src/itest/java/com/iexec/sms/tee/GramineBeansLoadingTests.java @@ -1,6 +1,6 @@ package com.iexec.sms.tee; -import com.iexec.sms.tee.config.GramineInternalServicesConfiguration; +import com.iexec.sms.api.config.GramineServicesProperties; import com.iexec.sms.tee.session.gramine.GramineSessionHandlerService; import com.iexec.sms.tee.session.gramine.GramineSessionMakerService; import com.iexec.sms.tee.session.gramine.sps.SpsConfiguration; @@ -14,7 +14,7 @@ @ActiveProfiles(profiles = "gramine") public class GramineBeansLoadingTests extends TeeBeansLoadingTests { @Autowired - GramineInternalServicesConfiguration gramineInternalServicesConfiguration; + GramineServicesProperties gramineServicesProperties; @Autowired GramineSessionHandlerService gramineSessionHandlerService; @Autowired @@ -29,7 +29,7 @@ public class GramineBeansLoadingTests extends TeeBeansLoadingTests { @Test @Override void checkTeeBeansAreLoaded() { - Assertions.assertNotNull(gramineInternalServicesConfiguration); + Assertions.assertNotNull(gramineServicesProperties); Assertions.assertNotNull(gramineSessionHandlerService); Assertions.assertNotNull(gramineSessionMakerService); Assertions.assertNotNull(spsConfiguration); diff --git a/src/itest/java/com/iexec/sms/tee/SconeBeansLoadingTests.java b/src/itest/java/com/iexec/sms/tee/SconeBeansLoadingTests.java index c41eb40d..03a997cf 100644 --- a/src/itest/java/com/iexec/sms/tee/SconeBeansLoadingTests.java +++ b/src/itest/java/com/iexec/sms/tee/SconeBeansLoadingTests.java @@ -1,6 +1,6 @@ package com.iexec.sms.tee; -import com.iexec.sms.tee.config.SconeInternalServicesConfiguration; +import com.iexec.sms.api.config.SconeServicesProperties; import com.iexec.sms.tee.session.scone.SconeSessionHandlerService; import com.iexec.sms.tee.session.scone.SconeSessionMakerService; import com.iexec.sms.tee.session.scone.SconeSessionSecurityConfig; @@ -16,7 +16,7 @@ @ActiveProfiles(profiles = "scone") public class SconeBeansLoadingTests extends TeeBeansLoadingTests { @Autowired - SconeInternalServicesConfiguration sconeInternalServicesConfiguration; + SconeServicesProperties sconeServicesProperties; @Autowired SconeSessionHandlerService sconeSessionHandlerService; @Autowired @@ -35,7 +35,7 @@ public class SconeBeansLoadingTests extends TeeBeansLoadingTests { @Test @Override void checkTeeBeansAreLoaded() { - assertNotNull(sconeInternalServicesConfiguration); + assertNotNull(sconeServicesProperties); assertNotNull(sconeSessionHandlerService); assertNotNull(sconeSessionMakerService); assertNotNull(sconeSessionSecurityConfig); diff --git a/src/main/java/com/iexec/sms/tee/OnTeeProviderCondition.java b/src/main/java/com/iexec/sms/tee/OnTeeProviderCondition.java index 07c38757..f7c7728d 100644 --- a/src/main/java/com/iexec/sms/tee/OnTeeProviderCondition.java +++ b/src/main/java/com/iexec/sms/tee/OnTeeProviderCondition.java @@ -9,6 +9,7 @@ import org.springframework.context.annotation.ConditionContext; import org.springframework.core.type.AnnotatedTypeMetadata; import org.springframework.core.type.AnnotationMetadata; +import org.springframework.core.type.MethodMetadata; import java.util.Arrays; import java.util.Map; @@ -24,7 +25,14 @@ public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeM final Map attributes = metadata.getAnnotationAttributes(ConditionalOnTeeProvider.class.getName()); final String[] activeProfiles = context.getEnvironment().getActiveProfiles(); - final String beanClassName = ((AnnotationMetadata) metadata).getClassName(); + final String beanClassName; + + if (metadata instanceof AnnotationMetadata) { + beanClassName = ((AnnotationMetadata) metadata).getClassName(); + } else { + beanClassName = ((MethodMetadata) metadata).getMethodName(); + } + if (attributes == null) { log.warn("No attribute for bean annotation, won't be loaded [bean:{}", beanClassName); diff --git a/src/main/java/com/iexec/sms/tee/config/GramineInternalServicesConfiguration.java b/src/main/java/com/iexec/sms/tee/config/GramineInternalServicesConfiguration.java deleted file mode 100644 index b2b8a37a..00000000 --- a/src/main/java/com/iexec/sms/tee/config/GramineInternalServicesConfiguration.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.iexec.sms.tee.config; - -import com.iexec.common.tee.TeeEnclaveProvider; -import com.iexec.sms.api.config.GramineServicesProperties; -import com.iexec.sms.api.config.TeeAppProperties; -import com.iexec.sms.api.config.TeeServicesProperties; -import com.iexec.sms.tee.ConditionalOnTeeProvider; -import lombok.Getter; -import org.springframework.context.annotation.Configuration; - -@Configuration -@ConditionalOnTeeProvider(providers = TeeEnclaveProvider.GRAMINE) -@Getter -public class GramineInternalServicesConfiguration - extends GramineServicesProperties { - public GramineInternalServicesConfiguration( - TeeAppProperties preComputeProperties, - TeeAppProperties postComputeProperties) { - super(preComputeProperties, postComputeProperties); - } - - @Override - public TeeServicesProperties getProperties() { - return new GramineServicesProperties(getPreComputeProperties(), getPostComputeProperties()); - } -} diff --git a/src/main/java/com/iexec/sms/tee/config/SconeInternalServicesConfiguration.java b/src/main/java/com/iexec/sms/tee/config/SconeInternalServicesConfiguration.java deleted file mode 100644 index 89d874ea..00000000 --- a/src/main/java/com/iexec/sms/tee/config/SconeInternalServicesConfiguration.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.iexec.sms.tee.config; - -import com.iexec.common.tee.TeeEnclaveProvider; -import com.iexec.sms.api.config.SconeServicesProperties; -import com.iexec.sms.api.config.TeeAppProperties; -import com.iexec.sms.api.config.TeeServicesProperties; -import com.iexec.sms.tee.ConditionalOnTeeProvider; -import lombok.Getter; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Configuration; - -import javax.validation.constraints.NotBlank; - -@Configuration -@ConditionalOnTeeProvider(providers = TeeEnclaveProvider.SCONE) -@Getter -public class SconeInternalServicesConfiguration - extends SconeServicesProperties { - public SconeInternalServicesConfiguration( - TeeAppProperties preComputeProperties, - TeeAppProperties postComputeProperties, - @Value("${tee.scone.las-image}") - @NotBlank(message = "las image must be provided") - String lasImage) { - super(preComputeProperties, postComputeProperties, lasImage); - } - - @Override - public TeeServicesProperties getProperties() { - return new SconeServicesProperties(getPreComputeProperties(), getPostComputeProperties(), getLasImage()); - } -} diff --git a/src/main/java/com/iexec/sms/tee/config/TeeWorkerInternalConfiguration.java b/src/main/java/com/iexec/sms/tee/config/TeeWorkerInternalConfiguration.java index a0e0614d..dbe85f62 100644 --- a/src/main/java/com/iexec/sms/tee/config/TeeWorkerInternalConfiguration.java +++ b/src/main/java/com/iexec/sms/tee/config/TeeWorkerInternalConfiguration.java @@ -1,6 +1,10 @@ package com.iexec.sms.tee.config; +import com.iexec.common.tee.TeeEnclaveProvider; +import com.iexec.sms.api.config.GramineServicesProperties; +import com.iexec.sms.api.config.SconeServicesProperties; import com.iexec.sms.api.config.TeeAppProperties; +import com.iexec.sms.tee.ConditionalOnTeeProvider; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -57,4 +61,22 @@ TeeAppProperties postComputeProperties( ); } + @Bean + @ConditionalOnTeeProvider(providers = TeeEnclaveProvider.GRAMINE) + GramineServicesProperties gramineServicesProperties( + TeeAppProperties preComputeProperties, + TeeAppProperties postComputeProperties) { + return new GramineServicesProperties(preComputeProperties, postComputeProperties); + } + + @Bean + @ConditionalOnTeeProvider(providers = TeeEnclaveProvider.SCONE) + SconeServicesProperties sconeServicesProperties( + TeeAppProperties preComputeProperties, + TeeAppProperties postComputeProperties, + @Value("${tee.scone.las-image}") + @NotBlank(message = "las image must be provided") + String lasImage) { + return new SconeServicesProperties(preComputeProperties, postComputeProperties, lasImage); + } } From 59a4f1376c1f9d331b44fbb80151956b13e5f406 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Thu, 8 Sep 2022 16:43:19 +0200 Subject: [PATCH 104/293] Fix Gramine & Scone properties tests --- src/main/java/com/iexec/sms/tee/TeeController.java | 2 +- .../iexec/sms/tee/ConditionalOnTeeProviderTests.java | 10 ++++------ .../java/com/iexec/sms/tee/TeeControllerTests.java | 5 ++--- .../gramine/GramineSessionMakerServiceTests.java | 4 ++-- .../session/scone/SconeSessionMakerServiceTests.java | 4 ++-- 5 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/iexec/sms/tee/TeeController.java b/src/main/java/com/iexec/sms/tee/TeeController.java index 3c04290d..18cde178 100644 --- a/src/main/java/com/iexec/sms/tee/TeeController.java +++ b/src/main/java/com/iexec/sms/tee/TeeController.java @@ -96,7 +96,7 @@ public ResponseEntity getTeeServicesProperties( "[required:{}, actual:{}]", teeEnclaveProvider, teeServicesProperties.getTeeEnclaveProvider()); return ResponseEntity.status(HttpStatus.CONFLICT).build(); } - return ResponseEntity.ok(teeServicesProperties.getProperties()); + return ResponseEntity.ok(teeServicesProperties); } /** diff --git a/src/test/java/com/iexec/sms/tee/ConditionalOnTeeProviderTests.java b/src/test/java/com/iexec/sms/tee/ConditionalOnTeeProviderTests.java index dd852852..1735d2ab 100644 --- a/src/test/java/com/iexec/sms/tee/ConditionalOnTeeProviderTests.java +++ b/src/test/java/com/iexec/sms/tee/ConditionalOnTeeProviderTests.java @@ -1,8 +1,8 @@ package com.iexec.sms.tee; import com.iexec.common.tee.TeeEnclaveProvider; -import com.iexec.sms.tee.config.GramineInternalServicesConfiguration; -import com.iexec.sms.tee.config.SconeInternalServicesConfiguration; +import com.iexec.sms.api.config.GramineServicesProperties; +import com.iexec.sms.api.config.SconeServicesProperties; import com.iexec.sms.tee.session.generic.TeeSessionHandler; import com.iexec.sms.tee.session.gramine.GramineSessionHandlerService; import com.iexec.sms.tee.session.gramine.GramineSessionMakerService; @@ -50,7 +50,7 @@ void init() { static Stream sconeBeansClasses() { return Stream.of( - Arguments.of(SconeInternalServicesConfiguration.class), +// Arguments.of(SconeServicesProperties.class), // Can't test this bean as it is declared through a method, not a class Arguments.of(SconeSessionHandlerService.class), Arguments.of(SconeSessionMakerService.class), Arguments.of(SconeSessionSecurityConfig.class), @@ -61,7 +61,7 @@ static Stream sconeBeansClasses() { static Stream gramineBeansClasses() { return Stream.of( - Arguments.of(GramineInternalServicesConfiguration.class), +// Arguments.of(GramineServicesProperties.class), // Can't test this bean as it is declared through a method, not a class Arguments.of(GramineSessionHandlerService.class), Arguments.of(GramineSessionMakerService.class), Arguments.of(SpsConfiguration.class) @@ -180,8 +180,6 @@ void shouldNotMatchAnySinceClassDoesNotExist() { assertFalse(condition.matches(context, metadata)); } - - // endregion void setAttributesForMetadataMock(Class clazz) { diff --git a/src/test/java/com/iexec/sms/tee/TeeControllerTests.java b/src/test/java/com/iexec/sms/tee/TeeControllerTests.java index a2e7598d..dfcf1a11 100644 --- a/src/test/java/com/iexec/sms/tee/TeeControllerTests.java +++ b/src/test/java/com/iexec/sms/tee/TeeControllerTests.java @@ -12,7 +12,6 @@ import com.iexec.sms.authorization.AuthorizationError; import com.iexec.sms.authorization.AuthorizationService; import com.iexec.sms.tee.challenge.TeeChallengeService; -import com.iexec.sms.tee.config.SconeInternalServicesConfiguration; import com.iexec.sms.tee.session.TeeSessionService; import com.iexec.sms.tee.session.generic.TeeSessionGenerationException; import org.junit.jupiter.api.BeforeEach; @@ -114,7 +113,7 @@ void shouldGetGramineProvider() { // region getTeeServicesConfig @Test void shouldGetSconeProperties() { - final TeeServicesProperties properties = new SconeInternalServicesConfiguration( + final TeeServicesProperties properties = new SconeServicesProperties( preComputeProperties, postComputeProperties, LAS_IMAGE @@ -165,7 +164,7 @@ void shouldGetGramineProperties() { @Test void shouldNotGetSconePropertiesSinceGramineSms() { - final TeeServicesProperties properties = new SconeInternalServicesConfiguration( + final TeeServicesProperties properties = new SconeServicesProperties( preComputeProperties, postComputeProperties, LAS_IMAGE diff --git a/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerServiceTests.java b/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerServiceTests.java index 513031b8..e86c7441 100644 --- a/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerServiceTests.java @@ -2,8 +2,8 @@ import com.iexec.common.tee.TeeEnclaveConfiguration; import com.iexec.common.utils.FileHelper; +import com.iexec.sms.api.config.GramineServicesProperties; import com.iexec.sms.api.config.TeeAppProperties; -import com.iexec.sms.tee.config.GramineInternalServicesConfiguration; import com.iexec.sms.tee.session.base.SecretEnclaveBase; import com.iexec.sms.tee.session.base.SecretSessionBase; import com.iexec.sms.tee.session.base.SecretSessionBaseService; @@ -30,7 +30,7 @@ class GramineSessionMakerServiceTests { @Mock private TeeAppProperties postComputeProperties; @Mock - private GramineInternalServicesConfiguration teeServicesConfig; + private GramineServicesProperties teeServicesConfig; @Mock private SecretSessionBaseService teeSecretsService; @InjectMocks diff --git a/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionMakerServiceTests.java b/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionMakerServiceTests.java index 803f2def..3a814094 100644 --- a/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionMakerServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionMakerServiceTests.java @@ -18,8 +18,8 @@ import com.iexec.common.tee.TeeEnclaveConfiguration; import com.iexec.common.utils.FileHelper; +import com.iexec.sms.api.config.SconeServicesProperties; import com.iexec.sms.api.config.TeeAppProperties; -import com.iexec.sms.tee.config.SconeInternalServicesConfiguration; import com.iexec.sms.tee.session.base.SecretEnclaveBase; import com.iexec.sms.tee.session.base.SecretSessionBase; import com.iexec.sms.tee.session.base.SecretSessionBaseService; @@ -53,7 +53,7 @@ class SconeSessionMakerServiceTests { @Mock private TeeAppProperties postComputeProperties; @Mock - private SconeInternalServicesConfiguration teeServicesConfig; + private SconeServicesProperties teeServicesConfig; @Mock private SecretSessionBaseService teeSecretsService; @Mock From afb4700ecfcf79baecc4037e20e5d2d1efdfcfa8 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Thu, 8 Sep 2022 17:00:27 +0200 Subject: [PATCH 105/293] Remove unused `TeeServicesProperties#getProperties` method --- .../com/iexec/sms/api/config/GramineServicesProperties.java | 5 ----- .../com/iexec/sms/api/config/SconeServicesProperties.java | 5 ----- .../java/com/iexec/sms/api/config/TeeServicesProperties.java | 2 -- 3 files changed, 12 deletions(-) diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/GramineServicesProperties.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/GramineServicesProperties.java index 1bf510d0..a420b9d7 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/GramineServicesProperties.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/GramineServicesProperties.java @@ -16,9 +16,4 @@ public GramineServicesProperties(TeeAppProperties preComputeProperties, TeeAppProperties postComputeProperties) { super(TeeEnclaveProvider.GRAMINE, preComputeProperties, postComputeProperties); } - - @Override - public TeeServicesProperties getProperties() { - return new GramineServicesProperties(getPreComputeProperties(), getPostComputeProperties()); - } } diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/SconeServicesProperties.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/SconeServicesProperties.java index d606bb25..1a305d7f 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/SconeServicesProperties.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/SconeServicesProperties.java @@ -19,9 +19,4 @@ public SconeServicesProperties(TeeAppProperties preComputeProperties, super(TeeEnclaveProvider.SCONE, preComputeProperties, postComputeProperties); this.lasImage = lasImage; } - - @Override - public TeeServicesProperties getProperties() { - return new SconeServicesProperties(getPreComputeProperties(), getPostComputeProperties(), getLasImage()); - } } diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeServicesProperties.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeServicesProperties.java index 54cc275a..72e4279d 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeServicesProperties.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeServicesProperties.java @@ -18,6 +18,4 @@ public abstract class TeeServicesProperties { TeeServicesProperties(TeeEnclaveProvider teeEnclaveProvider) { this.teeEnclaveProvider = teeEnclaveProvider; } - - public abstract TeeServicesProperties getProperties(); } From 835b969e3d57ac74735de468118b72f10d8faedd Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Thu, 8 Sep 2022 17:13:02 +0200 Subject: [PATCH 106/293] Improve code coverage --- .../TeeWorkerInternalConfigurationTests.java | 87 +++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 src/test/java/com/iexec/sms/tee/config/TeeWorkerInternalConfigurationTests.java diff --git a/src/test/java/com/iexec/sms/tee/config/TeeWorkerInternalConfigurationTests.java b/src/test/java/com/iexec/sms/tee/config/TeeWorkerInternalConfigurationTests.java new file mode 100644 index 00000000..ddda313b --- /dev/null +++ b/src/test/java/com/iexec/sms/tee/config/TeeWorkerInternalConfigurationTests.java @@ -0,0 +1,87 @@ +package com.iexec.sms.tee.config; + +import com.iexec.common.tee.TeeEnclaveProvider; +import com.iexec.sms.api.config.GramineServicesProperties; +import com.iexec.sms.api.config.SconeServicesProperties; +import com.iexec.sms.api.config.TeeAppProperties; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.mock; + +class TeeWorkerInternalConfigurationTests { + private final static String IMAGE = "image"; + private final static String FINGERPRINT = "fingerprint"; + private final static String ENTRYPOINT = "entrypoint"; + private final static String LAS_IMAGE = "lasImage"; + private final static long HEAP_SIZE_GB = 3; + private final static long HEAP_SIZE_B = 3221225472L; + + private final TeeWorkerInternalConfiguration teeWorkerInternalConfiguration = + new TeeWorkerInternalConfiguration(); + + // region preComputeProperties + @Test + void preComputeProperties() { + TeeAppProperties properties = teeWorkerInternalConfiguration.preComputeProperties( + IMAGE, + FINGERPRINT, + ENTRYPOINT, + HEAP_SIZE_GB + ); + + assertEquals(IMAGE, properties.getImage()); + assertEquals(FINGERPRINT, properties.getFingerprint()); + assertEquals(ENTRYPOINT, properties.getEntrypoint()); + assertEquals(HEAP_SIZE_B, properties.getHeapSizeInBytes()); + } + // endregion + + // region postComputeProperties + @Test + void postComputeProperties() { + TeeAppProperties properties = teeWorkerInternalConfiguration.postComputeProperties( + IMAGE, + FINGERPRINT, + ENTRYPOINT, + HEAP_SIZE_GB + ); + + assertEquals(IMAGE, properties.getImage()); + assertEquals(FINGERPRINT, properties.getFingerprint()); + assertEquals(ENTRYPOINT, properties.getEntrypoint()); + assertEquals(HEAP_SIZE_B, properties.getHeapSizeInBytes()); + } + // endregion + + // region gramineServicesProperties + @Test + void gramineServicesProperties() { + TeeAppProperties preComputeProperties = mock(TeeAppProperties.class); + TeeAppProperties postComputeProperties = mock(TeeAppProperties.class); + + GramineServicesProperties properties = + teeWorkerInternalConfiguration.gramineServicesProperties(preComputeProperties, postComputeProperties); + + assertEquals(TeeEnclaveProvider.GRAMINE, properties.getTeeEnclaveProvider()); + assertEquals(preComputeProperties, properties.getPreComputeProperties()); + assertEquals(postComputeProperties, properties.getPostComputeProperties()); + } + // endregion + + // region sconeServicesProperties + @Test + void sconeServicesProperties() { + TeeAppProperties preComputeProperties = mock(TeeAppProperties.class); + TeeAppProperties postComputeProperties = mock(TeeAppProperties.class); + + SconeServicesProperties properties = + teeWorkerInternalConfiguration.sconeServicesProperties(preComputeProperties, postComputeProperties, LAS_IMAGE); + + assertEquals(TeeEnclaveProvider.SCONE, properties.getTeeEnclaveProvider()); + assertEquals(preComputeProperties, properties.getPreComputeProperties()); + assertEquals(postComputeProperties, properties.getPostComputeProperties()); + assertEquals(LAS_IMAGE, properties.getLasImage()); + } + // endregion +} \ No newline at end of file From 1669c167524b3a5bfb70844bbc61b7d941bcb70a Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Fri, 9 Sep 2022 11:36:21 +0200 Subject: [PATCH 107/293] Introduce `ExpiringTaskMapFactory` --- .../src/main/java/com/iexec/sms/api/SmsClientProvider.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java index c9a8d1c2..9f053729 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java @@ -2,6 +2,7 @@ import com.iexec.common.chain.ChainDeal; import com.iexec.common.task.TaskDescription; +import com.iexec.common.utils.purge.ExpiringTaskMapFactory; import com.iexec.common.utils.purge.Purgeable; import feign.Logger; import lombok.extern.slf4j.Slf4j; @@ -17,7 +18,8 @@ */ @Slf4j public class SmsClientProvider implements Purgeable { - private final Map> taskIdToSmsUrl = new HashMap<>(); + private final Map> taskIdToSmsUrl = + ExpiringTaskMapFactory.getExpiringTaskMap(); private final Map urlToSmsClient = new HashMap<>(); private final Logger.Level loggerLevel; From cd595d49f184fa9c1b122a875d12a04a65da9022 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Mon, 12 Sep 2022 09:50:08 +0200 Subject: [PATCH 108/293] Add `@NonNull` annotation on `SconeSessionMakerService#generateSession` --- .../iexec/sms/tee/session/scone/SconeSessionMakerService.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionMakerService.java b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionMakerService.java index e8162515..9d559e4c 100644 --- a/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionMakerService.java +++ b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionMakerService.java @@ -31,6 +31,7 @@ import com.iexec.sms.tee.session.scone.cas.SconeSession.Image.Volume; import com.iexec.sms.tee.session.scone.cas.SconeSession.Security; import com.iexec.sms.tee.session.scone.cas.SconeSession.Volumes; +import lombok.NonNull; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -77,6 +78,7 @@ public SconeSessionMakerService( * @param request session request details * @return session config in yaml string format */ + @NonNull public SconeSession generateSession(TeeSessionRequest request) throws TeeSessionGenerationException { List policy = Arrays.asList("CREATOR"); From 049569599b05a7f2bae294f46dbd552f856fd9ff Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Mon, 12 Sep 2022 09:54:44 +0200 Subject: [PATCH 109/293] Upgrade `SconeSessionHandlerService#buildAndPostSession` implementation --- .../scone/SconeSessionHandlerService.java | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerService.java b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerService.java index beaa1178..bc5e8772 100644 --- a/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerService.java +++ b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerService.java @@ -34,10 +34,10 @@ @Component @ConditionalOnTeeProvider(providers = TeeEnclaveProvider.SCONE) public class SconeSessionHandlerService implements TeeSessionHandler { - private SconeSessionMakerService sessionService; - private CasClient apiClient; - private TeeSessionLogConfiguration teeSessionLogConfiguration; - private CasConfiguration casConfiguration; + private final SconeSessionMakerService sessionService; + private final CasClient apiClient; + private final TeeSessionLogConfiguration teeSessionLogConfiguration; + private final CasConfiguration casConfiguration; public SconeSessionHandlerService(SconeSessionMakerService sessionService, CasClient apiClient, @@ -54,20 +54,19 @@ public SconeSessionHandlerService(SconeSessionMakerService sessionService, * * @param request tee session generation request * @return String secret provisioning service url - * @throws TeeSessionGenerationException + * @throws TeeSessionGenerationException if call to CAS failed */ @Override public String buildAndPostSession(TeeSessionRequest request) throws TeeSessionGenerationException { SconeSession session = sessionService.generateSession(request); - if (session != null - && teeSessionLogConfiguration.isDisplayDebugSessionEnabled()) { + if (teeSessionLogConfiguration.isDisplayDebugSessionEnabled()) { log.info("Session content [taskId:{}]\n{}", - request.getTaskDescription().getChainTaskId(), session.toString()); + request.getTaskDescription().getChainTaskId(), session); } ResponseEntity postSession = apiClient.postSession(session.toString()); - int httpCode = postSession != null ? postSession.getStatusCodeValue() : null; - if (httpCode != 201) { + Integer httpCode = postSession != null ? postSession.getStatusCodeValue() : null; + if (httpCode == null || httpCode != 201) { throw new TeeSessionGenerationException( TeeSessionGenerationError.SECURE_SESSION_STORAGE_CALL_FAILED, "Failed to post session: " + httpCode); From 22d10e728772730688fd8a3f23901ca4bc9e1e50 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Mon, 12 Sep 2022 10:04:04 +0200 Subject: [PATCH 110/293] Improve `SconeSessionHandlerService#buildAndPostSession` test coverage --- .../SconeSessionHandlerServiceTests.java | 41 ++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerServiceTests.java b/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerServiceTests.java index af4b9e4c..7009e917 100644 --- a/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerServiceTests.java @@ -46,7 +46,7 @@ void beforeEach() { } @Test - void shouldBuildAndPostSession(CapturedOutput output) + void shouldBuildAndPostSessionWithLogs(CapturedOutput output) throws TeeSessionGenerationException { TeeSessionRequest request = mock(TeeSessionRequest.class); TaskDescription taskDescription = mock(TaskDescription.class); @@ -68,6 +68,28 @@ void shouldBuildAndPostSession(CapturedOutput output) .contains("Session content [taskId:null]\nsessionContent\n")); } + @Test + void shouldBuildAndPostSessionWithoutLogs(CapturedOutput output) + throws TeeSessionGenerationException { + TeeSessionRequest request = mock(TeeSessionRequest.class); + TaskDescription taskDescription = mock(TaskDescription.class); + when(request.getTaskDescription()).thenReturn(taskDescription); + SconeSession casSession = mock(SconeSession.class); + when(casSession.toString()).thenReturn("sessionContent"); + when(sessionService.generateSession(request)).thenReturn(casSession); + when(teeSessionLogConfiguration.isDisplayDebugSessionEnabled()) + .thenReturn(false); + when(apiClient.postSession(casSession.toString())) + .thenReturn(ResponseEntity.created(null).body("sessionId")); + + assertEquals(CAS_URL, + sessionHandlerService.buildAndPostSession(request)); + // Testing output here since it reflects a business feature (ability to + // catch a + // session in debug mode) + assertTrue(output.getOut().isEmpty()); + } + @Test void shouldNotBuildAndPostSessionSinceBuildSessionFailed() throws TeeSessionGenerationException { @@ -98,4 +120,21 @@ void shouldNotBuildAndPostSessionSincePostSessionFailed() assertThrows(TeeSessionGenerationException.class, () -> sessionHandlerService.buildAndPostSession(request)); } + + @Test + void shouldNotBuildAndPostSessionSinceNoResponse() + throws TeeSessionGenerationException { + TeeSessionRequest request = mock(TeeSessionRequest.class); + TaskDescription taskDescription = mock(TaskDescription.class); + when(request.getTaskDescription()).thenReturn(taskDescription); + SconeSession casSession = mock(SconeSession.class); + when(sessionService.generateSession(request)).thenReturn(casSession); + when(teeSessionLogConfiguration.isDisplayDebugSessionEnabled()) + .thenReturn(true); + when(apiClient.postSession(casSession.toString())) + .thenReturn(null); + + assertThrows(TeeSessionGenerationException.class, + () -> sessionHandlerService.buildAndPostSession(request)); + } } From ebd1cb307f96e3b08956e836074068547acfdbcb Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Mon, 12 Sep 2022 16:08:00 +0200 Subject: [PATCH 111/293] Introduce `IEXEC_SMS_TEE_RUNTIME_FRAMEWORK` env var --- src/main/resources/application.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index ece1c2fe..71f6e221 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -22,6 +22,8 @@ server: # Embedded H2 inside JVM spring: + profiles: + active: ${IEXEC_SMS_TEE_RUNTIME_FRAMEWORK:} # gramine/scone datasource: url: ${IEXEC_SMS_H2_URL:jdbc:h2:file:/tmp/h2/sms-h2} # will get or create /tmp/h2/sms-h2.mv.db driver-class-name: org.h2.Driver From 8605580ad827268a2f05472aafd61ee561d125a4 Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Tue, 13 Sep 2022 16:07:37 +0200 Subject: [PATCH 112/293] Complete Web2SecretsService tests coverage --- .../secret/web2/Web2SecretsServiceTests.java | 36 ++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/src/test/java/com/iexec/sms/secret/web2/Web2SecretsServiceTests.java b/src/test/java/com/iexec/sms/secret/web2/Web2SecretsServiceTests.java index a2dfc280..771bfb2a 100644 --- a/src/test/java/com/iexec/sms/secret/web2/Web2SecretsServiceTests.java +++ b/src/test/java/com/iexec/sms/secret/web2/Web2SecretsServiceTests.java @@ -52,7 +52,7 @@ void beforeEach() { } @Test - void shouldGetAndDecryptWeb2Secrets() { + void shouldGetAndDecryptSecret() { ownerAddress = ownerAddress.toLowerCase(); Secret encryptedSecret = new Secret(secretAddress, encryptedSecretValue); encryptedSecret.setEncryptedValue(true); @@ -70,6 +70,23 @@ void shouldGetAndDecryptWeb2Secrets() { assertThat(result.get().getValue()).isEqualTo(plainSecretValue); } + @Test + void shouldGetEncryptedSecret() { + ownerAddress = ownerAddress.toLowerCase(); + Secret encryptedSecret = new Secret(secretAddress, encryptedSecretValue); + encryptedSecret.setEncryptedValue(true); + List secretList = List.of(encryptedSecret); + Web2Secrets web2Secrets = new Web2Secrets(ownerAddress); + web2Secrets.setSecrets(secretList); + when(web2SecretsRepository.findWeb2SecretsByOwnerAddress(ownerAddress)) + .thenReturn(Optional.of(web2Secrets)); + + Optional result = web2SecretsService.getSecret(ownerAddress, secretAddress); + assertThat(result) + .isNotEmpty() + .contains(encryptedSecret); + } + @Test void shouldAddSecret() { ownerAddress = ownerAddress.toLowerCase(); @@ -77,6 +94,23 @@ void shouldAddSecret() { verify(web2SecretsRepository, times(1)).save(any()); } + @Test + void shouldNotUpdateSecretIfPresent() { + ownerAddress = ownerAddress.toLowerCase(); + Secret encryptedSecret = new Secret(secretAddress, encryptedSecretValue); + encryptedSecret.setEncryptedValue(true); + List secretList = List.of(encryptedSecret); + Web2Secrets web2Secrets = new Web2Secrets(ownerAddress); + web2Secrets.setSecrets(secretList); + when(web2SecretsRepository.findWeb2SecretsByOwnerAddress(ownerAddress)) + .thenReturn(Optional.of(web2Secrets)); + when(encryptionService.encrypt(plainSecretValue)) + .thenReturn(encryptedSecretValue); + + web2SecretsService.updateSecret(ownerAddress, secretAddress, plainSecretValue); + verify(web2SecretsRepository, never()).save(web2Secrets); + } + @Test void shouldUpdateSecret() { ownerAddress = ownerAddress.toLowerCase(); From 971ea14e605addfa1d9a3f6517f00284dbc65f61 Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Tue, 13 Sep 2022 16:52:23 +0200 Subject: [PATCH 113/293] Add Web3SecretService tests --- .../secret/web2/Web2SecretsServiceTests.java | 2 +- .../secret/web3/Web3SecretServiceTests.java | 88 +++++++++++++++++++ .../secret/web3/Web3SecretsServiceTests.java | 21 ----- 3 files changed, 89 insertions(+), 22 deletions(-) create mode 100644 src/test/java/com/iexec/sms/secret/web3/Web3SecretServiceTests.java delete mode 100644 src/test/java/com/iexec/sms/secret/web3/Web3SecretsServiceTests.java diff --git a/src/test/java/com/iexec/sms/secret/web2/Web2SecretsServiceTests.java b/src/test/java/com/iexec/sms/secret/web2/Web2SecretsServiceTests.java index 771bfb2a..64015999 100644 --- a/src/test/java/com/iexec/sms/secret/web2/Web2SecretsServiceTests.java +++ b/src/test/java/com/iexec/sms/secret/web2/Web2SecretsServiceTests.java @@ -52,7 +52,7 @@ void beforeEach() { } @Test - void shouldGetAndDecryptSecret() { + void shouldGetDecryptedSecret() { ownerAddress = ownerAddress.toLowerCase(); Secret encryptedSecret = new Secret(secretAddress, encryptedSecretValue); encryptedSecret.setEncryptedValue(true); diff --git a/src/test/java/com/iexec/sms/secret/web3/Web3SecretServiceTests.java b/src/test/java/com/iexec/sms/secret/web3/Web3SecretServiceTests.java new file mode 100644 index 00000000..fb45fcc5 --- /dev/null +++ b/src/test/java/com/iexec/sms/secret/web3/Web3SecretServiceTests.java @@ -0,0 +1,88 @@ +/* + * Copyright 2020 IEXEC BLOCKCHAIN TECH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.iexec.sms.secret.web3; + +import com.iexec.sms.encryption.EncryptionService; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +class Web3SecretServiceTests { + + String secretAddress = "secretAddress".toLowerCase(); + String plainSecretValue = "plainSecretValue"; + String encryptedSecretValue = "encryptedSecretValue"; + + @Mock + private EncryptionService encryptionService; + @Mock + private Web3SecretRepository web3SecretRepository; + @InjectMocks + private Web3SecretService web3SecretService; + + @BeforeEach + void init() { + MockitoAnnotations.openMocks(this); + } + + @Test + void shouldAddSecret() { + when(encryptionService.encrypt(plainSecretValue)).thenReturn(encryptedSecretValue); + web3SecretService.addSecret(secretAddress, plainSecretValue); + verify(encryptionService).encrypt(any()); + verify(web3SecretRepository).save(any()); + } + + @Test + void shouldGetDecryptedSecret() { + Web3Secret encryptedSecret = new Web3Secret(secretAddress, encryptedSecretValue); + encryptedSecret.setEncryptedValue(true); + when(web3SecretRepository.findWeb3SecretByAddress(secretAddress)).thenReturn(Optional.of(encryptedSecret)); + when(encryptionService.decrypt(encryptedSecretValue)).thenReturn(plainSecretValue); + Optional result = web3SecretService.getSecret(secretAddress, true); + assertThat(result).contains(new Web3Secret(secretAddress, plainSecretValue)); + verify(web3SecretRepository).findWeb3SecretByAddress(secretAddress); + verify(encryptionService).decrypt(any()); + } + + @Test + void shouldGetEncryptedSecret() { + Web3Secret encryptedSecret = new Web3Secret(secretAddress, encryptedSecretValue); + when(web3SecretRepository.findWeb3SecretByAddress(secretAddress)).thenReturn(Optional.of(encryptedSecret)); + assertThat(web3SecretService.getSecret(secretAddress)) + .contains(encryptedSecret); + verify(web3SecretRepository).findWeb3SecretByAddress(secretAddress); + verifyNoInteractions(encryptionService); + } + + @Test + void shouldGetEmptyResultIfSecretNotPresent() { + when(web3SecretRepository.findWeb3SecretByAddress(secretAddress)).thenReturn(Optional.empty()); + assertThat(web3SecretService.getSecret(secretAddress)).isEmpty(); + verify(web3SecretRepository).findWeb3SecretByAddress(secretAddress); + verifyNoInteractions(encryptionService); + } + +} \ No newline at end of file diff --git a/src/test/java/com/iexec/sms/secret/web3/Web3SecretsServiceTests.java b/src/test/java/com/iexec/sms/secret/web3/Web3SecretsServiceTests.java deleted file mode 100644 index 15135ea0..00000000 --- a/src/test/java/com/iexec/sms/secret/web3/Web3SecretsServiceTests.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2020 IEXEC BLOCKCHAIN TECH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.iexec.sms.secret.web3; - -class Web3SecretsServiceTests { - -} \ No newline at end of file From 071129fe25d0ff37f2e8a19d5b4da891e9c10dff Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Wed, 14 Sep 2022 09:34:31 +0200 Subject: [PATCH 114/293] Update `purgeTask` logic + remove if key is present + return whether the key is still present (`false`) or is now absent (`true`) --- .../java/com/iexec/sms/api/SmsClientProvider.java | 15 +++++++-------- .../com/iexec/sms/api/SmsClientProviderTests.java | 5 ++--- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java index 9f053729..e9df7a90 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java @@ -84,16 +84,15 @@ public SmsClient getOrCreateSmsClientForUninitializedTask(ChainDeal deal, String return urlToSmsClient.computeIfAbsent(smsUrl.get(), url -> SmsClientBuilder.getInstance(loggerLevel, url)); } + /** + * Try and remove SMS URL related to given task ID. + * @param chainTaskId Task ID whose related SMS URL should be purged + * @return {@literal true} if key is not stored anymore, + * {@literal false} otherwise. + */ @Override public boolean purgeTask(String chainTaskId) { - // Returning `taskIdToSmsUrl.remove(chainTaskId) != null` throws a warning: - // don't compare an `Optional` with null. - // So let's use a longer form. - - if (!taskIdToSmsUrl.containsKey(chainTaskId)) { - return false; - } taskIdToSmsUrl.remove(chainTaskId); - return true; + return !taskIdToSmsUrl.containsKey(chainTaskId); } } diff --git a/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientProviderTests.java b/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientProviderTests.java index 44b37863..761c900d 100644 --- a/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientProviderTests.java +++ b/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientProviderTests.java @@ -177,9 +177,8 @@ void shouldPurgeTask() { } @Test - void shouldNotPurgeTaskSinceTaskNeverAccessed() { - boolean purged = smsClientProvider.purgeTask(CHAIN_TASK_ID_1); - assertFalse(purged); + void shouldPurgeTaskEvenThoughTaskNeverAccessed() { + assertTrue(smsClientProvider.purgeTask(CHAIN_TASK_ID_1)); } // endregion } \ No newline at end of file From 0a2fcc500ce1c2aa8928cf77ae0fb5ed23e76d2b Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Wed, 14 Sep 2022 11:01:04 +0200 Subject: [PATCH 115/293] Manage Purgeable services end of life + Purge all task-related data on `@PreDestroy` --- .../src/main/java/com/iexec/sms/api/SmsClientProvider.java | 5 +++++ .../java/com/iexec/sms/api/SmsClientProviderTests.java | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java index e9df7a90..0aa4aa35 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java @@ -95,4 +95,9 @@ public boolean purgeTask(String chainTaskId) { taskIdToSmsUrl.remove(chainTaskId); return !taskIdToSmsUrl.containsKey(chainTaskId); } + + @Override + public void purgeAllTasksData() { + taskIdToSmsUrl.clear(); + } } diff --git a/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientProviderTests.java b/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientProviderTests.java index 761c900d..bc44a2f2 100644 --- a/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientProviderTests.java +++ b/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientProviderTests.java @@ -181,4 +181,11 @@ void shouldPurgeTaskEvenThoughTaskNeverAccessed() { assertTrue(smsClientProvider.purgeTask(CHAIN_TASK_ID_1)); } // endregion + + // region purgeAllTasksData + @Test + void shouldPurgeAllTasksData() { + assertDoesNotThrow(smsClientProvider::purgeAllTasksData); + } + // endregion } \ No newline at end of file From 9e3584fcbf08b169235fa1dc58f9c5dd37d45cbc Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Wed, 14 Sep 2022 11:42:20 +0200 Subject: [PATCH 116/293] Move purge elements to `com.iexec.common.lifecycle.purge` package --- .../src/main/java/com/iexec/sms/api/SmsClientProvider.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java index 0aa4aa35..b46fdb76 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java @@ -2,8 +2,8 @@ import com.iexec.common.chain.ChainDeal; import com.iexec.common.task.TaskDescription; -import com.iexec.common.utils.purge.ExpiringTaskMapFactory; -import com.iexec.common.utils.purge.Purgeable; +import com.iexec.common.lifecycle.purge.ExpiringTaskMapFactory; +import com.iexec.common.lifecycle.purge.Purgeable; import feign.Logger; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; From 720773f3e7433a688f7f5fe2b7d08a1efbfc572b Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Fri, 16 Sep 2022 14:20:37 +0200 Subject: [PATCH 117/293] Log specific message in `buildAndPostSession` when no return from CAS --- .../tee/session/scone/SconeSessionHandlerService.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerService.java b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerService.java index bc5e8772..1c635564 100644 --- a/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerService.java +++ b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerService.java @@ -65,8 +65,15 @@ public String buildAndPostSession(TeeSessionRequest request) request.getTaskDescription().getChainTaskId(), session); } ResponseEntity postSession = apiClient.postSession(session.toString()); - Integer httpCode = postSession != null ? postSession.getStatusCodeValue() : null; - if (httpCode == null || httpCode != 201) { + + if (postSession == null) { + throw new TeeSessionGenerationException( + TeeSessionGenerationError.SECURE_SESSION_STORAGE_CALL_FAILED, + "Failed to post session, no return from CAS."); + } + + int httpCode = postSession.getStatusCodeValue(); + if (httpCode != 201) { throw new TeeSessionGenerationException( TeeSessionGenerationError.SECURE_SESSION_STORAGE_CALL_FAILED, "Failed to post session: " + httpCode); From 916c78646890347a582d21a3b3945e59f460c50e Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Fri, 16 Sep 2022 15:26:13 +0200 Subject: [PATCH 118/293] Refactor secret controller and web2/web3 secret services to check secret existence in add methods --- .../iexec/sms/secret/SecretController.java | 6 ++--- .../sms/secret/web2/Web2SecretsService.java | 8 ++++++- .../sms/secret/web3/Web3SecretService.java | 9 ++++++- .../sms/secret/SecretControllerTests.java | 24 ++++++++++++------- .../secret/web2/Web2SecretsServiceTests.java | 23 +++++++++++------- .../secret/web3/Web3SecretServiceTests.java | 12 +++++++++- 6 files changed, 58 insertions(+), 24 deletions(-) diff --git a/src/main/java/com/iexec/sms/secret/SecretController.java b/src/main/java/com/iexec/sms/secret/SecretController.java index 44153379..bdbe1de9 100644 --- a/src/main/java/com/iexec/sms/secret/SecretController.java +++ b/src/main/java/com/iexec/sms/secret/SecretController.java @@ -86,11 +86,10 @@ public ResponseEntity addWeb3Secret(@RequestHeader String authorization, return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build(); } - if (web3SecretService.getSecret(secretAddress).isPresent()) { + if (!web3SecretService.addSecret(secretAddress, secretValue)) { return ResponseEntity.status(HttpStatus.CONFLICT).build(); // secret already exists } - web3SecretService.addSecret(secretAddress, secretValue); return ResponseEntity.noContent().build(); } @@ -135,11 +134,10 @@ public ResponseEntity addWeb2Secret(@RequestHeader String authorization, return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build(); } - if (web2SecretsService.getSecret(ownerAddress, secretName).isPresent()) { + if (!web2SecretsService.addSecret(ownerAddress, secretName, secretValue)) { return ResponseEntity.status(HttpStatus.CONFLICT).build(); } - web2SecretsService.addSecret(ownerAddress, secretName, secretValue); return ResponseEntity.noContent().build(); } diff --git a/src/main/java/com/iexec/sms/secret/web2/Web2SecretsService.java b/src/main/java/com/iexec/sms/secret/web2/Web2SecretsService.java index baffb935..912298dc 100644 --- a/src/main/java/com/iexec/sms/secret/web2/Web2SecretsService.java +++ b/src/main/java/com/iexec/sms/secret/web2/Web2SecretsService.java @@ -53,17 +53,23 @@ public Optional getSecret(String ownerAddress, String secretAddress, boo return shouldDecryptValue ? oSecret.map(this::decryptSecret) : oSecret; } - public void addSecret(String ownerAddress, String secretAddress, String secretValue) { + public boolean addSecret(String ownerAddress, String secretAddress, String secretValue) { ownerAddress = ownerAddress.toLowerCase(); Web2Secrets web2Secrets = getWeb2Secrets(ownerAddress) .orElse(new Web2Secrets(ownerAddress)); + if (web2Secrets.getSecret(secretAddress).isPresent()) { + log.error("Secret already exists [ownerAddress:{}, secretAddress:{}]", ownerAddress, secretAddress); + return false; + } + Secret secret = new Secret(secretAddress, secretValue); encryptSecret(secret); log.info("Adding new secret [ownerAddress:{}, secretAddress:{}, encryptedSecretValue:{}]", ownerAddress, secretAddress, secret.getValue()); web2Secrets.getSecrets().add(secret); web2SecretsRepository.save(web2Secrets); + return true; } public void updateSecret(String ownerAddress, String secretAddress, String newSecretValue) { diff --git a/src/main/java/com/iexec/sms/secret/web3/Web3SecretService.java b/src/main/java/com/iexec/sms/secret/web3/Web3SecretService.java index ecf197b8..7ea4eb12 100644 --- a/src/main/java/com/iexec/sms/secret/web3/Web3SecretService.java +++ b/src/main/java/com/iexec/sms/secret/web3/Web3SecretService.java @@ -56,13 +56,20 @@ public Optional getSecret(String secretAddress) { * * Stores encrypted secrets * */ - public void addSecret(String secretAddress, String secretValue) { + public boolean addSecret(String secretAddress, String secretValue) { secretAddress = secretAddress.toLowerCase(); + + if (web3SecretRepository.findWeb3SecretByAddress(secretAddress).isPresent()) { + log.error("Secret already exists [secretAddress:{}]", secretAddress); + return false; + } + Web3Secret web3Secret = new Web3Secret(secretAddress, secretValue); encryptSecret(web3Secret); log.info("Adding new web3 secret [secretAddress:{}, encryptedSecretValue:{}]", secretAddress, web3Secret.getValue()); web3SecretRepository.save(web3Secret); + return true; } } diff --git a/src/test/java/com/iexec/sms/secret/SecretControllerTests.java b/src/test/java/com/iexec/sms/secret/SecretControllerTests.java index edb0e03a..2a238121 100644 --- a/src/test/java/com/iexec/sms/secret/SecretControllerTests.java +++ b/src/test/java/com/iexec/sms/secret/SecretControllerTests.java @@ -135,7 +135,7 @@ void getWeb3Secret(boolean shouldDecryptSecret) { void failToAddWeb3SecretWhenPayloadTooLarge() { assertThat(secretController.addWeb3Secret(AUTHORIZATION, WEB3_SECRET_ADDRESS, getRandomString(4097))) .isEqualTo(ResponseEntity.status(HttpStatus.PAYLOAD_TOO_LARGE).build()); - verifyNoInteractions(web2SecretsService, web3SecretService); + verifyNoInteractions(authorizationService, web2SecretsService, web3SecretService); } @Test @@ -155,10 +155,12 @@ void failToAddWeb3SecretWhenSecretAlreadyExists() { .thenReturn(CHALLENGE); when(authorizationService.isSignedByOwner(CHALLENGE, AUTHORIZATION, WEB3_SECRET_ADDRESS)) .thenReturn(true); - when(web3SecretService.getSecret(WEB3_SECRET_ADDRESS)) - .thenReturn(Optional.of(new Web3Secret())); + when(web3SecretService.addSecret(WEB3_SECRET_ADDRESS, WEB3_SECRET_VALUE)) + .thenReturn(false); assertThat(secretController.addWeb3Secret(AUTHORIZATION, WEB3_SECRET_ADDRESS, WEB3_SECRET_VALUE)) .isEqualTo(ResponseEntity.status(HttpStatus.CONFLICT).build()); + verifyNoInteractions(web2SecretsService); + verify(web3SecretService).addSecret(WEB3_SECRET_ADDRESS, WEB3_SECRET_VALUE); } @Test @@ -167,10 +169,12 @@ void addWeb3Secret() { .thenReturn(CHALLENGE); when(authorizationService.isSignedByOwner(CHALLENGE, AUTHORIZATION, WEB3_SECRET_ADDRESS)) .thenReturn(true); - when(web3SecretService.getSecret(WEB3_SECRET_ADDRESS)) - .thenReturn(Optional.empty()); + when(web3SecretService.addSecret(WEB3_SECRET_ADDRESS, WEB3_SECRET_VALUE)) + .thenReturn(true); assertThat(secretController.addWeb3Secret(AUTHORIZATION, WEB3_SECRET_ADDRESS, WEB3_SECRET_VALUE)) .isEqualTo(ResponseEntity.noContent().build()); + verifyNoInteractions(web2SecretsService); + verify(web3SecretService).addSecret(WEB3_SECRET_ADDRESS, WEB3_SECRET_VALUE); } //endregion @@ -262,10 +266,11 @@ void failToAddWeb2SecretWhenSecretAlreadyExists() { .thenReturn(CHALLENGE); when(authorizationService.isSignedByHimself(CHALLENGE, AUTHORIZATION, WEB2_OWNER_ADDRESS)) .thenReturn(true); - when(web2SecretsService.getSecret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME)) - .thenReturn(Optional.of(new Secret())); + when(web2SecretsService.addSecret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, WEB2_SECRET_VALUE)) + .thenReturn(false); assertThat(secretController.addWeb2Secret(AUTHORIZATION, WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, WEB2_SECRET_VALUE)) .isEqualTo(ResponseEntity.status(HttpStatus.CONFLICT).build()); + verify(web2SecretsService).addSecret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, WEB2_SECRET_VALUE); } @Test @@ -274,10 +279,11 @@ void addWeb2Secret() { .thenReturn(CHALLENGE); when(authorizationService.isSignedByHimself(CHALLENGE, AUTHORIZATION, WEB2_OWNER_ADDRESS)) .thenReturn(true); - when(web2SecretsService.getSecret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME)) - .thenReturn(Optional.empty()); + when(web2SecretsService.addSecret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, WEB2_SECRET_VALUE)) + .thenReturn(true); assertThat(secretController.addWeb2Secret(AUTHORIZATION, WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, WEB2_SECRET_VALUE)) .isEqualTo(ResponseEntity.noContent().build()); + verify(web2SecretsService).addSecret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, WEB2_SECRET_VALUE); } //endregion diff --git a/src/test/java/com/iexec/sms/secret/web2/Web2SecretsServiceTests.java b/src/test/java/com/iexec/sms/secret/web2/Web2SecretsServiceTests.java index 64015999..b17f0782 100644 --- a/src/test/java/com/iexec/sms/secret/web2/Web2SecretsServiceTests.java +++ b/src/test/java/com/iexec/sms/secret/web2/Web2SecretsServiceTests.java @@ -32,7 +32,7 @@ class Web2SecretsServiceTests { - String ownerAddress = "ownerAddress"; + String ownerAddress = "ownerAddress".toLowerCase(); String secretAddress = "secretAddress"; String plainSecretValue = "plainSecretValue"; String encryptedSecretValue = "encryptedSecretValue"; @@ -53,7 +53,6 @@ void beforeEach() { @Test void shouldGetDecryptedSecret() { - ownerAddress = ownerAddress.toLowerCase(); Secret encryptedSecret = new Secret(secretAddress, encryptedSecretValue); encryptedSecret.setEncryptedValue(true); List secretList = List.of(encryptedSecret); @@ -72,7 +71,6 @@ void shouldGetDecryptedSecret() { @Test void shouldGetEncryptedSecret() { - ownerAddress = ownerAddress.toLowerCase(); Secret encryptedSecret = new Secret(secretAddress, encryptedSecretValue); encryptedSecret.setEncryptedValue(true); List secretList = List.of(encryptedSecret); @@ -87,16 +85,26 @@ void shouldGetEncryptedSecret() { .contains(encryptedSecret); } + @Test + void shouldNotAddSecretIfPresent() { + Web2Secrets web2Secrets = new Web2Secrets(ownerAddress); + web2Secrets.getSecrets().add(new Secret(secretAddress, encryptedSecretValue)); + when(web2SecretsRepository.findWeb2SecretsByOwnerAddress(ownerAddress)).thenReturn(Optional.of(web2Secrets)); + assertThat(web2SecretsService.addSecret(ownerAddress, secretAddress, plainSecretValue)).isFalse(); + verifyNoInteractions(encryptionService); + verify(web2SecretsRepository, never()).save(any()); + } + @Test void shouldAddSecret() { - ownerAddress = ownerAddress.toLowerCase(); - web2SecretsService.addSecret(ownerAddress, secretAddress, plainSecretValue); - verify(web2SecretsRepository, times(1)).save(any()); + when(encryptionService.encrypt(plainSecretValue)).thenReturn(encryptedSecretValue); + assertThat(web2SecretsService.addSecret(ownerAddress, secretAddress, plainSecretValue)).isTrue(); + verify(encryptionService).encrypt(any()); + verify(web2SecretsRepository).save(any()); } @Test void shouldNotUpdateSecretIfPresent() { - ownerAddress = ownerAddress.toLowerCase(); Secret encryptedSecret = new Secret(secretAddress, encryptedSecretValue); encryptedSecret.setEncryptedValue(true); List secretList = List.of(encryptedSecret); @@ -113,7 +121,6 @@ void shouldNotUpdateSecretIfPresent() { @Test void shouldUpdateSecret() { - ownerAddress = ownerAddress.toLowerCase(); Secret encryptedSecret = new Secret(secretAddress, encryptedSecretValue); encryptedSecret.setEncryptedValue(true); String newSecretValue = "newSecretValue"; diff --git a/src/test/java/com/iexec/sms/secret/web3/Web3SecretServiceTests.java b/src/test/java/com/iexec/sms/secret/web3/Web3SecretServiceTests.java index fb45fcc5..1bd66d28 100644 --- a/src/test/java/com/iexec/sms/secret/web3/Web3SecretServiceTests.java +++ b/src/test/java/com/iexec/sms/secret/web3/Web3SecretServiceTests.java @@ -47,10 +47,20 @@ void init() { MockitoAnnotations.openMocks(this); } + @Test + void shouldNotAddSecretIfPresent() { + Web3Secret web3Secret = new Web3Secret(secretAddress, encryptedSecretValue); + when(web3SecretRepository.findWeb3SecretByAddress(secretAddress)).thenReturn(Optional.of(web3Secret)); + assertThat(web3SecretService.addSecret(secretAddress, plainSecretValue)).isFalse(); + verifyNoInteractions(encryptionService); + verify(web3SecretRepository, never()).save(any()); + } + @Test void shouldAddSecret() { + when(web3SecretRepository.findWeb3SecretByAddress(secretAddress)).thenReturn(Optional.empty()); when(encryptionService.encrypt(plainSecretValue)).thenReturn(encryptedSecretValue); - web3SecretService.addSecret(secretAddress, plainSecretValue); + assertThat(web3SecretService.addSecret(secretAddress, plainSecretValue)).isTrue(); verify(encryptionService).encrypt(any()); verify(web3SecretRepository).save(any()); } From e966d64155c9e1269d82f8b5679fb9f536f5f734 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Mon, 19 Sep 2022 10:42:13 +0200 Subject: [PATCH 119/293] Add //FIXME on `SmsClientProvider#taskIdToSmsUrl` --- .../src/main/java/com/iexec/sms/api/SmsClientProvider.java | 1 + 1 file changed, 1 insertion(+) diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java index b46fdb76..9d49bb45 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java @@ -18,6 +18,7 @@ */ @Slf4j public class SmsClientProvider implements Purgeable { + // FIXME: `Optional` is useless here. We should remove it. private final Map> taskIdToSmsUrl = ExpiringTaskMapFactory.getExpiringTaskMap(); private final Map urlToSmsClient = new HashMap<>(); From 93eac04ce721ef9c130fc00db747cdde4f113899 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Mon, 19 Sep 2022 11:40:58 +0200 Subject: [PATCH 120/293] Add //FIXME on `SmsClientProvider#getOrCreateSmsClientForUninitializedTask` --- .../src/main/java/com/iexec/sms/api/SmsClientProvider.java | 1 + 1 file changed, 1 insertion(+) diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java index 9d49bb45..27f9425a 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java @@ -71,6 +71,7 @@ public SmsClient getOrCreateSmsClientForTask(TaskDescription taskDescription) { * @throws SmsClientCreationException if SMS URL can't be retrieved. * @return An instance of {@link SmsClient} pointing on the deal's specified SMS. */ + // FIXME: merge with `getOrCreateSmsClientForTask` public SmsClient getOrCreateSmsClientForUninitializedTask(ChainDeal deal, String chainTaskId) { final Optional smsUrl = taskIdToSmsUrl.computeIfAbsent( chainTaskId, From 088c1b1d9f194843848a00045190bbbe0c945bd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20James=20Toussaint?= Date: Mon, 19 Sep 2022 12:27:40 +0200 Subject: [PATCH 121/293] Expose getSmsClient(url) in library --- .../com/iexec/sms/api/SmsClientProvider.java | 52 +----- .../iexec/sms/api/SmsClientProviderTests.java | 160 ++---------------- 2 files changed, 19 insertions(+), 193 deletions(-) diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java index a83a3859..57168968 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java @@ -1,14 +1,10 @@ package com.iexec.sms.api; -import com.iexec.common.chain.ChainDeal; -import com.iexec.common.task.TaskDescription; import feign.Logger; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; import java.util.HashMap; import java.util.Map; -import java.util.Optional; /** * Manages the {@link SmsClient}, providing an easy way to access SMS @@ -17,7 +13,6 @@ @Slf4j public class SmsClientProvider { // TODO: purge once task has been completed - private final Map> taskIdToSmsUrl = new HashMap<>(); private final Map urlToSmsClient = new HashMap<>(); private final Logger.Level loggerLevel; @@ -31,54 +26,17 @@ public SmsClientProvider(Logger.Level loggerLevel) { } /** - * Retrieves the specified SMS URL for this task, then: + * Retrieves an SMS client for the specified SMS URL: *

    *
  • If this SMS has already been accessed, returns the already-constructed {@link SmsClient};
  • *
  • Otherwise, constructs, stores and returns a new {@link SmsClient}.
  • *
* - * @param taskDescription Task the specified SMS URL should be retrieved for. - * @throws SmsClientCreationException if SMS URL can't be retrieved. - * @return An instance of {@link SmsClient} pointing on the task's specified SMS. + * @param smsUrl URL of the SMS. + * @return An instance of {@link SmsClient} pointing to the specified SMS. */ - public SmsClient getOrCreateSmsClientForTask(TaskDescription taskDescription) { - final String chainTaskId = taskDescription.getChainTaskId(); - - final Optional smsUrl = taskIdToSmsUrl.computeIfAbsent( - chainTaskId, - id -> Optional.ofNullable(taskDescription.getSmsUrl()) - ); - - if (smsUrl.isEmpty() || StringUtils.isEmpty(smsUrl.get())) { - throw new SmsClientCreationException("No SMS URL defined for given task [chainTaskId: " + chainTaskId +"]"); - } - - return urlToSmsClient.computeIfAbsent(smsUrl.get(), url -> SmsClientBuilder.getInstance(loggerLevel, url)); + public SmsClient getSmsClient(String smsUrl) { + return urlToSmsClient.computeIfAbsent(smsUrl, url -> SmsClientBuilder.getInstance(loggerLevel, url)); } - /** - * Retrieves the specified SMS URL for this task based on its dealId, then: - *
    - *
  • If this SMS has already been accessed, returns the already-constructed {@link SmsClient};
  • - *
  • Otherwise, constructs, stores and returns a new {@link SmsClient}.
  • - *
- * - * @param deal Deal of the task the specified SMS URL should be retrieved. - * @param chainTaskId ID of the task the specified SMS URL should be stored. - * @throws SmsClientCreationException if SMS URL can't be retrieved. - * @return An instance of {@link SmsClient} pointing on the deal's specified SMS. - */ - public SmsClient getOrCreateSmsClientForUninitializedTask(ChainDeal deal, String chainTaskId) { - final Optional smsUrl = taskIdToSmsUrl.computeIfAbsent( - chainTaskId, - id -> Optional.ofNullable(deal.getParams().getIexecSmsUrl()) - ); - - if (smsUrl.isEmpty() || StringUtils.isEmpty(smsUrl.get())) { - throw new SmsClientCreationException("No SMS URL defined for given deal " + - "[chainDealId: " + deal.getChainDealId() + ", chainTaskId: " + chainTaskId +"]"); - } - - return urlToSmsClient.computeIfAbsent(smsUrl.get(), url -> SmsClientBuilder.getInstance(loggerLevel, url)); - } } diff --git a/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientProviderTests.java b/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientProviderTests.java index 0c948c60..ed794a10 100644 --- a/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientProviderTests.java +++ b/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientProviderTests.java @@ -1,167 +1,35 @@ package com.iexec.sms.api; -import com.iexec.common.chain.ChainDeal; -import com.iexec.common.chain.DealParams; -import com.iexec.common.task.TaskDescription; import feign.Logger; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.MockitoAnnotations; import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.spy; class SmsClientProviderTests { - private static final String CHAIN_DEAL_ID_1 = "chainDealId1"; - private static final String CHAIN_TASK_ID_1 = "chainTaskId1"; private static final String SMS_URL_1 = "smsUrl1"; - private static final ChainDeal CHAIN_DEAL_1 = ChainDeal.builder() - .params(DealParams.builder().iexecSmsUrl(SMS_URL_1).build()) - .build(); - private static final TaskDescription TASK_DESCRIPTION_1 = TaskDescription.builder() - .chainTaskId(CHAIN_TASK_ID_1) - .smsUrl(SMS_URL_1) - .build(); - - private static final String CHAIN_DEAL_ID_2 = "chainDealId2"; - private static final String CHAIN_TASK_ID_2 = "chainTaskId2"; private static final String SMS_URL_2 = "smsUrl2"; - private static final ChainDeal CHAIN_DEAL_2 = ChainDeal.builder() - .chainDealId(CHAIN_DEAL_ID_2) - .params(DealParams.builder().iexecSmsUrl(SMS_URL_2).build()) - .build(); - private static final TaskDescription TASK_DESCRIPTION_2 = TaskDescription.builder() - .chainTaskId(CHAIN_TASK_ID_2) - .smsUrl(SMS_URL_2) - .build(); - - private static final String CHAIN_TASK_ID_3 = "chainTaskId3"; - private static final ChainDeal CHAIN_DEAL_3 = ChainDeal.builder() - .params(DealParams.builder().iexecSmsUrl(SMS_URL_1).build()) - .build(); - private static final TaskDescription TASK_DESCRIPTION_3 = TaskDescription.builder() - .chainTaskId(CHAIN_TASK_ID_3) - .smsUrl(SMS_URL_1) - .build(); - - SmsClientProvider smsClientProvider; + private SmsClientProvider smsClientProvider; @BeforeEach - void init() { + void init() { MockitoAnnotations.openMocks(this); - smsClientProvider = spy(new SmsClientProvider(Logger.Level.NONE)); - } - - // region getOrCreateSmsClientForTask - @Test - void shouldGetSmsClientForTaskDescription() { - final SmsClient smsClient = assertDoesNotThrow(() -> smsClientProvider.getOrCreateSmsClientForTask(TASK_DESCRIPTION_1)); - assertNotNull(smsClient); - } - - @Test - void shouldNotRetrieveAgainSmsClientForSameTaskDescription() { - final SmsClient smsClient1 = assertDoesNotThrow(() -> smsClientProvider.getOrCreateSmsClientForTask(TASK_DESCRIPTION_1)); - assertNotNull(smsClient1); - - final SmsClient smsClient2 = assertDoesNotThrow(() -> smsClientProvider.getOrCreateSmsClientForTask(TASK_DESCRIPTION_1)); - assertNotNull(smsClient2); - - assertEquals(smsClient1, smsClient2); - } - - @Test - void shouldNotRetrieveAgainSmsClientForSameSmsUrlOnAnotherTaskDescription() { - final SmsClient smsClient1 = assertDoesNotThrow(() -> smsClientProvider.getOrCreateSmsClientForTask(TASK_DESCRIPTION_1)); - assertNotNull(smsClient1); - - final SmsClient smsClient2 = assertDoesNotThrow(() -> smsClientProvider.getOrCreateSmsClientForTask(TASK_DESCRIPTION_3)); - assertNotNull(smsClient2); - - assertEquals(smsClient1, smsClient2); - } - - @Test - void shouldRetrieveAnotherSmsClientForTaskDescriptionOnSecondCallForAnotherSms() { - final SmsClient smsClientForTask1 = assertDoesNotThrow(() -> smsClientProvider.getOrCreateSmsClientForTask(TASK_DESCRIPTION_1)); - assertNotNull(smsClientForTask1); - - final SmsClient smsClientForTask2 = assertDoesNotThrow(() -> smsClientProvider.getOrCreateSmsClientForTask(TASK_DESCRIPTION_2)); - assertNotNull(smsClientForTask2); - - assertNotEquals(smsClientForTask1, smsClientForTask2); - } - - @Test - void shouldNotGetSmsClientForTaskDescriptionWhenNoSmsUrl() { - final TaskDescription taskDescription = TaskDescription.builder().chainTaskId(CHAIN_TASK_ID_1).build(); - final SmsClientCreationException e = assertThrows(SmsClientCreationException.class, - () -> smsClientProvider.getOrCreateSmsClientForTask(taskDescription)); - assertEquals("No SMS URL defined for given task [chainTaskId: " + CHAIN_TASK_ID_1 +"]", e.getMessage()); - } - - @Test - void shouldNotGetSmsClientForTaskDescriptionWhenEmptySmsUrl() { - final TaskDescription taskDescription = TaskDescription.builder().chainTaskId(CHAIN_TASK_ID_1).smsUrl("").build(); - final SmsClientCreationException e = assertThrows(SmsClientCreationException.class, - () -> smsClientProvider.getOrCreateSmsClientForTask(taskDescription)); - assertEquals("No SMS URL defined for given task [chainTaskId: " + CHAIN_TASK_ID_1 + "]", e.getMessage()); - } - // endregion - - // region getOrCreateSmsClientForUninitializedTask - @Test - void shouldGetSmsClientForUninitializedTask() { - final SmsClient smsClient = assertDoesNotThrow(() -> smsClientProvider.getOrCreateSmsClientForUninitializedTask(CHAIN_DEAL_1, CHAIN_TASK_ID_1)); - assertNotNull(smsClient); - } - - @Test - void shouldNotRetrieveAgainSmsClientForSameDeal() { - final SmsClient smsClient1 = assertDoesNotThrow(() -> smsClientProvider.getOrCreateSmsClientForUninitializedTask(CHAIN_DEAL_1, CHAIN_TASK_ID_1)); - assertNotNull(smsClient1); - - final SmsClient smsClient2 = assertDoesNotThrow(() -> smsClientProvider.getOrCreateSmsClientForUninitializedTask(CHAIN_DEAL_1, CHAIN_TASK_ID_1)); - assertNotNull(smsClient2); - - assertEquals(smsClient1, smsClient2); - } - - @Test - void shouldNotRetrieveAgainSmsClientForSameSmsUrlOnAnotherDeal() { - final SmsClient smsClient1 = assertDoesNotThrow(() -> smsClientProvider.getOrCreateSmsClientForUninitializedTask(CHAIN_DEAL_1, CHAIN_TASK_ID_1)); - assertNotNull(smsClient1); - - final SmsClient smsClient2 = assertDoesNotThrow(() -> smsClientProvider.getOrCreateSmsClientForUninitializedTask(CHAIN_DEAL_3, CHAIN_TASK_ID_3)); - assertNotNull(smsClient2); - - assertEquals(smsClient1, smsClient2); - } - - @Test - void shouldRetrieveAnotherSmsClientForUninitializedTaskOnSecondCallForAnotherSms() { - final SmsClient smsClientForUninitializedTask1 = assertDoesNotThrow(() -> smsClientProvider.getOrCreateSmsClientForUninitializedTask(CHAIN_DEAL_1, CHAIN_TASK_ID_1)); - assertNotNull(smsClientForUninitializedTask1); - - final SmsClient smsClientForUninitializedTask2 = assertDoesNotThrow(() -> smsClientProvider.getOrCreateSmsClientForUninitializedTask(CHAIN_DEAL_2, CHAIN_TASK_ID_2)); - assertNotNull(smsClientForUninitializedTask2); - - assertNotEquals(smsClientForUninitializedTask1, smsClientForUninitializedTask2); + smsClientProvider = new SmsClientProvider(Logger.Level.NONE); } + // region getSmsClient @Test - void shouldNotGetSmsClientForUninitializedTaskWhenNoSmsUrl() { - final ChainDeal chainDeal = ChainDeal - .builder() - .chainDealId(CHAIN_DEAL_ID_1) - .params(DealParams.builder().build()) - .build(); - final SmsClientCreationException e = assertThrows(SmsClientCreationException.class, - () -> smsClientProvider.getOrCreateSmsClientForUninitializedTask(chainDeal, CHAIN_TASK_ID_1)); - assertEquals( - "No SMS URL defined for given deal" + - " [chainDealId: " + CHAIN_DEAL_ID_1 + ", chainTaskId: " + CHAIN_TASK_ID_1 +"]", - e.getMessage()); + void shouldGetSmsClientForUrl() { + // Get same SMS client + SmsClient smsClient1a = smsClientProvider.getSmsClient(SMS_URL_1); + assertNotNull(smsClient1a); + // Get same SMS client on same URL + SmsClient smsClient1b = smsClientProvider.getSmsClient(SMS_URL_1); + assertEquals(smsClient1a, smsClient1b); + // Get different SMS clients + SmsClient smsClient2b = smsClientProvider.getSmsClient(SMS_URL_2); + assertNotEquals(smsClient1a, smsClient2b); } // endregion } \ No newline at end of file From 117405383fb09aa9dbf69cb27f905ffd59a74cc4 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Mon, 19 Sep 2022 16:18:25 +0200 Subject: [PATCH 122/293] Add `@NonNull` annotation on `GramineSessionMakerService#generateSession` --- .../tee/session/gramine/GramineSessionHandlerService.java | 5 ++--- .../sms/tee/session/gramine/GramineSessionMakerService.java | 2 ++ 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerService.java b/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerService.java index 052cb14a..d148a25f 100644 --- a/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerService.java +++ b/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerService.java @@ -55,10 +55,9 @@ public GramineSessionHandlerService(GramineSessionMakerService sessionService, public String buildAndPostSession(TeeSessionRequest request) throws TeeSessionGenerationException { GramineSession session = sessionService.generateSession(request); - if (session != null - && teeSessionLogConfiguration.isDisplayDebugSessionEnabled()) { + if (teeSessionLogConfiguration.isDisplayDebugSessionEnabled()) { log.info("Session content [taskId:{}]\n{}", - request.getTaskDescription().getChainTaskId(), session.toString()); + request.getTaskDescription().getChainTaskId(), session); } try { diff --git a/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerService.java b/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerService.java index dbad4a69..f2ca0b9f 100644 --- a/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerService.java +++ b/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerService.java @@ -27,6 +27,7 @@ import com.iexec.sms.tee.session.gramine.sps.GramineEnclave; import com.iexec.sms.tee.session.gramine.sps.GramineSession; import com.iexec.sms.tee.session.gramine.sps.GramineSession.GramineSessionBuilder; +import lombok.NonNull; import org.springframework.stereotype.Service; import java.util.List; @@ -51,6 +52,7 @@ public GramineSessionMakerService(SecretSessionBaseService secretSessionBaseServ * @param request session request details * @return session config */ + @NonNull public GramineSession generateSession(TeeSessionRequest request) throws TeeSessionGenerationException { SecretSessionBase baseSession = secretSessionBaseService.getSecretsTokens(request); GramineSessionBuilder gramineSession = GramineSession.builder() From ae2aa639aca1364efb75539e0def1924e99f0fa3 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Mon, 19 Sep 2022 16:33:13 +0200 Subject: [PATCH 123/293] Remove Feign logging --- src/main/resources/logback-spring.xml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main/resources/logback-spring.xml b/src/main/resources/logback-spring.xml index 75e42e5f..411ed485 100644 --- a/src/main/resources/logback-spring.xml +++ b/src/main/resources/logback-spring.xml @@ -25,8 +25,4 @@ - - - - \ No newline at end of file From e47b6dd4e75c51b8764bdf04e69f68ad90a218b9 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton <87655102+mcornaton@users.noreply.github.com> Date: Tue, 20 Sep 2022 09:30:40 +0200 Subject: [PATCH 124/293] Update gradle.properties MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jérémy James Toussaint <33313130+jeremyjams@users.noreply.github.com> --- gradle.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle.properties b/gradle.properties index 66c4844e..8a0d86d7 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ -version=gramine -iexecCommonVersion=gramine-NEXT-SNAPSHOT +version=7.1.0 +iexecCommonVersion=6.0.1 nexusUser nexusPassword From 810281597c5ca41722b2172477a07e8b84ecac83 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton <87655102+mcornaton@users.noreply.github.com> Date: Tue, 20 Sep 2022 10:01:49 +0200 Subject: [PATCH 125/293] Update gradle.properties --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 8a0d86d7..6244ab53 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ version=7.1.0 -iexecCommonVersion=6.0.1 +iexecCommonVersion=6.0.1-NEXT-SNAPSHOT nexusUser nexusPassword From d12b1947cfd3ba3d5cde336a519ff3f5c13dd16a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20James=20Toussaint?= Date: Tue, 20 Sep 2022 11:39:35 +0200 Subject: [PATCH 126/293] Remove public on test class --- .../tee/session/gramine/GramineSessionHandlerServiceTests.java | 2 +- .../sms/tee/session/scone/SconeSessionHandlerServiceTests.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerServiceTests.java b/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerServiceTests.java index d58a0b9d..b2379c41 100644 --- a/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerServiceTests.java @@ -41,7 +41,7 @@ import static org.mockito.Mockito.when; @ExtendWith(OutputCaptureExtension.class) -public class GramineSessionHandlerServiceTests { +class GramineSessionHandlerServiceTests { private static String SPS_URL = "spsUrl"; @Mock diff --git a/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerServiceTests.java b/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerServiceTests.java index 7009e917..a726ec46 100644 --- a/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerServiceTests.java @@ -25,7 +25,7 @@ import static org.mockito.Mockito.when; @ExtendWith(OutputCaptureExtension.class) -public class SconeSessionHandlerServiceTests { +class SconeSessionHandlerServiceTests { private static final String CAS_URL = "casUrl"; @Mock From 09631d1389c856c19a4b7c7e8d67d67e25469ecc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20James=20Toussaint?= Date: Tue, 20 Sep 2022 15:56:20 +0200 Subject: [PATCH 127/293] Build platform jar --- gradle.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle.properties b/gradle.properties index 6244ab53..33e34f6e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ -version=7.1.0 -iexecCommonVersion=6.0.1-NEXT-SNAPSHOT +version=7.1.0-platform +iexecCommonVersion=6.0.1-platform-NEXT-SNAPSHOT nexusUser nexusPassword From eeeb5bae07e6729815a53c76c966d6625301aaeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20James=20Toussaint?= <33313130+jeremyjams@users.noreply.github.com> Date: Fri, 23 Sep 2022 09:40:56 +0200 Subject: [PATCH 128/293] Update gradle.properties --- gradle.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle.properties b/gradle.properties index 33e34f6e..6244ab53 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ -version=7.1.0-platform -iexecCommonVersion=6.0.1-platform-NEXT-SNAPSHOT +version=7.1.0 +iexecCommonVersion=6.0.1-NEXT-SNAPSHOT nexusUser nexusPassword From 34dab2785ae36af9b6521399235950dc6d1df121 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Mon, 26 Sep 2022 16:39:24 +0200 Subject: [PATCH 129/293] Remove standard secrets support --- .../java/com/iexec/sms/api/SmsClient.java | 7 -- .../com/iexec/sms/untee/UnTeeController.java | 77 --------------- .../sms/untee/secret/UnTeeSecretService.java | 97 ------------------- 3 files changed, 181 deletions(-) delete mode 100644 src/main/java/com/iexec/sms/untee/UnTeeController.java delete mode 100644 src/main/java/com/iexec/sms/untee/secret/UnTeeSecretService.java diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java index 013b1026..d81f6edb 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java @@ -104,13 +104,6 @@ String setWeb3Secret( @Param("secretAddress") String secretAddress, String secretValue ); - - @RequestLine("POST /untee/secrets") - @Headers("Authorization: {authorization}") - SmsSecretResponse getUnTeeSecrets( - @Param("authorization") String authorization, - WorkerpoolAuthorization workerpoolAuthorization - ); // endregion // region TEE diff --git a/src/main/java/com/iexec/sms/untee/UnTeeController.java b/src/main/java/com/iexec/sms/untee/UnTeeController.java deleted file mode 100644 index 9b7c2543..00000000 --- a/src/main/java/com/iexec/sms/untee/UnTeeController.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2020 IEXEC BLOCKCHAIN TECH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.iexec.sms.untee; - - -import com.iexec.common.chain.WorkerpoolAuthorization; -import com.iexec.common.sms.secret.*; -import com.iexec.sms.authorization.AuthorizationService; -import com.iexec.sms.untee.secret.UnTeeSecretService; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; - -import java.util.Optional; - -@RestController -public class UnTeeController { - - private UnTeeSecretService unTeeSecretService; - private AuthorizationService authorizationService; - - public UnTeeController( - AuthorizationService authorizationService, - UnTeeSecretService unTeeSecretService) { - this.authorizationService = authorizationService; - this.unTeeSecretService = unTeeSecretService; - } - - /* - * Retrieve secrets when non-tee execution : We shouldn't do this.. - * */ - @PostMapping("/untee/secrets") - public ResponseEntity getUnTeeSecrets(@RequestHeader("Authorization") String authorization, - @RequestBody WorkerpoolAuthorization workerpoolAuthorization) { - String workerAddress = workerpoolAuthorization.getWorkerWallet(); - String challenge = authorizationService.getChallengeForWorker(workerpoolAuthorization); - if (!authorizationService.isSignedByHimself(challenge, authorization, workerAddress)) { - return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build(); - } - - if (!authorizationService.isAuthorizedOnExecution(workerpoolAuthorization, false)) { - return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build(); - } - - Optional unTeeTaskSecrets = unTeeSecretService.getUnTeeTaskSecrets(workerpoolAuthorization.getChainTaskId()); - if (unTeeTaskSecrets.isEmpty()) { - return ResponseEntity.status(HttpStatus.NOT_FOUND).build(); - } - - SmsSecretResponseData smsSecretResponseData = SmsSecretResponseData.builder() - .secrets(unTeeTaskSecrets.get()) - .build(); - - SmsSecretResponse smsSecretResponse = SmsSecretResponse.builder() - .data(smsSecretResponseData) - .build(); - - return Optional.of(smsSecretResponse).map(ResponseEntity::ok).orElseGet(() -> ResponseEntity.notFound().build()); - } - - -} - diff --git a/src/main/java/com/iexec/sms/untee/secret/UnTeeSecretService.java b/src/main/java/com/iexec/sms/untee/secret/UnTeeSecretService.java deleted file mode 100644 index 7e97b60c..00000000 --- a/src/main/java/com/iexec/sms/untee/secret/UnTeeSecretService.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2020 IEXEC BLOCKCHAIN TECH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.iexec.sms.untee.secret; - -import com.iexec.common.chain.ChainDeal; -import com.iexec.common.chain.ChainTask; -import com.iexec.common.sms.secret.SmsSecret; -import com.iexec.common.sms.secret.TaskSecrets; -import com.iexec.sms.blockchain.IexecHubService; -import com.iexec.sms.secret.Secret; -import com.iexec.sms.secret.web2.Web2SecretsService; -import com.iexec.sms.secret.web3.Web3Secret; -import com.iexec.sms.secret.web3.Web3SecretService; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Service; - -import java.util.Optional; - -import static com.iexec.sms.secret.ReservedSecretKeyName.IEXEC_RESULT_ENCRYPTION_PUBLIC_KEY; - -@Service -@Slf4j -public class UnTeeSecretService { - - private final IexecHubService iexecHubService; - private final Web3SecretService web3SecretService; - private final Web2SecretsService web2SecretsService; - - public UnTeeSecretService(IexecHubService iexecHubService, - Web3SecretService web3SecretService, - Web2SecretsService web2SecretsService - ) { - this.iexecHubService = iexecHubService; - this.web3SecretService = web3SecretService; - this.web2SecretsService = web2SecretsService; - } - - /* - * Untested yet - */ - public Optional getUnTeeTaskSecrets(String chainTaskId) { - TaskSecrets.TaskSecretsBuilder taskSecretsBuilder = TaskSecrets.builder(); - - // TODO use taskDescription instead of chainDeal - Optional oChainTask = iexecHubService.getChainTask(chainTaskId); - if (oChainTask.isEmpty()) { - log.error("getUnTeeTaskSecrets failed (getChainTask failed) [chainTaskId:{}]", chainTaskId); - return Optional.empty(); - } - ChainTask chainTask = oChainTask.get(); - Optional oChainDeal = iexecHubService.getChainDeal(chainTask.getDealid()); - if (oChainDeal.isEmpty()) { - log.error("getUnTeeTaskSecrets failed (getChainDeal failed) [chainTaskId:{}]", chainTaskId); - return Optional.empty(); - } - ChainDeal chainDeal = oChainDeal.get(); - String chainDatasetId = chainDeal.getChainDataset().getChainDatasetId(); - - Optional datasetSecret = web3SecretService.getSecret(chainDatasetId, true); - if (datasetSecret.isEmpty()) { - log.error("getUnTeeTaskSecrets failed (datasetSecret failed) [chainTaskId:{}]", chainTaskId); - return Optional.empty(); - } - taskSecretsBuilder.datasetSecret(SmsSecret.builder() - .address(datasetSecret.get().getAddress()) - .secret(datasetSecret.get().getValue()) - .build()); - - Optional beneficiarySecret = web2SecretsService.getSecret(chainDeal.getBeneficiary(), - IEXEC_RESULT_ENCRYPTION_PUBLIC_KEY, true); - if (beneficiarySecret.isEmpty()) { - log.error("getUnTeeTaskSecrets failed (beneficiarySecret empty) [chainTaskId:{}]", chainTaskId); - return Optional.empty(); - } - taskSecretsBuilder.beneficiarySecret(SmsSecret.builder() - .address(beneficiarySecret.get().getAddress()) - .secret(beneficiarySecret.get().getValue()) - .build()); - - return Optional.of(taskSecretsBuilder.build()); - } - -} From 7329b8fdd44ae1773d7430093c66a72669895f98 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Tue, 27 Sep 2022 10:30:22 +0200 Subject: [PATCH 130/293] Remove unused import --- iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java | 1 - 1 file changed, 1 deletion(-) diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java index d81f6edb..0c4f43f7 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java @@ -17,7 +17,6 @@ package com.iexec.sms.api; import com.iexec.common.chain.WorkerpoolAuthorization; -import com.iexec.common.sms.secret.SmsSecretResponse; import com.iexec.common.tee.TeeEnclaveProvider; import com.iexec.common.web.ApiResponseBody; import com.iexec.sms.api.config.GramineServicesProperties; From 2b03034d6002564afe469d08872fd67a6732ff35 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Tue, 4 Oct 2022 13:44:36 +0200 Subject: [PATCH 131/293] Add Scone resources --- Jenkinsfile | 11 +++++++++++ docker/sconify.args | 13 +++++++++++++ docker/sconify.sh | 24 ++++++++++++++++++++++++ 3 files changed, 48 insertions(+) create mode 100644 docker/sconify.args create mode 100755 docker/sconify.sh diff --git a/Jenkinsfile b/Jenkinsfile index 08c82fc3..5a7c4a6a 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,4 +1,7 @@ @Library('global-jenkins-library@2.2.0') _ + +String repositoryName = 'iexec-sms' + buildJavaProject( buildInfo: getBuildInfo(), integrationTestsEnvVars: [], @@ -11,3 +14,11 @@ buildJavaProject( developVisibility: 'iex.ec', preProductionVisibility: 'docker.io', productionVisibility: 'docker.io') + +sconeBuildUnlocked( + nativeImage: "docker-regis.iex.ec/$repositoryName:$buildInfo.imageTag", + imageName: repositoryName, + imageTag: buildInfo.imageTag, + sconifyArgsPath: './docker/sconify.args', + sconifyVersion: '5.7.0-wal' +) diff --git a/docker/sconify.args b/docker/sconify.args new file mode 100644 index 00000000..77ea6f97 --- /dev/null +++ b/docker/sconify.args @@ -0,0 +1,13 @@ +--verbose \ +--name=iexec-sms \ +--base=ubuntu:20.04 \ +--from=${IMG_FROM} \ +--to=${IMG_TO} \ +--binary=/usr/local/openjdk-11/bin/java \ +--heap="8G" \ +--stack="8M" \ +--fork="1" \ +--binary-fs \ +--fs-dir=/app \ +--host-path=/etc/hosts \ +--host-path=/etc/resolv.conf \ diff --git a/docker/sconify.sh b/docker/sconify.sh new file mode 100755 index 00000000..a880474f --- /dev/null +++ b/docker/sconify.sh @@ -0,0 +1,24 @@ +#!/bin/bash +# IMG_FROM=docker.io/iexechub/iexec-sms:dev IMG_TO=docker.io/iexechub/iexec-sms:dev-debug ./sconify.sh +cd $(dirname $0) + +SCONE_IMG_NAME=sconecuratedimages/iexec-sconify-image +SCONE_IMG_VERSION=5.7.0-wal + +IMG_TO=${IMG_TO}-sconify-${SCONE_IMG_VERSION}-debug + +ARGS=$(sed -e "s'\${IMG_FROM}'${IMG_FROM}'" -e "s'\${IMG_TO}'${IMG_TO}'" sconify.args) +echo $ARGS + +SCONE_IMAGE="registry.scontain.com:5050/${SCONE_IMG_NAME}:${SCONE_IMG_VERSION}" + +/bin/bash -c "docker run -t --rm \ + -v /var/run/docker.sock:/var/run/docker.sock \ + ${SCONE_IMAGE} \ + sconify_iexec \ + --cli=${SCONE_IMAGE} \ + --crosscompiler=${SCONE_IMAGE} \ + $ARGS" + +echo +docker run --rm -e SCONE_HASH=1 $IMG_TO From 9b24a16144b29158f4265a2d85c72e2e7ce0d4fa Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Tue, 4 Oct 2022 14:03:40 +0200 Subject: [PATCH 132/293] Add `buildInfo` var to Jenkinsfile --- Jenkinsfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Jenkinsfile b/Jenkinsfile index 5a7c4a6a..5c79d056 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -2,6 +2,8 @@ String repositoryName = 'iexec-sms' +buildInfo = getBuildInfo() + buildJavaProject( buildInfo: getBuildInfo(), integrationTestsEnvVars: [], From dd713c14d78dfc35de9fd01e40173ab00a7548b5 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Wed, 5 Oct 2022 09:25:02 +0200 Subject: [PATCH 133/293] Replace `getBuildInfo()` call by already known `buildInfo` --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 5c79d056..afa7b9d3 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -5,7 +5,7 @@ String repositoryName = 'iexec-sms' buildInfo = getBuildInfo() buildJavaProject( - buildInfo: getBuildInfo(), + buildInfo: buildInfo, integrationTestsEnvVars: [], shouldPublishJars: true, shouldPublishDockerImages: true, From 7e0adae1bbe85eb2a32690ad7ab8de5aab730139 Mon Sep 17 00:00:00 2001 From: mcornaton Date: Wed, 5 Oct 2022 09:45:08 +0200 Subject: [PATCH 134/293] Use correct base image --- docker/sconify.args | 2 +- docker/sconify.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docker/sconify.args b/docker/sconify.args index 77ea6f97..37d6d374 100644 --- a/docker/sconify.args +++ b/docker/sconify.args @@ -1,6 +1,6 @@ --verbose \ --name=iexec-sms \ ---base=ubuntu:20.04 \ +--base=openjdk:11.0.15-jre-slim \ --from=${IMG_FROM} \ --to=${IMG_TO} \ --binary=/usr/local/openjdk-11/bin/java \ diff --git a/docker/sconify.sh b/docker/sconify.sh index a880474f..9a67af3c 100755 --- a/docker/sconify.sh +++ b/docker/sconify.sh @@ -1,5 +1,5 @@ #!/bin/bash -# IMG_FROM=docker.io/iexechub/iexec-sms:dev IMG_TO=docker.io/iexechub/iexec-sms:dev-debug ./sconify.sh +# IMG_FROM=iexechub/iexec-sms:7.1.0 IMG_TO=iexechub/iexec-sms:7.1.0-debug ./sconify.sh cd $(dirname $0) SCONE_IMG_NAME=sconecuratedimages/iexec-sconify-image From e4ace63403a43834209f6eba5da441e0a53ef92e Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Wed, 5 Oct 2022 09:57:30 +0200 Subject: [PATCH 135/293] Use custom unlocked TEE debug image build --- Jenkinsfile | 57 ++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 50 insertions(+), 7 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index afa7b9d3..009cd986 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -17,10 +17,53 @@ buildJavaProject( preProductionVisibility: 'docker.io', productionVisibility: 'docker.io') -sconeBuildUnlocked( - nativeImage: "docker-regis.iex.ec/$repositoryName:$buildInfo.imageTag", - imageName: repositoryName, - imageTag: buildInfo.imageTag, - sconifyArgsPath: './docker/sconify.args', - sconifyVersion: '5.7.0-wal' -) +stage("Validate configuration") { + def config = [ + nativeImage: "docker-regis.iex.ec/$repositoryName:$buildInfo.imageTag", + imageName: repositoryName, + imageTag: buildInfo.imageTag, + sconifyArgsPath: './docker/sconify.args', + sconifyVersion: '5.7.0-wal' + ] + + if (config == null) { + error('Build requires proper config') + } + for (key in ["imageName", "imageTag", "nativeImage", "sconifyArgsPath"]) { + if (config[key] == null || config[key] == '') { + error "Build parameters require $key" + } + } + for (key in config.keySet()) { + if (!["imageName", "imageTag", "nativeImage", "sconifyArgsPath", "sconifyVersion"].contains(key)) { + error "Unknown key $key does not belong to [imageName, imageTag, nativeImage, sconifyArgsPath, sconifyVersion]" + } + } + imageName = config.imageName + imageTag = config.imageTag + nativeImage = config.nativeImage + sconifyArgsPath = config.sconifyArgsPath + + sconifyVersion = config.sconifyVersion + if (sconifyVersion == null || sconifyVersion == '') { + echo 'Falling back to default sconify tool version' + sconifyVersion = DEFAULT_SCONIFY_VERSION + } + + echo "imageName $imageName" + echo "imageTag $imageTag" + echo "nativeImage $nativeImage" + echo "sconifyArgsPath $sconifyArgsPath" + echo "sconifyVersion $sconifyVersion" +} + +stage('Trigger "unlocked" TEE debug image build') { + sconeSigning( + IMG_FROM: nativeImage, + IMG_TO: "docker-regis.iex.ec/$imageName-unlocked:$imageTag-sconify-$sconifyVersion-debug", + SCRIPT_CONFIG: sconifyArgsPath, + SCONE_IMG_NAME: 'scone-debug/iexec-sconify-image', + SCONE_IMG_VERS: sconifyVersion, + FLAVOR: 'DEBUG' + ) +} \ No newline at end of file From 488215c119c465b3dbd399bc48bf8d54097be60b Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Wed, 5 Oct 2022 10:02:40 +0200 Subject: [PATCH 136/293] Use correct repo --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 009cd986..9bd6e921 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -62,7 +62,7 @@ stage('Trigger "unlocked" TEE debug image build') { IMG_FROM: nativeImage, IMG_TO: "docker-regis.iex.ec/$imageName-unlocked:$imageTag-sconify-$sconifyVersion-debug", SCRIPT_CONFIG: sconifyArgsPath, - SCONE_IMG_NAME: 'scone-debug/iexec-sconify-image', + SCONE_IMG_NAME: 'sconecuratedimages/iexec-sconify-image', SCONE_IMG_VERS: sconifyVersion, FLAVOR: 'DEBUG' ) From 8c868b761caf6a715dae49ec75d017b50eff98f3 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Wed, 5 Oct 2022 10:49:51 +0200 Subject: [PATCH 137/293] Make Jenkinsfile simpler --- Jenkinsfile | 46 ++++++---------------------------------------- 1 file changed, 6 insertions(+), 40 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 9bd6e921..39e32c08 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -17,47 +17,13 @@ buildJavaProject( preProductionVisibility: 'docker.io', productionVisibility: 'docker.io') -stage("Validate configuration") { - def config = [ - nativeImage: "docker-regis.iex.ec/$repositoryName:$buildInfo.imageTag", - imageName: repositoryName, - imageTag: buildInfo.imageTag, - sconifyArgsPath: './docker/sconify.args', - sconifyVersion: '5.7.0-wal' - ] +stage('Trigger TEE debug image build') { + def nativeImage = "docker-regis.iex.ec/$repositoryName:$buildInfo.imageTag" + def imageName = repositoryName + def imageTag = buildInfo.imageTag + def sconifyArgsPath = './docker/sconify.args' + def sconifyVersion = '5.7.0-wal' - if (config == null) { - error('Build requires proper config') - } - for (key in ["imageName", "imageTag", "nativeImage", "sconifyArgsPath"]) { - if (config[key] == null || config[key] == '') { - error "Build parameters require $key" - } - } - for (key in config.keySet()) { - if (!["imageName", "imageTag", "nativeImage", "sconifyArgsPath", "sconifyVersion"].contains(key)) { - error "Unknown key $key does not belong to [imageName, imageTag, nativeImage, sconifyArgsPath, sconifyVersion]" - } - } - imageName = config.imageName - imageTag = config.imageTag - nativeImage = config.nativeImage - sconifyArgsPath = config.sconifyArgsPath - - sconifyVersion = config.sconifyVersion - if (sconifyVersion == null || sconifyVersion == '') { - echo 'Falling back to default sconify tool version' - sconifyVersion = DEFAULT_SCONIFY_VERSION - } - - echo "imageName $imageName" - echo "imageTag $imageTag" - echo "nativeImage $nativeImage" - echo "sconifyArgsPath $sconifyArgsPath" - echo "sconifyVersion $sconifyVersion" -} - -stage('Trigger "unlocked" TEE debug image build') { sconeSigning( IMG_FROM: nativeImage, IMG_TO: "docker-regis.iex.ec/$imageName-unlocked:$imageTag-sconify-$sconifyVersion-debug", From 30d0a6d29a3f7f3c8345a6cf6456192a40accade Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Wed, 5 Oct 2022 11:03:01 +0200 Subject: [PATCH 138/293] Add missing line break --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 39e32c08..fa0f9133 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -32,4 +32,4 @@ stage('Trigger TEE debug image build') { SCONE_IMG_VERS: sconifyVersion, FLAVOR: 'DEBUG' ) -} \ No newline at end of file +} From e6e87793e6bda31a03041ec184b1b18079b61552 Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Thu, 6 Oct 2022 10:58:09 +0200 Subject: [PATCH 139/293] Use TeeFramework instead of TeeEnclaveProvider in iexec-sms-library --- .../main/java/com/iexec/sms/api/SmsClient.java | 15 +++++++++++++-- .../sms/api/config/GramineServicesProperties.java | 6 +++--- .../sms/api/config/SconeServicesProperties.java | 6 +++--- .../sms/api/config/TeeServicesProperties.java | 8 ++++---- .../java/com/iexec/sms/api/SmsClientTests.java | 8 ++++---- 5 files changed, 27 insertions(+), 16 deletions(-) diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java index 0c4f43f7..fb452e69 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java @@ -18,6 +18,7 @@ import com.iexec.common.chain.WorkerpoolAuthorization; import com.iexec.common.tee.TeeEnclaveProvider; +import com.iexec.common.tee.TeeFramework; import com.iexec.common.web.ApiResponseBody; import com.iexec.sms.api.config.GramineServicesProperties; import com.iexec.sms.api.config.SconeServicesProperties; @@ -116,19 +117,29 @@ ApiResponseBody generat WorkerpoolAuthorization workerpoolAuthorization ); + /** @deprecated Use {@code getTeeFramework()} instead */ + @Deprecated(forRemoval = true) @RequestLine("GET /tee/provider") TeeEnclaveProvider getTeeEnclaveProvider(); + @RequestLine("GET /tee/framework") + TeeFramework getTeeFramework(); + @RequestLine("GET /tee/properties/scone") SconeServicesProperties getSconeServicesProperties(); @RequestLine("GET /tee/properties/gramine") GramineServicesProperties getGramineServicesProperties(); + @Deprecated(forRemoval = true) default T getTeeServicesProperties(TeeEnclaveProvider teeEnclaveProvider) { - if (teeEnclaveProvider == TeeEnclaveProvider.SCONE) { + return getTeeServicesProperties(TeeFramework.valueOf(teeEnclaveProvider.toString())); + } + + default T getTeeServicesProperties(TeeFramework teeFramework) { + if (teeFramework == TeeFramework.SCONE) { return (T) getSconeServicesProperties(); - } else if (teeEnclaveProvider == TeeEnclaveProvider.GRAMINE) { + } else if (teeFramework == TeeFramework.GRAMINE) { return (T) getGramineServicesProperties(); } diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/GramineServicesProperties.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/GramineServicesProperties.java index a420b9d7..5b4e8a91 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/GramineServicesProperties.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/GramineServicesProperties.java @@ -1,6 +1,6 @@ package com.iexec.sms.api.config; -import com.iexec.common.tee.TeeEnclaveProvider; +import com.iexec.common.tee.TeeFramework; import lombok.Getter; import lombok.Setter; @@ -9,11 +9,11 @@ public class GramineServicesProperties extends TeeServicesProperties { public GramineServicesProperties() { - super(TeeEnclaveProvider.GRAMINE); + super(TeeFramework.GRAMINE); } public GramineServicesProperties(TeeAppProperties preComputeProperties, TeeAppProperties postComputeProperties) { - super(TeeEnclaveProvider.GRAMINE, preComputeProperties, postComputeProperties); + super(TeeFramework.GRAMINE, preComputeProperties, postComputeProperties); } } diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/SconeServicesProperties.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/SconeServicesProperties.java index 1a305d7f..0e474af5 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/SconeServicesProperties.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/SconeServicesProperties.java @@ -1,6 +1,6 @@ package com.iexec.sms.api.config; -import com.iexec.common.tee.TeeEnclaveProvider; +import com.iexec.common.tee.TeeFramework; import lombok.Getter; import lombok.Setter; @@ -10,13 +10,13 @@ public class SconeServicesProperties extends TeeServicesProperties { private String lasImage; public SconeServicesProperties() { - super(TeeEnclaveProvider.SCONE); + super(TeeFramework.SCONE); } public SconeServicesProperties(TeeAppProperties preComputeProperties, TeeAppProperties postComputeProperties, String lasImage) { - super(TeeEnclaveProvider.SCONE, preComputeProperties, postComputeProperties); + super(TeeFramework.SCONE, preComputeProperties, postComputeProperties); this.lasImage = lasImage; } } diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeServicesProperties.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeServicesProperties.java index 72e4279d..aa6108aa 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeServicesProperties.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeServicesProperties.java @@ -1,6 +1,6 @@ package com.iexec.sms.api.config; -import com.iexec.common.tee.TeeEnclaveProvider; +import com.iexec.common.tee.TeeFramework; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; @@ -11,11 +11,11 @@ @Getter @Setter public abstract class TeeServicesProperties { - private TeeEnclaveProvider teeEnclaveProvider; + private TeeFramework teeFramework; private TeeAppProperties preComputeProperties; private TeeAppProperties postComputeProperties; - TeeServicesProperties(TeeEnclaveProvider teeEnclaveProvider) { - this.teeEnclaveProvider = teeEnclaveProvider; + TeeServicesProperties(TeeFramework teeFramework) { + this.teeFramework = teeFramework; } } diff --git a/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientTests.java b/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientTests.java index 31218210..14ede04d 100644 --- a/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientTests.java +++ b/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientTests.java @@ -16,7 +16,7 @@ package com.iexec.sms.api; -import com.iexec.common.tee.TeeEnclaveProvider; +import com.iexec.common.tee.TeeFramework; import com.iexec.sms.api.config.GramineServicesProperties; import com.iexec.sms.api.config.SconeServicesProperties; import com.iexec.sms.api.config.TeeAppProperties; @@ -50,7 +50,7 @@ void shouldGetSconeServicesProperties() { when(smsClient.getSconeServicesProperties()).thenReturn(properties); final TeeServicesProperties teeServicesProperties = - smsClient.getTeeServicesProperties(TeeEnclaveProvider.SCONE); + smsClient.getTeeServicesProperties(TeeFramework.SCONE); assertEquals(properties, teeServicesProperties); } @@ -66,7 +66,7 @@ void shouldGetGramineServicesProperties() { when(smsClient.getGramineServicesProperties()).thenReturn(properties); final TeeServicesProperties teeServicesProperties = - smsClient.getTeeServicesProperties(TeeEnclaveProvider.GRAMINE); + smsClient.getTeeServicesProperties(TeeFramework.GRAMINE); assertEquals(properties, teeServicesProperties); } @@ -78,7 +78,7 @@ void shouldNotGetTeeServicesPropertiesSinceUnknownProvider() { when(smsClient.getGramineServicesProperties()).thenReturn(null); final TeeServicesProperties teeServicesProperties = - smsClient.getTeeServicesProperties(TeeEnclaveProvider.GRAMINE); + smsClient.getTeeServicesProperties(TeeFramework.GRAMINE); assertNull(teeServicesProperties); } From 9885323ff35c0201d35f3e7dc44c56da98c2fb39 Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Thu, 6 Oct 2022 11:38:48 +0200 Subject: [PATCH 140/293] Rename ConditionalOnTeeProvider to ConditionalOnTeeFramework --- ...er.java => ConditionalOnTeeFramework.java} | 12 ++++----- ...tion.java => OnTeeFrameworkCondition.java} | 26 +++++++++---------- .../TeeWorkerInternalConfiguration.java | 8 +++--- .../gramine/GramineSessionHandlerService.java | 12 ++++----- .../gramine/GramineSessionMakerService.java | 6 ++--- .../session/gramine/sps/SpsConfiguration.java | 6 ++--- .../scone/SconeSessionHandlerService.java | 6 ++--- .../scone/SconeSessionMakerService.java | 6 ++--- .../scone/SconeSessionSecurityConfig.java | 6 ++--- .../sms/tee/session/scone/cas/CasClient.java | 6 ++--- .../session/scone/cas/CasConfiguration.java | 8 +++--- ...va => ConditionalOnTeeFrameworkTests.java} | 16 ++++++------ 12 files changed, 59 insertions(+), 59 deletions(-) rename src/main/java/com/iexec/sms/tee/{ConditionalOnTeeProvider.java => ConditionalOnTeeFramework.java} (72%) rename src/main/java/com/iexec/sms/tee/{OnTeeProviderCondition.java => OnTeeFrameworkCondition.java} (70%) rename src/test/java/com/iexec/sms/tee/{ConditionalOnTeeProviderTests.java => ConditionalOnTeeFrameworkTests.java} (93%) diff --git a/src/main/java/com/iexec/sms/tee/ConditionalOnTeeProvider.java b/src/main/java/com/iexec/sms/tee/ConditionalOnTeeFramework.java similarity index 72% rename from src/main/java/com/iexec/sms/tee/ConditionalOnTeeProvider.java rename to src/main/java/com/iexec/sms/tee/ConditionalOnTeeFramework.java index f0d2aa56..8f83b789 100644 --- a/src/main/java/com/iexec/sms/tee/ConditionalOnTeeProvider.java +++ b/src/main/java/com/iexec/sms/tee/ConditionalOnTeeFramework.java @@ -1,6 +1,6 @@ package com.iexec.sms.tee; -import com.iexec.common.tee.TeeEnclaveProvider; +import com.iexec.common.tee.TeeFramework; import org.springframework.context.annotation.Conditional; import java.lang.annotation.ElementType; @@ -13,15 +13,15 @@ *

* E.g.: *

    - *
  • a {@code SconeConfig} bean annotated with {@code ConditionalOnTeeProvider(teeProviders = SCONE)} + *
  • a {@code SconeConfig} bean annotated with {@code ConditionalOnTeeFramework(frameworks = SCONE)} * will be loaded only if a {@code scone} profile is active.
  • - *
  • a {@code TeeConfig} bean annotated with {@code ConditionalOnTeeProvider(teeProviders = {SCONE, GRAMINE})} + *
  • a {@code TeeConfig} bean annotated with {@code ConditionalOnTeeFramework(frameworks = {SCONE, GRAMINE})} * will be loaded only if any of {@code scone} or {@code gramine} profile is active.
  • *
*/ @Target({ ElementType.TYPE, ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) -@Conditional(OnTeeProviderCondition.class) -public @interface ConditionalOnTeeProvider { - TeeEnclaveProvider[] providers(); +@Conditional(OnTeeFrameworkCondition.class) +public @interface ConditionalOnTeeFramework { + TeeFramework[] frameworks(); } diff --git a/src/main/java/com/iexec/sms/tee/OnTeeProviderCondition.java b/src/main/java/com/iexec/sms/tee/OnTeeFrameworkCondition.java similarity index 70% rename from src/main/java/com/iexec/sms/tee/OnTeeProviderCondition.java rename to src/main/java/com/iexec/sms/tee/OnTeeFrameworkCondition.java index f7c7728d..741215b6 100644 --- a/src/main/java/com/iexec/sms/tee/OnTeeProviderCondition.java +++ b/src/main/java/com/iexec/sms/tee/OnTeeFrameworkCondition.java @@ -1,6 +1,6 @@ package com.iexec.sms.tee; -import com.iexec.common.tee.TeeEnclaveProvider; +import com.iexec.common.tee.TeeFramework; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.autoconfigure.condition.ConditionMessage; import org.springframework.boot.autoconfigure.condition.ConditionOutcome; @@ -16,13 +16,13 @@ /** * {@link Condition} that checks for a specific profile to be enabled. - * To be used with {@link ConditionalOnTeeProvider}. + * To be used with {@link ConditionalOnTeeFramework}. */ @Slf4j -public class OnTeeProviderCondition extends SpringBootCondition { +public class OnTeeFrameworkCondition extends SpringBootCondition { @Override public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) { - final Map attributes = metadata.getAnnotationAttributes(ConditionalOnTeeProvider.class.getName()); + final Map attributes = metadata.getAnnotationAttributes(ConditionalOnTeeFramework.class.getName()); final String[] activeProfiles = context.getEnvironment().getActiveProfiles(); final String beanClassName; @@ -38,25 +38,25 @@ public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeM beanClassName); return new ConditionOutcome( false, - ConditionMessage.forCondition(ConditionalOnTeeProvider.class).didNotFind("any TEE enclave providers").atAll()); + ConditionMessage.forCondition(ConditionalOnTeeFramework.class).didNotFind("any TEE frameworks").atAll()); } - final TeeEnclaveProvider[] providers = (TeeEnclaveProvider[]) attributes.get("providers"); - if (providers == null || providers.length == 0) { + final TeeFramework[] frameworks = (TeeFramework[]) attributes.get("frameworks"); + if (frameworks == null || frameworks.length == 0) { log.warn( - "No TEE provider defined for bean, won't be loaded [bean:{}]", + "No TEE framework defined for bean, won't be loaded [bean:{}]", beanClassName); return new ConditionOutcome( false, - ConditionMessage.forCondition(ConditionalOnTeeProvider.class).didNotFind("any TEE enclave providers").atAll()); + ConditionMessage.forCondition(ConditionalOnTeeFramework.class).didNotFind("any TEE frameworks").atAll()); } for (String activeProfile : activeProfiles) { - for (TeeEnclaveProvider teeProvider : providers) { - if (activeProfile.equalsIgnoreCase(teeProvider.name())) { + for (TeeFramework framework : frameworks) { + if (activeProfile.equalsIgnoreCase(framework.name())) { return new ConditionOutcome( true, - ConditionMessage.forCondition(ConditionalOnTeeProvider.class).foundExactly(teeProvider)); + ConditionMessage.forCondition(ConditionalOnTeeFramework.class).foundExactly(framework)); } } } @@ -67,6 +67,6 @@ public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeM return new ConditionOutcome( false, - ConditionMessage.forCondition(ConditionalOnTeeProvider.class).didNotFind("profile", "profiles").items(Arrays.asList(providers))); + ConditionMessage.forCondition(ConditionalOnTeeFramework.class).didNotFind("profile", "profiles").items(Arrays.asList(frameworks))); } } diff --git a/src/main/java/com/iexec/sms/tee/config/TeeWorkerInternalConfiguration.java b/src/main/java/com/iexec/sms/tee/config/TeeWorkerInternalConfiguration.java index dbe85f62..e907ba26 100644 --- a/src/main/java/com/iexec/sms/tee/config/TeeWorkerInternalConfiguration.java +++ b/src/main/java/com/iexec/sms/tee/config/TeeWorkerInternalConfiguration.java @@ -1,10 +1,10 @@ package com.iexec.sms.tee.config; -import com.iexec.common.tee.TeeEnclaveProvider; +import com.iexec.common.tee.TeeFramework; import com.iexec.sms.api.config.GramineServicesProperties; import com.iexec.sms.api.config.SconeServicesProperties; import com.iexec.sms.api.config.TeeAppProperties; -import com.iexec.sms.tee.ConditionalOnTeeProvider; +import com.iexec.sms.tee.ConditionalOnTeeFramework; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -62,7 +62,7 @@ TeeAppProperties postComputeProperties( } @Bean - @ConditionalOnTeeProvider(providers = TeeEnclaveProvider.GRAMINE) + @ConditionalOnTeeFramework(frameworks = TeeFramework.GRAMINE) GramineServicesProperties gramineServicesProperties( TeeAppProperties preComputeProperties, TeeAppProperties postComputeProperties) { @@ -70,7 +70,7 @@ GramineServicesProperties gramineServicesProperties( } @Bean - @ConditionalOnTeeProvider(providers = TeeEnclaveProvider.SCONE) + @ConditionalOnTeeFramework(frameworks = TeeFramework.SCONE) SconeServicesProperties sconeServicesProperties( TeeAppProperties preComputeProperties, TeeAppProperties postComputeProperties, diff --git a/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerService.java b/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerService.java index d148a25f..862899be 100644 --- a/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerService.java +++ b/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerService.java @@ -16,9 +16,9 @@ package com.iexec.sms.tee.session.gramine; -import com.iexec.common.tee.TeeEnclaveProvider; +import com.iexec.common.tee.TeeFramework; import com.iexec.sms.api.TeeSessionGenerationError; -import com.iexec.sms.tee.ConditionalOnTeeProvider; +import com.iexec.sms.tee.ConditionalOnTeeFramework; import com.iexec.sms.tee.session.TeeSessionLogConfiguration; import com.iexec.sms.tee.session.generic.TeeSessionGenerationException; import com.iexec.sms.tee.session.generic.TeeSessionHandler; @@ -30,11 +30,11 @@ @Slf4j @Component -@ConditionalOnTeeProvider(providers = TeeEnclaveProvider.GRAMINE) +@ConditionalOnTeeFramework(frameworks = TeeFramework.GRAMINE) public class GramineSessionHandlerService implements TeeSessionHandler { - private GramineSessionMakerService sessionService; - private SpsConfiguration spsConfiguration; - private TeeSessionLogConfiguration teeSessionLogConfiguration; + private final GramineSessionMakerService sessionService; + private final SpsConfiguration spsConfiguration; + private final TeeSessionLogConfiguration teeSessionLogConfiguration; public GramineSessionHandlerService(GramineSessionMakerService sessionService, SpsConfiguration spsConfiguration, diff --git a/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerService.java b/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerService.java index f2ca0b9f..e4d8ec87 100644 --- a/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerService.java +++ b/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerService.java @@ -16,9 +16,9 @@ package com.iexec.sms.tee.session.gramine; -import com.iexec.common.tee.TeeEnclaveProvider; +import com.iexec.common.tee.TeeFramework; import com.iexec.sms.api.config.TeeServicesProperties; -import com.iexec.sms.tee.ConditionalOnTeeProvider; +import com.iexec.sms.tee.ConditionalOnTeeFramework; import com.iexec.sms.tee.session.base.SecretEnclaveBase; import com.iexec.sms.tee.session.base.SecretSessionBase; import com.iexec.sms.tee.session.base.SecretSessionBaseService; @@ -33,7 +33,7 @@ import java.util.List; @Service -@ConditionalOnTeeProvider(providers = TeeEnclaveProvider.GRAMINE) +@ConditionalOnTeeFramework(frameworks = TeeFramework.GRAMINE) public class GramineSessionMakerService { private final SecretSessionBaseService secretSessionBaseService; diff --git a/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsConfiguration.java b/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsConfiguration.java index 7e893fa5..bb2e628a 100644 --- a/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsConfiguration.java +++ b/src/main/java/com/iexec/sms/tee/session/gramine/sps/SpsConfiguration.java @@ -16,16 +16,16 @@ package com.iexec.sms.tee.session.gramine.sps; -import com.iexec.common.tee.TeeEnclaveProvider; +import com.iexec.common.tee.TeeFramework; import com.iexec.common.utils.FeignBuilder; -import com.iexec.sms.tee.ConditionalOnTeeProvider; +import com.iexec.sms.tee.ConditionalOnTeeFramework; import feign.Logger.Level; import lombok.Getter; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; @Configuration -@ConditionalOnTeeProvider(providers = TeeEnclaveProvider.GRAMINE) +@ConditionalOnTeeFramework(frameworks = TeeFramework.GRAMINE) @Getter public class SpsConfiguration { @Value("${tee.secret-provisioner.web.hostname}") diff --git a/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerService.java b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerService.java index 1c635564..a77e31c0 100644 --- a/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerService.java +++ b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionHandlerService.java @@ -16,9 +16,9 @@ package com.iexec.sms.tee.session.scone; -import com.iexec.common.tee.TeeEnclaveProvider; +import com.iexec.common.tee.TeeFramework; import com.iexec.sms.api.TeeSessionGenerationError; -import com.iexec.sms.tee.ConditionalOnTeeProvider; +import com.iexec.sms.tee.ConditionalOnTeeFramework; import com.iexec.sms.tee.session.TeeSessionLogConfiguration; import com.iexec.sms.tee.session.generic.TeeSessionGenerationException; import com.iexec.sms.tee.session.generic.TeeSessionHandler; @@ -32,7 +32,7 @@ @Slf4j @Component -@ConditionalOnTeeProvider(providers = TeeEnclaveProvider.SCONE) +@ConditionalOnTeeFramework(frameworks = TeeFramework.SCONE) public class SconeSessionHandlerService implements TeeSessionHandler { private final SconeSessionMakerService sessionService; private final CasClient apiClient; diff --git a/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionMakerService.java b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionMakerService.java index 9d559e4c..a2161f04 100644 --- a/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionMakerService.java +++ b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionMakerService.java @@ -16,9 +16,9 @@ package com.iexec.sms.tee.session.scone; -import com.iexec.common.tee.TeeEnclaveProvider; +import com.iexec.common.tee.TeeFramework; import com.iexec.sms.api.config.TeeServicesProperties; -import com.iexec.sms.tee.ConditionalOnTeeProvider; +import com.iexec.sms.tee.ConditionalOnTeeFramework; import com.iexec.sms.tee.session.base.SecretEnclaveBase; import com.iexec.sms.tee.session.base.SecretSessionBase; import com.iexec.sms.tee.session.base.SecretSessionBaseService; @@ -40,7 +40,7 @@ //TODO Rename and move @Slf4j @Service -@ConditionalOnTeeProvider(providers = TeeEnclaveProvider.SCONE) +@ConditionalOnTeeFramework(frameworks = TeeFramework.SCONE) public class SconeSessionMakerService { // Internal values required for setting up a palaemon session diff --git a/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionSecurityConfig.java b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionSecurityConfig.java index 974870f6..1124f157 100644 --- a/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionSecurityConfig.java +++ b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionSecurityConfig.java @@ -16,8 +16,8 @@ package com.iexec.sms.tee.session.scone; -import com.iexec.common.tee.TeeEnclaveProvider; -import com.iexec.sms.tee.ConditionalOnTeeProvider; +import com.iexec.common.tee.TeeFramework; +import com.iexec.sms.tee.ConditionalOnTeeFramework; import lombok.Getter; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; @@ -25,7 +25,7 @@ import java.util.List; @Configuration -@ConditionalOnTeeProvider(providers = TeeEnclaveProvider.SCONE) +@ConditionalOnTeeFramework(frameworks = TeeFramework.SCONE) public class SconeSessionSecurityConfig { @Value("${tee.scone.attestation.tolerated-insecure-options}") diff --git a/src/main/java/com/iexec/sms/tee/session/scone/cas/CasClient.java b/src/main/java/com/iexec/sms/tee/session/scone/cas/CasClient.java index 7832ff94..5ece94b0 100644 --- a/src/main/java/com/iexec/sms/tee/session/scone/cas/CasClient.java +++ b/src/main/java/com/iexec/sms/tee/session/scone/cas/CasClient.java @@ -16,9 +16,9 @@ package com.iexec.sms.tee.session.scone.cas; -import com.iexec.common.tee.TeeEnclaveProvider; +import com.iexec.common.tee.TeeFramework; import com.iexec.sms.ssl.TwoWaySslClient; -import com.iexec.sms.tee.ConditionalOnTeeProvider; +import com.iexec.sms.tee.ConditionalOnTeeFramework; import org.springframework.http.HttpEntity; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; @@ -26,7 +26,7 @@ import java.nio.charset.StandardCharsets; @Service -@ConditionalOnTeeProvider(providers = TeeEnclaveProvider.SCONE) +@ConditionalOnTeeFramework(frameworks = TeeFramework.SCONE) public class CasClient { private final CasConfiguration casConfiguration; diff --git a/src/main/java/com/iexec/sms/tee/session/scone/cas/CasConfiguration.java b/src/main/java/com/iexec/sms/tee/session/scone/cas/CasConfiguration.java index efe28130..eeb96ac0 100644 --- a/src/main/java/com/iexec/sms/tee/session/scone/cas/CasConfiguration.java +++ b/src/main/java/com/iexec/sms/tee/session/scone/cas/CasConfiguration.java @@ -16,8 +16,8 @@ package com.iexec.sms.tee.session.scone.cas; -import com.iexec.common.tee.TeeEnclaveProvider; -import com.iexec.sms.tee.ConditionalOnTeeProvider; +import com.iexec.common.tee.TeeFramework; +import com.iexec.sms.tee.ConditionalOnTeeFramework; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; @@ -31,12 +31,12 @@ * When a service wants to access those secrets, it sends a quote with its MREnclave. * The CAS attests the quote through Intel Attestation Service and sends the secrets * if the MREnclave is as expected. - * + *

* MREnclave: an enclave identifier, created by hashing all its * code. It guarantees that a code behaves exactly as expected. */ @Component -@ConditionalOnTeeProvider(providers = TeeEnclaveProvider.SCONE) +@ConditionalOnTeeFramework(frameworks = TeeFramework.SCONE) @Getter @NoArgsConstructor @AllArgsConstructor diff --git a/src/test/java/com/iexec/sms/tee/ConditionalOnTeeProviderTests.java b/src/test/java/com/iexec/sms/tee/ConditionalOnTeeFrameworkTests.java similarity index 93% rename from src/test/java/com/iexec/sms/tee/ConditionalOnTeeProviderTests.java rename to src/test/java/com/iexec/sms/tee/ConditionalOnTeeFrameworkTests.java index dfa75f49..a8924c4b 100644 --- a/src/test/java/com/iexec/sms/tee/ConditionalOnTeeProviderTests.java +++ b/src/test/java/com/iexec/sms/tee/ConditionalOnTeeFrameworkTests.java @@ -1,6 +1,6 @@ package com.iexec.sms.tee; -import com.iexec.common.tee.TeeEnclaveProvider; +import com.iexec.common.tee.TeeFramework; import com.iexec.sms.tee.session.generic.TeeSessionHandler; import com.iexec.sms.tee.session.gramine.GramineSessionHandlerService; import com.iexec.sms.tee.session.gramine.GramineSessionMakerService; @@ -29,8 +29,8 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.when; -class ConditionalOnTeeProviderTests { - @ConditionalOnTeeProvider(providers = {}) +class ConditionalOnTeeFrameworkTests { + @ConditionalOnTeeFramework(frameworks = {}) static class NoProvidersSet {} @Mock @@ -39,7 +39,7 @@ static class NoProvidersSet {} ConditionContext context; @Mock AnnotationMetadata metadata; - OnTeeProviderCondition condition = new OnTeeProviderCondition(); + OnTeeFrameworkCondition condition = new OnTeeFrameworkCondition(); @BeforeEach void init() { @@ -181,9 +181,9 @@ void shouldNotMatchAnySinceClassDoesNotExist() { // endregion void setAttributesForMetadataMock(Class clazz) { - ConditionalOnTeeProvider annotation = clazz.getAnnotation(ConditionalOnTeeProvider.class); - TeeEnclaveProvider[] providers = annotation.providers(); - when(metadata.getAnnotationAttributes(ConditionalOnTeeProvider.class.getName())) - .thenReturn(Map.of("providers", providers)); + ConditionalOnTeeFramework annotation = clazz.getAnnotation(ConditionalOnTeeFramework.class); + TeeFramework[] frameworks = annotation.frameworks(); + when(metadata.getAnnotationAttributes(ConditionalOnTeeFramework.class.getName())) + .thenReturn(Map.of("frameworks", frameworks)); } } From 9047e6bc4b18b5cc50e0eb23acb9a190849ef41a Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Thu, 6 Oct 2022 11:39:30 +0200 Subject: [PATCH 141/293] Fix integration tests --- .../TeeTaskComputeSecretIntegrationTests.java | 2 +- .../com/iexec/sms/tee/TeeBeansLoadingTests.java | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/itest/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretIntegrationTests.java b/src/itest/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretIntegrationTests.java index d1742e7c..5d3e3133 100644 --- a/src/itest/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretIntegrationTests.java +++ b/src/itest/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretIntegrationTests.java @@ -91,7 +91,7 @@ private static String generateRandomAscii(int count) { } @BeforeEach - private void setUp() { + public void setUp() { apiClient = SmsClientBuilder.getInstance(Logger.Level.FULL, "http://localhost:" + randomServerPort); final Ownable appContract = mock(Ownable.class); when(appContract.getContractAddress()).thenReturn(APP_ADDRESS); diff --git a/src/itest/java/com/iexec/sms/tee/TeeBeansLoadingTests.java b/src/itest/java/com/iexec/sms/tee/TeeBeansLoadingTests.java index 42d7b8f2..611eb23a 100644 --- a/src/itest/java/com/iexec/sms/tee/TeeBeansLoadingTests.java +++ b/src/itest/java/com/iexec/sms/tee/TeeBeansLoadingTests.java @@ -1,6 +1,6 @@ package com.iexec.sms.tee; -import com.iexec.common.tee.TeeEnclaveProvider; +import com.iexec.common.tee.TeeFramework; import com.iexec.sms.CommonTestSetup; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Test; @@ -26,7 +26,7 @@ public abstract class TeeBeansLoadingTests extends CommonTestSetup { final String[] activeProfiles; TeeBeansLoadingTests(@Autowired Environment environment) { - this.annotatedTypeScanner = new AnnotatedTypeScanner(true, ConditionalOnTeeProvider.class); + this.annotatedTypeScanner = new AnnotatedTypeScanner(true, ConditionalOnTeeFramework.class); this.annotatedTypeScanner.setEnvironment(environment); this.activeProfiles = environment.getActiveProfiles(); } @@ -40,18 +40,18 @@ void checkNoUnwantedBeanIsLoaded() { final Set> sconeClasses = annotatedTypeScanner.findTypes("com", "iexec", "sms"); for (Class clazz : sconeClasses) { log.info("{} is loaded", clazz); - final TeeEnclaveProvider[] providers = clazz.getAnnotation(ConditionalOnTeeProvider.class).providers(); + final TeeFramework[] frameworks = clazz.getAnnotation(ConditionalOnTeeFramework.class).frameworks(); assertTrue( - areProfilesAndProvidersMatching(providers), + areProfilesAndFrameworksMatching(frameworks), clazz.getName() + " should not have been loaded [profiles:" + Arrays.toString(activeProfiles) + "]" ); } } - private boolean areProfilesAndProvidersMatching(TeeEnclaveProvider[] providers) { - for (TeeEnclaveProvider provider : providers) { + private boolean areProfilesAndFrameworksMatching(TeeFramework[] frameworks) { + for (TeeFramework framework : frameworks) { for (String activeProfile : activeProfiles) { - if (provider.name().equalsIgnoreCase(activeProfile)) { + if (framework.name().equalsIgnoreCase(activeProfile)) { return true; } } From f1a1d330eb3526c587ad5b9204d3e3e6443945ec Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Thu, 6 Oct 2022 11:46:08 +0200 Subject: [PATCH 142/293] Replace TeeEnclaveProvider with TeeFramework --- .../java/com/iexec/sms/tee/TeeController.java | 26 +++++++++++----- .../sms/tee/session/TeeSessionService.java | 6 ++-- .../com/iexec/sms/tee/TeeControllerTests.java | 30 +++++++++---------- .../TeeWorkerInternalConfigurationTests.java | 8 ++--- .../tee/session/TeeSessionServiceTests.java | 15 +++------- .../base/SecretSessionBaseServiceTests.java | 6 ++-- 6 files changed, 48 insertions(+), 43 deletions(-) diff --git a/src/main/java/com/iexec/sms/tee/TeeController.java b/src/main/java/com/iexec/sms/tee/TeeController.java index 18cde178..d35c3d50 100644 --- a/src/main/java/com/iexec/sms/tee/TeeController.java +++ b/src/main/java/com/iexec/sms/tee/TeeController.java @@ -19,6 +19,7 @@ import com.iexec.common.chain.WorkerpoolAuthorization; import com.iexec.common.tee.TeeEnclaveProvider; +import com.iexec.common.tee.TeeFramework; import com.iexec.common.web.ApiResponseBody; import com.iexec.sms.api.TeeSessionGenerationError; import com.iexec.sms.api.TeeSessionGenerationResponse; @@ -74,26 +75,37 @@ public TeeController( /** * Return which TEE enclave provider this SMS is configured to use. * @return TEE enclave provider this SMS is configured to use. + * @deprecated Use {@link #getTeeFramework()} instead */ + @Deprecated(forRemoval = true) @GetMapping("/provider") public ResponseEntity getTeeEnclaveProvider() { - return ResponseEntity.ok(teeServicesProperties.getTeeEnclaveProvider()); + return ResponseEntity.ok(TeeEnclaveProvider.valueOf(teeServicesProperties.getTeeFramework().toString())); + } + + /** + * Return which TEE framework this SMS is configured to use. + * @return TEE framework this SMS is configured to use. + */ + @GetMapping("/framework") + public ResponseEntity getTeeFramework() { + return ResponseEntity.ok(teeServicesProperties.getTeeFramework()); } /** * Retrieve properties for TEE services. This includes properties * for pre-compute and post-compute stages - * and potential TEE provider's specific data. + * and potential TEE framework's specific data. * * @return TEE services properties (pre-compute image uri, post-compute image uri, * heap size, ...) */ - @GetMapping("/properties/{teeEnclaveProvider}") + @GetMapping("/properties/{teeFramework}") public ResponseEntity getTeeServicesProperties( - @PathVariable TeeEnclaveProvider teeEnclaveProvider) { - if (teeEnclaveProvider != teeServicesProperties.getTeeEnclaveProvider()) { - log.error("SMS configured to use another TeeEnclaveProvider " + - "[required:{}, actual:{}]", teeEnclaveProvider, teeServicesProperties.getTeeEnclaveProvider()); + @PathVariable TeeFramework teeFramework) { + if (teeFramework != teeServicesProperties.getTeeFramework()) { + log.error("SMS configured to use another TeeFramework " + + "[required:{}, actual:{}]", teeFramework, teeServicesProperties.getTeeFramework()); return ResponseEntity.status(HttpStatus.CONFLICT).build(); } return ResponseEntity.ok(teeServicesProperties); diff --git a/src/main/java/com/iexec/sms/tee/session/TeeSessionService.java b/src/main/java/com/iexec/sms/tee/session/TeeSessionService.java index bd0b13ec..bbcc70ed 100644 --- a/src/main/java/com/iexec/sms/tee/session/TeeSessionService.java +++ b/src/main/java/com/iexec/sms/tee/session/TeeSessionService.java @@ -17,7 +17,7 @@ package com.iexec.sms.tee.session; import com.iexec.common.task.TaskDescription; -import com.iexec.common.tee.TeeEnclaveProvider; +import com.iexec.common.tee.TeeFramework; import com.iexec.sms.api.TeeSessionGenerationResponse; import com.iexec.sms.blockchain.IexecHubService; import com.iexec.sms.tee.session.generic.TeeSessionGenerationException; @@ -63,8 +63,8 @@ public TeeSessionGenerationResponse generateTeeSession( .enclaveChallenge(teeChallenge) .build(); - final TeeEnclaveProvider teeEnclaveProvider = taskDescription.getTeeEnclaveProvider(); - if (teeEnclaveProvider == null) { + final TeeFramework teeFramework = taskDescription.getTeeFramework(); + if (teeFramework == null) { throw new TeeSessionGenerationException( SECURE_SESSION_NO_TEE_PROVIDER, String.format("TEE provider can't be null [taskId:%s]", taskId)); diff --git a/src/test/java/com/iexec/sms/tee/TeeControllerTests.java b/src/test/java/com/iexec/sms/tee/TeeControllerTests.java index dfcf1a11..89741a5d 100644 --- a/src/test/java/com/iexec/sms/tee/TeeControllerTests.java +++ b/src/test/java/com/iexec/sms/tee/TeeControllerTests.java @@ -1,7 +1,7 @@ package com.iexec.sms.tee; import com.iexec.common.chain.WorkerpoolAuthorization; -import com.iexec.common.tee.TeeEnclaveProvider; +import com.iexec.common.tee.TeeFramework; import com.iexec.common.web.ApiResponseBody; import com.iexec.sms.api.TeeSessionGenerationError; import com.iexec.sms.api.TeeSessionGenerationResponse; @@ -80,13 +80,13 @@ void shouldGetSconeProvider() { authorizationService, teeChallengeService, teeSessionService, properties ); - final ResponseEntity response = - teeController.getTeeEnclaveProvider(); + final ResponseEntity response = + teeController.getTeeFramework(); assertEquals(HttpStatus.OK, response.getStatusCode()); - final TeeEnclaveProvider result = response.getBody(); - assertEquals(TeeEnclaveProvider.SCONE, result); + final TeeFramework result = response.getBody(); + assertEquals(TeeFramework.SCONE, result); } @Test @@ -100,13 +100,13 @@ void shouldGetGramineProvider() { authorizationService, teeChallengeService, teeSessionService, properties ); - final ResponseEntity response = - teeController.getTeeEnclaveProvider(); + final ResponseEntity response = + teeController.getTeeFramework(); assertEquals(HttpStatus.OK, response.getStatusCode()); - final TeeEnclaveProvider result = response.getBody(); - assertEquals(TeeEnclaveProvider.GRAMINE, result); + final TeeFramework result = response.getBody(); + assertEquals(TeeFramework.GRAMINE, result); } // endregion @@ -124,14 +124,14 @@ void shouldGetSconeProperties() { ); final ResponseEntity response = - teeController.getTeeServicesProperties(TeeEnclaveProvider.SCONE); + teeController.getTeeServicesProperties(TeeFramework.SCONE); assertEquals(HttpStatus.OK, response.getStatusCode()); final TeeServicesProperties result = response.getBody(); assertNotNull(result); assertInstanceOf(SconeServicesProperties.class, result); - assertEquals(TeeEnclaveProvider.SCONE, result.getTeeEnclaveProvider()); + assertEquals(TeeFramework.SCONE, result.getTeeFramework()); assertEquals(preComputeProperties, result.getPreComputeProperties()); assertEquals(postComputeProperties, result.getPostComputeProperties()); assertEquals(postComputeProperties, result.getPostComputeProperties()); @@ -150,14 +150,14 @@ void shouldGetGramineProperties() { ); final ResponseEntity response = - teeController.getTeeServicesProperties(TeeEnclaveProvider.GRAMINE); + teeController.getTeeServicesProperties(TeeFramework.GRAMINE); assertEquals(HttpStatus.OK, response.getStatusCode()); final TeeServicesProperties result = response.getBody(); assertNotNull(result); assertInstanceOf(GramineServicesProperties.class, result); - assertEquals(TeeEnclaveProvider.GRAMINE, result.getTeeEnclaveProvider()); + assertEquals(TeeFramework.GRAMINE, result.getTeeFramework()); assertEquals(preComputeProperties, result.getPreComputeProperties()); assertEquals(postComputeProperties, result.getPostComputeProperties()); } @@ -175,7 +175,7 @@ void shouldNotGetSconePropertiesSinceGramineSms() { ); final ResponseEntity response = - teeController.getTeeServicesProperties(TeeEnclaveProvider.GRAMINE); + teeController.getTeeServicesProperties(TeeFramework.GRAMINE); assertEquals(HttpStatus.CONFLICT, response.getStatusCode()); } @@ -192,7 +192,7 @@ void shouldNotGetGraminePropertiesSinceSconeSms() { ); final ResponseEntity response = - teeController.getTeeServicesProperties(TeeEnclaveProvider.SCONE); + teeController.getTeeServicesProperties(TeeFramework.SCONE); assertEquals(HttpStatus.CONFLICT, response.getStatusCode()); } diff --git a/src/test/java/com/iexec/sms/tee/config/TeeWorkerInternalConfigurationTests.java b/src/test/java/com/iexec/sms/tee/config/TeeWorkerInternalConfigurationTests.java index ddda313b..28554630 100644 --- a/src/test/java/com/iexec/sms/tee/config/TeeWorkerInternalConfigurationTests.java +++ b/src/test/java/com/iexec/sms/tee/config/TeeWorkerInternalConfigurationTests.java @@ -1,12 +1,12 @@ package com.iexec.sms.tee.config; -import com.iexec.common.tee.TeeEnclaveProvider; +import com.iexec.common.tee.TeeFramework; import com.iexec.sms.api.config.GramineServicesProperties; import com.iexec.sms.api.config.SconeServicesProperties; import com.iexec.sms.api.config.TeeAppProperties; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.mock; class TeeWorkerInternalConfigurationTests { @@ -63,7 +63,7 @@ void gramineServicesProperties() { GramineServicesProperties properties = teeWorkerInternalConfiguration.gramineServicesProperties(preComputeProperties, postComputeProperties); - assertEquals(TeeEnclaveProvider.GRAMINE, properties.getTeeEnclaveProvider()); + assertEquals(TeeFramework.GRAMINE, properties.getTeeFramework()); assertEquals(preComputeProperties, properties.getPreComputeProperties()); assertEquals(postComputeProperties, properties.getPostComputeProperties()); } @@ -78,7 +78,7 @@ void sconeServicesProperties() { SconeServicesProperties properties = teeWorkerInternalConfiguration.sconeServicesProperties(preComputeProperties, postComputeProperties, LAS_IMAGE); - assertEquals(TeeEnclaveProvider.SCONE, properties.getTeeEnclaveProvider()); + assertEquals(TeeFramework.SCONE, properties.getTeeFramework()); assertEquals(preComputeProperties, properties.getPreComputeProperties()); assertEquals(postComputeProperties, properties.getPostComputeProperties()); assertEquals(LAS_IMAGE, properties.getLasImage()); diff --git a/src/test/java/com/iexec/sms/tee/session/TeeSessionServiceTests.java b/src/test/java/com/iexec/sms/tee/session/TeeSessionServiceTests.java index 0b71b03d..707c12b1 100644 --- a/src/test/java/com/iexec/sms/tee/session/TeeSessionServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/TeeSessionServiceTests.java @@ -1,25 +1,18 @@ package com.iexec.sms.tee.session; import com.iexec.common.task.TaskDescription; -import com.iexec.common.tee.TeeEnclaveProvider; +import com.iexec.common.tee.TeeFramework; import com.iexec.sms.api.TeeSessionGenerationError; import com.iexec.sms.api.TeeSessionGenerationResponse; import com.iexec.sms.blockchain.IexecHubService; import com.iexec.sms.tee.session.generic.TeeSessionGenerationException; -import com.iexec.sms.tee.session.generic.TeeSessionHandler; import com.iexec.sms.tee.session.gramine.GramineSessionHandlerService; import com.iexec.sms.tee.session.scone.SconeSessionHandlerService; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.MethodSource; -import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import java.util.Map; -import java.util.stream.Stream; - import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; @@ -48,7 +41,7 @@ void shouldGenerateSconeSession() final TaskDescription taskDescription = TaskDescription.builder() .chainTaskId(TASK_ID) - .teeEnclaveProvider(TeeEnclaveProvider.SCONE) + .teeFramework(TeeFramework.SCONE) .build(); when(iexecHubService.getTaskDescription(TASK_ID)).thenReturn(taskDescription); when(sconeService.buildAndPostSession(any())).thenReturn(SECRET_PROVISIONING_URL); @@ -68,7 +61,7 @@ void shouldGenerateGramineSession() final TaskDescription taskDescription = TaskDescription.builder() .chainTaskId(TASK_ID) - .teeEnclaveProvider(TeeEnclaveProvider.GRAMINE) + .teeFramework(TeeFramework.GRAMINE) .build(); when(iexecHubService.getTaskDescription(TASK_ID)).thenReturn(taskDescription); when(gramineService.buildAndPostSession(any())).thenReturn(SECRET_PROVISIONING_URL); @@ -102,7 +95,7 @@ void shouldNotGenerateTeeSessionSinceNoTeeEnclaveProvider() { final TaskDescription taskDescription = TaskDescription.builder() .chainTaskId(TASK_ID) - .teeEnclaveProvider(null) + .teeFramework(null) .build(); when(iexecHubService.getTaskDescription(TASK_ID)).thenReturn(taskDescription); diff --git a/src/test/java/com/iexec/sms/tee/session/base/SecretSessionBaseServiceTests.java b/src/test/java/com/iexec/sms/tee/session/base/SecretSessionBaseServiceTests.java index fe443fc1..f4301abe 100644 --- a/src/test/java/com/iexec/sms/tee/session/base/SecretSessionBaseServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/base/SecretSessionBaseServiceTests.java @@ -1,14 +1,14 @@ package com.iexec.sms.tee.session.base; import com.iexec.common.chain.DealParams; -import com.iexec.common.sms.secret.ReservedSecretKeyName; import com.iexec.common.task.TaskDescription; import com.iexec.common.tee.TeeEnclaveConfiguration; -import com.iexec.common.tee.TeeEnclaveProvider; +import com.iexec.common.tee.TeeFramework; import com.iexec.common.utils.IexecEnvUtils; import com.iexec.sms.api.TeeSessionGenerationError; import com.iexec.sms.api.config.TeeAppProperties; import com.iexec.sms.api.config.TeeServicesProperties; +import com.iexec.sms.secret.ReservedSecretKeyName; import com.iexec.sms.secret.Secret; import com.iexec.sms.secret.compute.OnChainObjectType; import com.iexec.sms.secret.compute.SecretOwnerRole; @@ -50,7 +50,7 @@ class SecretSessionBaseServiceTests { private static final TeeEnclaveConfiguration enclaveConfig = TeeEnclaveConfiguration.builder() - .provider(TeeEnclaveProvider.SCONE)// any would be fine + .framework(TeeFramework.SCONE)// any would be fine .entrypoint(APP_ENTRYPOINT) .fingerprint(APP_FINGERPRINT) .heapSize(1) From 9b372840dd35f2abfd2aa6db85bc17d6988ce196 Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Thu, 6 Oct 2022 12:23:52 +0200 Subject: [PATCH 143/293] Add final keyword in some classes --- .../java/com/iexec/sms/encryption/EncryptionService.java | 2 +- .../com/iexec/sms/tee/challenge/TeeChallengeService.java | 4 ++-- .../iexec/sms/tee/challenge/TeeChallengeServiceTests.java | 6 +++--- .../session/gramine/GramineSessionHandlerServiceTests.java | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/iexec/sms/encryption/EncryptionService.java b/src/main/java/com/iexec/sms/encryption/EncryptionService.java index 50b1382c..deef1559 100644 --- a/src/main/java/com/iexec/sms/encryption/EncryptionService.java +++ b/src/main/java/com/iexec/sms/encryption/EncryptionService.java @@ -33,7 +33,7 @@ public class EncryptionService { private final String DEFAULT_MESSAGE = "Hello message to test AES key integrity"; - private byte[] aesKey; + private final byte[] aesKey; public EncryptionService(EncryptionConfiguration configuration) { this.aesKey = getOrCreateAesKey(configuration.getAesKeyPath()); diff --git a/src/main/java/com/iexec/sms/tee/challenge/TeeChallengeService.java b/src/main/java/com/iexec/sms/tee/challenge/TeeChallengeService.java index 992db397..551e0c61 100644 --- a/src/main/java/com/iexec/sms/tee/challenge/TeeChallengeService.java +++ b/src/main/java/com/iexec/sms/tee/challenge/TeeChallengeService.java @@ -29,8 +29,8 @@ @Service public class TeeChallengeService { - private TeeChallengeRepository teeChallengeRepository; - private EncryptionService encryptionService; + private final TeeChallengeRepository teeChallengeRepository; + private final EncryptionService encryptionService; public TeeChallengeService(TeeChallengeRepository teeChallengeRepository, EncryptionService encryptionService) { diff --git a/src/test/java/com/iexec/sms/tee/challenge/TeeChallengeServiceTests.java b/src/test/java/com/iexec/sms/tee/challenge/TeeChallengeServiceTests.java index 6cc471b4..59680917 100644 --- a/src/test/java/com/iexec/sms/tee/challenge/TeeChallengeServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/challenge/TeeChallengeServiceTests.java @@ -36,9 +36,9 @@ class TeeChallengeServiceTests { - private final static String TASK_ID = "0x123"; - private final static String PLAIN_PRIVATE = "plainPrivate"; - private final static String ENC_PRIVATE = "encPrivate"; + private static final String TASK_ID = "0x123"; + private static final String PLAIN_PRIVATE = "plainPrivate"; + private static final String ENC_PRIVATE = "encPrivate"; @Mock private TeeChallengeRepository teeChallengeRepository; diff --git a/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerServiceTests.java b/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerServiceTests.java index b2379c41..6d9a8a9f 100644 --- a/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionHandlerServiceTests.java @@ -43,7 +43,7 @@ @ExtendWith(OutputCaptureExtension.class) class GramineSessionHandlerServiceTests { - private static String SPS_URL = "spsUrl"; + private static final String SPS_URL = "spsUrl"; @Mock private GramineSessionMakerService sessionService; @Mock From 8bbe2013170880359262e2e1c27c122136a48966 Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Fri, 7 Oct 2022 09:45:50 +0200 Subject: [PATCH 144/293] Replace TeeEnclaveProviderConverter with TeeFrameworkConverter --- .../sms/tee/TeeEnclaveProviderConverter.java | 17 ----------------- .../iexec/sms/tee/TeeFrameworkConverter.java | 17 +++++++++++++++++ ...sts.java => TeeFrameworkConverterTests.java} | 11 ++++++----- 3 files changed, 23 insertions(+), 22 deletions(-) delete mode 100644 src/main/java/com/iexec/sms/tee/TeeEnclaveProviderConverter.java create mode 100644 src/main/java/com/iexec/sms/tee/TeeFrameworkConverter.java rename src/test/java/com/iexec/sms/tee/{TeeEnclaveProviderConverterTests.java => TeeFrameworkConverterTests.java} (73%) diff --git a/src/main/java/com/iexec/sms/tee/TeeEnclaveProviderConverter.java b/src/main/java/com/iexec/sms/tee/TeeEnclaveProviderConverter.java deleted file mode 100644 index 924920b6..00000000 --- a/src/main/java/com/iexec/sms/tee/TeeEnclaveProviderConverter.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.iexec.sms.tee; - -import com.iexec.common.tee.TeeEnclaveProvider; -import org.springframework.core.convert.converter.Converter; -import org.springframework.stereotype.Component; - -/** - * This class is needed to have a case-insensitive `teeEnclaveProvider` path variable in - * {@link TeeController#getTeeServicesProperties(TeeEnclaveProvider)}. - */ -@Component -public class TeeEnclaveProviderConverter implements Converter { - @Override - public TeeEnclaveProvider convert(String value) { - return TeeEnclaveProvider.valueOf(value.toUpperCase()); - } -} diff --git a/src/main/java/com/iexec/sms/tee/TeeFrameworkConverter.java b/src/main/java/com/iexec/sms/tee/TeeFrameworkConverter.java new file mode 100644 index 00000000..78ccd54e --- /dev/null +++ b/src/main/java/com/iexec/sms/tee/TeeFrameworkConverter.java @@ -0,0 +1,17 @@ +package com.iexec.sms.tee; + +import com.iexec.common.tee.TeeFramework; +import org.springframework.core.convert.converter.Converter; +import org.springframework.stereotype.Component; + +/** + * This class is needed to have a case-insensitive `teeFramework` path variable in + * {@link TeeController#getTeeServicesProperties(TeeFramework)}. + */ +@Component +public class TeeFrameworkConverter implements Converter { + @Override + public TeeFramework convert(String value) { + return TeeFramework.valueOf(value.toUpperCase()); + } +} diff --git a/src/test/java/com/iexec/sms/tee/TeeEnclaveProviderConverterTests.java b/src/test/java/com/iexec/sms/tee/TeeFrameworkConverterTests.java similarity index 73% rename from src/test/java/com/iexec/sms/tee/TeeEnclaveProviderConverterTests.java rename to src/test/java/com/iexec/sms/tee/TeeFrameworkConverterTests.java index 3c21e100..02697da5 100644 --- a/src/test/java/com/iexec/sms/tee/TeeEnclaveProviderConverterTests.java +++ b/src/test/java/com/iexec/sms/tee/TeeFrameworkConverterTests.java @@ -4,12 +4,13 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; -import static com.iexec.common.tee.TeeEnclaveProvider.GRAMINE; -import static com.iexec.common.tee.TeeEnclaveProvider.SCONE; -import static org.junit.jupiter.api.Assertions.*; +import static com.iexec.common.tee.TeeFramework.GRAMINE; +import static com.iexec.common.tee.TeeFramework.SCONE; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; -class TeeEnclaveProviderConverterTests { - private final TeeEnclaveProviderConverter converter = new TeeEnclaveProviderConverter(); +class TeeFrameworkConverterTests { + private final TeeFrameworkConverter converter = new TeeFrameworkConverter(); // region convert @Test From fe778f3b90e247d0903524f633759a6f0b55aea0 Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Mon, 10 Oct 2022 17:14:36 +0200 Subject: [PATCH 145/293] Add missing headers in com.iexec.sms.api.config package classes --- .../api/config/GramineServicesProperties.java | 16 ++++++++++++++++ .../sms/api/config/SconeServicesProperties.java | 16 ++++++++++++++++ .../iexec/sms/api/config/TeeAppProperties.java | 16 ++++++++++++++++ .../sms/api/config/TeeServicesProperties.java | 16 ++++++++++++++++ 4 files changed, 64 insertions(+) diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/GramineServicesProperties.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/GramineServicesProperties.java index 5b4e8a91..74fb74ae 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/GramineServicesProperties.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/GramineServicesProperties.java @@ -1,3 +1,19 @@ +/* + * Copyright 2022 IEXEC BLOCKCHAIN TECH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.iexec.sms.api.config; import com.iexec.common.tee.TeeFramework; diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/SconeServicesProperties.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/SconeServicesProperties.java index 0e474af5..4e60bcf5 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/SconeServicesProperties.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/SconeServicesProperties.java @@ -1,3 +1,19 @@ +/* + * Copyright 2022 IEXEC BLOCKCHAIN TECH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.iexec.sms.api.config; import com.iexec.common.tee.TeeFramework; diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeAppProperties.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeAppProperties.java index 62e6c4f9..4e7399cb 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeAppProperties.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeAppProperties.java @@ -1,3 +1,19 @@ +/* + * Copyright 2022 IEXEC BLOCKCHAIN TECH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.iexec.sms.api.config; import lombok.AllArgsConstructor; diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeServicesProperties.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeServicesProperties.java index aa6108aa..4172edef 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeServicesProperties.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeServicesProperties.java @@ -1,3 +1,19 @@ +/* + * Copyright 2022 IEXEC BLOCKCHAIN TECH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.iexec.sms.api.config; import com.iexec.common.tee.TeeFramework; From 843cfe375c49cfb5eeabebc69eb421009e4224ce Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Mon, 10 Oct 2022 17:15:53 +0200 Subject: [PATCH 146/293] Use annotations to configure Tee services properties serialization and deserialization --- .../api/config/GramineServicesProperties.java | 8 ++--- .../api/config/SconeServicesProperties.java | 8 ++--- .../sms/api/config/TeeServicesProperties.java | 19 +++++----- .../config/TeeServicesPropertiesTests.java | 35 +++++++++++++++++++ 4 files changed, 49 insertions(+), 21 deletions(-) create mode 100644 iexec-sms-library/src/test/java/com/iexec/sms/api/config/TeeServicesPropertiesTests.java diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/GramineServicesProperties.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/GramineServicesProperties.java index 74fb74ae..eab283c8 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/GramineServicesProperties.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/GramineServicesProperties.java @@ -18,16 +18,12 @@ import com.iexec.common.tee.TeeFramework; import lombok.Getter; -import lombok.Setter; +import lombok.NoArgsConstructor; @Getter -@Setter +@NoArgsConstructor public class GramineServicesProperties extends TeeServicesProperties { - public GramineServicesProperties() { - super(TeeFramework.GRAMINE); - } - public GramineServicesProperties(TeeAppProperties preComputeProperties, TeeAppProperties postComputeProperties) { super(TeeFramework.GRAMINE, preComputeProperties, postComputeProperties); diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/SconeServicesProperties.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/SconeServicesProperties.java index 4e60bcf5..cddc5ff2 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/SconeServicesProperties.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/SconeServicesProperties.java @@ -18,17 +18,13 @@ import com.iexec.common.tee.TeeFramework; import lombok.Getter; -import lombok.Setter; +import lombok.NoArgsConstructor; @Getter -@Setter +@NoArgsConstructor public class SconeServicesProperties extends TeeServicesProperties { private String lasImage; - public SconeServicesProperties() { - super(TeeFramework.SCONE); - } - public SconeServicesProperties(TeeAppProperties preComputeProperties, TeeAppProperties postComputeProperties, String lasImage) { diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeServicesProperties.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeServicesProperties.java index 4172edef..ea0d8944 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeServicesProperties.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeServicesProperties.java @@ -16,22 +16,23 @@ package com.iexec.sms.api.config; +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.iexec.common.tee.TeeFramework; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; -import lombok.Setter; @NoArgsConstructor @AllArgsConstructor @Getter -@Setter +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "teeFramework", visible = true) +@JsonSubTypes({ + @JsonSubTypes.Type(name = "SCONE", value = SconeServicesProperties.class), + @JsonSubTypes.Type(name = "GRAMINE", value = GramineServicesProperties.class) +}) public abstract class TeeServicesProperties { - private TeeFramework teeFramework; - private TeeAppProperties preComputeProperties; - private TeeAppProperties postComputeProperties; - - TeeServicesProperties(TeeFramework teeFramework) { - this.teeFramework = teeFramework; - } + protected TeeFramework teeFramework; + protected TeeAppProperties preComputeProperties; + protected TeeAppProperties postComputeProperties; } diff --git a/iexec-sms-library/src/test/java/com/iexec/sms/api/config/TeeServicesPropertiesTests.java b/iexec-sms-library/src/test/java/com/iexec/sms/api/config/TeeServicesPropertiesTests.java new file mode 100644 index 00000000..7dfd36b0 --- /dev/null +++ b/iexec-sms-library/src/test/java/com/iexec/sms/api/config/TeeServicesPropertiesTests.java @@ -0,0 +1,35 @@ +package com.iexec.sms.api.config; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +@Slf4j +class TeeServicesPropertiesTests { + + private static final ObjectMapper mapper = new ObjectMapper(); + + @Test + void shouldSerializeAndDeserialize() throws JsonProcessingException { + List teeProperties = new ArrayList<>(); + TeeAppProperties sconePreCompute = new TeeAppProperties("scone-pre-compute", "scone-pre-compute-fingerprint", "scone-pre-compute-entrypoint", 1L); + TeeAppProperties sconePostCompute = new TeeAppProperties("scone-post-compute", "scone-post-compute-fingerprint", "scone-post-compute-entrypoint", 1L); + teeProperties.add(new SconeServicesProperties(sconePreCompute, sconePostCompute, "lasImage")); + + TeeAppProperties graminePreCompute = new TeeAppProperties("gramine-pre-compute", "gramine-pre-compute-fingerprint", "gramine-pre-compute-entrypoint", 1L); + TeeAppProperties graminePostCompute = new TeeAppProperties("gramine-post-compute", "gramine-post-compute-fingerprint", "gramine-post-compute-entrypoint", 1L); + teeProperties.add(new GramineServicesProperties(graminePreCompute, graminePostCompute)); + + String jsonString = mapper.writeValueAsString(teeProperties); + + List deserializedProperties = mapper.readValue(jsonString, new TypeReference<>() {}); + assertThat(deserializedProperties).usingRecursiveComparison().isEqualTo(teeProperties); + } +} From 400b3acb1c02ecaf2237c49dbc7892e74d36f496 Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Mon, 10 Oct 2022 17:20:09 +0200 Subject: [PATCH 147/293] Simplify getTeeServicesProperties implementation --- .../java/com/iexec/sms/api/SmsClient.java | 17 +--- .../com/iexec/sms/api/SmsClientTests.java | 86 ------------------- 2 files changed, 2 insertions(+), 101 deletions(-) delete mode 100644 iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientTests.java diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java index fb452e69..f02347b2 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java @@ -125,25 +125,12 @@ ApiResponseBody generat @RequestLine("GET /tee/framework") TeeFramework getTeeFramework(); - @RequestLine("GET /tee/properties/scone") - SconeServicesProperties getSconeServicesProperties(); - - @RequestLine("GET /tee/properties/gramine") - GramineServicesProperties getGramineServicesProperties(); + @RequestLine("GET /tee/properties/{teeFramework}") + T getTeeServicesProperties(@Param("teeFramework") TeeFramework teeFramework); @Deprecated(forRemoval = true) default T getTeeServicesProperties(TeeEnclaveProvider teeEnclaveProvider) { return getTeeServicesProperties(TeeFramework.valueOf(teeEnclaveProvider.toString())); } - - default T getTeeServicesProperties(TeeFramework teeFramework) { - if (teeFramework == TeeFramework.SCONE) { - return (T) getSconeServicesProperties(); - } else if (teeFramework == TeeFramework.GRAMINE) { - return (T) getGramineServicesProperties(); - } - - return null; - } // endregion } diff --git a/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientTests.java b/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientTests.java deleted file mode 100644 index 14ede04d..00000000 --- a/iexec-sms-library/src/test/java/com/iexec/sms/api/SmsClientTests.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2022 IEXEC BLOCKCHAIN TECH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.iexec.sms.api; - -import com.iexec.common.tee.TeeFramework; -import com.iexec.sms.api.config.GramineServicesProperties; -import com.iexec.sms.api.config.SconeServicesProperties; -import com.iexec.sms.api.config.TeeAppProperties; -import com.iexec.sms.api.config.TeeServicesProperties; -import org.junit.jupiter.api.Test; -import org.mockito.Mock; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.when; - -class SmsClientTests { - private static final String LAS_IMAGE = "lasImage"; - - @Mock - TeeAppProperties preComputeProperties; - @Mock - TeeAppProperties postComputeProperties; - - // region getTeeServicesProperties - @Test - void shouldGetSconeServicesProperties() { - final SmsClient smsClient = spy(SmsClient.class); - final SconeServicesProperties properties = new SconeServicesProperties( - preComputeProperties, - postComputeProperties, - LAS_IMAGE - ); - - when(smsClient.getSconeServicesProperties()).thenReturn(properties); - - final TeeServicesProperties teeServicesProperties = - smsClient.getTeeServicesProperties(TeeFramework.SCONE); - - assertEquals(properties, teeServicesProperties); - } - - @Test - void shouldGetGramineServicesProperties() { - final SmsClient smsClient = spy(SmsClient.class); - final GramineServicesProperties properties = new GramineServicesProperties( - preComputeProperties, - postComputeProperties - ); - - when(smsClient.getGramineServicesProperties()).thenReturn(properties); - - final TeeServicesProperties teeServicesProperties = - smsClient.getTeeServicesProperties(TeeFramework.GRAMINE); - - assertEquals(properties, teeServicesProperties); - } - - @Test - void shouldNotGetTeeServicesPropertiesSinceUnknownProvider() { - final SmsClient smsClient = spy(SmsClient.class); - - when(smsClient.getGramineServicesProperties()).thenReturn(null); - - final TeeServicesProperties teeServicesProperties = - smsClient.getTeeServicesProperties(TeeFramework.GRAMINE); - - assertNull(teeServicesProperties); - } - // endregion -} From b798ce4d107f360b5b0b31268b70cc9234c30942 Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Mon, 10 Oct 2022 17:31:10 +0200 Subject: [PATCH 148/293] Add missing assertj dependency in iexec-sms-library project --- iexec-sms-library/build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/iexec-sms-library/build.gradle b/iexec-sms-library/build.gradle index 1ec202dd..c6736157 100644 --- a/iexec-sms-library/build.gradle +++ b/iexec-sms-library/build.gradle @@ -7,6 +7,7 @@ plugins { dependencies { implementation "com.iexec.common:iexec-common:$iexecCommonVersion" + testImplementation "org.assertj:assertj-core:3.22.0" testImplementation 'org.junit.jupiter:junit-jupiter:5.8.2' testImplementation 'org.mockito:mockito-junit-jupiter:4.7.0' } From 7f4e5903da8c839158e389eab231006b6452eaf6 Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Tue, 11 Oct 2022 09:31:48 +0200 Subject: [PATCH 149/293] Use annotation to define constructor used during deserialization --- .../sms/api/config/GramineServicesProperties.java | 9 +++++---- .../sms/api/config/SconeServicesProperties.java | 13 +++++++------ .../iexec/sms/api/config/TeeServicesProperties.java | 4 +--- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/GramineServicesProperties.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/GramineServicesProperties.java index eab283c8..85e17089 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/GramineServicesProperties.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/GramineServicesProperties.java @@ -16,16 +16,17 @@ package com.iexec.sms.api.config; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; import com.iexec.common.tee.TeeFramework; import lombok.Getter; -import lombok.NoArgsConstructor; @Getter -@NoArgsConstructor public class GramineServicesProperties extends TeeServicesProperties { - public GramineServicesProperties(TeeAppProperties preComputeProperties, - TeeAppProperties postComputeProperties) { + @JsonCreator + public GramineServicesProperties(@JsonProperty("preComputeProperties") TeeAppProperties preComputeProperties, + @JsonProperty("postComputeProperties") TeeAppProperties postComputeProperties) { super(TeeFramework.GRAMINE, preComputeProperties, postComputeProperties); } } diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/SconeServicesProperties.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/SconeServicesProperties.java index cddc5ff2..887e0e1d 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/SconeServicesProperties.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/SconeServicesProperties.java @@ -16,18 +16,19 @@ package com.iexec.sms.api.config; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; import com.iexec.common.tee.TeeFramework; import lombok.Getter; -import lombok.NoArgsConstructor; @Getter -@NoArgsConstructor public class SconeServicesProperties extends TeeServicesProperties { - private String lasImage; + private final String lasImage; - public SconeServicesProperties(TeeAppProperties preComputeProperties, - TeeAppProperties postComputeProperties, - String lasImage) { + @JsonCreator + public SconeServicesProperties(@JsonProperty("preComputeProperties") TeeAppProperties preComputeProperties, + @JsonProperty("postComputeProperties") TeeAppProperties postComputeProperties, + @JsonProperty("lasImage") String lasImage) { super(TeeFramework.SCONE, preComputeProperties, postComputeProperties); this.lasImage = lasImage; } diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeServicesProperties.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeServicesProperties.java index ea0d8944..8d8bf70b 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeServicesProperties.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeServicesProperties.java @@ -21,11 +21,9 @@ import com.iexec.common.tee.TeeFramework; import lombok.AllArgsConstructor; import lombok.Getter; -import lombok.NoArgsConstructor; -@NoArgsConstructor -@AllArgsConstructor @Getter +@AllArgsConstructor @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "teeFramework", visible = true) @JsonSubTypes({ @JsonSubTypes.Type(name = "SCONE", value = SconeServicesProperties.class), From 687bccec2d4e5b8c8ad22e69497c7a70281e6f53 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Tue, 11 Oct 2022 10:51:25 +0200 Subject: [PATCH 150/293] Push SMS in enclave image to usual repo --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index fa0f9133..2f596603 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -26,7 +26,7 @@ stage('Trigger TEE debug image build') { sconeSigning( IMG_FROM: nativeImage, - IMG_TO: "docker-regis.iex.ec/$imageName-unlocked:$imageTag-sconify-$sconifyVersion-debug", + IMG_TO: "docker-regis.iex.ec/$imageName:$imageTag-sconify-$sconifyVersion-debug", SCRIPT_CONFIG: sconifyArgsPath, SCONE_IMG_NAME: 'sconecuratedimages/iexec-sconify-image', SCONE_IMG_VERS: sconifyVersion, From 042bb4389a2731bca36419d90c74c674b4c694ac Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Tue, 11 Oct 2022 12:07:43 +0200 Subject: [PATCH 151/293] Remove setters from TeeAppProperties --- .../main/java/com/iexec/sms/api/config/TeeAppProperties.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeAppProperties.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeAppProperties.java index 4e7399cb..cfe0a9b4 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeAppProperties.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeAppProperties.java @@ -19,12 +19,10 @@ import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; -import lombok.Setter; +@Getter @NoArgsConstructor @AllArgsConstructor -@Getter -@Setter public class TeeAppProperties { private String image; private String fingerprint; From c1fa85828928914d97b59838a412a6ad2d11eb34 Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Tue, 11 Oct 2022 12:08:31 +0200 Subject: [PATCH 152/293] Declare TeeServicesProperties fields as private final and add TODO regarding java 17 sealed classes --- .../com/iexec/sms/api/config/TeeServicesProperties.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeServicesProperties.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeServicesProperties.java index 8d8bf70b..9c50746d 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeServicesProperties.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/config/TeeServicesProperties.java @@ -29,8 +29,9 @@ @JsonSubTypes.Type(name = "SCONE", value = SconeServicesProperties.class), @JsonSubTypes.Type(name = "GRAMINE", value = GramineServicesProperties.class) }) +// TODO upgrade to sealed class in Java 17 public abstract class TeeServicesProperties { - protected TeeFramework teeFramework; - protected TeeAppProperties preComputeProperties; - protected TeeAppProperties postComputeProperties; + private final TeeFramework teeFramework; + private final TeeAppProperties preComputeProperties; + private final TeeAppProperties postComputeProperties; } From 4fc8a0430b291aa717e10e1d7f3e30ded152f580 Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Tue, 11 Oct 2022 12:28:31 +0200 Subject: [PATCH 153/293] Remove unused imports in SmsClient --- .../src/main/java/com/iexec/sms/api/SmsClient.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java index f02347b2..de1cf73a 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java @@ -20,8 +20,6 @@ import com.iexec.common.tee.TeeEnclaveProvider; import com.iexec.common.tee.TeeFramework; import com.iexec.common.web.ApiResponseBody; -import com.iexec.sms.api.config.GramineServicesProperties; -import com.iexec.sms.api.config.SconeServicesProperties; import com.iexec.sms.api.config.TeeServicesProperties; import feign.Headers; import feign.Param; From 219b4e294a39e8b476173d3b9684c6c5909ea1d7 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Thu, 13 Oct 2022 10:32:17 +0200 Subject: [PATCH 154/293] Add `isUp` request to `SmsClient` --- .../src/main/java/com/iexec/sms/api/SmsClient.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java index de1cf73a..57c9c0c6 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java @@ -35,6 +35,9 @@ */ public interface SmsClient { + @RequestLine("GET /up") + String isUp(); + // region Secrets @RequestLine("POST /apps/{appAddress}/secrets/1") @Headers("Authorization: {authorization}") From d0ccc240c58b8865526a237c34667c05184156c0 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Thu, 13 Oct 2022 11:37:55 +0200 Subject: [PATCH 155/293] Set 3 Go for SMS in enclave heap size --- docker/sconify.args | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/sconify.args b/docker/sconify.args index 37d6d374..d8572741 100644 --- a/docker/sconify.args +++ b/docker/sconify.args @@ -4,7 +4,7 @@ --from=${IMG_FROM} \ --to=${IMG_TO} \ --binary=/usr/local/openjdk-11/bin/java \ ---heap="8G" \ +--heap="3G" \ --stack="8M" \ --fork="1" \ --binary-fs \ From 222fa06be2d99bb22c2ae8b253424a3120f7798e Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Thu, 13 Oct 2022 11:59:47 +0200 Subject: [PATCH 156/293] Revert "Set 3 Go for SMS in enclave heap size" This reverts commit d0ccc240c58b8865526a237c34667c05184156c0. --- docker/sconify.args | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/sconify.args b/docker/sconify.args index d8572741..37d6d374 100644 --- a/docker/sconify.args +++ b/docker/sconify.args @@ -4,7 +4,7 @@ --from=${IMG_FROM} \ --to=${IMG_TO} \ --binary=/usr/local/openjdk-11/bin/java \ ---heap="3G" \ +--heap="8G" \ --stack="8M" \ --fork="1" \ --binary-fs \ From 7cc6ea2a7906a23eff6937fde035739400dc49f7 Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Tue, 18 Oct 2022 17:17:48 +0200 Subject: [PATCH 157/293] Remove deprecated TeeProvider usages --- .../main/java/com/iexec/sms/api/SmsClient.java | 10 ---------- .../java/com/iexec/sms/tee/TeeController.java | 15 ++------------- 2 files changed, 2 insertions(+), 23 deletions(-) diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java index 57c9c0c6..71e1908e 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java @@ -118,20 +118,10 @@ ApiResponseBody generat WorkerpoolAuthorization workerpoolAuthorization ); - /** @deprecated Use {@code getTeeFramework()} instead */ - @Deprecated(forRemoval = true) - @RequestLine("GET /tee/provider") - TeeEnclaveProvider getTeeEnclaveProvider(); - @RequestLine("GET /tee/framework") TeeFramework getTeeFramework(); @RequestLine("GET /tee/properties/{teeFramework}") T getTeeServicesProperties(@Param("teeFramework") TeeFramework teeFramework); - - @Deprecated(forRemoval = true) - default T getTeeServicesProperties(TeeEnclaveProvider teeEnclaveProvider) { - return getTeeServicesProperties(TeeFramework.valueOf(teeEnclaveProvider.toString())); - } // endregion } diff --git a/src/main/java/com/iexec/sms/tee/TeeController.java b/src/main/java/com/iexec/sms/tee/TeeController.java index d35c3d50..bd15ba0d 100644 --- a/src/main/java/com/iexec/sms/tee/TeeController.java +++ b/src/main/java/com/iexec/sms/tee/TeeController.java @@ -72,17 +72,6 @@ public TeeController( this.teeServicesProperties = teeServicesProperties; } - /** - * Return which TEE enclave provider this SMS is configured to use. - * @return TEE enclave provider this SMS is configured to use. - * @deprecated Use {@link #getTeeFramework()} instead - */ - @Deprecated(forRemoval = true) - @GetMapping("/provider") - public ResponseEntity getTeeEnclaveProvider() { - return ResponseEntity.ok(TeeEnclaveProvider.valueOf(teeServicesProperties.getTeeFramework().toString())); - } - /** * Return which TEE framework this SMS is configured to use. * @return TEE framework this SMS is configured to use. @@ -180,8 +169,8 @@ public ResponseEntitybuilder() - .data(teeSessionGenerationResponse) - .build()); + .data(teeSessionGenerationResponse) + .build()); } catch(TeeSessionGenerationException e) { log.error("Failed to generate secure session [taskId:{}, workerAddress:{}]", taskId, workerAddress, e); From 950e18161bf18cc5bcd0f0884b61e02b48ee3f2b Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Tue, 18 Oct 2022 17:27:16 +0200 Subject: [PATCH 158/293] Remove unused TeeEnclaveProvider imports --- iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java | 1 - src/main/java/com/iexec/sms/tee/TeeController.java | 1 - 2 files changed, 2 deletions(-) diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java index 71e1908e..11d8341a 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java @@ -17,7 +17,6 @@ package com.iexec.sms.api; import com.iexec.common.chain.WorkerpoolAuthorization; -import com.iexec.common.tee.TeeEnclaveProvider; import com.iexec.common.tee.TeeFramework; import com.iexec.common.web.ApiResponseBody; import com.iexec.sms.api.config.TeeServicesProperties; diff --git a/src/main/java/com/iexec/sms/tee/TeeController.java b/src/main/java/com/iexec/sms/tee/TeeController.java index bd15ba0d..d52a468c 100644 --- a/src/main/java/com/iexec/sms/tee/TeeController.java +++ b/src/main/java/com/iexec/sms/tee/TeeController.java @@ -18,7 +18,6 @@ import com.iexec.common.chain.WorkerpoolAuthorization; -import com.iexec.common.tee.TeeEnclaveProvider; import com.iexec.common.tee.TeeFramework; import com.iexec.common.web.ApiResponseBody; import com.iexec.sms.api.TeeSessionGenerationError; From 6536beb8edd20d799fbb10efdc99aa8958455d57 Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Wed, 19 Oct 2022 10:33:45 +0200 Subject: [PATCH 159/293] Fix missed renamings from Tee enclave provider to Tee framework --- src/itest/java/com/iexec/sms/tee/TeeBeansLoadingTests.java | 2 +- .../java/com/iexec/sms/tee/session/TeeSessionService.java | 2 +- .../com/iexec/sms/tee/ConditionalOnTeeFrameworkTests.java | 6 +++--- src/test/java/com/iexec/sms/tee/TeeControllerTests.java | 6 +++--- .../com/iexec/sms/tee/session/TeeSessionServiceTests.java | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/itest/java/com/iexec/sms/tee/TeeBeansLoadingTests.java b/src/itest/java/com/iexec/sms/tee/TeeBeansLoadingTests.java index 611eb23a..5322bd53 100644 --- a/src/itest/java/com/iexec/sms/tee/TeeBeansLoadingTests.java +++ b/src/itest/java/com/iexec/sms/tee/TeeBeansLoadingTests.java @@ -60,7 +60,7 @@ private boolean areProfilesAndFrameworksMatching(TeeFramework[] frameworks) { } /** - * Implement this method to check all beans of given TEE enclave provider are loaded (= not null). + * Implement this method to check all beans of given TEE framework are loaded (= not null). */ abstract void checkTeeBeansAreLoaded(); } diff --git a/src/main/java/com/iexec/sms/tee/session/TeeSessionService.java b/src/main/java/com/iexec/sms/tee/session/TeeSessionService.java index bbcc70ed..d86b1339 100644 --- a/src/main/java/com/iexec/sms/tee/session/TeeSessionService.java +++ b/src/main/java/com/iexec/sms/tee/session/TeeSessionService.java @@ -67,7 +67,7 @@ public TeeSessionGenerationResponse generateTeeSession( if (teeFramework == null) { throw new TeeSessionGenerationException( SECURE_SESSION_NO_TEE_PROVIDER, - String.format("TEE provider can't be null [taskId:%s]", taskId)); + String.format("TEE framework can't be null [taskId:%s]", taskId)); } // /!\ TODO clean expired tasks sessions diff --git a/src/test/java/com/iexec/sms/tee/ConditionalOnTeeFrameworkTests.java b/src/test/java/com/iexec/sms/tee/ConditionalOnTeeFrameworkTests.java index a8924c4b..be828dba 100644 --- a/src/test/java/com/iexec/sms/tee/ConditionalOnTeeFrameworkTests.java +++ b/src/test/java/com/iexec/sms/tee/ConditionalOnTeeFrameworkTests.java @@ -31,7 +31,7 @@ class ConditionalOnTeeFrameworkTests { @ConditionalOnTeeFramework(frameworks = {}) - static class NoProvidersSet {} + static class NoFrameworksSet {} @Mock Environment environment; @@ -157,8 +157,8 @@ void shouldNotMatchAnySinceNoAnnotation(Class clazz) { } @Test - void shouldNotMatchAnySinceNoProviderDefined() { - final Class clazz = NoProvidersSet.class; + void shouldNotMatchAnySinceNoFrameworkDefined() { + final Class clazz = NoFrameworksSet.class; when(context.getEnvironment()).thenReturn(environment); when(environment.getActiveProfiles()).thenReturn(new String[]{"scone", "gramine"}); diff --git a/src/test/java/com/iexec/sms/tee/TeeControllerTests.java b/src/test/java/com/iexec/sms/tee/TeeControllerTests.java index 89741a5d..252efb71 100644 --- a/src/test/java/com/iexec/sms/tee/TeeControllerTests.java +++ b/src/test/java/com/iexec/sms/tee/TeeControllerTests.java @@ -67,9 +67,9 @@ void setUp() { MockitoAnnotations.openMocks(this); } - // region getTeeEnclaveProvider + // region getTeeFramework @Test - void shouldGetSconeProvider() { + void shouldGetSconeFramework() { final TeeServicesProperties properties = new SconeServicesProperties( preComputeProperties, postComputeProperties, @@ -90,7 +90,7 @@ void shouldGetSconeProvider() { } @Test - void shouldGetGramineProvider() { + void shouldGetGramineFramework() { final TeeServicesProperties properties = new GramineServicesProperties( preComputeProperties, postComputeProperties diff --git a/src/test/java/com/iexec/sms/tee/session/TeeSessionServiceTests.java b/src/test/java/com/iexec/sms/tee/session/TeeSessionServiceTests.java index 707c12b1..4acc4227 100644 --- a/src/test/java/com/iexec/sms/tee/session/TeeSessionServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/TeeSessionServiceTests.java @@ -90,7 +90,7 @@ void shouldNotGenerateTeeSessionSinceCantGetTaskDescription() { } @Test - void shouldNotGenerateTeeSessionSinceNoTeeEnclaveProvider() { + void shouldNotGenerateTeeSessionSinceNoTeeFramework() { final TeeSessionService teeSessionService = new TeeSessionService(iexecHubService, sconeService); final TaskDescription taskDescription = TaskDescription.builder() @@ -105,7 +105,7 @@ void shouldNotGenerateTeeSessionSinceNoTeeEnclaveProvider() { () -> teeSessionService.generateTeeSession(TASK_ID, WORKER_ADDRESS, TEE_CHALLENGE)); assertEquals(TeeSessionGenerationError.SECURE_SESSION_NO_TEE_PROVIDER, teeSessionGenerationException.getError()); - assertEquals(String.format("TEE provider can't be null [taskId:%s]", + assertEquals(String.format("TEE framework can't be null [taskId:%s]", TASK_ID), teeSessionGenerationException.getMessage()); } From 1d414f8fee4672d45216d4de7ae88fb6f8275aa3 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Mon, 24 Oct 2022 11:48:25 +0200 Subject: [PATCH 160/293] Use last Jenkins lib to build SMS in enclave image --- Jenkinsfile | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 2f596603..877cd18d 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,4 +1,4 @@ -@Library('global-jenkins-library@2.2.0') _ +@Library('global-jenkins-library@2.2.1') _ String repositoryName = 'iexec-sms' @@ -17,19 +17,11 @@ buildJavaProject( preProductionVisibility: 'docker.io', productionVisibility: 'docker.io') -stage('Trigger TEE debug image build') { - def nativeImage = "docker-regis.iex.ec/$repositoryName:$buildInfo.imageTag" - def imageName = repositoryName - def imageTag = buildInfo.imageTag - def sconifyArgsPath = './docker/sconify.args' - def sconifyVersion = '5.7.0-wal' - - sconeSigning( - IMG_FROM: nativeImage, - IMG_TO: "docker-regis.iex.ec/$imageName:$imageTag-sconify-$sconifyVersion-debug", - SCRIPT_CONFIG: sconifyArgsPath, - SCONE_IMG_NAME: 'sconecuratedimages/iexec-sconify-image', - SCONE_IMG_VERS: sconifyVersion, - FLAVOR: 'DEBUG' - ) -} +sconeBuildUnlocked( + nativeImage: "docker-regis.iex.ec/$repositoryName:$buildInfo.imageTag", + imageName: repositoryName, + imageTag: buildInfo.imageTag, + sconifyArgsPath: './docker/sconify.args', + sconifyImage: 'sconecuratedimages/iexec-sconify-image', + sconifyVersion: '5.7.0-wal' +) \ No newline at end of file From 9eafe2c30a3b51bc825ec357da5dc23d9a5b34b4 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Mon, 24 Oct 2022 12:22:40 +0200 Subject: [PATCH 161/293] Add missing new line --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 877cd18d..564271d1 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -24,4 +24,4 @@ sconeBuildUnlocked( sconifyArgsPath: './docker/sconify.args', sconifyImage: 'sconecuratedimages/iexec-sconify-image', sconifyVersion: '5.7.0-wal' -) \ No newline at end of file +) From bf1a4b165c072f465f91a7e4bed2b318f330add6 Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Tue, 25 Oct 2022 13:15:09 +0200 Subject: [PATCH 162/293] Use TeeEnclaveConfiguration builder in tests --- .../sms/tee/session/base/SecretSessionBaseServiceTests.java | 2 +- .../session/gramine/GramineSessionMakerServiceTests.java | 6 ++---- .../tee/session/scone/SconeSessionMakerServiceTests.java | 6 ++---- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/test/java/com/iexec/sms/tee/session/base/SecretSessionBaseServiceTests.java b/src/test/java/com/iexec/sms/tee/session/base/SecretSessionBaseServiceTests.java index f4301abe..e65c0f14 100644 --- a/src/test/java/com/iexec/sms/tee/session/base/SecretSessionBaseServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/base/SecretSessionBaseServiceTests.java @@ -341,7 +341,7 @@ void shouldFailToGetAppTokensSinceNoEnclaveConfig() { @Test void shouldFailToGetAppTokensInvalidEnclaveConfig() { // invalid enclave config - TeeSessionRequest request = createSessionRequest(createTaskDescription(new TeeEnclaveConfiguration())); + TeeSessionRequest request = createSessionRequest(createTaskDescription(TeeEnclaveConfiguration.builder().build())); TeeSessionGenerationException exception = assertThrows(TeeSessionGenerationException.class, () -> teeSecretsService.getAppTokens(request)); diff --git a/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerServiceTests.java b/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerServiceTests.java index e86c7441..cb71f45e 100644 --- a/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerServiceTests.java @@ -20,7 +20,6 @@ import java.util.Map; import static com.iexec.sms.tee.session.TeeSessionTestUtils.*; -import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @Slf4j @@ -46,13 +45,12 @@ void beforeEach() { // region getSessionYml @Test void shouldGetSessionJson() throws Exception { - TeeEnclaveConfiguration enclaveConfig = mock(TeeEnclaveConfiguration.class); + TeeEnclaveConfiguration enclaveConfig = TeeEnclaveConfiguration.builder() + .fingerprint(APP_FINGERPRINT).entrypoint("/apploader.sh").build(); TeeSessionRequest request = createSessionRequest(createTaskDescription(enclaveConfig)); when(postComputeProperties.getFingerprint()).thenReturn(POST_COMPUTE_FINGERPRINT); when(postComputeProperties.getEntrypoint()).thenReturn(POST_COMPUTE_ENTRYPOINT); - when(enclaveConfig.getFingerprint()).thenReturn(APP_FINGERPRINT); - when(enclaveConfig.getEntrypoint()).thenReturn("/apploader.sh"); SecretEnclaveBase appCompute = SecretEnclaveBase.builder() .name("app") diff --git a/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionMakerServiceTests.java b/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionMakerServiceTests.java index 3a814094..10357180 100644 --- a/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionMakerServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionMakerServiceTests.java @@ -37,7 +37,6 @@ import java.util.Map; import static com.iexec.sms.tee.session.TeeSessionTestUtils.*; -import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @Slf4j @@ -72,13 +71,12 @@ void beforeEach() { // region getSessionYml @Test void shouldGetSessionYml() throws Exception { - TeeEnclaveConfiguration enclaveConfig = mock(TeeEnclaveConfiguration.class); + TeeEnclaveConfiguration enclaveConfig = TeeEnclaveConfiguration.builder() + .fingerprint(APP_FINGERPRINT).entrypoint(APP_ENTRYPOINT).build(); TeeSessionRequest request = createSessionRequest(createTaskDescription(enclaveConfig)); when(preComputeProperties.getEntrypoint()).thenReturn(PRE_COMPUTE_ENTRYPOINT); when(postComputeProperties.getEntrypoint()).thenReturn(POST_COMPUTE_ENTRYPOINT); - when(enclaveConfig.getFingerprint()).thenReturn(APP_FINGERPRINT); - when(enclaveConfig.getEntrypoint()).thenReturn(APP_ENTRYPOINT); SecretEnclaveBase preCompute = SecretEnclaveBase.builder() .name("pre-compute") From c1d5287f184e215302b8ecb963e6d068510b58fa Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Tue, 25 Oct 2022 14:26:10 +0200 Subject: [PATCH 163/293] Write a single builder statement per line --- .../tee/session/gramine/GramineSessionMakerServiceTests.java | 4 +++- .../sms/tee/session/scone/SconeSessionMakerServiceTests.java | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerServiceTests.java b/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerServiceTests.java index cb71f45e..a035c2e1 100644 --- a/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerServiceTests.java @@ -46,7 +46,9 @@ void beforeEach() { @Test void shouldGetSessionJson() throws Exception { TeeEnclaveConfiguration enclaveConfig = TeeEnclaveConfiguration.builder() - .fingerprint(APP_FINGERPRINT).entrypoint("/apploader.sh").build(); + .fingerprint(APP_FINGERPRINT) + .entrypoint("/apploader.sh") + .build(); TeeSessionRequest request = createSessionRequest(createTaskDescription(enclaveConfig)); when(postComputeProperties.getFingerprint()).thenReturn(POST_COMPUTE_FINGERPRINT); diff --git a/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionMakerServiceTests.java b/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionMakerServiceTests.java index 10357180..816984dd 100644 --- a/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionMakerServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionMakerServiceTests.java @@ -72,7 +72,9 @@ void beforeEach() { @Test void shouldGetSessionYml() throws Exception { TeeEnclaveConfiguration enclaveConfig = TeeEnclaveConfiguration.builder() - .fingerprint(APP_FINGERPRINT).entrypoint(APP_ENTRYPOINT).build(); + .fingerprint(APP_FINGERPRINT) + .entrypoint(APP_ENTRYPOINT) + .build(); TeeSessionRequest request = createSessionRequest(createTaskDescription(enclaveConfig)); when(preComputeProperties.getEntrypoint()).thenReturn(PRE_COMPUTE_ENTRYPOINT); From 739491c94a55595f7dafdd821c84e46e51113bd8 Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Thu, 27 Oct 2022 09:53:25 +0200 Subject: [PATCH 164/293] Remove palaemon template files and keep a single Dockerfile --- build.gradle | 56 +------ src/main/resources/Dockerfile | 51 +------ src/main/resources/Dockerfile.untrusted | 16 -- src/main/resources/palaemonTemplate.vm | 143 ------------------ .../resources/sms-palaemon-conf.yml.template | 34 ----- 5 files changed, 7 insertions(+), 293 deletions(-) delete mode 100644 src/main/resources/Dockerfile.untrusted delete mode 100644 src/main/resources/palaemonTemplate.vm delete mode 100644 src/main/resources/sms-palaemon-conf.yml.template diff --git a/build.gradle b/build.gradle index 5ff4c001..0ab72ab3 100644 --- a/build.gradle +++ b/build.gradle @@ -168,7 +168,7 @@ task buildImage(type: Exec) { group 'Build' description 'Builds an OCI image from a Dockerfile.' dependsOn bootJar - commandLine ('sh', '-c', "docker build -f build/resources/main/Dockerfile.untrusted --build-arg jar=$jarPathForOCI" + commandLine ('sh', '-c', "docker build -f build/resources/main/Dockerfile --build-arg jar=$jarPathForOCI" + " -t $ociImageName:$gitShortCommit . && docker tag $ociImageName:$gitShortCommit $ociImageName:dev") standardOutput = new ByteArrayOutputStream() @@ -177,57 +177,3 @@ task buildImage(type: Exec) { return standardOutput.toString() } } - -task buildTrustedImage(type: Exec) { - group 'Build' - description 'Builds a trusted OCI image from a trusted Dockerfile.' - dependsOn bootJar - commandLine ('sh', '-c', "docker image build -f build/resources/main/Dockerfile --build-arg jar=$jarPathForOCI" - + " -t $ociImageName:$gitShortCommit-trusted --no-cache . && docker tag $ociImageName:$gitShortCommit-trusted $ociImageName:dev-trusted") -} - -task templatePalaemon { - String smsMrEnclave - String smsFspfKey - String smsFspfTag - - /* - * Docker build will produce such logs: "RUN .. $MRENCLAVE ... abcdef" - * We need to extract the 2nd occurence 'abcdef' - */ - ext.extractValueBetweenTags = { s, tag -> - String beginTag = '<' + tag + '>' - String endTag = '' - return s.substring(s.indexOf(beginTag, s.indexOf(beginTag) + 2) + beginTag.length(), s.indexOf(endTag, s.indexOf(endTag) + 2)) - } - - doFirst { - String logs = buildImage.output() - smsMrEnclave = extractValueBetweenTags(logs, 'MRENCLAVE') - smsFspfKey = extractValueBetweenTags(logs, 'FSPF_KEY') - smsFspfTag = extractValueBetweenTags(logs, 'FSPF_TAG') - } - - doLast { - copy { - // delete old one - delete 'src/main/resources/boot/sms-palaemon-conf.yml' - // use and copy template to the new location - from 'src/main/resources/sms-palaemon-conf.yml.template' - into 'src/main/resources/boot/' - - rename { String fileName -> - fileName.replace('.template', '') - } - // replace tokens in the template file - filter(ReplaceTokens, tokens: [ - IEXEC_SMS_PALAEMON_SERVICE_NAME: "${rootProject.name}".toString(), - IEXEC_SMS_MRENCLAVE: smsMrEnclave, - IEXEC_SMS_FSPF_KEY: smsFspfKey, - IEXEC_SMS_FSPF_TAG: smsFspfTag, - ]) - } - } -} -//templatePalaemon.dependsOn buildImage -//buildImage.finalizedBy templatePalaemon diff --git a/src/main/resources/Dockerfile b/src/main/resources/Dockerfile index 7327ed5c..912dfe65 100644 --- a/src/main/resources/Dockerfile +++ b/src/main/resources/Dockerfile @@ -1,55 +1,16 @@ -FROM nexus.iex.ec/sconecuratedimages-apps-java:jdk-alpine-scone3.0 +FROM openjdk:11.0.15-jre-slim ARG jar RUN test -n "$jar" COPY $jar /app/iexec-sms.jar -COPY build/resources/main/palaemonTemplate.vm /app/palaemonTemplate.vm COPY src/main/resources/ssl-keystore-dev.p12 /app/ssl-keystore-dev.p12 -# #### Docker ENV vars should be placed in palaemon conf for Scone ### +ENV IEXEC_SMS_SSL_KEYSTORE=/app/ssl-keystore-dev.p12 +ENV IEXEC_SMS_STORAGE_ENCRYPTION_AES_KEY_PATH=/scone/iexec-sms-aes.key +ENV IEXEC_SMS_BLOCKCHAIN_NODE_ADDRESS=http://chain:8545 +ENV IEXEC_SCONE_CAS_HOST=iexec-cas +ENV IEXEC_SMS_H2_URL=jdbc:h2:file:/scone/sms-h2 -RUN SCONE_MODE=sim SCONE_HEAP=128M && \ - # This path must match the one in palaemon session. - FSPF_PB_FILE=/fspf.pb && \ - # This path can be changed safely. - FSPF_PB_FILE_KEYTAG=/fspf.keytag && \ - # This path can be change safely. - FINGERPRINT_FILE=/fingerprint.txt && \ - # This value must match the heap size value - # provided at runtime. - RUNTIME_HEAP_SIZE=3G && \ - # Save the current file system state in fspf.pb file. - scone fspf create ${FSPF_PB_FILE} && \ - scone fspf addr ${FSPF_PB_FILE} / --not-protected --kernel / && \ - scone fspf addr ${FSPF_PB_FILE} /usr --authenticated --kernel /usr && \ - scone fspf addf ${FSPF_PB_FILE} /usr /usr && \ - scone fspf addr ${FSPF_PB_FILE} /bin --authenticated --kernel /bin && \ - scone fspf addf ${FSPF_PB_FILE} /bin /bin && \ - scone fspf addr ${FSPF_PB_FILE} /lib --authenticated --kernel /lib && \ - scone fspf addf ${FSPF_PB_FILE} /lib /lib && \ - scone fspf addr ${FSPF_PB_FILE} /etc/ssl --authenticated --kernel /etc/ssl && \ - scone fspf addf ${FSPF_PB_FILE} /etc/ssl /etc/ssl && \ - scone fspf addr ${FSPF_PB_FILE} /sbin --authenticated --kernel /sbin && \ - scone fspf addf ${FSPF_PB_FILE} /sbin /sbin && \ - scone fspf addr ${FSPF_PB_FILE} /app --authenticated --kernel /app && \ - scone fspf addf ${FSPF_PB_FILE} /app /app && \ - # Encrypt fspf.pb file with a randomly generated key - scone fspf encrypt ${FSPF_PB_FILE} > ${FSPF_PB_FILE_KEYTAG} && \ - # Get the runtime mrenclave - MRENCLAVE="$(SCONE_HASH=1 SCONE_HEAP=${RUNTIME_HEAP_SIZE} java)" && \ - # Get fspf.pb file tag - FSPF_TAG=$(awk '{print $9}' ${FSPF_PB_FILE_KEYTAG}) && \ - # Get fspf.pb file key - FSPF_KEY=$(awk '{print $11}' ${FSPF_PB_FILE_KEYTAG}) && \ - # The complete fingerprint is composed of 3 parts - FINGERPRINT="${FSPF_KEY}|${FSPF_TAG}|${MRENCLAVE}" && \ - echo ${FINGERPRINT} > ${FINGERPRINT_FILE} && \ - echo "${MRENCLAVE}" && \ - echo "${FSPF_KEY}" && \ - echo "${FSPF_TAG}" && \ - echo "${FINGERPRINT}" - -# /!\ This should match the "command" entry in the palaemon config ENTRYPOINT [ "/bin/sh", "-c", "java -jar /app/iexec-sms.jar" ] diff --git a/src/main/resources/Dockerfile.untrusted b/src/main/resources/Dockerfile.untrusted deleted file mode 100644 index 912dfe65..00000000 --- a/src/main/resources/Dockerfile.untrusted +++ /dev/null @@ -1,16 +0,0 @@ -FROM openjdk:11.0.15-jre-slim - -ARG jar - -RUN test -n "$jar" - -COPY $jar /app/iexec-sms.jar -COPY src/main/resources/ssl-keystore-dev.p12 /app/ssl-keystore-dev.p12 - -ENV IEXEC_SMS_SSL_KEYSTORE=/app/ssl-keystore-dev.p12 -ENV IEXEC_SMS_STORAGE_ENCRYPTION_AES_KEY_PATH=/scone/iexec-sms-aes.key -ENV IEXEC_SMS_BLOCKCHAIN_NODE_ADDRESS=http://chain:8545 -ENV IEXEC_SCONE_CAS_HOST=iexec-cas -ENV IEXEC_SMS_H2_URL=jdbc:h2:file:/scone/sms-h2 - -ENTRYPOINT [ "/bin/sh", "-c", "java -jar /app/iexec-sms.jar" ] diff --git a/src/main/resources/palaemonTemplate.vm b/src/main/resources/palaemonTemplate.vm deleted file mode 100644 index 645c75fe..00000000 --- a/src/main/resources/palaemonTemplate.vm +++ /dev/null @@ -1,143 +0,0 @@ -#* - It is safer to keep all values single-quoted to escape yaml - special characters (in dataset names for example). We also - ran into some parsing issues on the CAS's side when integers - were not quoted ("invalid type: integer `0`, expected a string"). - - Null values should be replaced by an empty string in the code - otherwise we end up with 'null' instead of ''. -*# - -name: '$SESSION_ID' -version: '0.3' - -access_policy: - read: - - CREATOR - update: - - CREATOR - -services: - - #* - Pre-compute enclave. - Only when dataset is requested. - *# - #if ($IS_PRE_COMPUTE_REQUIRED) - - name: 'pre-compute' - image_name: 'pre-compute-image' - mrenclaves: ['$PRE_COMPUTE_MRENCLAVE'] - pwd: '/' - command: '$PRE_COMPUTE_ENTRYPOINT' - environment: - LD_LIBRARY_PATH: '/usr/lib/jvm/java-11-openjdk/lib/server:/usr/lib/jvm/java-11-openjdk/lib:/usr/lib/jvm/java-11-openjdk/../lib' - JAVA_TOOL_OPTIONS: '-Xmx256m' - IEXEC_TASK_ID: '$env.get("IEXEC_TASK_ID")' - IEXEC_PRE_COMPUTE_OUT: '/iexec_in' - #* dataset *# - IS_DATASET_REQUIRED: '$IS_DATASET_REQUIRED' - IEXEC_DATASET_KEY: '$IEXEC_DATASET_KEY' - IEXEC_DATASET_URL: '$env.get("IEXEC_DATASET_URL")' - IEXEC_DATASET_FILENAME: '$env.get("IEXEC_DATASET_FILENAME")' - IEXEC_DATASET_CHECKSUM: '$env.get("IEXEC_DATASET_CHECKSUM")' - #* input files *# - IEXEC_INPUT_FILES_FOLDER: '$env.get("IEXEC_INPUT_FILES_FOLDER")' - IEXEC_INPUT_FILES_NUMBER: '$env.get("IEXEC_INPUT_FILES_NUMBER")' - #foreach($key in $INPUT_FILE_URLS.keySet()) - $key: '$INPUT_FILE_URLS.get($key)' - #end - #end - - #* - Application enclave - *# - - name: 'app' - image_name: 'app-image' - mrenclaves: ['$APP_MRENCLAVE'] - pwd: '/' - command: '$APP_ARGS' - environment: - IEXEC_TASK_ID: '$env.get("IEXEC_TASK_ID")' - IEXEC_IN: '$env.get("IEXEC_IN")' - IEXEC_OUT: '$env.get("IEXEC_OUT")' - #* dataset *# - IEXEC_DATASET_ADDRESS: '$env.get("IEXEC_DATASET_ADDRESS")' - IEXEC_DATASET_FILENAME: '$env.get("IEXEC_DATASET_FILENAME")' - #* BoT *# - IEXEC_BOT_SIZE: '$env.get("IEXEC_BOT_SIZE")' - IEXEC_BOT_FIRST_INDEX: '$env.get("IEXEC_BOT_FIRST_INDEX")' - IEXEC_BOT_TASK_INDEX: '$env.get("IEXEC_BOT_TASK_INDEX")' - #* input files *# - IEXEC_INPUT_FILES_FOLDER: '$env.get("IEXEC_INPUT_FILES_FOLDER")' - IEXEC_INPUT_FILES_NUMBER: '$env.get("IEXEC_INPUT_FILES_NUMBER")' - #foreach($key in $INPUT_FILE_NAMES.keySet()) - $key: '$INPUT_FILE_NAMES.get($key)' - #end - IEXEC_APP_DEVELOPER_SECRET: '$IEXEC_APP_DEVELOPER_SECRET_1' - IEXEC_APP_DEVELOPER_SECRET_1: '$IEXEC_APP_DEVELOPER_SECRET_1' - #foreach($key in $REQUESTER_SECRETS.keySet()) - $key: '$REQUESTER_SECRETS.get($key)' - #end - - #* - Post-compute enclave - *# - - name: 'post-compute' - image_name: 'post-compute-image' - mrenclaves: ['$POST_COMPUTE_MRENCLAVE'] - pwd: '/' - command: '$POST_COMPUTE_ENTRYPOINT' - environment: - LD_LIBRARY_PATH: '/usr/lib/jvm/java-11-openjdk/lib/server:/usr/lib/jvm/java-11-openjdk/lib:/usr/lib/jvm/java-11-openjdk/../lib' - JAVA_TOOL_OPTIONS: '-Xmx256m' - RESULT_TASK_ID: '$RESULT_TASK_ID' - RESULT_ENCRYPTION: '$RESULT_ENCRYPTION' - RESULT_ENCRYPTION_PUBLIC_KEY: '$RESULT_ENCRYPTION_PUBLIC_KEY' - RESULT_STORAGE_PROVIDER: '$RESULT_STORAGE_PROVIDER' - RESULT_STORAGE_PROXY: '$RESULT_STORAGE_PROXY' - RESULT_STORAGE_TOKEN: '$RESULT_STORAGE_TOKEN' - RESULT_STORAGE_CALLBACK: '$RESULT_STORAGE_CALLBACK' - RESULT_SIGN_WORKER_ADDRESS: '$RESULT_SIGN_WORKER_ADDRESS' - RESULT_SIGN_TEE_CHALLENGE_PRIVATE_KEY: '$RESULT_SIGN_TEE_CHALLENGE_PRIVATE_KEY' - -#** - Images used by each service -*# -images: - #* pre-compute. Only when dataset is requested *# - #if ($IS_PRE_COMPUTE_REQUIRED) - - name: pre-compute-image - volumes: - - name: 'iexec_in' - path: '/iexec_in' - #end - - #* application *# - - name: app-image - volumes: - - name: 'iexec_in' - path: '/iexec_in' - - name: 'iexec_out' - path: '/iexec_out' - - #* post-compute *# - - name: post-compute-image - volumes: - - name: 'iexec_out' - path: '/iexec_out' - - name: 'post-compute-tmp' - path: '/post-compute-tmp' - -#** - Volumes that will be protected - for each service. -*# -volumes: - - name: iexec_in - - name: iexec_out - - name: post-compute-tmp - -security: - attestation: - tolerate: [$TOLERATED_INSECURE_OPTIONS] - ignore_advisories: [$IGNORED_SGX_ADVISORIES] diff --git a/src/main/resources/sms-palaemon-conf.yml.template b/src/main/resources/sms-palaemon-conf.yml.template deleted file mode 100644 index 781dba24..00000000 --- a/src/main/resources/sms-palaemon-conf.yml.template +++ /dev/null @@ -1,34 +0,0 @@ -## Palaemon config ## -name: s1 -digest: create - -services: - - name: @IEXEC_SMS_PALAEMON_SERVICE_NAME@ - image_name: image3 - mrenclaves: [@IEXEC_SMS_MRENCLAVE@] - tags: [demo] - pwd: / - command: java -jar /app/iexec-sms.jar - fspf_path: /fspf.pb - fspf_key: @IEXEC_SMS_FSPF_KEY@ - fspf_tag: @IEXEC_SMS_FSPF_TAG@ - environment: - LD_LIBRARY_PATH: '/usr/lib/jvm/java-11-openjdk/lib/server:/usr/lib/jvm/java-11-openjdk/lib:/usr/lib/jvm/java-11-openjdk/../lib' - JAVA_TOOL_OPTIONS: -Xmx256m - IEXEC_SMS_BLOCKCHAIN_NODE_ADDRESS: http://chain:8545 - IEXEC_SCONE_CAS_HOST: iexec-cas - IEXEC_PALAEMON_TEMPLATE: /palaemonTemplate.vm - IEXEC_SMS_SSL_KEYSTORE: /ssl-keystore-dev.p12 - IEXEC_SMS_STORAGE_ENCRYPTION_AES_KEY_PATH: /scone/iexec-sms-aes.key - IEXEC_SMS_H2_URL: jdbc:h2:file:/scone/sms-h2 - -images: - - name: image3 - mrenclaves: [@IEXEC_SMS_MRENCLAVE@] - tags: [demo] - volumes: - - name: scone - path: /scone - -volumes: - - name: scone From 5f98e99269c26c2b11b8bdb85281859e312d5eb1 Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Thu, 27 Oct 2022 10:20:36 +0200 Subject: [PATCH 165/293] Update Jenkinsfile --- Jenkinsfile | 1 - 1 file changed, 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 564271d1..093ff6eb 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -10,7 +10,6 @@ buildJavaProject( shouldPublishJars: true, shouldPublishDockerImages: true, dockerfileDir: 'build/resources/main', - dockerfileFilename: 'Dockerfile.untrusted', buildContext: '.', preDevelopVisibility: 'iex.ec', developVisibility: 'iex.ec', From 246d87d55e8a1f59d2dcbd23e8439502d25fa8b7 Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Thu, 27 Oct 2022 11:52:48 +0200 Subject: [PATCH 166/293] Add buildSconeImage --- build.gradle | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/build.gradle b/build.gradle index 0ab72ab3..5ee63c87 100644 --- a/build.gradle +++ b/build.gradle @@ -177,3 +177,12 @@ task buildImage(type: Exec) { return standardOutput.toString() } } + +task buildTrustedImage(type: Exec) { + group "Build" + description "Build an OCI image compatible with scontain TEE framework" + dependsOn buildImage + commandLine "docker/sconify.sh" + environment "IMG_FROM", "$ociImageName:dev" + environment "IMG_TO", "$ociImageName-unlocked:dev" +} From e817e578da1d7cc5e1eb27b7d994fd54bc4a12be Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Thu, 27 Oct 2022 15:57:22 +0200 Subject: [PATCH 167/293] Make Web2 & Web3 secrets immutable --- .../sms/secret/AbstractSecretService.java | 21 +------ .../java/com/iexec/sms/secret/Secret.java | 31 +++++----- .../iexec/sms/secret/SecretController.java | 2 +- .../iexec/sms/secret/web2/Web2Secrets.java | 48 +++++++++++---- .../sms/secret/web2/Web2SecretsService.java | 54 ++++++++++------- .../com/iexec/sms/secret/web3/Web3Secret.java | 34 +++++++---- .../sms/secret/web3/Web3SecretService.java | 16 ++--- .../sms/secret/SecretControllerTests.java | 8 +-- .../secret/web2/Web2SecretsServiceTests.java | 58 +++++++++---------- .../secret/web3/Web3SecretServiceTests.java | 14 +++-- .../base/SecretSessionBaseServiceTests.java | 18 +++--- 11 files changed, 176 insertions(+), 128 deletions(-) diff --git a/src/main/java/com/iexec/sms/secret/AbstractSecretService.java b/src/main/java/com/iexec/sms/secret/AbstractSecretService.java index 48978428..30a51325 100644 --- a/src/main/java/com/iexec/sms/secret/AbstractSecretService.java +++ b/src/main/java/com/iexec/sms/secret/AbstractSecretService.java @@ -20,26 +20,9 @@ public abstract class AbstractSecretService { - private final EncryptionService encryptionService; + protected final EncryptionService encryptionService; protected AbstractSecretService(EncryptionService encryptionService) { this.encryptionService = encryptionService; } - - public Secret encryptSecret(Secret secret) { - if (!secret.isEncryptedValue()) { - String encrypted = encryptionService.encrypt(secret.getValue()); - secret.setValue(encrypted, true); - } - return secret; - } - - public Secret decryptSecret(Secret secret) { - if (secret.isEncryptedValue()) { - String decrypted = encryptionService.decrypt(secret.getValue()); - secret.setValue(decrypted, false); - } - return secret; - } - -} \ No newline at end of file +} diff --git a/src/main/java/com/iexec/sms/secret/Secret.java b/src/main/java/com/iexec/sms/secret/Secret.java index 096f238d..01a2bc9b 100644 --- a/src/main/java/com/iexec/sms/secret/Secret.java +++ b/src/main/java/com/iexec/sms/secret/Secret.java @@ -16,10 +16,7 @@ package com.iexec.sms.secret; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.Getter; -import lombok.NoArgsConstructor; +import lombok.*; import org.hibernate.annotations.GenericGenerator; import javax.persistence.Column; @@ -28,11 +25,11 @@ import javax.persistence.Id; import java.util.Objects; -@Data -@Getter -@AllArgsConstructor @Entity -@NoArgsConstructor +@Builder +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor(access = AccessLevel.PROTECTED) public class Secret { @Id @@ -46,16 +43,24 @@ public class Secret { private boolean isEncryptedValue; /* Clear secrets at construction */ - public Secret(String address, String value) { + public Secret(String address, String value, boolean isEncryptedValue) { this.address = address; - this.setValue(value, false); - } - - public void setValue(String value, boolean isEncryptedValue) { this.value = value; this.isEncryptedValue = isEncryptedValue; } + /** + * Copies the current {@link Secret} object, + * while replacing the old value with the new one. + * + * @param newValue Value to use for new object. + * @param isEncryptedValue Whether this value is encrypted. + * @return A new {@link Secret} object with new value. + */ + public Secret withValue(String newValue, boolean isEncryptedValue) { + return new Secret(this.id, this.address, newValue, isEncryptedValue); + } + /** * Get the secret value without possible leading or trailing * newline characters. This should be used when putting diff --git a/src/main/java/com/iexec/sms/secret/SecretController.java b/src/main/java/com/iexec/sms/secret/SecretController.java index bdbe1de9..54219371 100644 --- a/src/main/java/com/iexec/sms/secret/SecretController.java +++ b/src/main/java/com/iexec/sms/secret/SecretController.java @@ -134,7 +134,7 @@ public ResponseEntity addWeb2Secret(@RequestHeader String authorization, return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build(); } - if (!web2SecretsService.addSecret(ownerAddress, secretName, secretValue)) { + if (web2SecretsService.addSecret(ownerAddress, secretName, secretValue).isEmpty()) { return ResponseEntity.status(HttpStatus.CONFLICT).build(); } diff --git a/src/main/java/com/iexec/sms/secret/web2/Web2Secrets.java b/src/main/java/com/iexec/sms/secret/web2/Web2Secrets.java index e884d0fb..428f39b5 100644 --- a/src/main/java/com/iexec/sms/secret/web2/Web2Secrets.java +++ b/src/main/java/com/iexec/sms/secret/web2/Web2Secrets.java @@ -17,20 +17,18 @@ package com.iexec.sms.secret.web2; import com.iexec.sms.secret.Secret; -import lombok.Data; -import lombok.Getter; -import lombok.NoArgsConstructor; +import lombok.*; import org.hibernate.annotations.GenericGenerator; import javax.persistence.*; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; +import java.util.*; +import java.util.stream.Collectors; -@Data -@Getter @Entity -@NoArgsConstructor +@Getter +@Builder +@NoArgsConstructor(access = AccessLevel.PRIVATE) +@AllArgsConstructor(access = AccessLevel.PRIVATE) public class Web2Secrets { @Id @@ -43,8 +41,12 @@ public class Web2Secrets { private List secrets; Web2Secrets(String ownerAddress) { - this.ownerAddress = ownerAddress; - this.secrets = new ArrayList<>(); + this(ownerAddress, List.of()); + } + + public Web2Secrets(String ownerAddress, List secrets) { + this.ownerAddress = ownerAddress.toLowerCase(); + this.secrets = Collections.unmodifiableList(secrets); } public Optional getSecret(String secretAddress) { @@ -52,4 +54,28 @@ public Optional getSecret(String secretAddress) { .filter(secret -> secret.getAddress().equals(secretAddress)) .findFirst(); } + + /** + * Copies the current {@link Web2Secrets} object, while adding given {@link Secret} to the secrets list. + * In case of an update, + * given secret is removed from the secrets list before the new object is created. + * + * @param newSecret {@link Secret} to add to the list + * @return A new {@link Web2Secrets} object with given new {@link Secret}. + */ + public Web2Secrets withNewSecret(Secret newSecret) { + List newSecrets; + if (newSecret.getId() == null) { + // New secret, no need to remove any old corresponding secret. + newSecrets = new ArrayList<>(secrets); + } else { + // Update of existing secret, remove the old secret. + newSecrets = secrets.stream() + .filter(secret -> !Objects.equals(secret.getId(), newSecret.getId())) + .collect(Collectors.toList()); + } + newSecrets.add(newSecret); + + return new Web2Secrets(id, ownerAddress, newSecrets); + } } diff --git a/src/main/java/com/iexec/sms/secret/web2/Web2SecretsService.java b/src/main/java/com/iexec/sms/secret/web2/Web2SecretsService.java index 912298dc..c5f35674 100644 --- a/src/main/java/com/iexec/sms/secret/web2/Web2SecretsService.java +++ b/src/main/java/com/iexec/sms/secret/web2/Web2SecretsService.java @@ -50,43 +50,57 @@ public Optional getSecret(String ownerAddress, String secretAddress, boo ownerAddress = ownerAddress.toLowerCase(); Optional oSecret = getWeb2Secrets(ownerAddress) .flatMap(web2Secrets -> web2Secrets.getSecret(secretAddress)); - return shouldDecryptValue ? oSecret.map(this::decryptSecret) : oSecret; + + if (oSecret.isEmpty() || !shouldDecryptValue) { + return oSecret; + } + + final Secret secret = oSecret.get(); + final String decryptedValue = encryptionService.decrypt(secret.getValue()); + return Optional.of(secret.withValue(decryptedValue, false)); } - public boolean addSecret(String ownerAddress, String secretAddress, String secretValue) { + public Optional addSecret(String ownerAddress, String secretAddress, String secretValue) { ownerAddress = ownerAddress.toLowerCase(); - Web2Secrets web2Secrets = getWeb2Secrets(ownerAddress) + final Web2Secrets web2Secrets = getWeb2Secrets(ownerAddress) .orElse(new Web2Secrets(ownerAddress)); if (web2Secrets.getSecret(secretAddress).isPresent()) { log.error("Secret already exists [ownerAddress:{}, secretAddress:{}]", ownerAddress, secretAddress); - return false; + return Optional.empty(); } - Secret secret = new Secret(secretAddress, secretValue); - encryptSecret(secret); + final String encryptedValue = encryptionService.encrypt(secretValue); log.info("Adding new secret [ownerAddress:{}, secretAddress:{}, encryptedSecretValue:{}]", - ownerAddress, secretAddress, secret.getValue()); - web2Secrets.getSecrets().add(secret); - web2SecretsRepository.save(web2Secrets); - return true; + ownerAddress, secretAddress, encryptedValue); + + final Secret secret = new Secret(secretAddress, encryptedValue, true); + addSecretAndSave(web2Secrets, secret); + return Optional.of(secret); } - public void updateSecret(String ownerAddress, String secretAddress, String newSecretValue) { + public Optional updateSecret(String ownerAddress, String secretAddress, String newSecretValue) { ownerAddress = ownerAddress.toLowerCase(); - Secret newSecret = new Secret(secretAddress, newSecretValue); - encryptSecret(newSecret); - Web2Secrets web2Secrets = getWeb2Secrets(ownerAddress).orElseThrow(); - Secret existingSecret = web2Secrets.getSecret(secretAddress).orElseThrow(); - if (existingSecret.getValue().equals(newSecret.getValue())) { + final Web2Secrets web2Secrets = getWeb2Secrets(ownerAddress).orElseThrow(); + final Secret existingSecret = web2Secrets.getSecret(secretAddress).orElseThrow(); + + final String encryptedValue = encryptionService.encrypt(newSecretValue); + if (existingSecret.getValue().equals(encryptedValue)) { log.info("No need to update secret [ownerAddress:{}, secretAddress:{}]", ownerAddress, secretAddress); - return; + return Optional.empty(); } log.info("Updating secret [ownerAddress:{}, secretAddress:{}, oldEncryptedSecretValue:{}, newEncryptedSecretValue:{}]", - ownerAddress, secretAddress, existingSecret.getValue(), newSecret.getValue()); - existingSecret.setValue(newSecret.getValue(), true); - web2SecretsRepository.save(web2Secrets); + ownerAddress, secretAddress, existingSecret.getValue(), encryptedValue); + + final Secret newSecret = existingSecret.withValue(encryptedValue, true); + addSecretAndSave(web2Secrets, newSecret); + return Optional.of(newSecret); + } + + private void addSecretAndSave(Web2Secrets web2Secrets, Secret secret) { + final Web2Secrets newWeb2Secrets = web2Secrets.withNewSecret(secret); + web2SecretsRepository.save(newWeb2Secrets); } } diff --git a/src/main/java/com/iexec/sms/secret/web3/Web3Secret.java b/src/main/java/com/iexec/sms/secret/web3/Web3Secret.java index 570f2a8d..efd5816d 100644 --- a/src/main/java/com/iexec/sms/secret/web3/Web3Secret.java +++ b/src/main/java/com/iexec/sms/secret/web3/Web3Secret.java @@ -17,21 +17,17 @@ package com.iexec.sms.secret.web3; import com.iexec.sms.secret.Secret; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.Getter; -import lombok.NoArgsConstructor; +import lombok.*; import org.hibernate.annotations.GenericGenerator; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; -@EqualsAndHashCode(callSuper = true) -@Data -@Getter @Entity -@NoArgsConstructor +@Getter +@NoArgsConstructor(access = AccessLevel.PRIVATE) +@AllArgsConstructor(access = AccessLevel.PRIVATE) public class Web3Secret extends Secret { @Id @@ -39,7 +35,25 @@ public class Web3Secret extends Secret { @GenericGenerator(name = "system-uuid", strategy = "uuid") private String id; - public Web3Secret(String address, String value) { - super(address, value); + private Web3Secret(String superId, String id, String address, String value, boolean isEncryptedValue) { + super(superId, address, value, isEncryptedValue); + this.id = id; + } + + public Web3Secret(String address, String value, boolean isEncryptedValue) { + super(address, value, isEncryptedValue); + } + + /** + * Copies the current {@link Web3Secret} object, + * while replacing the old value with the new one. + * + * @param newValue Value to use for new object. + * @param isEncryptedValue Whether this value is encrypted. + * @return A new {@link Web3Secret} object with new value. + */ + @Override + public Web3Secret withValue(String newValue, boolean isEncryptedValue) { + return new Web3Secret(super.getId(), this.id, this.getAddress(), newValue, isEncryptedValue); } } diff --git a/src/main/java/com/iexec/sms/secret/web3/Web3SecretService.java b/src/main/java/com/iexec/sms/secret/web3/Web3SecretService.java index 7ea4eb12..3772698d 100644 --- a/src/main/java/com/iexec/sms/secret/web3/Web3SecretService.java +++ b/src/main/java/com/iexec/sms/secret/web3/Web3SecretService.java @@ -38,14 +38,15 @@ public Web3SecretService(Web3SecretRepository web3SecretRepository, public Optional getSecret(String secretAddress, boolean shouldDecryptValue) { secretAddress = secretAddress.toLowerCase(); - Optional secret = web3SecretRepository.findWeb3SecretByAddress(secretAddress); - if (secret.isEmpty()) { + Optional oSecret = web3SecretRepository.findWeb3SecretByAddress(secretAddress); + if (oSecret.isEmpty()) { return Optional.empty(); } if (shouldDecryptValue) { - decryptSecret(secret.get()); + final String decryptedValue = encryptionService.decrypt(oSecret.get().getValue()); + return oSecret.map(secret -> secret.withValue(decryptedValue, false)); } - return secret; + return oSecret; } public Optional getSecret(String secretAddress) { @@ -64,10 +65,11 @@ public boolean addSecret(String secretAddress, String secretValue) { return false; } - Web3Secret web3Secret = new Web3Secret(secretAddress, secretValue); - encryptSecret(web3Secret); + final String encryptedValue = encryptionService.encrypt(secretValue); log.info("Adding new web3 secret [secretAddress:{}, encryptedSecretValue:{}]", - secretAddress, web3Secret.getValue()); + secretAddress, encryptedValue); + + final Web3Secret web3Secret = new Web3Secret(secretAddress, encryptedValue, true); web3SecretRepository.save(web3Secret); return true; } diff --git a/src/test/java/com/iexec/sms/secret/SecretControllerTests.java b/src/test/java/com/iexec/sms/secret/SecretControllerTests.java index 2a238121..25101634 100644 --- a/src/test/java/com/iexec/sms/secret/SecretControllerTests.java +++ b/src/test/java/com/iexec/sms/secret/SecretControllerTests.java @@ -71,7 +71,7 @@ public void init() { @Test void shouldReturnNoContentWhenWeb3SecretExists() { when(web3SecretService.getSecret(WEB3_SECRET_ADDRESS)) - .thenReturn(Optional.of(new Web3Secret())); + .thenReturn(Optional.of(mock(Web3Secret.class))); assertThat(secretController.isWeb3SecretSet(WEB3_SECRET_ADDRESS)) .isEqualTo(ResponseEntity.noContent().build()); verifyNoInteractions(authorizationService, web2SecretsService); @@ -117,7 +117,7 @@ void failToGetWeb3SecretWhenSecretDoesNotExist(boolean shouldDecryptValue) { @ParameterizedTest @ValueSource(strings = {"true", "false"}) void getWeb3Secret(boolean shouldDecryptSecret) { - Web3Secret expectedSecret = new Web3Secret(); + Web3Secret expectedSecret = mock(Web3Secret.class); when(authorizationService.getChallengeForGetWeb3Secret(WEB3_SECRET_ADDRESS)) .thenReturn(CHALLENGE); when(authorizationService.isSignedByOwner(CHALLENGE, AUTHORIZATION, WEB3_SECRET_ADDRESS)) @@ -267,7 +267,7 @@ void failToAddWeb2SecretWhenSecretAlreadyExists() { when(authorizationService.isSignedByHimself(CHALLENGE, AUTHORIZATION, WEB2_OWNER_ADDRESS)) .thenReturn(true); when(web2SecretsService.addSecret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, WEB2_SECRET_VALUE)) - .thenReturn(false); + .thenReturn(Optional.empty()); assertThat(secretController.addWeb2Secret(AUTHORIZATION, WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, WEB2_SECRET_VALUE)) .isEqualTo(ResponseEntity.status(HttpStatus.CONFLICT).build()); verify(web2SecretsService).addSecret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, WEB2_SECRET_VALUE); @@ -280,7 +280,7 @@ void addWeb2Secret() { when(authorizationService.isSignedByHimself(CHALLENGE, AUTHORIZATION, WEB2_OWNER_ADDRESS)) .thenReturn(true); when(web2SecretsService.addSecret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, WEB2_SECRET_VALUE)) - .thenReturn(true); + .thenReturn(Optional.of(new Secret(WEB2_SECRET_NAME, WEB2_SECRET_VALUE, true))); assertThat(secretController.addWeb2Secret(AUTHORIZATION, WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, WEB2_SECRET_VALUE)) .isEqualTo(ResponseEntity.noContent().build()); verify(web2SecretsService).addSecret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, WEB2_SECRET_VALUE); diff --git a/src/test/java/com/iexec/sms/secret/web2/Web2SecretsServiceTests.java b/src/test/java/com/iexec/sms/secret/web2/Web2SecretsServiceTests.java index b17f0782..0dbe122d 100644 --- a/src/test/java/com/iexec/sms/secret/web2/Web2SecretsServiceTests.java +++ b/src/test/java/com/iexec/sms/secret/web2/Web2SecretsServiceTests.java @@ -53,11 +53,8 @@ void beforeEach() { @Test void shouldGetDecryptedSecret() { - Secret encryptedSecret = new Secret(secretAddress, encryptedSecretValue); - encryptedSecret.setEncryptedValue(true); - List secretList = List.of(encryptedSecret); - Web2Secrets web2SecretsMock = new Web2Secrets(ownerAddress); - web2SecretsMock.setSecrets(secretList); + Secret encryptedSecret = new Secret(secretAddress, encryptedSecretValue, true); + Web2Secrets web2SecretsMock = new Web2Secrets(ownerAddress, List.of(encryptedSecret)); when(web2SecretsRepository.findWeb2SecretsByOwnerAddress(ownerAddress)) .thenReturn(Optional.of(web2SecretsMock)); when(encryptionService.decrypt(encryptedSecret.getValue())) @@ -65,17 +62,15 @@ void shouldGetDecryptedSecret() { Optional result = web2SecretsService.getSecret(ownerAddress, secretAddress, true); assertThat(result).isNotEmpty(); - assertThat(result.get().getAddress()).isEqualTo(secretAddress); - assertThat(result.get().getValue()).isEqualTo(plainSecretValue); + assertThat(result).get().extracting(Secret::getAddress).isEqualTo(secretAddress); + assertThat(result).get().extracting(Secret::getValue).isEqualTo(plainSecretValue); + assertThat(result).get().extracting(Secret::isEncryptedValue).isEqualTo(false); } @Test void shouldGetEncryptedSecret() { - Secret encryptedSecret = new Secret(secretAddress, encryptedSecretValue); - encryptedSecret.setEncryptedValue(true); - List secretList = List.of(encryptedSecret); - Web2Secrets web2Secrets = new Web2Secrets(ownerAddress); - web2Secrets.setSecrets(secretList); + Secret encryptedSecret = new Secret(secretAddress, encryptedSecretValue, true); + Web2Secrets web2Secrets = new Web2Secrets(ownerAddress, List.of(encryptedSecret)); when(web2SecretsRepository.findWeb2SecretsByOwnerAddress(ownerAddress)) .thenReturn(Optional.of(web2Secrets)); @@ -87,10 +82,9 @@ void shouldGetEncryptedSecret() { @Test void shouldNotAddSecretIfPresent() { - Web2Secrets web2Secrets = new Web2Secrets(ownerAddress); - web2Secrets.getSecrets().add(new Secret(secretAddress, encryptedSecretValue)); + Web2Secrets web2Secrets = new Web2Secrets(ownerAddress, List.of(new Secret(secretAddress, encryptedSecretValue, true))); when(web2SecretsRepository.findWeb2SecretsByOwnerAddress(ownerAddress)).thenReturn(Optional.of(web2Secrets)); - assertThat(web2SecretsService.addSecret(ownerAddress, secretAddress, plainSecretValue)).isFalse(); + assertThat(web2SecretsService.addSecret(ownerAddress, secretAddress, plainSecretValue)).isEmpty(); verifyNoInteractions(encryptionService); verify(web2SecretsRepository, never()).save(any()); } @@ -98,42 +92,48 @@ void shouldNotAddSecretIfPresent() { @Test void shouldAddSecret() { when(encryptionService.encrypt(plainSecretValue)).thenReturn(encryptedSecretValue); - assertThat(web2SecretsService.addSecret(ownerAddress, secretAddress, plainSecretValue)).isTrue(); + + final Optional newSecret = web2SecretsService.addSecret(ownerAddress, secretAddress, plainSecretValue); + assertThat(newSecret).isPresent(); + assertThat(newSecret).get().extracting(Secret::getAddress).isEqualTo(secretAddress); + assertThat(newSecret).get().extracting(Secret::getValue).isEqualTo(encryptedSecretValue); + assertThat(newSecret).get().extracting(Secret::isEncryptedValue).isEqualTo(true); + verify(encryptionService).encrypt(any()); verify(web2SecretsRepository).save(any()); } @Test void shouldNotUpdateSecretIfPresent() { - Secret encryptedSecret = new Secret(secretAddress, encryptedSecretValue); - encryptedSecret.setEncryptedValue(true); - List secretList = List.of(encryptedSecret); - Web2Secrets web2Secrets = new Web2Secrets(ownerAddress); - web2Secrets.setSecrets(secretList); + Secret encryptedSecret = new Secret(secretAddress, encryptedSecretValue, true); + Web2Secrets web2Secrets = new Web2Secrets(ownerAddress, List.of(encryptedSecret)); when(web2SecretsRepository.findWeb2SecretsByOwnerAddress(ownerAddress)) .thenReturn(Optional.of(web2Secrets)); when(encryptionService.encrypt(plainSecretValue)) .thenReturn(encryptedSecretValue); - web2SecretsService.updateSecret(ownerAddress, secretAddress, plainSecretValue); + assertThat(web2SecretsService.updateSecret(ownerAddress, secretAddress, plainSecretValue)).isEmpty(); verify(web2SecretsRepository, never()).save(web2Secrets); } @Test void shouldUpdateSecret() { - Secret encryptedSecret = new Secret(secretAddress, encryptedSecretValue); - encryptedSecret.setEncryptedValue(true); + Secret encryptedSecret = new Secret(secretAddress, encryptedSecretValue, true); String newSecretValue = "newSecretValue"; String newEncryptedSecretValue = "newEncryptedSecretValue"; - List secretList = List.of(encryptedSecret); - Web2Secrets web2SecretsMock = new Web2Secrets(ownerAddress); - web2SecretsMock.setSecrets(secretList); + Web2Secrets web2SecretsMock = new Web2Secrets(ownerAddress, List.of(encryptedSecret)); when(web2SecretsRepository.findWeb2SecretsByOwnerAddress(ownerAddress)) .thenReturn(Optional.of(web2SecretsMock)); when(encryptionService.encrypt(newSecretValue)) .thenReturn(newEncryptedSecretValue); - web2SecretsService.updateSecret(ownerAddress, secretAddress, newSecretValue); - verify(web2SecretsRepository, times(1)).save(web2SecretsMock); + final Optional newSecret = web2SecretsService.updateSecret(ownerAddress, secretAddress, newSecretValue); + assertThat(newSecret).isPresent(); + assertThat(newSecret).get().extracting(Secret::getAddress).isEqualTo(secretAddress); + assertThat(newSecret).get().extracting(Secret::getValue).isEqualTo(newEncryptedSecretValue); + assertThat(newSecret).get().extracting(Secret::isEncryptedValue).isEqualTo(true); + + verify(web2SecretsRepository, never()).save(web2SecretsMock); // Current object should not be updated + verify(web2SecretsRepository, times(1)).save(any()); // A new object should be created with the same ID } } \ No newline at end of file diff --git a/src/test/java/com/iexec/sms/secret/web3/Web3SecretServiceTests.java b/src/test/java/com/iexec/sms/secret/web3/Web3SecretServiceTests.java index 1bd66d28..74593668 100644 --- a/src/test/java/com/iexec/sms/secret/web3/Web3SecretServiceTests.java +++ b/src/test/java/com/iexec/sms/secret/web3/Web3SecretServiceTests.java @@ -49,7 +49,7 @@ void init() { @Test void shouldNotAddSecretIfPresent() { - Web3Secret web3Secret = new Web3Secret(secretAddress, encryptedSecretValue); + Web3Secret web3Secret = new Web3Secret(secretAddress, encryptedSecretValue, true); when(web3SecretRepository.findWeb3SecretByAddress(secretAddress)).thenReturn(Optional.of(web3Secret)); assertThat(web3SecretService.addSecret(secretAddress, plainSecretValue)).isFalse(); verifyNoInteractions(encryptionService); @@ -67,19 +67,23 @@ void shouldAddSecret() { @Test void shouldGetDecryptedSecret() { - Web3Secret encryptedSecret = new Web3Secret(secretAddress, encryptedSecretValue); - encryptedSecret.setEncryptedValue(true); + Web3Secret encryptedSecret = new Web3Secret(secretAddress, encryptedSecretValue, true); when(web3SecretRepository.findWeb3SecretByAddress(secretAddress)).thenReturn(Optional.of(encryptedSecret)); when(encryptionService.decrypt(encryptedSecretValue)).thenReturn(plainSecretValue); + Optional result = web3SecretService.getSecret(secretAddress, true); - assertThat(result).contains(new Web3Secret(secretAddress, plainSecretValue)); + assertThat(result).isPresent(); + assertThat(result).get().extracting(Web3Secret::getAddress).isEqualTo(secretAddress); + assertThat(result).get().extracting(Web3Secret::getValue).isEqualTo(plainSecretValue); + assertThat(result).get().extracting(Web3Secret::isEncryptedValue).isEqualTo(false); + verify(web3SecretRepository).findWeb3SecretByAddress(secretAddress); verify(encryptionService).decrypt(any()); } @Test void shouldGetEncryptedSecret() { - Web3Secret encryptedSecret = new Web3Secret(secretAddress, encryptedSecretValue); + Web3Secret encryptedSecret = new Web3Secret(secretAddress, encryptedSecretValue, true); when(web3SecretRepository.findWeb3SecretByAddress(secretAddress)).thenReturn(Optional.of(encryptedSecret)); assertThat(web3SecretService.getSecret(secretAddress)) .contains(encryptedSecret); diff --git a/src/test/java/com/iexec/sms/tee/session/base/SecretSessionBaseServiceTests.java b/src/test/java/com/iexec/sms/tee/session/base/SecretSessionBaseServiceTests.java index e65c0f14..b992c666 100644 --- a/src/test/java/com/iexec/sms/tee/session/base/SecretSessionBaseServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/base/SecretSessionBaseServiceTests.java @@ -90,11 +90,11 @@ void shouldGetSecretsTokens() throws Exception { // pre when(preComputeProperties.getFingerprint()) .thenReturn(PRE_COMPUTE_FINGERPRINT); - Web3Secret secret = new Web3Secret(DATASET_ADDRESS, DATASET_KEY); + Web3Secret secret = new Web3Secret(DATASET_ADDRESS, DATASET_KEY, true); when(web3SecretService.getSecret(DATASET_ADDRESS, true)) .thenReturn(Optional.of(secret)); // post - Secret publicKeySecret = new Secret("address", ENCRYPTION_PUBLIC_KEY); + Secret publicKeySecret = new Secret("address", ENCRYPTION_PUBLIC_KEY, true); when(postComputeProperties.getFingerprint()) .thenReturn(POST_COMPUTE_FINGERPRINT); when(web2SecretsService.getSecret( @@ -102,7 +102,7 @@ void shouldGetSecretsTokens() throws Exception { ReservedSecretKeyName.IEXEC_RESULT_ENCRYPTION_PUBLIC_KEY, true)) .thenReturn(Optional.of(publicKeySecret)); - Secret storageSecret = new Secret("address", STORAGE_TOKEN); + Secret storageSecret = new Secret("address", STORAGE_TOKEN, true); when(web2SecretsService.getSecret(taskDescription.getRequester(), ReservedSecretKeyName.IEXEC_RESULT_IEXEC_IPFS_TOKEN, true)) .thenReturn(Optional.of(storageSecret)); @@ -164,7 +164,7 @@ void shouldGetPreComputeTokens() throws Exception { TeeSessionRequest request = createSessionRequest(taskDescription); when(preComputeProperties.getFingerprint()) .thenReturn(PRE_COMPUTE_FINGERPRINT); - Web3Secret secret = new Web3Secret(DATASET_ADDRESS, DATASET_KEY); + Web3Secret secret = new Web3Secret(DATASET_ADDRESS, DATASET_KEY, true); when(web3SecretService.getSecret(DATASET_ADDRESS, true)) .thenReturn(Optional.of(secret)); @@ -391,7 +391,7 @@ void shouldGetPostComputeTokens() throws Exception { String requesterAddress = request.getTaskDescription().getRequester(); - Secret publicKeySecret = new Secret("address", ENCRYPTION_PUBLIC_KEY); + Secret publicKeySecret = new Secret("address", ENCRYPTION_PUBLIC_KEY, true); when(postComputeProperties.getFingerprint()) .thenReturn(POST_COMPUTE_FINGERPRINT); when(web2SecretsService.getSecret( @@ -399,7 +399,7 @@ void shouldGetPostComputeTokens() throws Exception { ReservedSecretKeyName.IEXEC_RESULT_ENCRYPTION_PUBLIC_KEY, true)) .thenReturn(Optional.of(publicKeySecret)); - Secret storageSecret = new Secret("address", STORAGE_TOKEN); + Secret storageSecret = new Secret("address", STORAGE_TOKEN, true); when(web2SecretsService.getSecret( requesterAddress, ReservedSecretKeyName.IEXEC_RESULT_IEXEC_IPFS_TOKEN, @@ -470,7 +470,7 @@ void shouldGetPostComputeStorageTokensOnIpfs() { final String secretValue = "Secret value"; when(web2SecretsService.getSecret(taskDescription.getRequester(), ReservedSecretKeyName.IEXEC_RESULT_IEXEC_IPFS_TOKEN, true)) - .thenReturn(Optional.of(new Secret(null, secretValue))); + .thenReturn(Optional.of(new Secret(null, secretValue, true))); final Map tokens = assertDoesNotThrow( () -> teeSecretsService.getPostComputeStorageTokens(sessionRequest)); @@ -493,7 +493,7 @@ void shouldGetPostComputeStorageTokensOnDropbox() { final String secretValue = "Secret value"; when(web2SecretsService.getSecret(taskDescription.getRequester(), ReservedSecretKeyName.IEXEC_RESULT_DROPBOX_TOKEN, true)) - .thenReturn(Optional.of(new Secret(null, secretValue))); + .thenReturn(Optional.of(new Secret(null, secretValue, true))); final Map tokens = assertDoesNotThrow( () -> teeSecretsService.getPostComputeStorageTokens(sessionRequest)); @@ -636,7 +636,7 @@ void shouldNotGetPostComputeSignTokensSinceNoEnclaveCredentialsPrivateKey() { void shouldGetPostComputeEncryptionTokensWithEncryption() { TeeSessionRequest request = createSessionRequest(createTaskDescription(enclaveConfig)); - Secret publicKeySecret = new Secret("address", ENCRYPTION_PUBLIC_KEY); + Secret publicKeySecret = new Secret("address", ENCRYPTION_PUBLIC_KEY, true); when(web2SecretsService.getSecret( request.getTaskDescription().getBeneficiary(), ReservedSecretKeyName.IEXEC_RESULT_ENCRYPTION_PUBLIC_KEY, From 0387d46e55e63b64dfef293b2f07d9f8cb715961 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Fri, 28 Oct 2022 09:12:07 +0200 Subject: [PATCH 168/293] Remove useless `@Builder` annotations --- src/main/java/com/iexec/sms/secret/Secret.java | 1 - src/main/java/com/iexec/sms/secret/web2/Web2Secrets.java | 1 - 2 files changed, 2 deletions(-) diff --git a/src/main/java/com/iexec/sms/secret/Secret.java b/src/main/java/com/iexec/sms/secret/Secret.java index 01a2bc9b..0d18f7f3 100644 --- a/src/main/java/com/iexec/sms/secret/Secret.java +++ b/src/main/java/com/iexec/sms/secret/Secret.java @@ -26,7 +26,6 @@ import java.util.Objects; @Entity -@Builder @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) @AllArgsConstructor(access = AccessLevel.PROTECTED) diff --git a/src/main/java/com/iexec/sms/secret/web2/Web2Secrets.java b/src/main/java/com/iexec/sms/secret/web2/Web2Secrets.java index 428f39b5..2a1b965a 100644 --- a/src/main/java/com/iexec/sms/secret/web2/Web2Secrets.java +++ b/src/main/java/com/iexec/sms/secret/web2/Web2Secrets.java @@ -26,7 +26,6 @@ @Entity @Getter -@Builder @NoArgsConstructor(access = AccessLevel.PRIVATE) @AllArgsConstructor(access = AccessLevel.PRIVATE) public class Web2Secrets { From 34f82417e5e18dce5d6474b040c249438c3eaa4c Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Fri, 28 Oct 2022 11:36:21 +0200 Subject: [PATCH 169/293] Remove getWeb2Secret and getWeb3Secret in SecretController --- .../iexec/sms/secret/SecretController.java | 32 ------- .../sms/secret/SecretControllerTests.java | 86 ------------------- 2 files changed, 118 deletions(-) diff --git a/src/main/java/com/iexec/sms/secret/SecretController.java b/src/main/java/com/iexec/sms/secret/SecretController.java index bdbe1de9..5cc8eb5a 100644 --- a/src/main/java/com/iexec/sms/secret/SecretController.java +++ b/src/main/java/com/iexec/sms/secret/SecretController.java @@ -55,22 +55,6 @@ public ResponseEntity isWeb3SecretSet(@RequestParam String secretAddress) return secret.isPresent() ? ResponseEntity.noContent().build() : ResponseEntity.notFound().build(); } - @GetMapping("/web3") - public ResponseEntity getWeb3Secret(@RequestHeader String authorization, - @RequestParam String secretAddress, - @RequestParam(required = false, defaultValue = "false") boolean shouldDecryptSecret) { - String challenge = authorizationService.getChallengeForGetWeb3Secret(secretAddress); - - //TODO: also isAuthorizedOnExecution(..) - if (!authorizationService.isSignedByOwner(challenge, authorization, secretAddress)) { - log.error("Unauthorized to getWeb3Secret [expectedChallenge:{}]", challenge); - return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build(); - } - - Optional secret = web3SecretService.getSecret(secretAddress, shouldDecryptSecret); - return ResponseEntity.of(secret); - } - @PostMapping("/web3") public ResponseEntity addWeb3Secret(@RequestHeader String authorization, @RequestParam String secretAddress, @@ -102,22 +86,6 @@ public ResponseEntity isWeb2SecretSet(@RequestParam String ownerAddress, return secret.isPresent() ? ResponseEntity.noContent().build() : ResponseEntity.notFound().build(); } - @GetMapping("/web2") - public ResponseEntity getWeb2Secret(@RequestHeader String authorization, - @RequestParam String ownerAddress, - @RequestParam String secretName, - @RequestParam(required = false, defaultValue = "false") boolean shouldDecryptSecret) { - String challenge = authorizationService.getChallengeForGetWeb2Secret(ownerAddress, secretName); - - if (!authorizationService.isSignedByHimself(challenge, authorization, ownerAddress)) { - log.error("Unauthorized to getWeb2Secret [expectedChallenge:{}]", challenge); - return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build(); - } - - Optional secret = web2SecretsService.getSecret(ownerAddress, secretName, shouldDecryptSecret); - return ResponseEntity.of(secret); - } - @PostMapping("/web2") public ResponseEntity addWeb2Secret(@RequestHeader String authorization, @RequestParam String ownerAddress, diff --git a/src/test/java/com/iexec/sms/secret/SecretControllerTests.java b/src/test/java/com/iexec/sms/secret/SecretControllerTests.java index 2a238121..1c519fc9 100644 --- a/src/test/java/com/iexec/sms/secret/SecretControllerTests.java +++ b/src/test/java/com/iexec/sms/secret/SecretControllerTests.java @@ -87,49 +87,6 @@ void shouldReturnNotFoundWhenWeb3SecretDoesNotExist() { } //endregion - //region getWeb3Secret - @ParameterizedTest - @ValueSource(strings = {"true", "false"}) - void failToGetWeb3SecretWhenBadAuthorization(boolean shouldDecryptValue) { - when(authorizationService.getChallengeForGetWeb3Secret(WEB3_SECRET_ADDRESS)) - .thenReturn(CHALLENGE); - when(authorizationService.isSignedByOwner(CHALLENGE, AUTHORIZATION, WEB3_SECRET_ADDRESS)) - .thenReturn(false); - assertThat(secretController.getWeb3Secret(AUTHORIZATION, WEB3_SECRET_ADDRESS, shouldDecryptValue)) - .isEqualTo(ResponseEntity.status(HttpStatus.UNAUTHORIZED).build()); - verifyNoInteractions(web2SecretsService, web3SecretService); - } - - @ParameterizedTest - @ValueSource(strings = {"true", "false"}) - void failToGetWeb3SecretWhenSecretDoesNotExist(boolean shouldDecryptValue) { - when(authorizationService.getChallengeForGetWeb3Secret(WEB3_SECRET_ADDRESS)) - .thenReturn(CHALLENGE); - when(authorizationService.isSignedByOwner(CHALLENGE, AUTHORIZATION, WEB3_SECRET_ADDRESS)) - .thenReturn(true); - when(web3SecretService.getSecret(WEB3_SECRET_ADDRESS, shouldDecryptValue)) - .thenReturn(Optional.empty()); - assertThat(secretController.getWeb3Secret(AUTHORIZATION, WEB3_SECRET_ADDRESS, shouldDecryptValue)) - .isEqualTo(ResponseEntity.notFound().build()); - verifyNoInteractions(web2SecretsService); - } - - @ParameterizedTest - @ValueSource(strings = {"true", "false"}) - void getWeb3Secret(boolean shouldDecryptSecret) { - Web3Secret expectedSecret = new Web3Secret(); - when(authorizationService.getChallengeForGetWeb3Secret(WEB3_SECRET_ADDRESS)) - .thenReturn(CHALLENGE); - when(authorizationService.isSignedByOwner(CHALLENGE, AUTHORIZATION, WEB3_SECRET_ADDRESS)) - .thenReturn(true); - when(web3SecretService.getSecret(WEB3_SECRET_ADDRESS, shouldDecryptSecret)) - .thenReturn(Optional.of(expectedSecret)); - assertThat(secretController.getWeb3Secret(AUTHORIZATION, WEB3_SECRET_ADDRESS, shouldDecryptSecret)) - .isEqualTo(ResponseEntity.ok(expectedSecret)); - verifyNoInteractions(web2SecretsService); - } - //endregion - //region addWeb3Secret @Test void failToAddWeb3SecretWhenPayloadTooLarge() { @@ -198,49 +155,6 @@ void shouldReturnNotFoundWhenWeb2SecretDoesNotExist() { } //endregion - //region getWeb2Secret - @ParameterizedTest - @ValueSource(strings = {"true", "false"}) - void failToGetWeb2SecretWhenBadAuthorization(boolean shouldDecryptValue) { - when(authorizationService.getChallengeForGetWeb2Secret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME)) - .thenReturn(CHALLENGE); - when(authorizationService.isSignedByHimself(CHALLENGE, AUTHORIZATION, WEB2_OWNER_ADDRESS)) - .thenReturn(false); - assertThat(secretController.getWeb2Secret(AUTHORIZATION, WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, shouldDecryptValue)) - .isEqualTo(ResponseEntity.status(HttpStatus.UNAUTHORIZED).build()); - verifyNoInteractions(web2SecretsService, web3SecretService); - } - - @ParameterizedTest - @ValueSource(strings = {"true", "false"}) - void failToGetWeb2SecretWhenSecretDoesNotExist(boolean shouldDecryptValue) { - when(authorizationService.getChallengeForGetWeb2Secret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME)) - .thenReturn(CHALLENGE); - when(authorizationService.isSignedByHimself(CHALLENGE, AUTHORIZATION, WEB2_OWNER_ADDRESS)) - .thenReturn(true); - when(web2SecretsService.getSecret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, shouldDecryptValue)) - .thenReturn(Optional.empty()); - assertThat(secretController.getWeb2Secret(AUTHORIZATION, WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, shouldDecryptValue)) - .isEqualTo(ResponseEntity.notFound().build()); - verifyNoInteractions(web3SecretService); - } - - @ParameterizedTest - @ValueSource(strings = {"true", "false"}) - void getWeb2Secret(boolean shouldDecryptSecret) { - Secret expectedSecret = new Secret(); - when(authorizationService.getChallengeForGetWeb2Secret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME)) - .thenReturn(CHALLENGE); - when(authorizationService.isSignedByHimself(CHALLENGE, AUTHORIZATION, WEB2_OWNER_ADDRESS)) - .thenReturn(true); - when(web2SecretsService.getSecret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, shouldDecryptSecret)) - .thenReturn(Optional.of(expectedSecret)); - assertThat(secretController.getWeb2Secret(AUTHORIZATION, WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, shouldDecryptSecret)) - .isEqualTo(ResponseEntity.ok(expectedSecret)); - verifyNoInteractions(web3SecretService); - } - //endregion - //region addWeb2Secret @Test void failToAddWeb2SecretWhenPayloadTooLarge() { From 667228b3b82fc77f7397b1e76062722b82e8798e Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Fri, 28 Oct 2022 11:46:23 +0200 Subject: [PATCH 170/293] Split `withNewSecret` into `addNewSecret` & `updateSecret` --- .../iexec/sms/secret/SecretController.java | 3 +- .../web2/NotAnExistingSecretException.java | 14 ++++ .../sms/secret/web2/SameSecretException.java | 15 +++++ .../web2/SecretAlreadyExistsException.java | 14 ++++ .../iexec/sms/secret/web2/Web2Secrets.java | 67 ++++++++++++++----- .../sms/secret/web2/Web2SecretsService.java | 45 ++++++------- .../sms/secret/SecretControllerTests.java | 15 ++++- .../secret/web2/Web2SecretsServiceTests.java | 48 +++++++++---- 8 files changed, 165 insertions(+), 56 deletions(-) create mode 100644 src/main/java/com/iexec/sms/secret/web2/NotAnExistingSecretException.java create mode 100644 src/main/java/com/iexec/sms/secret/web2/SameSecretException.java create mode 100644 src/main/java/com/iexec/sms/secret/web2/SecretAlreadyExistsException.java diff --git a/src/main/java/com/iexec/sms/secret/SecretController.java b/src/main/java/com/iexec/sms/secret/SecretController.java index 54219371..acd4edb2 100644 --- a/src/main/java/com/iexec/sms/secret/SecretController.java +++ b/src/main/java/com/iexec/sms/secret/SecretController.java @@ -18,6 +18,7 @@ import com.iexec.sms.authorization.AuthorizationService; +import com.iexec.sms.secret.web2.NotAnExistingSecretException; import com.iexec.sms.secret.web2.Web2SecretsService; import com.iexec.sms.secret.web3.Web3Secret; import com.iexec.sms.secret.web3.Web3SecretService; @@ -160,7 +161,7 @@ public ResponseEntity updateWeb2Secret(@RequestHeader String authorizati try { web2SecretsService.updateSecret(ownerAddress, secretName, newSecretValue); return ResponseEntity.noContent().build(); - } catch (NoSuchElementException e) { + } catch (NoSuchElementException | NotAnExistingSecretException e) { return ResponseEntity.notFound().build(); } } diff --git a/src/main/java/com/iexec/sms/secret/web2/NotAnExistingSecretException.java b/src/main/java/com/iexec/sms/secret/web2/NotAnExistingSecretException.java new file mode 100644 index 00000000..a85749f4 --- /dev/null +++ b/src/main/java/com/iexec/sms/secret/web2/NotAnExistingSecretException.java @@ -0,0 +1,14 @@ +package com.iexec.sms.secret.web2; + +import lombok.Getter; + +@Getter +public class NotAnExistingSecretException extends Exception { + private final String ownerAddress; + private final String secretAddress; + + public NotAnExistingSecretException(String ownerAddress, String secretAddress) { + this.ownerAddress = ownerAddress; + this.secretAddress = secretAddress; + } +} diff --git a/src/main/java/com/iexec/sms/secret/web2/SameSecretException.java b/src/main/java/com/iexec/sms/secret/web2/SameSecretException.java new file mode 100644 index 00000000..f9e22a05 --- /dev/null +++ b/src/main/java/com/iexec/sms/secret/web2/SameSecretException.java @@ -0,0 +1,15 @@ +package com.iexec.sms.secret.web2; + +import com.iexec.sms.secret.Secret; +import lombok.Getter; + +@Getter +public class SameSecretException extends Exception { + private final String ownerAddress; + private final String secretAddress; + + public SameSecretException(String ownerAddress, Secret secret) { + this.ownerAddress = ownerAddress; + this.secretAddress = secret.getAddress(); + } +} diff --git a/src/main/java/com/iexec/sms/secret/web2/SecretAlreadyExistsException.java b/src/main/java/com/iexec/sms/secret/web2/SecretAlreadyExistsException.java new file mode 100644 index 00000000..eac3d0bb --- /dev/null +++ b/src/main/java/com/iexec/sms/secret/web2/SecretAlreadyExistsException.java @@ -0,0 +1,14 @@ +package com.iexec.sms.secret.web2; + +import lombok.Getter; + +@Getter +public class SecretAlreadyExistsException extends Exception { + private final String ownerAddress; + private final String secretAddress; + + public SecretAlreadyExistsException(String ownerAddress, String secretAddress) { + this.ownerAddress = ownerAddress; + this.secretAddress = secretAddress; + } +} diff --git a/src/main/java/com/iexec/sms/secret/web2/Web2Secrets.java b/src/main/java/com/iexec/sms/secret/web2/Web2Secrets.java index 2a1b965a..244e59f1 100644 --- a/src/main/java/com/iexec/sms/secret/web2/Web2Secrets.java +++ b/src/main/java/com/iexec/sms/secret/web2/Web2Secrets.java @@ -17,12 +17,14 @@ package com.iexec.sms.secret.web2; import com.iexec.sms.secret.Secret; -import lombok.*; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; import org.hibernate.annotations.GenericGenerator; import javax.persistence.*; import java.util.*; -import java.util.stream.Collectors; @Entity @Getter @@ -56,25 +58,56 @@ public Optional getSecret(String secretAddress) { /** * Copies the current {@link Web2Secrets} object, while adding given {@link Secret} to the secrets list. - * In case of an update, - * given secret is removed from the secrets list before the new object is created. * - * @param newSecret {@link Secret} to add to the list - * @return A new {@link Web2Secrets} object with given new {@link Secret}. + * @param secretAddress Address of the new secret. + * @param secretValue Value of the new secret. + * @param isEncryptedValue Whether this value is encrypted. + * @return A new {@link Web2Secrets} instance, with a new {@link Secret} element. + * @throws SecretAlreadyExistsException thrown when a secret with same address already exists. */ - public Web2Secrets withNewSecret(Secret newSecret) { - List newSecrets; - if (newSecret.getId() == null) { - // New secret, no need to remove any old corresponding secret. - newSecrets = new ArrayList<>(secrets); - } else { - // Update of existing secret, remove the old secret. - newSecrets = secrets.stream() - .filter(secret -> !Objects.equals(secret.getId(), newSecret.getId())) - .collect(Collectors.toList()); + public Web2Secrets addNewSecret(String secretAddress, String secretValue, boolean isEncryptedValue) + throws SecretAlreadyExistsException { + // A new secret can't already exist + if (getSecret(secretAddress).isPresent()) { + throw new SecretAlreadyExistsException(ownerAddress, secretAddress); } - newSecrets.add(newSecret); + final List newSecrets = new ArrayList<>(this.secrets); + newSecrets.add(new Secret(secretAddress, secretValue, isEncryptedValue)); return new Web2Secrets(id, ownerAddress, newSecrets); } + + /** + * Copies the current {@link Web2Secrets} object, while updating {@link Secret} at given {@code secretAddress}. + * + * @param secretAddress Address of the secret to update. + * @param newSecretValue New value for the secret. + * @param isEncryptedValue Whether this value is encrypted. + * @return A new {@link Web2Secrets} instance, with a {@link Secret} whose value has been updated. + * @throws NotAnExistingSecretException thrown when requested address is not known. + * @throws SameSecretException thrown when secret has already given value. + */ + public Web2Secrets updateSecret(String secretAddress, String newSecretValue, boolean isEncryptedValue) + throws NotAnExistingSecretException, SameSecretException { + final Optional oSecretToUpdate = getSecret(secretAddress); + + // Can't update a secret that doesn't exist + if (oSecretToUpdate.isEmpty()) { + throw new NotAnExistingSecretException(ownerAddress, secretAddress); + } + + // No need to update if same value + final Secret secretToUpdate = oSecretToUpdate.get(); + if (secretToUpdate.isEncryptedValue() == isEncryptedValue && Objects.equals(secretToUpdate.getValue(), newSecretValue)) { + throw new SameSecretException(ownerAddress, secretToUpdate); + } + + final List updatedSecretsList = new ArrayList<>(secrets); + // Filtering out old secret + updatedSecretsList.remove(secretToUpdate); + // Adding updated secret + updatedSecretsList.add(secretToUpdate.withValue(newSecretValue, isEncryptedValue)); + + return new Web2Secrets(id, ownerAddress, updatedSecretsList); + } } diff --git a/src/main/java/com/iexec/sms/secret/web2/Web2SecretsService.java b/src/main/java/com/iexec/sms/secret/web2/Web2SecretsService.java index c5f35674..f4d9d76d 100644 --- a/src/main/java/com/iexec/sms/secret/web2/Web2SecretsService.java +++ b/src/main/java/com/iexec/sms/secret/web2/Web2SecretsService.java @@ -65,42 +65,39 @@ public Optional addSecret(String ownerAddress, String secretAddress, Str final Web2Secrets web2Secrets = getWeb2Secrets(ownerAddress) .orElse(new Web2Secrets(ownerAddress)); - if (web2Secrets.getSecret(secretAddress).isPresent()) { - log.error("Secret already exists [ownerAddress:{}, secretAddress:{}]", ownerAddress, secretAddress); - return Optional.empty(); - } - final String encryptedValue = encryptionService.encrypt(secretValue); log.info("Adding new secret [ownerAddress:{}, secretAddress:{}, encryptedSecretValue:{}]", ownerAddress, secretAddress, encryptedValue); - final Secret secret = new Secret(secretAddress, encryptedValue, true); - addSecretAndSave(web2Secrets, secret); - return Optional.of(secret); + try { + final Web2Secrets newWeb2Secrets = web2Secrets.addNewSecret(secretAddress, encryptedValue, true); + web2SecretsRepository.save(newWeb2Secrets); + return newWeb2Secrets.getSecret(secretAddress); + } catch (SecretAlreadyExistsException e) { + log.error("Secret already exists [ownerAddress:{}, secretAddress:{}]", ownerAddress, secretAddress, e); + return Optional.empty(); + } } - public Optional updateSecret(String ownerAddress, String secretAddress, String newSecretValue) { + public Optional updateSecret(String ownerAddress, String secretAddress, String newSecretValue) throws NotAnExistingSecretException { ownerAddress = ownerAddress.toLowerCase(); final Web2Secrets web2Secrets = getWeb2Secrets(ownerAddress).orElseThrow(); - final Secret existingSecret = web2Secrets.getSecret(secretAddress).orElseThrow(); - final String encryptedValue = encryptionService.encrypt(newSecretValue); - if (existingSecret.getValue().equals(encryptedValue)) { + log.info("Updating secret [ownerAddress:{}, secretAddress:{}, newEncryptedSecretValue:{}]", + ownerAddress, secretAddress, encryptedValue); + + try { + final Web2Secrets newWeb2Secrets = web2Secrets.updateSecret(secretAddress, encryptedValue, true); + web2SecretsRepository.save(newWeb2Secrets); + return newWeb2Secrets.getSecret(secretAddress); + } catch (NotAnExistingSecretException e) { + log.error("Secret does not exist, can't update it [ownerAddress:{}, secretAddress:{}]", + ownerAddress, secretAddress, e); + throw e; + } catch (SameSecretException e) { log.info("No need to update secret [ownerAddress:{}, secretAddress:{}]", ownerAddress, secretAddress); return Optional.empty(); } - - log.info("Updating secret [ownerAddress:{}, secretAddress:{}, oldEncryptedSecretValue:{}, newEncryptedSecretValue:{}]", - ownerAddress, secretAddress, existingSecret.getValue(), encryptedValue); - - final Secret newSecret = existingSecret.withValue(encryptedValue, true); - addSecretAndSave(web2Secrets, newSecret); - return Optional.of(newSecret); - } - - private void addSecretAndSave(Web2Secrets web2Secrets, Secret secret) { - final Web2Secrets newWeb2Secrets = web2Secrets.withNewSecret(secret); - web2SecretsRepository.save(newWeb2Secrets); } } diff --git a/src/test/java/com/iexec/sms/secret/SecretControllerTests.java b/src/test/java/com/iexec/sms/secret/SecretControllerTests.java index 25101634..c62d9605 100644 --- a/src/test/java/com/iexec/sms/secret/SecretControllerTests.java +++ b/src/test/java/com/iexec/sms/secret/SecretControllerTests.java @@ -17,6 +17,7 @@ package com.iexec.sms.secret; import com.iexec.sms.authorization.AuthorizationService; +import com.iexec.sms.secret.web2.NotAnExistingSecretException; import com.iexec.sms.secret.web2.Web2SecretsService; import com.iexec.sms.secret.web3.Web3Secret; import com.iexec.sms.secret.web3.Web3SecretService; @@ -307,7 +308,7 @@ void failToUpdateWeb2SecretWhenBadAuthorization() { } @Test - void failToUpdateWeb2SecretWhenSecretIsMissing() { + void failToUpdateWeb2SecretWhenSecretsListIsMissing() throws NotAnExistingSecretException { when(authorizationService.getChallengeForSetWeb2Secret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, WEB2_SECRET_VALUE)) .thenReturn(CHALLENGE); when(authorizationService.isSignedByHimself(CHALLENGE, AUTHORIZATION, WEB2_OWNER_ADDRESS)) @@ -318,6 +319,18 @@ void failToUpdateWeb2SecretWhenSecretIsMissing() { .isEqualTo(ResponseEntity.notFound().build()); } + @Test + void failToUpdateWeb2SecretWhenSecretIsMissing() throws NotAnExistingSecretException { + when(authorizationService.getChallengeForSetWeb2Secret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, WEB2_SECRET_VALUE)) + .thenReturn(CHALLENGE); + when(authorizationService.isSignedByHimself(CHALLENGE, AUTHORIZATION, WEB2_OWNER_ADDRESS)) + .thenReturn(true); + doThrow(NotAnExistingSecretException.class).when(web2SecretsService) + .updateSecret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, WEB2_SECRET_VALUE); + assertThat(secretController.updateWeb2Secret(AUTHORIZATION, WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, WEB2_SECRET_VALUE)) + .isEqualTo(ResponseEntity.notFound().build()); + } + @Test void updateWeb2Secret() { when(authorizationService.getChallengeForSetWeb2Secret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, WEB2_SECRET_VALUE)) diff --git a/src/test/java/com/iexec/sms/secret/web2/Web2SecretsServiceTests.java b/src/test/java/com/iexec/sms/secret/web2/Web2SecretsServiceTests.java index 0dbe122d..39c1861d 100644 --- a/src/test/java/com/iexec/sms/secret/web2/Web2SecretsServiceTests.java +++ b/src/test/java/com/iexec/sms/secret/web2/Web2SecretsServiceTests.java @@ -18,16 +18,18 @@ import com.iexec.sms.encryption.EncryptionService; import com.iexec.sms.secret.Secret; +import org.assertj.core.api.ThrowableAssertAlternative; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.mockito.Spy; import java.util.List; import java.util.Optional; -import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.*; import static org.mockito.Mockito.*; class Web2SecretsServiceTests { @@ -44,6 +46,7 @@ class Web2SecretsServiceTests { private EncryptionService encryptionService; @InjectMocks + @Spy private Web2SecretsService web2SecretsService; @BeforeEach @@ -85,7 +88,7 @@ void shouldNotAddSecretIfPresent() { Web2Secrets web2Secrets = new Web2Secrets(ownerAddress, List.of(new Secret(secretAddress, encryptedSecretValue, true))); when(web2SecretsRepository.findWeb2SecretsByOwnerAddress(ownerAddress)).thenReturn(Optional.of(web2Secrets)); assertThat(web2SecretsService.addSecret(ownerAddress, secretAddress, plainSecretValue)).isEmpty(); - verifyNoInteractions(encryptionService); + verify(encryptionService, times(1)).encrypt(plainSecretValue); verify(web2SecretsRepository, never()).save(any()); } @@ -104,10 +107,10 @@ void shouldAddSecret() { } @Test - void shouldNotUpdateSecretIfPresent() { - Secret encryptedSecret = new Secret(secretAddress, encryptedSecretValue, true); - Web2Secrets web2Secrets = new Web2Secrets(ownerAddress, List.of(encryptedSecret)); - when(web2SecretsRepository.findWeb2SecretsByOwnerAddress(ownerAddress)) + void shouldNotUpdateSecretIfPresent() throws NotAnExistingSecretException { + final Secret encryptedSecret = new Secret(secretAddress, encryptedSecretValue, true); + final Web2Secrets web2Secrets = new Web2Secrets(ownerAddress, List.of(encryptedSecret)); + when(web2SecretsService.getWeb2Secrets(ownerAddress)) .thenReturn(Optional.of(web2Secrets)); when(encryptionService.encrypt(plainSecretValue)) .thenReturn(encryptedSecretValue); @@ -117,21 +120,40 @@ void shouldNotUpdateSecretIfPresent() { } @Test - void shouldUpdateSecret() { + void shouldNotUpdateSecretIfOldSecretDoesntExist() { + final Web2Secrets web2Secrets = new Web2Secrets(ownerAddress, List.of()); + when(web2SecretsService.getWeb2Secrets(ownerAddress)) + .thenReturn(Optional.of(web2Secrets)); + when(encryptionService.encrypt(plainSecretValue)) + .thenReturn(encryptedSecretValue); + + final ThrowableAssertAlternative exception = + assertThatExceptionOfType(NotAnExistingSecretException.class) + .isThrownBy(() -> web2SecretsService.updateSecret(ownerAddress, secretAddress, plainSecretValue)); + exception.extracting(NotAnExistingSecretException::getOwnerAddress).isEqualTo(ownerAddress); + exception.extracting(NotAnExistingSecretException::getSecretAddress).isEqualTo(secretAddress); + + verify(web2SecretsRepository, never()).save(web2Secrets); + } + + @Test + void shouldUpdateSecret() throws NotAnExistingSecretException { Secret encryptedSecret = new Secret(secretAddress, encryptedSecretValue, true); String newSecretValue = "newSecretValue"; String newEncryptedSecretValue = "newEncryptedSecretValue"; Web2Secrets web2SecretsMock = new Web2Secrets(ownerAddress, List.of(encryptedSecret)); - when(web2SecretsRepository.findWeb2SecretsByOwnerAddress(ownerAddress)) + when(web2SecretsService.getWeb2Secrets(ownerAddress)) .thenReturn(Optional.of(web2SecretsMock)); when(encryptionService.encrypt(newSecretValue)) .thenReturn(newEncryptedSecretValue); - final Optional newSecret = web2SecretsService.updateSecret(ownerAddress, secretAddress, newSecretValue); - assertThat(newSecret).isPresent(); - assertThat(newSecret).get().extracting(Secret::getAddress).isEqualTo(secretAddress); - assertThat(newSecret).get().extracting(Secret::getValue).isEqualTo(newEncryptedSecretValue); - assertThat(newSecret).get().extracting(Secret::isEncryptedValue).isEqualTo(true); + final Optional oNewSecret = web2SecretsService.updateSecret(ownerAddress, secretAddress, newSecretValue); + assertThat(oNewSecret).isPresent(); + + final Secret newSecret = oNewSecret.get(); + assertThat(newSecret).extracting(Secret::getAddress).isEqualTo(secretAddress); + assertThat(newSecret).extracting(Secret::getValue).isEqualTo(newEncryptedSecretValue); + assertThat(newSecret).extracting(Secret::isEncryptedValue).isEqualTo(true); verify(web2SecretsRepository, never()).save(web2SecretsMock); // Current object should not be updated verify(web2SecretsRepository, times(1)).save(any()); // A new object should be created with the same ID From 16156ec6a8394e6ad04b0c2a4332e63004f837b7 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Fri, 28 Oct 2022 11:53:03 +0200 Subject: [PATCH 171/293] Replace `withValue` with `withEncrypted/decryptedValue` methods --- .../java/com/iexec/sms/secret/Secret.java | 19 +++++++++++++---- .../iexec/sms/secret/web2/Web2Secrets.java | 2 +- .../sms/secret/web2/Web2SecretsService.java | 2 +- .../com/iexec/sms/secret/web3/Web3Secret.java | 21 ++++++++++++++----- .../sms/secret/web3/Web3SecretService.java | 2 +- 5 files changed, 34 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/iexec/sms/secret/Secret.java b/src/main/java/com/iexec/sms/secret/Secret.java index 0d18f7f3..98a95cb1 100644 --- a/src/main/java/com/iexec/sms/secret/Secret.java +++ b/src/main/java/com/iexec/sms/secret/Secret.java @@ -50,16 +50,27 @@ public Secret(String address, String value, boolean isEncryptedValue) { /** * Copies the current {@link Secret} object, - * while replacing the old value with the new one. + * while replacing the old value with a new encrypted value. * * @param newValue Value to use for new object. - * @param isEncryptedValue Whether this value is encrypted. * @return A new {@link Secret} object with new value. */ - public Secret withValue(String newValue, boolean isEncryptedValue) { - return new Secret(this.id, this.address, newValue, isEncryptedValue); + public Secret withEncryptedValue(String newValue) { + return new Secret(this.id, this.address, newValue, true); } + /** + * Copies the current {@link Secret} object, + * while replacing the old value with a new decrypted value. + * + * @param newValue Value to use for new object. + * @return A new {@link Secret} object with new value. + */ + public Secret withDecryptedValue(String newValue) { + return new Secret(this.id, this.address, newValue, false); + } + + /** * Get the secret value without possible leading or trailing * newline characters. This should be used when putting diff --git a/src/main/java/com/iexec/sms/secret/web2/Web2Secrets.java b/src/main/java/com/iexec/sms/secret/web2/Web2Secrets.java index 244e59f1..6da75074 100644 --- a/src/main/java/com/iexec/sms/secret/web2/Web2Secrets.java +++ b/src/main/java/com/iexec/sms/secret/web2/Web2Secrets.java @@ -106,7 +106,7 @@ public Web2Secrets updateSecret(String secretAddress, String newSecretValue, boo // Filtering out old secret updatedSecretsList.remove(secretToUpdate); // Adding updated secret - updatedSecretsList.add(secretToUpdate.withValue(newSecretValue, isEncryptedValue)); + updatedSecretsList.add(secretToUpdate.withEncryptedValue(newSecretValue)); return new Web2Secrets(id, ownerAddress, updatedSecretsList); } diff --git a/src/main/java/com/iexec/sms/secret/web2/Web2SecretsService.java b/src/main/java/com/iexec/sms/secret/web2/Web2SecretsService.java index f4d9d76d..08794001 100644 --- a/src/main/java/com/iexec/sms/secret/web2/Web2SecretsService.java +++ b/src/main/java/com/iexec/sms/secret/web2/Web2SecretsService.java @@ -57,7 +57,7 @@ public Optional getSecret(String ownerAddress, String secretAddress, boo final Secret secret = oSecret.get(); final String decryptedValue = encryptionService.decrypt(secret.getValue()); - return Optional.of(secret.withValue(decryptedValue, false)); + return Optional.of(secret.withDecryptedValue(decryptedValue)); } public Optional addSecret(String ownerAddress, String secretAddress, String secretValue) { diff --git a/src/main/java/com/iexec/sms/secret/web3/Web3Secret.java b/src/main/java/com/iexec/sms/secret/web3/Web3Secret.java index efd5816d..8e7e9f73 100644 --- a/src/main/java/com/iexec/sms/secret/web3/Web3Secret.java +++ b/src/main/java/com/iexec/sms/secret/web3/Web3Secret.java @@ -46,14 +46,25 @@ public Web3Secret(String address, String value, boolean isEncryptedValue) { /** * Copies the current {@link Web3Secret} object, - * while replacing the old value with the new one. + * while replacing the old value with a new encrypted value. * - * @param newValue Value to use for new object. - * @param isEncryptedValue Whether this value is encrypted. + * @param newValue Value to use for new object. * @return A new {@link Web3Secret} object with new value. */ @Override - public Web3Secret withValue(String newValue, boolean isEncryptedValue) { - return new Web3Secret(super.getId(), this.id, this.getAddress(), newValue, isEncryptedValue); + public Web3Secret withEncryptedValue(String newValue) { + return new Web3Secret(super.getId(), this.id, this.getAddress(), newValue, true); + } + + /** + * Copies the current {@link Web3Secret} object, + * while replacing the old value with a new decrypted value. + * + * @param newValue Value to use for new object. + * @return A new {@link Web3Secret} object with new value. + */ + @Override + public Web3Secret withDecryptedValue(String newValue) { + return new Web3Secret(super.getId(), this.id, this.getAddress(), newValue, false); } } diff --git a/src/main/java/com/iexec/sms/secret/web3/Web3SecretService.java b/src/main/java/com/iexec/sms/secret/web3/Web3SecretService.java index 3772698d..6082a262 100644 --- a/src/main/java/com/iexec/sms/secret/web3/Web3SecretService.java +++ b/src/main/java/com/iexec/sms/secret/web3/Web3SecretService.java @@ -44,7 +44,7 @@ public Optional getSecret(String secretAddress, boolean shouldDecryp } if (shouldDecryptValue) { final String decryptedValue = encryptionService.decrypt(oSecret.get().getValue()); - return oSecret.map(secret -> secret.withValue(decryptedValue, false)); + return oSecret.map(secret -> secret.withDecryptedValue(decryptedValue)); } return oSecret; } From eb782ff6cdccf5f86dc6975a9c4a8c3bcf889804 Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Fri, 28 Oct 2022 12:04:30 +0200 Subject: [PATCH 172/293] Invert calling order in getSecret implementations for web2 and web3 secrets --- .../iexec/sms/secret/web2/Web2SecretsService.java | 8 ++++---- .../iexec/sms/secret/web3/Web3SecretService.java | 14 ++++++-------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/iexec/sms/secret/web2/Web2SecretsService.java b/src/main/java/com/iexec/sms/secret/web2/Web2SecretsService.java index 912298dc..42fb6721 100644 --- a/src/main/java/com/iexec/sms/secret/web2/Web2SecretsService.java +++ b/src/main/java/com/iexec/sms/secret/web2/Web2SecretsService.java @@ -43,13 +43,13 @@ public Optional getWeb2Secrets(String ownerAddress) { } public Optional getSecret(String ownerAddress, String secretAddress) { - return getSecret(ownerAddress, secretAddress, false); + ownerAddress = ownerAddress.toLowerCase(); + return getWeb2Secrets(ownerAddress) + .flatMap(web2Secrets -> web2Secrets.getSecret(secretAddress)); } public Optional getSecret(String ownerAddress, String secretAddress, boolean shouldDecryptValue) { - ownerAddress = ownerAddress.toLowerCase(); - Optional oSecret = getWeb2Secrets(ownerAddress) - .flatMap(web2Secrets -> web2Secrets.getSecret(secretAddress)); + Optional oSecret = getSecret(ownerAddress, secretAddress); return shouldDecryptValue ? oSecret.map(this::decryptSecret) : oSecret; } diff --git a/src/main/java/com/iexec/sms/secret/web3/Web3SecretService.java b/src/main/java/com/iexec/sms/secret/web3/Web3SecretService.java index 7ea4eb12..6c788858 100644 --- a/src/main/java/com/iexec/sms/secret/web3/Web3SecretService.java +++ b/src/main/java/com/iexec/sms/secret/web3/Web3SecretService.java @@ -38,18 +38,16 @@ public Web3SecretService(Web3SecretRepository web3SecretRepository, public Optional getSecret(String secretAddress, boolean shouldDecryptValue) { secretAddress = secretAddress.toLowerCase(); - Optional secret = web3SecretRepository.findWeb3SecretByAddress(secretAddress); - if (secret.isEmpty()) { - return Optional.empty(); + Optional oSecret = getSecret(secretAddress); + if (oSecret.isPresent() && shouldDecryptValue) { + decryptSecret(oSecret.get()); } - if (shouldDecryptValue) { - decryptSecret(secret.get()); - } - return secret; + return oSecret; } public Optional getSecret(String secretAddress) { - return getSecret(secretAddress, false); + secretAddress = secretAddress.toLowerCase(); + return web3SecretRepository.findWeb3SecretByAddress(secretAddress); } /* From 75938aef44b7d0b85abec1f08151c463bbe57ab5 Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Fri, 28 Oct 2022 12:46:26 +0200 Subject: [PATCH 173/293] Update web2 and web3 service tests --- .../secret/web2/Web2SecretsServiceTests.java | 42 ++++++++++++++++--- .../secret/web3/Web3SecretServiceTests.java | 12 ++++-- 2 files changed, 44 insertions(+), 10 deletions(-) diff --git a/src/test/java/com/iexec/sms/secret/web2/Web2SecretsServiceTests.java b/src/test/java/com/iexec/sms/secret/web2/Web2SecretsServiceTests.java index b17f0782..cc662c6d 100644 --- a/src/test/java/com/iexec/sms/secret/web2/Web2SecretsServiceTests.java +++ b/src/test/java/com/iexec/sms/secret/web2/Web2SecretsServiceTests.java @@ -25,9 +25,11 @@ import org.mockito.MockitoAnnotations; import java.util.List; +import java.util.NoSuchElementException; import java.util.Optional; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.Mockito.*; class Web2SecretsServiceTests { @@ -79,10 +81,22 @@ void shouldGetEncryptedSecret() { when(web2SecretsRepository.findWeb2SecretsByOwnerAddress(ownerAddress)) .thenReturn(Optional.of(web2Secrets)); - Optional result = web2SecretsService.getSecret(ownerAddress, secretAddress); - assertThat(result) - .isNotEmpty() - .contains(encryptedSecret); + Optional oSecret1 = web2SecretsService.getSecret(ownerAddress, secretAddress); + Optional oSecret2 = web2SecretsService.getSecret(ownerAddress, secretAddress, false); + assertThat(oSecret1) + .contains(encryptedSecret) + .isEqualTo(oSecret2); + verify(web2SecretsRepository, times(2)).findWeb2SecretsByOwnerAddress(ownerAddress); + verifyNoInteractions(encryptionService); + } + + @Test + void shouldGetEmptyResultIfSecretNotPresent() { + when(web2SecretsRepository.findWeb2SecretsByOwnerAddress(ownerAddress)).thenReturn(Optional.empty()); + assertThat(web2SecretsService.getSecret(ownerAddress, secretAddress)).isEmpty(); + assertThat(web2SecretsService.getSecret(ownerAddress, secretAddress, false)).isEmpty(); + verify(web2SecretsRepository, times(2)).findWeb2SecretsByOwnerAddress(ownerAddress); + verifyNoInteractions(encryptionService); } @Test @@ -104,7 +118,23 @@ void shouldAddSecret() { } @Test - void shouldNotUpdateSecretIfPresent() { + void shouldNotUpdateSecretIfMissing() { + Secret encryptedSecret = new Secret(secretAddress, encryptedSecretValue); + encryptedSecret.setEncryptedValue(true); + Web2Secrets web2Secrets = new Web2Secrets(ownerAddress); + web2Secrets.setSecrets(List.of()); + when(web2SecretsRepository.findWeb2SecretsByOwnerAddress(ownerAddress)) + .thenReturn(Optional.empty()) + .thenReturn(Optional.of(web2Secrets)); + assertThatThrownBy(() -> web2SecretsService.updateSecret(ownerAddress, secretAddress, plainSecretValue)) + .isInstanceOf(NoSuchElementException.class); + assertThatThrownBy(() -> web2SecretsService.updateSecret(ownerAddress, secretAddress, plainSecretValue)) + .isInstanceOf(NoSuchElementException.class); + verify(web2SecretsRepository, never()).save(any()); + } + + @Test + void shouldNotUpdateSecretIfSameValue() { Secret encryptedSecret = new Secret(secretAddress, encryptedSecretValue); encryptedSecret.setEncryptedValue(true); List secretList = List.of(encryptedSecret); @@ -116,7 +146,7 @@ void shouldNotUpdateSecretIfPresent() { .thenReturn(encryptedSecretValue); web2SecretsService.updateSecret(ownerAddress, secretAddress, plainSecretValue); - verify(web2SecretsRepository, never()).save(web2Secrets); + verify(web2SecretsRepository, never()).save(any()); } @Test diff --git a/src/test/java/com/iexec/sms/secret/web3/Web3SecretServiceTests.java b/src/test/java/com/iexec/sms/secret/web3/Web3SecretServiceTests.java index 1bd66d28..c21dac82 100644 --- a/src/test/java/com/iexec/sms/secret/web3/Web3SecretServiceTests.java +++ b/src/test/java/com/iexec/sms/secret/web3/Web3SecretServiceTests.java @@ -81,9 +81,12 @@ void shouldGetDecryptedSecret() { void shouldGetEncryptedSecret() { Web3Secret encryptedSecret = new Web3Secret(secretAddress, encryptedSecretValue); when(web3SecretRepository.findWeb3SecretByAddress(secretAddress)).thenReturn(Optional.of(encryptedSecret)); - assertThat(web3SecretService.getSecret(secretAddress)) - .contains(encryptedSecret); - verify(web3SecretRepository).findWeb3SecretByAddress(secretAddress); + Optional oSecret1 = web3SecretService.getSecret(secretAddress, false); + Optional oSecret2 = web3SecretService.getSecret(secretAddress); + assertThat(oSecret1) + .contains(encryptedSecret) + .isEqualTo(oSecret2); + verify(web3SecretRepository, times(2)).findWeb3SecretByAddress(secretAddress); verifyNoInteractions(encryptionService); } @@ -91,7 +94,8 @@ void shouldGetEncryptedSecret() { void shouldGetEmptyResultIfSecretNotPresent() { when(web3SecretRepository.findWeb3SecretByAddress(secretAddress)).thenReturn(Optional.empty()); assertThat(web3SecretService.getSecret(secretAddress)).isEmpty(); - verify(web3SecretRepository).findWeb3SecretByAddress(secretAddress); + assertThat(web3SecretService.getSecret(secretAddress, false)).isEmpty(); + verify(web3SecretRepository, times(2)).findWeb3SecretByAddress(secretAddress); verifyNoInteractions(encryptionService); } From d8ef2158a2613e2bb6ee6fb093762e1a0c1730b0 Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Fri, 28 Oct 2022 15:07:11 +0200 Subject: [PATCH 174/293] Invert getSecret implementations order in Web3SecretService --- .../com/iexec/sms/secret/web3/Web3SecretService.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/iexec/sms/secret/web3/Web3SecretService.java b/src/main/java/com/iexec/sms/secret/web3/Web3SecretService.java index 6c788858..3d0698c3 100644 --- a/src/main/java/com/iexec/sms/secret/web3/Web3SecretService.java +++ b/src/main/java/com/iexec/sms/secret/web3/Web3SecretService.java @@ -36,6 +36,11 @@ public Web3SecretService(Web3SecretRepository web3SecretRepository, this.web3SecretRepository = web3SecretRepository; } + public Optional getSecret(String secretAddress) { + secretAddress = secretAddress.toLowerCase(); + return web3SecretRepository.findWeb3SecretByAddress(secretAddress); + } + public Optional getSecret(String secretAddress, boolean shouldDecryptValue) { secretAddress = secretAddress.toLowerCase(); Optional oSecret = getSecret(secretAddress); @@ -45,11 +50,6 @@ public Optional getSecret(String secretAddress, boolean shouldDecryp return oSecret; } - public Optional getSecret(String secretAddress) { - secretAddress = secretAddress.toLowerCase(); - return web3SecretRepository.findWeb3SecretByAddress(secretAddress); - } - /* * * Stores encrypted secrets From c7b18d9a4d5bab91cc9d888f887e5821838d466f Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Mon, 31 Oct 2022 10:40:31 +0100 Subject: [PATCH 175/293] Fix test after merge --- .../java/com/iexec/sms/secret/web2/Web2SecretsServiceTests.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/test/java/com/iexec/sms/secret/web2/Web2SecretsServiceTests.java b/src/test/java/com/iexec/sms/secret/web2/Web2SecretsServiceTests.java index def397ba..b155f370 100644 --- a/src/test/java/com/iexec/sms/secret/web2/Web2SecretsServiceTests.java +++ b/src/test/java/com/iexec/sms/secret/web2/Web2SecretsServiceTests.java @@ -129,8 +129,6 @@ void shouldNotUpdateSecretIfMissing() { .thenReturn(Optional.of(web2Secrets)); assertThatThrownBy(() -> web2SecretsService.updateSecret(ownerAddress, secretAddress, plainSecretValue)) .isInstanceOf(NoSuchElementException.class); - assertThatThrownBy(() -> web2SecretsService.updateSecret(ownerAddress, secretAddress, plainSecretValue)) - .isInstanceOf(NoSuchElementException.class); verify(web2SecretsRepository, never()).save(any()); } From 6544df901ac36a88c9a74e156a9269c14d824156 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Mon, 31 Oct 2022 10:53:04 +0100 Subject: [PATCH 176/293] Fix format --- src/main/java/com/iexec/sms/secret/Secret.java | 2 +- .../java/com/iexec/sms/secret/web2/Web2SecretsServiceTests.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/iexec/sms/secret/Secret.java b/src/main/java/com/iexec/sms/secret/Secret.java index 98a95cb1..da52bdd3 100644 --- a/src/main/java/com/iexec/sms/secret/Secret.java +++ b/src/main/java/com/iexec/sms/secret/Secret.java @@ -52,7 +52,7 @@ public Secret(String address, String value, boolean isEncryptedValue) { * Copies the current {@link Secret} object, * while replacing the old value with a new encrypted value. * - * @param newValue Value to use for new object. + * @param newValue Value to use for new object. * @return A new {@link Secret} object with new value. */ public Secret withEncryptedValue(String newValue) { diff --git a/src/test/java/com/iexec/sms/secret/web2/Web2SecretsServiceTests.java b/src/test/java/com/iexec/sms/secret/web2/Web2SecretsServiceTests.java index b155f370..e672199e 100644 --- a/src/test/java/com/iexec/sms/secret/web2/Web2SecretsServiceTests.java +++ b/src/test/java/com/iexec/sms/secret/web2/Web2SecretsServiceTests.java @@ -184,4 +184,4 @@ void shouldUpdateSecret() throws NotAnExistingSecretException { verify(web2SecretsRepository, never()).save(web2SecretsMock); // Current object should not be updated verify(web2SecretsRepository, times(1)).save(any()); // A new object should be created with the same ID } -} \ No newline at end of file +} From ce8d7a7898c41978990a660f4cebedf0909f3231 Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Mon, 31 Oct 2022 17:32:40 +0100 Subject: [PATCH 177/293] Rename server.ssl properties into tee.ssl properties --- .../java/com/iexec/sms/ssl/SslConfig.java | 20 ++++++++++--------- src/main/resources/application.yml | 16 ++++++++------- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/iexec/sms/ssl/SslConfig.java b/src/main/java/com/iexec/sms/ssl/SslConfig.java index 78eb0c54..82ff993b 100644 --- a/src/main/java/com/iexec/sms/ssl/SslConfig.java +++ b/src/main/java/com/iexec/sms/ssl/SslConfig.java @@ -16,6 +16,7 @@ package com.iexec.sms.ssl; +import lombok.extern.slf4j.Slf4j; import org.apache.http.ssl.SSLContexts; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; @@ -29,19 +30,20 @@ import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; +@Slf4j @Configuration public class SslConfig { - private String sslKeystore; - private String sslKeystoreType; - private String sslKeyAlias; - private char[] sslKeystorePasswordChar; + private final String sslKeystore; + private final String sslKeystoreType; + private final String sslKeyAlias; + private final char[] sslKeystorePasswordChar; public SslConfig( - @Value("${server.ssl.key-store}") String sslKeystore, - @Value("${server.ssl.key-store-type}") String sslKeystoreType, - @Value("${server.ssl.key-alias}") String sslKeyAlias, - @Value("${server.ssl.key-store-password}") String sslKeystorePassword) { + @Value("${tee.ssl.key-store}") String sslKeystore, + @Value("${tee.ssl.key-store-type}") String sslKeystoreType, + @Value("${tee.ssl.key-alias}") String sslKeyAlias, + @Value("${tee.ssl.key-store-password}") String sslKeystorePassword) { this.sslKeystore = sslKeystore; this.sslKeystoreType = sslKeystoreType; this.sslKeyAlias = sslKeyAlias; @@ -62,7 +64,7 @@ public SSLContext getFreshSslContext() { .loadTrustMaterial(null, (chain, authType) -> true)////TODO: Add CAS certificate to truststore .build(); } catch (IOException | NoSuchAlgorithmException | KeyStoreException | UnrecoverableKeyException | CertificateException | KeyManagementException e) { - e.printStackTrace(); + log.warn("Failed to create a fresh SSL context", e); } return null; } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 71f6e221..423e7ba4 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -3,12 +3,6 @@ server: http: enabled: ${IEXEC_SMS_HTTP_ENABLED:true} port: ${IEXEC_SMS_HTTP_PORT:13300} - ssl: - key-store: ${IEXEC_SMS_SSL_KEYSTORE:./src/main/resources/ssl-keystore-dev.p12} #iexec-core dev certificate for dev - key-store-password: ${IEXEC_SMS_SSL_KEYSTORE_PASSWORD:whatever} - key-store-type: ${IEXEC_SMS_SSL_KEYSTORE_TYPE:PKCS12} - key-alias: ${IEXEC_SMS_SSL_KEYSTORE_ALIAS:iexec-core} - client-auth: need # Not sure it's a good idea but here is a link for an embedded mongodb # https://www.baeldung.com/spring-boot-embedded-mongodb @@ -59,4 +53,12 @@ logging: springdoc: packagesToScan: com.iexec.sms - pathsToMatch: /** \ No newline at end of file + pathsToMatch: /** + +tee: + ssl: + key-store: ${IEXEC_SMS_SSL_KEYSTORE:./src/main/resources/ssl-keystore-dev.p12} #iexec-core dev certificate for dev + key-store-password: ${IEXEC_SMS_SSL_KEYSTORE_PASSWORD:whatever} + key-store-type: ${IEXEC_SMS_SSL_KEYSTORE_TYPE:PKCS12} + key-alias: ${IEXEC_SMS_SSL_KEYSTORE_ALIAS:iexec-core} + client-auth: need From f9443b89c288dbc7a3bf4f2e83478b76ae00ca83 Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Mon, 31 Oct 2022 17:34:27 +0100 Subject: [PATCH 178/293] Use default http context after removal of TLS configuration on default context --- .../config/HttpWebServerConfiguration.java | 58 ------------------- src/main/resources/application.yml | 5 +- 2 files changed, 1 insertion(+), 62 deletions(-) delete mode 100644 src/main/java/com/iexec/sms/config/HttpWebServerConfiguration.java diff --git a/src/main/java/com/iexec/sms/config/HttpWebServerConfiguration.java b/src/main/java/com/iexec/sms/config/HttpWebServerConfiguration.java deleted file mode 100644 index 24a680cf..00000000 --- a/src/main/java/com/iexec/sms/config/HttpWebServerConfiguration.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2020 IEXEC BLOCKCHAIN TECH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.iexec.sms.config; - -import org.apache.catalina.connector.Connector; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; -import org.springframework.boot.web.servlet.server.ServletWebServerFactory; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -@Configuration -public class HttpWebServerConfiguration { - - @Value("${server.http.enabled}") - private boolean isHttpEnabled; - - @Value("${server.http.port}") - private int httpPort; - - /* - * This method will allow http connections (without SSL) if set in configuration - * */ - @Bean - public ServletWebServerFactory servletContainer() { - if (isHttpEnabled) { - return getHttpWebServerFactory(); - } - return getStandardWebServerFactory(); - } - - private TomcatServletWebServerFactory getHttpWebServerFactory() { - TomcatServletWebServerFactory factory = getStandardWebServerFactory(); - Connector connector = new Connector(TomcatServletWebServerFactory.DEFAULT_PROTOCOL); - connector.setPort(httpPort); - factory.addAdditionalTomcatConnectors(connector); - return factory; - } - - private TomcatServletWebServerFactory getStandardWebServerFactory() { - return new TomcatServletWebServerFactory(); - } - -} \ No newline at end of file diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 423e7ba4..415943d6 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,8 +1,5 @@ server: - port: ${IEXEC_SMS_PORT:15443} - http: - enabled: ${IEXEC_SMS_HTTP_ENABLED:true} - port: ${IEXEC_SMS_HTTP_PORT:13300} + port: ${IEXEC_SMS_PORT:13300} # document variable name modification for release # Not sure it's a good idea but here is a link for an embedded mongodb # https://www.baeldung.com/spring-boot-embedded-mongodb From 98806f21ba5a129acc85480b5f3f8733f10447c2 Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Mon, 31 Oct 2022 17:36:43 +0100 Subject: [PATCH 179/293] Clean integration tests application-test.yml --- src/itest/resources/application-test.yml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/itest/resources/application-test.yml b/src/itest/resources/application-test.yml index 1f4db232..14cd01c5 100644 --- a/src/itest/resources/application-test.yml +++ b/src/itest/resources/application-test.yml @@ -1,10 +1,3 @@ -# Those `server` properties are needed so that a random port is chosen for the HTTP listener -server: - http: - enabled: false - ssl: - enabled: false - # Run database in-mem spring: datasource: From 6178075c4527f7b3844e0dffcbe4d36b0b7289d4 Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Mon, 31 Oct 2022 17:37:07 +0100 Subject: [PATCH 180/293] Rename 2 variables in application-gramine.yml --- src/main/resources/application-gramine.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/resources/application-gramine.yml b/src/main/resources/application-gramine.yml index 7601c07b..e505ae7c 100644 --- a/src/main/resources/application-gramine.yml +++ b/src/main/resources/application-gramine.yml @@ -21,5 +21,5 @@ tee: gramine: sps: - login: ${IEXEC_GRAPHENE_SPS_WEB_LOGIN:admin} - password: ${IEXEC_GRAPHENE_SPS_WEB_PASSWORD:admin} + login: ${IEXEC_GRAMINE_SPS_WEB_LOGIN:admin} + password: ${IEXEC_GRAMINE_SPS_WEB_PASSWORD:admin} From ebf1187eca4781279947a7f44fd097d89ddcbc35 Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Mon, 31 Oct 2022 17:38:11 +0100 Subject: [PATCH 181/293] Clean main App class --- src/main/java/com/iexec/sms/App.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/main/java/com/iexec/sms/App.java b/src/main/java/com/iexec/sms/App.java index 1ab99d63..704302f9 100644 --- a/src/main/java/com/iexec/sms/App.java +++ b/src/main/java/com/iexec/sms/App.java @@ -16,21 +16,16 @@ package com.iexec.sms; -import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.cloud.openfeign.EnableFeignClients; @SpringBootApplication -@EnableFeignClients -@Slf4j public class App { public static final String DOMAIN = "IEXEC_SMS_DOMAIN"; // TODO: Add session salt after domain public static void main(String[] args) { SpringApplication.run(App.class, args); - log.info("DEBUG - env: " + System.getenv().toString());//TODO: remove this later } } From f3f4fb7da7fe9db88e902d9acde35e4c45f56a18 Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Mon, 31 Oct 2022 17:39:42 +0100 Subject: [PATCH 182/293] Fix indentation in CasClient --- .../java/com/iexec/sms/tee/session/scone/cas/CasClient.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/iexec/sms/tee/session/scone/cas/CasClient.java b/src/main/java/com/iexec/sms/tee/session/scone/cas/CasClient.java index 5ece94b0..0ed6f964 100644 --- a/src/main/java/com/iexec/sms/tee/session/scone/cas/CasClient.java +++ b/src/main/java/com/iexec/sms/tee/session/scone/cas/CasClient.java @@ -33,7 +33,7 @@ public class CasClient { private final TwoWaySslClient twoWaySslClient; public CasClient(CasConfiguration teeCasConfiguration, - TwoWaySslClient twoWaySslClient) { + TwoWaySslClient twoWaySslClient) { this.casConfiguration = teeCasConfiguration; this.twoWaySslClient = twoWaySslClient; } From a01febc1ff0e99cc5f4b5696588a7fa55e6db607 Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Thu, 3 Nov 2022 09:43:11 +0100 Subject: [PATCH 183/293] Add condition on SCONE TEE framework for SSL configuration --- src/main/java/com/iexec/sms/ssl/SslConfig.java | 3 +++ src/main/java/com/iexec/sms/ssl/TwoWaySslClient.java | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/main/java/com/iexec/sms/ssl/SslConfig.java b/src/main/java/com/iexec/sms/ssl/SslConfig.java index 82ff993b..9f8a0ffd 100644 --- a/src/main/java/com/iexec/sms/ssl/SslConfig.java +++ b/src/main/java/com/iexec/sms/ssl/SslConfig.java @@ -16,6 +16,8 @@ package com.iexec.sms.ssl; +import com.iexec.common.tee.TeeFramework; +import com.iexec.sms.tee.ConditionalOnTeeFramework; import lombok.extern.slf4j.Slf4j; import org.apache.http.ssl.SSLContexts; import org.springframework.beans.factory.annotation.Value; @@ -32,6 +34,7 @@ @Slf4j @Configuration +@ConditionalOnTeeFramework(frameworks = TeeFramework.SCONE) public class SslConfig { private final String sslKeystore; diff --git a/src/main/java/com/iexec/sms/ssl/TwoWaySslClient.java b/src/main/java/com/iexec/sms/ssl/TwoWaySslClient.java index 9056488c..c6b0aad5 100644 --- a/src/main/java/com/iexec/sms/ssl/TwoWaySslClient.java +++ b/src/main/java/com/iexec/sms/ssl/TwoWaySslClient.java @@ -16,6 +16,8 @@ package com.iexec.sms.ssl; +import com.iexec.common.tee.TeeFramework; +import com.iexec.sms.tee.ConditionalOnTeeFramework; import org.apache.http.conn.ssl.NoopHostnameVerifier; import org.apache.http.impl.client.HttpClientBuilder; import org.springframework.context.annotation.Configuration; @@ -23,6 +25,7 @@ import org.springframework.web.client.RestTemplate; @Configuration +@ConditionalOnTeeFramework(frameworks = TeeFramework.SCONE) public class TwoWaySslClient { private final SslConfig sslConfig; From d7fee205749e8021d461719f277ae0c2b05a648b Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Thu, 3 Nov 2022 09:43:52 +0100 Subject: [PATCH 184/293] Move TLS configuration properties to application-scone.yml --- src/main/resources/application-scone.yml | 7 +++++++ src/main/resources/application.yml | 8 -------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/main/resources/application-scone.yml b/src/main/resources/application-scone.yml index a5f2fa05..7ddcaab6 100644 --- a/src/main/resources/application-scone.yml +++ b/src/main/resources/application-scone.yml @@ -7,6 +7,13 @@ tee: hostname: ${IEXEC_SECRET_PROVISIONER_ENCLAVE_HOSTNAME:localhost} port: ${IEXEC_SECRET_PROVISIONER_ENCLAVE_PORT:18765} + ssl: + key-store: ${IEXEC_SMS_SSL_KEYSTORE:./src/main/resources/ssl-keystore-dev.p12} #iexec-core dev certificate for dev + key-store-password: ${IEXEC_SMS_SSL_KEYSTORE_PASSWORD:whatever} + key-store-type: ${IEXEC_SMS_SSL_KEYSTORE_TYPE:PKCS12} + key-alias: ${IEXEC_SMS_SSL_KEYSTORE_ALIAS:iexec-core} + client-auth: need + worker: pre-compute: image: ${IEXEC_TEE_WORKER_PRE_COMPUTE_IMAGE:} # e.g.: docker.io/iexechub/tee-worker-pre-compute:x.y.z-production diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 415943d6..893f4e2d 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -51,11 +51,3 @@ logging: springdoc: packagesToScan: com.iexec.sms pathsToMatch: /** - -tee: - ssl: - key-store: ${IEXEC_SMS_SSL_KEYSTORE:./src/main/resources/ssl-keystore-dev.p12} #iexec-core dev certificate for dev - key-store-password: ${IEXEC_SMS_SSL_KEYSTORE_PASSWORD:whatever} - key-store-type: ${IEXEC_SMS_SSL_KEYSTORE_TYPE:PKCS12} - key-alias: ${IEXEC_SMS_SSL_KEYSTORE_ALIAS:iexec-core} - client-auth: need From ccfa909c3fc50e3c348f5001b26e3aa95f374e54 Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Thu, 3 Nov 2022 09:44:32 +0100 Subject: [PATCH 185/293] Rename buildTrustedImage task to buildSconeImage --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 5ee63c87..31ad42f0 100644 --- a/build.gradle +++ b/build.gradle @@ -178,7 +178,7 @@ task buildImage(type: Exec) { } } -task buildTrustedImage(type: Exec) { +task buildSconeImage(type: Exec) { group "Build" description "Build an OCI image compatible with scontain TEE framework" dependsOn buildImage From ff3b8112a51545fd45005d0704e9fb97d53718d2 Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Thu, 3 Nov 2022 16:46:56 +0100 Subject: [PATCH 186/293] Transform comment in TODO for v8 release --- src/main/resources/application.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 893f4e2d..fe0473aa 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,5 +1,5 @@ server: - port: ${IEXEC_SMS_PORT:13300} # document variable name modification for release + port: ${IEXEC_SMS_PORT:13300} # TODO document variable name modification for release # Not sure it's a good idea but here is a link for an embedded mongodb # https://www.baeldung.com/spring-boot-embedded-mongodb From 9e0f9c4ca0ebc1b40e77e6015e7e5e6b0dc16c2c Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Mon, 7 Nov 2022 09:48:33 +0100 Subject: [PATCH 187/293] Set entities no-args constructors visibility to package-private --- src/main/java/com/iexec/sms/secret/web2/Web2Secrets.java | 2 +- src/main/java/com/iexec/sms/secret/web3/Web3Secret.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/iexec/sms/secret/web2/Web2Secrets.java b/src/main/java/com/iexec/sms/secret/web2/Web2Secrets.java index 6da75074..8b85eb91 100644 --- a/src/main/java/com/iexec/sms/secret/web2/Web2Secrets.java +++ b/src/main/java/com/iexec/sms/secret/web2/Web2Secrets.java @@ -28,7 +28,7 @@ @Entity @Getter -@NoArgsConstructor(access = AccessLevel.PRIVATE) +@NoArgsConstructor(access = AccessLevel.PACKAGE) @AllArgsConstructor(access = AccessLevel.PRIVATE) public class Web2Secrets { diff --git a/src/main/java/com/iexec/sms/secret/web3/Web3Secret.java b/src/main/java/com/iexec/sms/secret/web3/Web3Secret.java index 8e7e9f73..3b12f03f 100644 --- a/src/main/java/com/iexec/sms/secret/web3/Web3Secret.java +++ b/src/main/java/com/iexec/sms/secret/web3/Web3Secret.java @@ -26,7 +26,7 @@ @Entity @Getter -@NoArgsConstructor(access = AccessLevel.PRIVATE) +@NoArgsConstructor(access = AccessLevel.PACKAGE) @AllArgsConstructor(access = AccessLevel.PRIVATE) public class Web3Secret extends Secret { From e76b4e0c8cffb4234d8c2765ddd2f4c27a73b89e Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Tue, 8 Nov 2022 09:15:59 +0100 Subject: [PATCH 188/293] Pass `String secretAddress` instead of `Secret secret` to `SameSecretException` constructor --- .../java/com/iexec/sms/secret/web2/SameSecretException.java | 5 ++--- src/main/java/com/iexec/sms/secret/web2/Web2Secrets.java | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/iexec/sms/secret/web2/SameSecretException.java b/src/main/java/com/iexec/sms/secret/web2/SameSecretException.java index f9e22a05..af06678b 100644 --- a/src/main/java/com/iexec/sms/secret/web2/SameSecretException.java +++ b/src/main/java/com/iexec/sms/secret/web2/SameSecretException.java @@ -1,6 +1,5 @@ package com.iexec.sms.secret.web2; -import com.iexec.sms.secret.Secret; import lombok.Getter; @Getter @@ -8,8 +7,8 @@ public class SameSecretException extends Exception { private final String ownerAddress; private final String secretAddress; - public SameSecretException(String ownerAddress, Secret secret) { + public SameSecretException(String ownerAddress, String secretAddress) { this.ownerAddress = ownerAddress; - this.secretAddress = secret.getAddress(); + this.secretAddress = secretAddress; } } diff --git a/src/main/java/com/iexec/sms/secret/web2/Web2Secrets.java b/src/main/java/com/iexec/sms/secret/web2/Web2Secrets.java index 8b85eb91..c6b43efd 100644 --- a/src/main/java/com/iexec/sms/secret/web2/Web2Secrets.java +++ b/src/main/java/com/iexec/sms/secret/web2/Web2Secrets.java @@ -99,7 +99,7 @@ public Web2Secrets updateSecret(String secretAddress, String newSecretValue, boo // No need to update if same value final Secret secretToUpdate = oSecretToUpdate.get(); if (secretToUpdate.isEncryptedValue() == isEncryptedValue && Objects.equals(secretToUpdate.getValue(), newSecretValue)) { - throw new SameSecretException(ownerAddress, secretToUpdate); + throw new SameSecretException(ownerAddress, secretAddress); } final List updatedSecretsList = new ArrayList<>(secrets); From 4e34f597c9b2761cbb07a8ee1696c4e34ab2db3f Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Tue, 8 Nov 2022 09:16:52 +0100 Subject: [PATCH 189/293] Add a `TODO` to `Web3Secret` --- src/main/java/com/iexec/sms/secret/web3/Web3Secret.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/iexec/sms/secret/web3/Web3Secret.java b/src/main/java/com/iexec/sms/secret/web3/Web3Secret.java index 3b12f03f..6fbd7d76 100644 --- a/src/main/java/com/iexec/sms/secret/web3/Web3Secret.java +++ b/src/main/java/com/iexec/sms/secret/web3/Web3Secret.java @@ -30,6 +30,7 @@ @AllArgsConstructor(access = AccessLevel.PRIVATE) public class Web3Secret extends Secret { + // TODO: remove this duplicate `id` field @Id @GeneratedValue(generator = "system-uuid") @GenericGenerator(name = "system-uuid", strategy = "uuid") From d74b75d0af7bfa4e1f34e1fbe4ed8cb46925fc3f Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Tue, 8 Nov 2022 15:46:21 +0100 Subject: [PATCH 190/293] Add TODO --- src/main/java/com/iexec/sms/secret/web2/Web2Secrets.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/iexec/sms/secret/web2/Web2Secrets.java b/src/main/java/com/iexec/sms/secret/web2/Web2Secrets.java index c6b43efd..fe4b680e 100644 --- a/src/main/java/com/iexec/sms/secret/web2/Web2Secrets.java +++ b/src/main/java/com/iexec/sms/secret/web2/Web2Secrets.java @@ -65,6 +65,7 @@ public Optional getSecret(String secretAddress) { * @return A new {@link Web2Secrets} instance, with a new {@link Secret} element. * @throws SecretAlreadyExistsException thrown when a secret with same address already exists. */ + // TODO: remove `isEncryptedValue` as we only have encrypted values there. public Web2Secrets addNewSecret(String secretAddress, String secretValue, boolean isEncryptedValue) throws SecretAlreadyExistsException { // A new secret can't already exist From 12e34cd7987a287063d3eb6bc730db7d0f69d0d1 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Wed, 9 Nov 2022 14:07:58 +0100 Subject: [PATCH 191/293] Replace global imports by specific imports --- src/main/java/com/iexec/sms/secret/Secret.java | 5 ++++- src/main/java/com/iexec/sms/secret/web3/Web3Secret.java | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/iexec/sms/secret/Secret.java b/src/main/java/com/iexec/sms/secret/Secret.java index da52bdd3..95e06f72 100644 --- a/src/main/java/com/iexec/sms/secret/Secret.java +++ b/src/main/java/com/iexec/sms/secret/Secret.java @@ -16,7 +16,10 @@ package com.iexec.sms.secret; -import lombok.*; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; import org.hibernate.annotations.GenericGenerator; import javax.persistence.Column; diff --git a/src/main/java/com/iexec/sms/secret/web3/Web3Secret.java b/src/main/java/com/iexec/sms/secret/web3/Web3Secret.java index 6fbd7d76..a2a32d27 100644 --- a/src/main/java/com/iexec/sms/secret/web3/Web3Secret.java +++ b/src/main/java/com/iexec/sms/secret/web3/Web3Secret.java @@ -17,7 +17,10 @@ package com.iexec.sms.secret.web3; import com.iexec.sms.secret.Secret; -import lombok.*; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; import org.hibernate.annotations.GenericGenerator; import javax.persistence.Entity; From eb27ea500c6757e7e1aef597cc14a778a1cc7bfc Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Tue, 15 Nov 2022 09:13:57 +0100 Subject: [PATCH 192/293] Fix default values for H2 database and encryption key in application.yml --- src/main/resources/application.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index fe0473aa..8a9e3dc0 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -16,7 +16,7 @@ spring: profiles: active: ${IEXEC_SMS_TEE_RUNTIME_FRAMEWORK:} # gramine/scone datasource: - url: ${IEXEC_SMS_H2_URL:jdbc:h2:file:/tmp/h2/sms-h2} # will get or create /tmp/h2/sms-h2.mv.db + url: ${IEXEC_SMS_H2_URL:jdbc:h2:file:/data/sms-h2} # will get or create /data/sms-h2.mv.db driver-class-name: org.h2.Driver username: sa password: @@ -32,13 +32,13 @@ spring: encryption: # Will get previous key or else create one on this path # this file shouldn't be clearly readable outside the enclave (but encrypted content could be copied outside) - aesKeyPath: ${IEXEC_SMS_STORAGE_ENCRYPTION_AES_KEY_PATH:./src/main/resources/iexec-sms-aes.key} # /scone/iexec-sms-aes.key + aesKeyPath: ${IEXEC_SMS_STORAGE_ENCRYPTION_AES_KEY_PATH:/data/iexec-sms-aes.key} blockchain: id: ${IEXEC_CHAIN_ID:17} node-address: ${IEXEC_SMS_BLOCKCHAIN_NODE_ADDRESS:http://localhost:8545} hub-address: ${IEXEC_HUB_ADDRESS:0xBF6B2B07e47326B7c8bfCb4A5460bef9f0Fd2002} - gas-price-multiplier: ${IEXEC_GAS_PRICE_MULTIPLIER:1.0} # txs will be send with networkGasPrice*gasPriceMultiplier, 4.0 means super fast + gas-price-multiplier: ${IEXEC_GAS_PRICE_MULTIPLIER:1.0} # txs will be sent with networkGasPrice*gasPriceMultiplier, 4.0 means superfast gas-price-cap: ${IEXEC_GAS_PRICE_CAP:22000000000} #in Wei, will be used for txs if networkGasPrice*gasPriceMultiplier > gasPriceCap is-sidechain: ${IEXEC_IS_SIDECHAIN:false} From 9f52375e11cf8a788b33f561402cc9c1c2c907d1 Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Tue, 15 Nov 2022 09:14:20 +0100 Subject: [PATCH 193/293] Remove scone specific environment variables from Dockerfile --- src/main/resources/Dockerfile | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/main/resources/Dockerfile b/src/main/resources/Dockerfile index 912dfe65..1911f97b 100644 --- a/src/main/resources/Dockerfile +++ b/src/main/resources/Dockerfile @@ -5,12 +5,7 @@ ARG jar RUN test -n "$jar" COPY $jar /app/iexec-sms.jar -COPY src/main/resources/ssl-keystore-dev.p12 /app/ssl-keystore-dev.p12 -ENV IEXEC_SMS_SSL_KEYSTORE=/app/ssl-keystore-dev.p12 -ENV IEXEC_SMS_STORAGE_ENCRYPTION_AES_KEY_PATH=/scone/iexec-sms-aes.key -ENV IEXEC_SMS_BLOCKCHAIN_NODE_ADDRESS=http://chain:8545 -ENV IEXEC_SCONE_CAS_HOST=iexec-cas -ENV IEXEC_SMS_H2_URL=jdbc:h2:file:/scone/sms-h2 +COPY src/main/resources/ssl-keystore-dev.p12 /app/ssl-keystore-dev.p12 ENTRYPOINT [ "/bin/sh", "-c", "java -jar /app/iexec-sms.jar" ] From eac272d27152179dee8e0039ee2f529c5caac2ae Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Tue, 15 Nov 2022 09:17:08 +0100 Subject: [PATCH 194/293] Set EncryptionConfiguration immutable --- src/main/java/com/iexec/sms/App.java | 2 ++ .../encryption/EncryptionConfiguration.java | 20 +++++++------------ 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/iexec/sms/App.java b/src/main/java/com/iexec/sms/App.java index 704302f9..b3ef1200 100644 --- a/src/main/java/com/iexec/sms/App.java +++ b/src/main/java/com/iexec/sms/App.java @@ -18,8 +18,10 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.context.properties.ConfigurationPropertiesScan; @SpringBootApplication +@ConfigurationPropertiesScan public class App { public static final String DOMAIN = "IEXEC_SMS_DOMAIN"; // TODO: Add session salt after domain diff --git a/src/main/java/com/iexec/sms/encryption/EncryptionConfiguration.java b/src/main/java/com/iexec/sms/encryption/EncryptionConfiguration.java index 70031c17..40c21757 100644 --- a/src/main/java/com/iexec/sms/encryption/EncryptionConfiguration.java +++ b/src/main/java/com/iexec/sms/encryption/EncryptionConfiguration.java @@ -16,19 +16,13 @@ package com.iexec.sms.encryption; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.context.properties.ConstructorBinding; -@Component -@Getter -@NoArgsConstructor -@AllArgsConstructor +@Data +@ConstructorBinding +@ConfigurationProperties(prefix = "encryption") public class EncryptionConfiguration { - - @Value("${encryption.aesKeyPath}") - private String aesKeyPath; - + private final String aesKeyPath; } From a7033984dc3a0be449a3092fb94bf0369bb8bbe0 Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Tue, 15 Nov 2022 09:25:45 +0100 Subject: [PATCH 195/293] Add configuration for integration tests --- .gitignore | 3 +-- src/itest/resources/application-test.yml | 5 +++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index defb9780..8dee8fdf 100644 --- a/.gitignore +++ b/.gitignore @@ -31,5 +31,4 @@ build ### iExec ### -src/main/resources/iexec-sms-aes.key -src/main/resources/boot/sms-palaemon-conf.yml +src/test/resources/iexec-sms-aes.key diff --git a/src/itest/resources/application-test.yml b/src/itest/resources/application-test.yml index 14cd01c5..29ab0dc1 100644 --- a/src/itest/resources/application-test.yml +++ b/src/itest/resources/application-test.yml @@ -3,6 +3,11 @@ spring: datasource: url: jdbc:h2:mem:db +encryption: + # Will get previous key or else create one on this path + # this file shouldn't be clearly readable outside the enclave (but encrypted content could be copied outside) + aesKeyPath: src/test/resources/iexec-sms-aes.key + tee: worker: pre-compute: From 5a0465a6ed05f97adc28c716cd3f9a80c3d986d8 Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Tue, 15 Nov 2022 09:26:51 +0100 Subject: [PATCH 196/293] Replace TestProperty annotation with test profile in integration tests --- src/itest/java/com/iexec/sms/CommonTestSetup.java | 2 -- .../secret/compute/TeeTaskComputeSecretIntegrationTests.java | 2 +- src/itest/java/com/iexec/sms/tee/GramineBeansLoadingTests.java | 2 +- src/itest/java/com/iexec/sms/tee/SconeBeansLoadingTests.java | 2 +- 4 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/itest/java/com/iexec/sms/CommonTestSetup.java b/src/itest/java/com/iexec/sms/CommonTestSetup.java index 0fccb7ba..494288f9 100644 --- a/src/itest/java/com/iexec/sms/CommonTestSetup.java +++ b/src/itest/java/com/iexec/sms/CommonTestSetup.java @@ -19,11 +19,9 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.web.server.LocalServerPort; import org.springframework.test.annotation.DirtiesContext; -import org.springframework.test.context.TestPropertySource; @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) -@TestPropertySource(properties = {"spring.config.location = classpath:/application.yml, classpath:/application-test.yml"}) public abstract class CommonTestSetup { @LocalServerPort diff --git a/src/itest/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretIntegrationTests.java b/src/itest/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretIntegrationTests.java index 5d3e3133..c4c110a3 100644 --- a/src/itest/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretIntegrationTests.java +++ b/src/itest/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretIntegrationTests.java @@ -52,7 +52,7 @@ import static org.mockito.Mockito.when; @Slf4j -@ActiveProfiles({MOCK_TEE_PROFILE, MOCK_CHAIN_PROFILE}) +@ActiveProfiles({MOCK_TEE_PROFILE, MOCK_CHAIN_PROFILE, "test"}) public class TeeTaskComputeSecretIntegrationTests extends CommonTestSetup { private static final String APP_ADDRESS = "0xabcd1339ec7e762e639f4887e2bfe5ee8023e23e"; private static final String UPPER_CASE_APP_ADDRESS = "0xABCD1339EC7E762E639F4887E2BFE5EE8023E23E"; diff --git a/src/itest/java/com/iexec/sms/tee/GramineBeansLoadingTests.java b/src/itest/java/com/iexec/sms/tee/GramineBeansLoadingTests.java index 19b557cc..b85d424f 100644 --- a/src/itest/java/com/iexec/sms/tee/GramineBeansLoadingTests.java +++ b/src/itest/java/com/iexec/sms/tee/GramineBeansLoadingTests.java @@ -11,7 +11,7 @@ import org.springframework.test.context.ActiveProfiles; -@ActiveProfiles(profiles = "gramine") +@ActiveProfiles(profiles = {"gramine", "test"}) public class GramineBeansLoadingTests extends TeeBeansLoadingTests { @Autowired GramineServicesProperties gramineServicesProperties; diff --git a/src/itest/java/com/iexec/sms/tee/SconeBeansLoadingTests.java b/src/itest/java/com/iexec/sms/tee/SconeBeansLoadingTests.java index 03a997cf..c5de91e3 100644 --- a/src/itest/java/com/iexec/sms/tee/SconeBeansLoadingTests.java +++ b/src/itest/java/com/iexec/sms/tee/SconeBeansLoadingTests.java @@ -13,7 +13,7 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; -@ActiveProfiles(profiles = "scone") +@ActiveProfiles(profiles = {"scone", "test"}) public class SconeBeansLoadingTests extends TeeBeansLoadingTests { @Autowired SconeServicesProperties sconeServicesProperties; From f5d510134b1c3d1f5540ab23c70db6f5b939713e Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Tue, 15 Nov 2022 12:03:52 +0100 Subject: [PATCH 197/293] Add `Web2Secret` classes and logic --- .../java/com/iexec/sms/secret/Secret.java | 16 ++ .../com/iexec/sms/secret/web2/Web2Secret.java | 61 ++++++ .../sms/secret/web2/Web2SecretRepository.java | 9 + .../sms/secret/web2/Web2SecretService.java | 92 +++++++++ .../secret/web2/Web2SecretServiceTests.java | 184 ++++++++++++++++++ .../sms/secret/web2/Web2SecretTests.java | 28 +++ 6 files changed, 390 insertions(+) create mode 100644 src/main/java/com/iexec/sms/secret/web2/Web2Secret.java create mode 100644 src/main/java/com/iexec/sms/secret/web2/Web2SecretRepository.java create mode 100644 src/main/java/com/iexec/sms/secret/web2/Web2SecretService.java create mode 100644 src/test/java/com/iexec/sms/secret/web2/Web2SecretServiceTests.java create mode 100644 src/test/java/com/iexec/sms/secret/web2/Web2SecretTests.java diff --git a/src/main/java/com/iexec/sms/secret/Secret.java b/src/main/java/com/iexec/sms/secret/Secret.java index 95e06f72..c81fd493 100644 --- a/src/main/java/com/iexec/sms/secret/Secret.java +++ b/src/main/java/com/iexec/sms/secret/Secret.java @@ -99,5 +99,21 @@ public String toString() { ", isEncryptedValue=" + isEncryptedValue + '}'; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Secret secret = (Secret) o; + return isEncryptedValue == secret.isEncryptedValue + && Objects.equals(id, secret.id) + && Objects.equals(address, secret.address) + && Objects.equals(value, secret.value); + } + + @Override + public int hashCode() { + return Objects.hash(id, address, value, isEncryptedValue); + } } diff --git a/src/main/java/com/iexec/sms/secret/web2/Web2Secret.java b/src/main/java/com/iexec/sms/secret/web2/Web2Secret.java new file mode 100644 index 00000000..127609b2 --- /dev/null +++ b/src/main/java/com/iexec/sms/secret/web2/Web2Secret.java @@ -0,0 +1,61 @@ +package com.iexec.sms.secret.web2; + +import com.iexec.sms.secret.Secret; +import lombok.*; + +import javax.persistence.Entity; +import java.util.Objects; + +@Entity +@Getter +@NoArgsConstructor(access = AccessLevel.PRIVATE) +@AllArgsConstructor(access = AccessLevel.PRIVATE) +public class Web2Secret extends Secret { + private String ownerAddress; + + Web2Secret(String id, String ownerAddress, String address, String value, boolean isEncryptedValue) { + super(id, address, value, isEncryptedValue); + this.ownerAddress = ownerAddress; + } + + public Web2Secret(String ownerAddress, String address, String value, boolean isEncryptedValue) { + super(address, value, isEncryptedValue); + this.ownerAddress = ownerAddress; + } + + /** + * Copies the current {@link Web2Secret} object, + * while replacing the old value with a new encrypted value. + * + * @param newValue Value to use for new object. + * @return A new {@link Web2Secret} object with new value. + */ + public Web2Secret withEncryptedValue(String newValue) { + return new Web2Secret(this.getId(), this.getOwnerAddress(), this.getAddress(), newValue, true); + } + + /** + * Copies the current {@link Web2Secret} object, + * while replacing the old value with a new decrypted value. + * + * @param newValue Value to use for new object. + * @return A new {@link Web2Secret} object with new value. + */ + public Web2Secret withDecryptedValue(String newValue) { + return new Web2Secret(this.getId(), this.getOwnerAddress(), this.getAddress(), newValue, false); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + Web2Secret that = (Web2Secret) o; + return Objects.equals(ownerAddress, that.ownerAddress); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), ownerAddress); + } +} diff --git a/src/main/java/com/iexec/sms/secret/web2/Web2SecretRepository.java b/src/main/java/com/iexec/sms/secret/web2/Web2SecretRepository.java new file mode 100644 index 00000000..a9fd172f --- /dev/null +++ b/src/main/java/com/iexec/sms/secret/web2/Web2SecretRepository.java @@ -0,0 +1,9 @@ +package com.iexec.sms.secret.web2; + +import org.springframework.data.repository.CrudRepository; + +import java.util.Optional; + +public interface Web2SecretRepository extends CrudRepository { + Optional findByOwnerAddressAndAddressAllIgnoreCase(String ownerAddress, String address); +} diff --git a/src/main/java/com/iexec/sms/secret/web2/Web2SecretService.java b/src/main/java/com/iexec/sms/secret/web2/Web2SecretService.java new file mode 100644 index 00000000..730cfd65 --- /dev/null +++ b/src/main/java/com/iexec/sms/secret/web2/Web2SecretService.java @@ -0,0 +1,92 @@ +package com.iexec.sms.secret.web2; + +import com.iexec.sms.encryption.EncryptionService; +import com.iexec.sms.secret.AbstractSecretService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.Objects; +import java.util.Optional; + +@Slf4j +@Service +public class Web2SecretService extends AbstractSecretService { + private final Web2SecretRepository web2SecretRepository; + + protected Web2SecretService(EncryptionService encryptionService, + Web2SecretRepository web2SecretRepository) { + super(encryptionService); + this.web2SecretRepository = web2SecretRepository; + } + + public Optional getSecret(String ownerAddress, String secretAddress) { + return web2SecretRepository.findByOwnerAddressAndAddressAllIgnoreCase(ownerAddress, secretAddress); + } + + public Optional getSecret(String ownerAddress, String secretAddress, boolean shouldDecryptValue) { + final Optional oSecret = getSecret(ownerAddress, secretAddress); + + if (oSecret.isEmpty() || !shouldDecryptValue) { + return oSecret; + } + + final Web2Secret secret = oSecret.get(); + final String decryptedValue = encryptionService.decrypt(secret.getValue()); + return Optional.of(secret.withDecryptedValue(decryptedValue)); + } + + /** + * Creates and saves a new {@link Web2Secret}. + * If a secret with same {@code ownerAddress}/{@code secretAddress} couple already exists, then cancels the save. + * + * @param ownerAddress Address of the secret owner. + * @param secretAddress Address of the secret. + * @param secretValue Unencrypted value of the secret. + * @return The {@link Web2Secret} that has been saved. + * @throws SecretAlreadyExistsException throw when a secret + * with same {@code ownerAddress}/{@code secretAddress} couple already exists + */ + public Web2Secret addSecret(String ownerAddress, String secretAddress, String secretValue) throws SecretAlreadyExistsException { + final Optional oSecret = getSecret(ownerAddress, secretAddress); + if (oSecret.isPresent()) { + log.error("Secret already exists [ownerAddress:{}, secretAddress:{}]", ownerAddress, secretAddress); + throw new SecretAlreadyExistsException(ownerAddress, secretAddress); + } + + final String encryptedValue = encryptionService.encrypt(secretValue); + final Web2Secret newSecret = new Web2Secret(ownerAddress, secretAddress, encryptedValue, true); + return web2SecretRepository.save(newSecret); + } + + /** + * Updates an existing {@link Web2Secret}. + * If the secret does not already exist, then cancels the save. + * If the secret already exists with the same encrypted value, then cancels the save. + * + * @param ownerAddress Address of the secret owner. + * @param secretAddress Address of the secret. + * @param newSecretValue New, unencrypted value of the secret. + * @return The {@link Web2Secret} that has been saved. + * @throws NotAnExistingSecretException thrown when the requested secret does not exist. + * @throws SameSecretException thrown when the requested secret already contains the encrypted value. + */ + public Web2Secret updateSecret(String ownerAddress, String secretAddress, String newSecretValue) throws NotAnExistingSecretException, SameSecretException { + final Optional oSecret = getSecret(ownerAddress, secretAddress); + if (oSecret.isEmpty()) { + log.error("Secret does not exist, can't update it [ownerAddress:{}, secretAddress:{}]", + ownerAddress, secretAddress); + throw new NotAnExistingSecretException(ownerAddress, secretAddress); + } + + final Web2Secret secret = oSecret.get(); + final String encryptedValue = encryptionService.encrypt(newSecretValue); + if (Objects.equals(secret.getValue(), encryptedValue)) { + log.info("No need to update secret [ownerAddress:{}, secretAddress:{}]", + ownerAddress, secretAddress); + throw new SameSecretException(ownerAddress, secretAddress); + } + + final Web2Secret newSecret = secret.withEncryptedValue(encryptedValue); + return web2SecretRepository.save(newSecret); + } +} diff --git a/src/test/java/com/iexec/sms/secret/web2/Web2SecretServiceTests.java b/src/test/java/com/iexec/sms/secret/web2/Web2SecretServiceTests.java new file mode 100644 index 00000000..908d78a7 --- /dev/null +++ b/src/test/java/com/iexec/sms/secret/web2/Web2SecretServiceTests.java @@ -0,0 +1,184 @@ +package com.iexec.sms.secret.web2; + +import com.iexec.sms.encryption.EncryptionService; +import com.iexec.sms.secret.Secret; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +class Web2SecretServiceTests { + private static final String ID = "id"; + private static final String OWNER_ADDRESS = "ownerAddress"; + private static final String SECRET_ADDRESS = "secretAddress"; + private static final String PLAIN_SECRET_VALUE = "plainSecretValue"; + private static final String ENCRYPTED_SECRET_VALUE = "encryptedSecretValue"; + + @Mock + private Web2SecretRepository web2SecretRepository; + + @Mock + private EncryptionService encryptionService; + + @InjectMocks + private Web2SecretService web2SecretService; + + @BeforeEach + void beforeEach() { + MockitoAnnotations.openMocks(this); + } + + // region getSecret + @Test + void shouldGetDecryptedSecret() { + final Web2Secret encryptedSecret = new Web2Secret(OWNER_ADDRESS, SECRET_ADDRESS, ENCRYPTED_SECRET_VALUE, true); + + when(web2SecretRepository.findByOwnerAddressAndAddressAllIgnoreCase(OWNER_ADDRESS, SECRET_ADDRESS)) + .thenReturn(Optional.of(encryptedSecret)); + when(encryptionService.decrypt(ENCRYPTED_SECRET_VALUE)) + .thenReturn(PLAIN_SECRET_VALUE); + + final Optional result = web2SecretService.getSecret(OWNER_ADDRESS, SECRET_ADDRESS, true); + assertThat(result).isNotEmpty(); + assertAll( + () -> assertThat(result).get().extracting(Secret::getAddress).isEqualTo(SECRET_ADDRESS), + () -> assertThat(result).get().extracting(Secret::getValue).isEqualTo(PLAIN_SECRET_VALUE), + () -> assertThat(result).get().extracting(Secret::isEncryptedValue).isEqualTo(false) + ); + } + + @Test + void shouldGetEncryptedSecret() { + final Web2Secret encryptedSecret = new Web2Secret(OWNER_ADDRESS, SECRET_ADDRESS, ENCRYPTED_SECRET_VALUE, true); + + when(web2SecretRepository.findByOwnerAddressAndAddressAllIgnoreCase(OWNER_ADDRESS, SECRET_ADDRESS)) + .thenReturn(Optional.of(encryptedSecret)); + + final Optional oSecret1 = web2SecretService.getSecret(OWNER_ADDRESS, SECRET_ADDRESS); + final Optional oSecret2 = web2SecretService.getSecret(OWNER_ADDRESS, SECRET_ADDRESS, false); + assertThat(oSecret1).isNotEmpty(); + assertAll( + () -> assertThat(oSecret1).isEqualTo(oSecret2), + () -> assertThat(oSecret1).get().extracting(Secret::getAddress).isEqualTo(SECRET_ADDRESS), + () -> assertThat(oSecret1).get().extracting(Secret::getValue).isEqualTo(ENCRYPTED_SECRET_VALUE), + () -> assertThat(oSecret1).get().extracting(Secret::isEncryptedValue).isEqualTo(true), + () -> verifyNoInteractions(encryptionService) + ); + } + + @Test + void shouldGetEmptyResultIfSecretNotPresent() { + when(web2SecretRepository.findByOwnerAddressAndAddressAllIgnoreCase(OWNER_ADDRESS, SECRET_ADDRESS)) + .thenReturn(Optional.empty()); + + assertThat(web2SecretService.getSecret(OWNER_ADDRESS, SECRET_ADDRESS)).isEmpty(); + assertThat(web2SecretService.getSecret(OWNER_ADDRESS, SECRET_ADDRESS, false)).isEmpty(); + verify(web2SecretRepository, times(2)) + .findByOwnerAddressAndAddressAllIgnoreCase(OWNER_ADDRESS, SECRET_ADDRESS); + verifyNoInteractions(encryptionService); + } + // endregion + + // region addSecret + @Test + void shouldAddSecret() throws SecretAlreadyExistsException { + when(web2SecretRepository.findByOwnerAddressAndAddressAllIgnoreCase(OWNER_ADDRESS, SECRET_ADDRESS)) + .thenReturn(Optional.empty()); + when(encryptionService.encrypt(PLAIN_SECRET_VALUE)).thenReturn(ENCRYPTED_SECRET_VALUE); + when(web2SecretRepository.save(any())).thenReturn(new Web2Secret(ID, OWNER_ADDRESS, SECRET_ADDRESS, ENCRYPTED_SECRET_VALUE, true)); + + final Web2Secret newSecret = web2SecretService.addSecret(OWNER_ADDRESS, SECRET_ADDRESS, PLAIN_SECRET_VALUE); + assertAll( + () -> assertThat(newSecret).extracting(Secret::getId).isEqualTo(ID), + () -> assertThat(newSecret).extracting(Secret::getAddress).isEqualTo(SECRET_ADDRESS), + () -> assertThat(newSecret).extracting(Secret::getValue).isEqualTo(ENCRYPTED_SECRET_VALUE), + () -> assertThat(newSecret).extracting(Secret::isEncryptedValue).isEqualTo(true), + + () -> verify(encryptionService).encrypt(any()), + () -> verify(web2SecretRepository).save(any()) + ); + } + + @Test + void shouldNotAddSecretIfPresent() { + final Web2Secret secret = new Web2Secret(ID, OWNER_ADDRESS, SECRET_ADDRESS, ENCRYPTED_SECRET_VALUE, true); + when(web2SecretRepository.findByOwnerAddressAndAddressAllIgnoreCase(OWNER_ADDRESS, SECRET_ADDRESS)) + .thenReturn(Optional.of(secret)); + + final SecretAlreadyExistsException exception = assertThrows(SecretAlreadyExistsException.class, + () -> web2SecretService.addSecret(OWNER_ADDRESS, SECRET_ADDRESS, ENCRYPTED_SECRET_VALUE)); + assertAll( + () -> assertEquals(OWNER_ADDRESS, exception.getOwnerAddress()), + () -> assertEquals(SECRET_ADDRESS, exception.getSecretAddress()), + () -> verify(encryptionService, never()).encrypt(PLAIN_SECRET_VALUE), + () -> verify(web2SecretRepository, never()).save(any()) + ); + } + // endregion + + // region updateSecret + @Test + void shouldUpdateSecret() throws NotAnExistingSecretException, SameSecretException { + final Web2Secret encryptedSecret = new Web2Secret(OWNER_ADDRESS, SECRET_ADDRESS, ENCRYPTED_SECRET_VALUE, true); + final String newSecretValue = "newSecretValue"; + final String newEncryptedSecretValue = "newEncryptedSecretValue"; + when(web2SecretService.getSecret(OWNER_ADDRESS, SECRET_ADDRESS)) + .thenReturn(Optional.of(encryptedSecret)); + when(encryptionService.encrypt(newSecretValue)) + .thenReturn(newEncryptedSecretValue); + final Web2Secret savedSecret = new Web2Secret(ID, OWNER_ADDRESS, SECRET_ADDRESS, newEncryptedSecretValue, true); + when(web2SecretRepository.save(any())) + .thenReturn(savedSecret); + + final Web2Secret newSecret = web2SecretService.updateSecret(OWNER_ADDRESS, SECRET_ADDRESS, newSecretValue); + assertAll( + () -> assertThat(newSecret).extracting(Web2Secret::getId).isEqualTo(ID), + () -> assertThat(newSecret).extracting(Web2Secret::getOwnerAddress).isEqualTo(OWNER_ADDRESS), + () -> assertThat(newSecret).extracting(Web2Secret::getAddress).isEqualTo(SECRET_ADDRESS), + () -> assertThat(newSecret).extracting(Web2Secret::getValue).isEqualTo(newEncryptedSecretValue), + () -> assertThat(newSecret).extracting(Web2Secret::isEncryptedValue).isEqualTo(true), + + () -> verify(web2SecretRepository, never()).save(encryptedSecret), // Current object should not be updated + () -> verify(web2SecretRepository, times(1)).save(any()) // A new object should be created with the same ID + ); + } + + @Test + void shouldNotUpdateSecretIfMissing() { + when(web2SecretRepository.findByOwnerAddressAndAddressAllIgnoreCase(OWNER_ADDRESS, SECRET_ADDRESS)) + .thenReturn(Optional.empty()); + + final NotAnExistingSecretException exception = assertThrows(NotAnExistingSecretException.class, + () -> web2SecretService.updateSecret(OWNER_ADDRESS, SECRET_ADDRESS, PLAIN_SECRET_VALUE)); + assertAll( + () -> assertEquals(OWNER_ADDRESS, exception.getOwnerAddress()), + () -> assertEquals(SECRET_ADDRESS, exception.getSecretAddress()), + () -> verify(web2SecretRepository, never()).save(any()) + ); + } + + @Test + void shouldNotUpdateSecretIfSameValue() { + final Web2Secret encryptedSecret = new Web2Secret(OWNER_ADDRESS, SECRET_ADDRESS, ENCRYPTED_SECRET_VALUE, true); + when(web2SecretService.getSecret(OWNER_ADDRESS, SECRET_ADDRESS)) + .thenReturn(Optional.of(encryptedSecret)); + when(encryptionService.encrypt(PLAIN_SECRET_VALUE)) + .thenReturn(ENCRYPTED_SECRET_VALUE); + + final SameSecretException exception = assertThrows(SameSecretException.class, + () -> web2SecretService.updateSecret(OWNER_ADDRESS, SECRET_ADDRESS, PLAIN_SECRET_VALUE)); + assertAll( + () -> assertEquals(OWNER_ADDRESS, exception.getOwnerAddress()), + () -> assertEquals(SECRET_ADDRESS, exception.getSecretAddress()), + () -> verify(web2SecretRepository, never()).save(any()) + ); + } + // endregion +} \ No newline at end of file diff --git a/src/test/java/com/iexec/sms/secret/web2/Web2SecretTests.java b/src/test/java/com/iexec/sms/secret/web2/Web2SecretTests.java new file mode 100644 index 00000000..5e89663e --- /dev/null +++ b/src/test/java/com/iexec/sms/secret/web2/Web2SecretTests.java @@ -0,0 +1,28 @@ +package com.iexec.sms.secret.web2; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class Web2SecretTests { + private static final String ID = "id"; + private static final String OWNER_ADDRESS = "ownerAddress"; + private static final String SECRET_ADDRESS = "secretAddress"; + + private static final String UNENCRYPTED_VALUE = "unencrypted value"; + private static final String ENCRYPTED_VALUE = "encrypted value"; + private static final Web2Secret UNENCRYPTED_SECRET = new Web2Secret(ID, OWNER_ADDRESS, SECRET_ADDRESS, UNENCRYPTED_VALUE, false); + private static final Web2Secret ENCRYPTED_SECRET = new Web2Secret(ID, OWNER_ADDRESS, SECRET_ADDRESS, ENCRYPTED_VALUE, true); + + @Test + void withEncryptedValue() { + assertEquals(ENCRYPTED_SECRET, UNENCRYPTED_SECRET.withEncryptedValue(ENCRYPTED_VALUE)); + assertEquals(ENCRYPTED_SECRET, ENCRYPTED_SECRET.withEncryptedValue(ENCRYPTED_VALUE)); + } + + @Test + void withDecryptedValue() { + assertEquals(UNENCRYPTED_SECRET, ENCRYPTED_SECRET.withDecryptedValue(UNENCRYPTED_VALUE)); + assertEquals(UNENCRYPTED_SECRET, UNENCRYPTED_SECRET.withDecryptedValue(UNENCRYPTED_VALUE)); + } +} \ No newline at end of file From 8d6bdb0b0a01d7e5008cade4a51a1d1e4a358134 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Tue, 15 Nov 2022 12:07:25 +0100 Subject: [PATCH 198/293] Add missing new lines --- .../java/com/iexec/sms/secret/web2/Web2SecretServiceTests.java | 2 +- src/test/java/com/iexec/sms/secret/web2/Web2SecretTests.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/com/iexec/sms/secret/web2/Web2SecretServiceTests.java b/src/test/java/com/iexec/sms/secret/web2/Web2SecretServiceTests.java index 908d78a7..577a2158 100644 --- a/src/test/java/com/iexec/sms/secret/web2/Web2SecretServiceTests.java +++ b/src/test/java/com/iexec/sms/secret/web2/Web2SecretServiceTests.java @@ -181,4 +181,4 @@ void shouldNotUpdateSecretIfSameValue() { ); } // endregion -} \ No newline at end of file +} diff --git a/src/test/java/com/iexec/sms/secret/web2/Web2SecretTests.java b/src/test/java/com/iexec/sms/secret/web2/Web2SecretTests.java index 5e89663e..4a7ccbae 100644 --- a/src/test/java/com/iexec/sms/secret/web2/Web2SecretTests.java +++ b/src/test/java/com/iexec/sms/secret/web2/Web2SecretTests.java @@ -25,4 +25,4 @@ void withDecryptedValue() { assertEquals(UNENCRYPTED_SECRET, ENCRYPTED_SECRET.withDecryptedValue(UNENCRYPTED_VALUE)); assertEquals(UNENCRYPTED_SECRET, UNENCRYPTED_SECRET.withDecryptedValue(UNENCRYPTED_VALUE)); } -} \ No newline at end of file +} From c53c8ed46fbc7d39c597d3bd2a386fb75bc3f29b Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Tue, 15 Nov 2022 12:16:48 +0100 Subject: [PATCH 199/293] Add copyright --- .../com/iexec/sms/secret/web2/Web2Secret.java | 18 ++++++++++++++++++ .../sms/secret/web2/Web2SecretRepository.java | 18 ++++++++++++++++++ .../sms/secret/web2/Web2SecretService.java | 18 ++++++++++++++++++ .../secret/web2/Web2SecretServiceTests.java | 18 ++++++++++++++++++ .../iexec/sms/secret/web2/Web2SecretTests.java | 18 ++++++++++++++++++ 5 files changed, 90 insertions(+) diff --git a/src/main/java/com/iexec/sms/secret/web2/Web2Secret.java b/src/main/java/com/iexec/sms/secret/web2/Web2Secret.java index 127609b2..262c5746 100644 --- a/src/main/java/com/iexec/sms/secret/web2/Web2Secret.java +++ b/src/main/java/com/iexec/sms/secret/web2/Web2Secret.java @@ -1,3 +1,21 @@ +/* + * + * * Copyright 2022 IEXEC BLOCKCHAIN TECH + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * + */ + package com.iexec.sms.secret.web2; import com.iexec.sms.secret.Secret; diff --git a/src/main/java/com/iexec/sms/secret/web2/Web2SecretRepository.java b/src/main/java/com/iexec/sms/secret/web2/Web2SecretRepository.java index a9fd172f..923cfd04 100644 --- a/src/main/java/com/iexec/sms/secret/web2/Web2SecretRepository.java +++ b/src/main/java/com/iexec/sms/secret/web2/Web2SecretRepository.java @@ -1,3 +1,21 @@ +/* + * + * * Copyright 2022 IEXEC BLOCKCHAIN TECH + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * + */ + package com.iexec.sms.secret.web2; import org.springframework.data.repository.CrudRepository; diff --git a/src/main/java/com/iexec/sms/secret/web2/Web2SecretService.java b/src/main/java/com/iexec/sms/secret/web2/Web2SecretService.java index 730cfd65..d3c0e2e4 100644 --- a/src/main/java/com/iexec/sms/secret/web2/Web2SecretService.java +++ b/src/main/java/com/iexec/sms/secret/web2/Web2SecretService.java @@ -1,3 +1,21 @@ +/* + * + * * Copyright 2022 IEXEC BLOCKCHAIN TECH + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * + */ + package com.iexec.sms.secret.web2; import com.iexec.sms.encryption.EncryptionService; diff --git a/src/test/java/com/iexec/sms/secret/web2/Web2SecretServiceTests.java b/src/test/java/com/iexec/sms/secret/web2/Web2SecretServiceTests.java index 577a2158..776b6c73 100644 --- a/src/test/java/com/iexec/sms/secret/web2/Web2SecretServiceTests.java +++ b/src/test/java/com/iexec/sms/secret/web2/Web2SecretServiceTests.java @@ -1,3 +1,21 @@ +/* + * + * * Copyright 2022 IEXEC BLOCKCHAIN TECH + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * + */ + package com.iexec.sms.secret.web2; import com.iexec.sms.encryption.EncryptionService; diff --git a/src/test/java/com/iexec/sms/secret/web2/Web2SecretTests.java b/src/test/java/com/iexec/sms/secret/web2/Web2SecretTests.java index 4a7ccbae..6319b025 100644 --- a/src/test/java/com/iexec/sms/secret/web2/Web2SecretTests.java +++ b/src/test/java/com/iexec/sms/secret/web2/Web2SecretTests.java @@ -1,3 +1,21 @@ +/* + * + * * Copyright 2022 IEXEC BLOCKCHAIN TECH + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * + */ + package com.iexec.sms.secret.web2; import org.junit.jupiter.api.Test; From 6c64d24929e8ebbc6a9e344b65aeb7546c3a03e6 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Tue, 15 Nov 2022 12:18:04 +0100 Subject: [PATCH 200/293] Add missing `@Override` annotations --- src/main/java/com/iexec/sms/secret/web2/Web2Secret.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/com/iexec/sms/secret/web2/Web2Secret.java b/src/main/java/com/iexec/sms/secret/web2/Web2Secret.java index 262c5746..f46f3519 100644 --- a/src/main/java/com/iexec/sms/secret/web2/Web2Secret.java +++ b/src/main/java/com/iexec/sms/secret/web2/Web2Secret.java @@ -48,6 +48,7 @@ public Web2Secret(String ownerAddress, String address, String value, boolean isE * @param newValue Value to use for new object. * @return A new {@link Web2Secret} object with new value. */ + @Override public Web2Secret withEncryptedValue(String newValue) { return new Web2Secret(this.getId(), this.getOwnerAddress(), this.getAddress(), newValue, true); } @@ -59,6 +60,7 @@ public Web2Secret withEncryptedValue(String newValue) { * @param newValue Value to use for new object. * @return A new {@link Web2Secret} object with new value. */ + @Override public Web2Secret withDecryptedValue(String newValue) { return new Web2Secret(this.getId(), this.getOwnerAddress(), this.getAddress(), newValue, false); } From a34d961a3c3787ead3fb044a3b51b46eef0d3a28 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Tue, 15 Nov 2022 13:05:44 +0100 Subject: [PATCH 201/293] Add `@Deprecated` annotations --- src/main/java/com/iexec/sms/secret/web2/Web2Secrets.java | 4 ++++ .../java/com/iexec/sms/secret/web2/Web2SecretsRepository.java | 4 ++++ .../java/com/iexec/sms/secret/web2/Web2SecretsService.java | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/src/main/java/com/iexec/sms/secret/web2/Web2Secrets.java b/src/main/java/com/iexec/sms/secret/web2/Web2Secrets.java index fe4b680e..cdbff3b6 100644 --- a/src/main/java/com/iexec/sms/secret/web2/Web2Secrets.java +++ b/src/main/java/com/iexec/sms/secret/web2/Web2Secrets.java @@ -26,6 +26,10 @@ import javax.persistence.*; import java.util.*; +/** + * @deprecated Use {@link Web2Secret} instead. + */ +@Deprecated(forRemoval = true) @Entity @Getter @NoArgsConstructor(access = AccessLevel.PACKAGE) diff --git a/src/main/java/com/iexec/sms/secret/web2/Web2SecretsRepository.java b/src/main/java/com/iexec/sms/secret/web2/Web2SecretsRepository.java index 062ae118..4b3d1371 100644 --- a/src/main/java/com/iexec/sms/secret/web2/Web2SecretsRepository.java +++ b/src/main/java/com/iexec/sms/secret/web2/Web2SecretsRepository.java @@ -21,6 +21,10 @@ import java.util.Optional; +/** + * @deprecated Use {@link Web2SecretRepository} instead. + */ +@Deprecated(forRemoval = true) public interface Web2SecretsRepository extends CrudRepository { Optional findWeb2SecretsByOwnerAddress(String ownerAddress); diff --git a/src/main/java/com/iexec/sms/secret/web2/Web2SecretsService.java b/src/main/java/com/iexec/sms/secret/web2/Web2SecretsService.java index 4eee0172..7de0893a 100644 --- a/src/main/java/com/iexec/sms/secret/web2/Web2SecretsService.java +++ b/src/main/java/com/iexec/sms/secret/web2/Web2SecretsService.java @@ -25,6 +25,10 @@ import java.util.Optional; +/** + * @deprecated Use {@link Web2SecretService} instead. + */ +@Deprecated(forRemoval = true) @Slf4j @Service public class Web2SecretsService extends AbstractSecretService { From 6323306fb3759f90d99b084ca5740d332272b203 Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Tue, 15 Nov 2022 13:22:08 +0100 Subject: [PATCH 202/293] Fix default value in application-scone.yml for 2-way TLS key store --- src/main/resources/application-scone.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/application-scone.yml b/src/main/resources/application-scone.yml index 7ddcaab6..2226a3cf 100644 --- a/src/main/resources/application-scone.yml +++ b/src/main/resources/application-scone.yml @@ -8,7 +8,7 @@ tee: port: ${IEXEC_SECRET_PROVISIONER_ENCLAVE_PORT:18765} ssl: - key-store: ${IEXEC_SMS_SSL_KEYSTORE:./src/main/resources/ssl-keystore-dev.p12} #iexec-core dev certificate for dev + key-store: ${IEXEC_SMS_SSL_KEYSTORE:/app/ssl-keystore-dev.p12} #iexec-core dev certificate for dev key-store-password: ${IEXEC_SMS_SSL_KEYSTORE_PASSWORD:whatever} key-store-type: ${IEXEC_SMS_SSL_KEYSTORE_TYPE:PKCS12} key-alias: ${IEXEC_SMS_SSL_KEYSTORE_ALIAS:iexec-core} From 95075a4cc3603908d5635cdc7bc5e5b9c1a304ba Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Tue, 15 Nov 2022 14:09:29 +0100 Subject: [PATCH 203/293] Remove `Web2Secrets` classes and services --- .../iexec/sms/secret/SecretController.java | 22 ++- .../iexec/sms/secret/web2/Web2Secrets.java | 118 ----------- .../secret/web2/Web2SecretsRepository.java | 32 --- .../sms/secret/web2/Web2SecretsService.java | 107 ---------- .../base/SecretSessionBaseService.java | 18 +- .../sms/secret/SecretControllerTests.java | 66 +++---- .../secret/web2/Web2SecretsServiceTests.java | 187 ------------------ .../base/SecretSessionBaseServiceTests.java | 45 +++-- 8 files changed, 71 insertions(+), 524 deletions(-) delete mode 100644 src/main/java/com/iexec/sms/secret/web2/Web2Secrets.java delete mode 100644 src/main/java/com/iexec/sms/secret/web2/Web2SecretsRepository.java delete mode 100644 src/main/java/com/iexec/sms/secret/web2/Web2SecretsService.java delete mode 100644 src/test/java/com/iexec/sms/secret/web2/Web2SecretsServiceTests.java diff --git a/src/main/java/com/iexec/sms/secret/SecretController.java b/src/main/java/com/iexec/sms/secret/SecretController.java index 07f4b64d..3bec3086 100644 --- a/src/main/java/com/iexec/sms/secret/SecretController.java +++ b/src/main/java/com/iexec/sms/secret/SecretController.java @@ -18,8 +18,7 @@ import com.iexec.sms.authorization.AuthorizationService; -import com.iexec.sms.secret.web2.NotAnExistingSecretException; -import com.iexec.sms.secret.web2.Web2SecretsService; +import com.iexec.sms.secret.web2.*; import com.iexec.sms.secret.web3.Web3Secret; import com.iexec.sms.secret.web3.Web3SecretService; import lombok.extern.slf4j.Slf4j; @@ -38,12 +37,12 @@ public class SecretController { private final AuthorizationService authorizationService; private final Web3SecretService web3SecretService; - private final Web2SecretsService web2SecretsService; + private final Web2SecretService web2SecretService; public SecretController(AuthorizationService authorizationService, - Web2SecretsService web2SecretsService, + Web2SecretService web2SecretService, Web3SecretService web3SecretService) { - this.web2SecretsService = web2SecretsService; + this.web2SecretService = web2SecretService; this.authorizationService = authorizationService; this.web3SecretService = web3SecretService; } @@ -83,7 +82,7 @@ public ResponseEntity addWeb3Secret(@RequestHeader String authorization, @RequestMapping(path = "/web2", method = RequestMethod.HEAD) public ResponseEntity isWeb2SecretSet(@RequestParam String ownerAddress, @RequestParam String secretName) { - Optional secret = web2SecretsService.getSecret(ownerAddress, secretName); + Optional secret = web2SecretService.getSecret(ownerAddress, secretName); return secret.isPresent() ? ResponseEntity.noContent().build() : ResponseEntity.notFound().build(); } @@ -103,11 +102,12 @@ public ResponseEntity addWeb2Secret(@RequestHeader String authorization, return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build(); } - if (web2SecretsService.addSecret(ownerAddress, secretName, secretValue).isEmpty()) { + try { + web2SecretService.addSecret(ownerAddress, secretName, secretValue); + return ResponseEntity.noContent().build(); + } catch (SecretAlreadyExistsException e) { return ResponseEntity.status(HttpStatus.CONFLICT).build(); } - - return ResponseEntity.noContent().build(); } @PutMapping("/web2") @@ -127,7 +127,9 @@ public ResponseEntity updateWeb2Secret(@RequestHeader String authorizati } try { - web2SecretsService.updateSecret(ownerAddress, secretName, newSecretValue); + web2SecretService.updateSecret(ownerAddress, secretName, newSecretValue); + return ResponseEntity.noContent().build(); + } catch (SameSecretException ignored) { return ResponseEntity.noContent().build(); } catch (NoSuchElementException | NotAnExistingSecretException e) { return ResponseEntity.notFound().build(); diff --git a/src/main/java/com/iexec/sms/secret/web2/Web2Secrets.java b/src/main/java/com/iexec/sms/secret/web2/Web2Secrets.java deleted file mode 100644 index cdbff3b6..00000000 --- a/src/main/java/com/iexec/sms/secret/web2/Web2Secrets.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright 2020 IEXEC BLOCKCHAIN TECH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.iexec.sms.secret.web2; - -import com.iexec.sms.secret.Secret; -import lombok.AccessLevel; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import org.hibernate.annotations.GenericGenerator; - -import javax.persistence.*; -import java.util.*; - -/** - * @deprecated Use {@link Web2Secret} instead. - */ -@Deprecated(forRemoval = true) -@Entity -@Getter -@NoArgsConstructor(access = AccessLevel.PACKAGE) -@AllArgsConstructor(access = AccessLevel.PRIVATE) -public class Web2Secrets { - - @Id - @GeneratedValue(generator = "system-uuid") - @GenericGenerator(name = "system-uuid", strategy = "uuid") - private String id; - - private String ownerAddress; - @OneToMany(cascade = {CascadeType.ALL}) - private List secrets; - - Web2Secrets(String ownerAddress) { - this(ownerAddress, List.of()); - } - - public Web2Secrets(String ownerAddress, List secrets) { - this.ownerAddress = ownerAddress.toLowerCase(); - this.secrets = Collections.unmodifiableList(secrets); - } - - public Optional getSecret(String secretAddress) { - return secrets.stream() - .filter(secret -> secret.getAddress().equals(secretAddress)) - .findFirst(); - } - - /** - * Copies the current {@link Web2Secrets} object, while adding given {@link Secret} to the secrets list. - * - * @param secretAddress Address of the new secret. - * @param secretValue Value of the new secret. - * @param isEncryptedValue Whether this value is encrypted. - * @return A new {@link Web2Secrets} instance, with a new {@link Secret} element. - * @throws SecretAlreadyExistsException thrown when a secret with same address already exists. - */ - // TODO: remove `isEncryptedValue` as we only have encrypted values there. - public Web2Secrets addNewSecret(String secretAddress, String secretValue, boolean isEncryptedValue) - throws SecretAlreadyExistsException { - // A new secret can't already exist - if (getSecret(secretAddress).isPresent()) { - throw new SecretAlreadyExistsException(ownerAddress, secretAddress); - } - - final List newSecrets = new ArrayList<>(this.secrets); - newSecrets.add(new Secret(secretAddress, secretValue, isEncryptedValue)); - return new Web2Secrets(id, ownerAddress, newSecrets); - } - - /** - * Copies the current {@link Web2Secrets} object, while updating {@link Secret} at given {@code secretAddress}. - * - * @param secretAddress Address of the secret to update. - * @param newSecretValue New value for the secret. - * @param isEncryptedValue Whether this value is encrypted. - * @return A new {@link Web2Secrets} instance, with a {@link Secret} whose value has been updated. - * @throws NotAnExistingSecretException thrown when requested address is not known. - * @throws SameSecretException thrown when secret has already given value. - */ - public Web2Secrets updateSecret(String secretAddress, String newSecretValue, boolean isEncryptedValue) - throws NotAnExistingSecretException, SameSecretException { - final Optional oSecretToUpdate = getSecret(secretAddress); - - // Can't update a secret that doesn't exist - if (oSecretToUpdate.isEmpty()) { - throw new NotAnExistingSecretException(ownerAddress, secretAddress); - } - - // No need to update if same value - final Secret secretToUpdate = oSecretToUpdate.get(); - if (secretToUpdate.isEncryptedValue() == isEncryptedValue && Objects.equals(secretToUpdate.getValue(), newSecretValue)) { - throw new SameSecretException(ownerAddress, secretAddress); - } - - final List updatedSecretsList = new ArrayList<>(secrets); - // Filtering out old secret - updatedSecretsList.remove(secretToUpdate); - // Adding updated secret - updatedSecretsList.add(secretToUpdate.withEncryptedValue(newSecretValue)); - - return new Web2Secrets(id, ownerAddress, updatedSecretsList); - } -} diff --git a/src/main/java/com/iexec/sms/secret/web2/Web2SecretsRepository.java b/src/main/java/com/iexec/sms/secret/web2/Web2SecretsRepository.java deleted file mode 100644 index 4b3d1371..00000000 --- a/src/main/java/com/iexec/sms/secret/web2/Web2SecretsRepository.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2020 IEXEC BLOCKCHAIN TECH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.iexec.sms.secret.web2; - - -import org.springframework.data.repository.CrudRepository; - -import java.util.Optional; - -/** - * @deprecated Use {@link Web2SecretRepository} instead. - */ -@Deprecated(forRemoval = true) -public interface Web2SecretsRepository extends CrudRepository { - - Optional findWeb2SecretsByOwnerAddress(String ownerAddress); - -} diff --git a/src/main/java/com/iexec/sms/secret/web2/Web2SecretsService.java b/src/main/java/com/iexec/sms/secret/web2/Web2SecretsService.java deleted file mode 100644 index 7de0893a..00000000 --- a/src/main/java/com/iexec/sms/secret/web2/Web2SecretsService.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright 2020 IEXEC BLOCKCHAIN TECH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.iexec.sms.secret.web2; - - -import com.iexec.sms.encryption.EncryptionService; -import com.iexec.sms.secret.AbstractSecretService; -import com.iexec.sms.secret.Secret; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Service; - -import java.util.Optional; - -/** - * @deprecated Use {@link Web2SecretService} instead. - */ -@Deprecated(forRemoval = true) -@Slf4j -@Service -public class Web2SecretsService extends AbstractSecretService { - - private final Web2SecretsRepository web2SecretsRepository; - - public Web2SecretsService(Web2SecretsRepository web2SecretsRepository, - EncryptionService encryptionService) { - super(encryptionService); - this.web2SecretsRepository = web2SecretsRepository; - } - - public Optional getWeb2Secrets(String ownerAddress) { - ownerAddress = ownerAddress.toLowerCase(); - return web2SecretsRepository.findWeb2SecretsByOwnerAddress(ownerAddress); - } - - public Optional getSecret(String ownerAddress, String secretAddress) { - ownerAddress = ownerAddress.toLowerCase(); - return getWeb2Secrets(ownerAddress) - .flatMap(web2Secrets -> web2Secrets.getSecret(secretAddress)); - } - - public Optional getSecret(String ownerAddress, String secretAddress, boolean shouldDecryptValue) { - Optional oSecret = getSecret(ownerAddress, secretAddress); - - if (oSecret.isEmpty() || !shouldDecryptValue) { - return oSecret; - } - - final Secret secret = oSecret.get(); - final String decryptedValue = encryptionService.decrypt(secret.getValue()); - return Optional.of(secret.withDecryptedValue(decryptedValue)); - } - - public Optional addSecret(String ownerAddress, String secretAddress, String secretValue) { - ownerAddress = ownerAddress.toLowerCase(); - final Web2Secrets web2Secrets = getWeb2Secrets(ownerAddress) - .orElse(new Web2Secrets(ownerAddress)); - - final String encryptedValue = encryptionService.encrypt(secretValue); - log.info("Adding new secret [ownerAddress:{}, secretAddress:{}, encryptedSecretValue:{}]", - ownerAddress, secretAddress, encryptedValue); - - try { - final Web2Secrets newWeb2Secrets = web2Secrets.addNewSecret(secretAddress, encryptedValue, true); - web2SecretsRepository.save(newWeb2Secrets); - return newWeb2Secrets.getSecret(secretAddress); - } catch (SecretAlreadyExistsException e) { - log.error("Secret already exists [ownerAddress:{}, secretAddress:{}]", ownerAddress, secretAddress, e); - return Optional.empty(); - } - } - - public Optional updateSecret(String ownerAddress, String secretAddress, String newSecretValue) throws NotAnExistingSecretException { - ownerAddress = ownerAddress.toLowerCase(); - final Web2Secrets web2Secrets = getWeb2Secrets(ownerAddress).orElseThrow(); - final String encryptedValue = encryptionService.encrypt(newSecretValue); - log.info("Updating secret [ownerAddress:{}, secretAddress:{}, newEncryptedSecretValue:{}]", - ownerAddress, secretAddress, encryptedValue); - - try { - final Web2Secrets newWeb2Secrets = web2Secrets.updateSecret(secretAddress, encryptedValue, true); - web2SecretsRepository.save(newWeb2Secrets); - return newWeb2Secrets.getSecret(secretAddress); - } catch (NotAnExistingSecretException e) { - log.error("Secret does not exist, can't update it [ownerAddress:{}, secretAddress:{}]", - ownerAddress, secretAddress, e); - throw e; - } catch (SameSecretException e) { - log.info("No need to update secret [ownerAddress:{}, secretAddress:{}]", - ownerAddress, secretAddress); - return Optional.empty(); - } - } -} diff --git a/src/main/java/com/iexec/sms/tee/session/base/SecretSessionBaseService.java b/src/main/java/com/iexec/sms/tee/session/base/SecretSessionBaseService.java index b7e9b58a..0ef10712 100644 --- a/src/main/java/com/iexec/sms/tee/session/base/SecretSessionBaseService.java +++ b/src/main/java/com/iexec/sms/tee/session/base/SecretSessionBaseService.java @@ -21,12 +21,12 @@ import com.iexec.common.utils.IexecEnvUtils; import com.iexec.common.utils.IexecFileHelper; import com.iexec.sms.api.config.TeeServicesProperties; -import com.iexec.sms.secret.Secret; import com.iexec.sms.secret.compute.OnChainObjectType; import com.iexec.sms.secret.compute.SecretOwnerRole; import com.iexec.sms.secret.compute.TeeTaskComputeSecret; import com.iexec.sms.secret.compute.TeeTaskComputeSecretService; -import com.iexec.sms.secret.web2.Web2SecretsService; +import com.iexec.sms.secret.web2.Web2Secret; +import com.iexec.sms.secret.web2.Web2SecretService; import com.iexec.sms.secret.web3.Web3SecretService; import com.iexec.sms.tee.challenge.TeeChallenge; import com.iexec.sms.tee.challenge.TeeChallengeService; @@ -67,19 +67,19 @@ public class SecretSessionBaseService { public static final String POST_COMPUTE_MRENCLAVE = "POST_COMPUTE_MRENCLAVE"; private final Web3SecretService web3SecretService; - private final Web2SecretsService web2SecretsService; + private final Web2SecretService web2SecretService; private final TeeChallengeService teeChallengeService; private final TeeServicesProperties teeServicesConfig; private final TeeTaskComputeSecretService teeTaskComputeSecretService; public SecretSessionBaseService( Web3SecretService web3SecretService, - Web2SecretsService web2SecretsService, + Web2SecretService web2SecretService, TeeChallengeService teeChallengeService, TeeServicesProperties teeServicesConfig, TeeTaskComputeSecretService teeTaskComputeSecretService) { this.web3SecretService = web3SecretService; - this.web2SecretsService = web2SecretsService; + this.web2SecretService = web2SecretService; this.teeChallengeService = teeChallengeService; this.teeServicesConfig = teeServicesConfig; this.teeTaskComputeSecretService = teeTaskComputeSecretService; @@ -316,7 +316,7 @@ public Map getPostComputeEncryptionTokens(TeeSessionRequest requ if (!shouldEncrypt) { return tokens; } - Optional beneficiaryResultEncryptionKeySecret = web2SecretsService.getSecret( + Optional beneficiaryResultEncryptionKeySecret = web2SecretService.getSecret( taskDescription.getBeneficiary(), IEXEC_RESULT_ENCRYPTION_PUBLIC_KEY, true); @@ -352,8 +352,10 @@ public Map getPostComputeStorageTokens(TeeSessionRequest request String keyName = storageProvider.equals(DROPBOX_RESULT_STORAGE_PROVIDER) ? IEXEC_RESULT_DROPBOX_TOKEN : IEXEC_RESULT_IEXEC_IPFS_TOKEN; - Optional requesterStorageTokenSecret = web2SecretsService.getSecret(taskDescription.getRequester(), - keyName, true); + Optional requesterStorageTokenSecret = web2SecretService.getSecret( + taskDescription.getRequester(), + keyName, + true); if (requesterStorageTokenSecret.isEmpty()) { log.error("Failed to get storage token [taskId:{}, storageProvider:{}, requester:{}]", taskId, storageProvider, taskDescription.getRequester()); diff --git a/src/test/java/com/iexec/sms/secret/SecretControllerTests.java b/src/test/java/com/iexec/sms/secret/SecretControllerTests.java index d9251347..9b36e4bf 100644 --- a/src/test/java/com/iexec/sms/secret/SecretControllerTests.java +++ b/src/test/java/com/iexec/sms/secret/SecretControllerTests.java @@ -17,14 +17,11 @@ package com.iexec.sms.secret; import com.iexec.sms.authorization.AuthorizationService; -import com.iexec.sms.secret.web2.NotAnExistingSecretException; -import com.iexec.sms.secret.web2.Web2SecretsService; +import com.iexec.sms.secret.web2.*; import com.iexec.sms.secret.web3.Web3Secret; import com.iexec.sms.secret.web3.Web3SecretService; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -33,7 +30,6 @@ import java.nio.charset.StandardCharsets; import java.security.SecureRandom; -import java.util.NoSuchElementException; import java.util.Optional; import static org.assertj.core.api.Assertions.assertThat; @@ -53,7 +49,7 @@ class SecretControllerTests { private AuthorizationService authorizationService; @Mock - private Web2SecretsService web2SecretsService; + private Web2SecretService web2SecretService; @Mock private Web3SecretService web3SecretService; @@ -75,7 +71,7 @@ void shouldReturnNoContentWhenWeb3SecretExists() { .thenReturn(Optional.of(mock(Web3Secret.class))); assertThat(secretController.isWeb3SecretSet(WEB3_SECRET_ADDRESS)) .isEqualTo(ResponseEntity.noContent().build()); - verifyNoInteractions(authorizationService, web2SecretsService); + verifyNoInteractions(authorizationService, web2SecretService); } @Test @@ -84,7 +80,7 @@ void shouldReturnNotFoundWhenWeb3SecretDoesNotExist() { .thenReturn(Optional.empty()); assertThat(secretController.isWeb3SecretSet(WEB3_SECRET_ADDRESS)) .isEqualTo(ResponseEntity.notFound().build()); - verifyNoInteractions(authorizationService, web2SecretsService); + verifyNoInteractions(authorizationService, web2SecretService); } //endregion @@ -93,7 +89,7 @@ void shouldReturnNotFoundWhenWeb3SecretDoesNotExist() { void failToAddWeb3SecretWhenPayloadTooLarge() { assertThat(secretController.addWeb3Secret(AUTHORIZATION, WEB3_SECRET_ADDRESS, getRandomString(4097))) .isEqualTo(ResponseEntity.status(HttpStatus.PAYLOAD_TOO_LARGE).build()); - verifyNoInteractions(authorizationService, web2SecretsService, web3SecretService); + verifyNoInteractions(authorizationService, web2SecretService, web3SecretService); } @Test @@ -104,7 +100,7 @@ void failToAddWeb3SecretWhenBadAuthorization() { .thenReturn(false); assertThat(secretController.addWeb3Secret(AUTHORIZATION, WEB3_SECRET_ADDRESS, WEB3_SECRET_VALUE)) .isEqualTo(ResponseEntity.status(HttpStatus.UNAUTHORIZED).build()); - verifyNoInteractions(web2SecretsService, web3SecretService); + verifyNoInteractions(web2SecretService, web3SecretService); } @Test @@ -117,7 +113,7 @@ void failToAddWeb3SecretWhenSecretAlreadyExists() { .thenReturn(false); assertThat(secretController.addWeb3Secret(AUTHORIZATION, WEB3_SECRET_ADDRESS, WEB3_SECRET_VALUE)) .isEqualTo(ResponseEntity.status(HttpStatus.CONFLICT).build()); - verifyNoInteractions(web2SecretsService); + verifyNoInteractions(web2SecretService); verify(web3SecretService).addSecret(WEB3_SECRET_ADDRESS, WEB3_SECRET_VALUE); } @@ -131,7 +127,7 @@ void addWeb3Secret() { .thenReturn(true); assertThat(secretController.addWeb3Secret(AUTHORIZATION, WEB3_SECRET_ADDRESS, WEB3_SECRET_VALUE)) .isEqualTo(ResponseEntity.noContent().build()); - verifyNoInteractions(web2SecretsService); + verifyNoInteractions(web2SecretService); verify(web3SecretService).addSecret(WEB3_SECRET_ADDRESS, WEB3_SECRET_VALUE); } //endregion @@ -139,8 +135,8 @@ void addWeb3Secret() { //region isWeb2SecretSet @Test void shouldReturnNoContentWhenWeb2SecretExists() { - when(web2SecretsService.getSecret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME)) - .thenReturn(Optional.of(new Secret())); + when(web2SecretService.getSecret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME)) + .thenReturn(Optional.of(new Web2Secret(WEB2_OWNER_ADDRESS, WEB3_SECRET_ADDRESS, WEB2_SECRET_VALUE, true))); assertThat(secretController.isWeb2SecretSet(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME)) .isEqualTo(ResponseEntity.noContent().build()); verifyNoInteractions(authorizationService, web3SecretService); @@ -148,7 +144,7 @@ void shouldReturnNoContentWhenWeb2SecretExists() { @Test void shouldReturnNotFoundWhenWeb2SecretDoesNotExist() { - when(web2SecretsService.getSecret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME)) + when(web2SecretService.getSecret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME)) .thenReturn(Optional.empty()); assertThat(secretController.isWeb2SecretSet(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME)) .isEqualTo(ResponseEntity.notFound().build()); @@ -161,7 +157,7 @@ void shouldReturnNotFoundWhenWeb2SecretDoesNotExist() { void failToAddWeb2SecretWhenPayloadTooLarge() { assertThat(secretController.addWeb2Secret(AUTHORIZATION, WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, getRandomString(4097))) .isEqualTo(ResponseEntity.status(HttpStatus.PAYLOAD_TOO_LARGE).build()); - verifyNoInteractions(web2SecretsService, web3SecretService); + verifyNoInteractions(web2SecretService, web3SecretService); } @Test @@ -172,33 +168,33 @@ void failToAddWeb2SecretWhenBadAuthorization() { .thenReturn(false); assertThat(secretController.addWeb2Secret(AUTHORIZATION, WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, WEB2_SECRET_VALUE)) .isEqualTo(ResponseEntity.status(HttpStatus.UNAUTHORIZED).build()); - verifyNoInteractions(web2SecretsService, web3SecretService); + verifyNoInteractions(web2SecretService, web3SecretService); } @Test - void failToAddWeb2SecretWhenSecretAlreadyExists() { + void failToAddWeb2SecretWhenSecretAlreadyExists() throws SecretAlreadyExistsException { when(authorizationService.getChallengeForSetWeb2Secret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, WEB2_SECRET_VALUE)) .thenReturn(CHALLENGE); when(authorizationService.isSignedByHimself(CHALLENGE, AUTHORIZATION, WEB2_OWNER_ADDRESS)) .thenReturn(true); - when(web2SecretsService.addSecret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, WEB2_SECRET_VALUE)) - .thenReturn(Optional.empty()); + when(web2SecretService.addSecret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, WEB2_SECRET_VALUE)) + .thenThrow(new SecretAlreadyExistsException(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME)); assertThat(secretController.addWeb2Secret(AUTHORIZATION, WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, WEB2_SECRET_VALUE)) .isEqualTo(ResponseEntity.status(HttpStatus.CONFLICT).build()); - verify(web2SecretsService).addSecret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, WEB2_SECRET_VALUE); + verify(web2SecretService).addSecret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, WEB2_SECRET_VALUE); } @Test - void addWeb2Secret() { + void addWeb2Secret() throws SecretAlreadyExistsException { when(authorizationService.getChallengeForSetWeb2Secret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, WEB2_SECRET_VALUE)) .thenReturn(CHALLENGE); when(authorizationService.isSignedByHimself(CHALLENGE, AUTHORIZATION, WEB2_OWNER_ADDRESS)) .thenReturn(true); - when(web2SecretsService.addSecret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, WEB2_SECRET_VALUE)) - .thenReturn(Optional.of(new Secret(WEB2_SECRET_NAME, WEB2_SECRET_VALUE, true))); + when(web2SecretService.addSecret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, WEB2_SECRET_VALUE)) + .thenReturn(new Web2Secret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, WEB2_SECRET_VALUE, true)); assertThat(secretController.addWeb2Secret(AUTHORIZATION, WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, WEB2_SECRET_VALUE)) .isEqualTo(ResponseEntity.noContent().build()); - verify(web2SecretsService).addSecret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, WEB2_SECRET_VALUE); + verify(web2SecretService).addSecret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, WEB2_SECRET_VALUE); } //endregion @@ -207,7 +203,7 @@ void addWeb2Secret() { void failToUpdateWeb2SecretWhenPayloadTooLarge() { assertThat(secretController.updateWeb2Secret(AUTHORIZATION, WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, getRandomString(4097))) .isEqualTo(ResponseEntity.status(HttpStatus.PAYLOAD_TOO_LARGE).build()); - verifyNoInteractions(web2SecretsService, web3SecretService); + verifyNoInteractions(web2SecretService, web3SecretService); } @Test @@ -218,28 +214,16 @@ void failToUpdateWeb2SecretWhenBadAuthorization() { .thenReturn(false); assertThat(secretController.updateWeb2Secret(AUTHORIZATION, WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, WEB2_SECRET_VALUE)) .isEqualTo(ResponseEntity.status(HttpStatus.UNAUTHORIZED).build()); - verifyNoInteractions(web2SecretsService, web3SecretService); - } - - @Test - void failToUpdateWeb2SecretWhenSecretsListIsMissing() throws NotAnExistingSecretException { - when(authorizationService.getChallengeForSetWeb2Secret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, WEB2_SECRET_VALUE)) - .thenReturn(CHALLENGE); - when(authorizationService.isSignedByHimself(CHALLENGE, AUTHORIZATION, WEB2_OWNER_ADDRESS)) - .thenReturn(true); - doThrow(NoSuchElementException.class).when(web2SecretsService) - .updateSecret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, WEB2_SECRET_VALUE); - assertThat(secretController.updateWeb2Secret(AUTHORIZATION, WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, WEB2_SECRET_VALUE)) - .isEqualTo(ResponseEntity.notFound().build()); + verifyNoInteractions(web2SecretService, web3SecretService); } @Test - void failToUpdateWeb2SecretWhenSecretIsMissing() throws NotAnExistingSecretException { + void failToUpdateWeb2SecretWhenSecretIsMissing() throws NotAnExistingSecretException, SameSecretException { when(authorizationService.getChallengeForSetWeb2Secret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, WEB2_SECRET_VALUE)) .thenReturn(CHALLENGE); when(authorizationService.isSignedByHimself(CHALLENGE, AUTHORIZATION, WEB2_OWNER_ADDRESS)) .thenReturn(true); - doThrow(NotAnExistingSecretException.class).when(web2SecretsService) + doThrow(NotAnExistingSecretException.class).when(web2SecretService) .updateSecret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, WEB2_SECRET_VALUE); assertThat(secretController.updateWeb2Secret(AUTHORIZATION, WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, WEB2_SECRET_VALUE)) .isEqualTo(ResponseEntity.notFound().build()); diff --git a/src/test/java/com/iexec/sms/secret/web2/Web2SecretsServiceTests.java b/src/test/java/com/iexec/sms/secret/web2/Web2SecretsServiceTests.java deleted file mode 100644 index e672199e..00000000 --- a/src/test/java/com/iexec/sms/secret/web2/Web2SecretsServiceTests.java +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Copyright 2020 IEXEC BLOCKCHAIN TECH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.iexec.sms.secret.web2; - -import com.iexec.sms.encryption.EncryptionService; -import com.iexec.sms.secret.Secret; -import org.assertj.core.api.ThrowableAssertAlternative; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.mockito.Spy; - -import java.util.List; -import java.util.NoSuchElementException; -import java.util.Optional; - -import static org.assertj.core.api.Assertions.*; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.mockito.Mockito.*; - -class Web2SecretsServiceTests { - - String ownerAddress = "ownerAddress".toLowerCase(); - String secretAddress = "secretAddress"; - String plainSecretValue = "plainSecretValue"; - String encryptedSecretValue = "encryptedSecretValue"; - - @Mock - private Web2SecretsRepository web2SecretsRepository; - - @Mock - private EncryptionService encryptionService; - - @InjectMocks - @Spy - private Web2SecretsService web2SecretsService; - - @BeforeEach - void beforeEach() { - MockitoAnnotations.openMocks(this); - } - - @Test - void shouldGetDecryptedSecret() { - Secret encryptedSecret = new Secret(secretAddress, encryptedSecretValue, true); - Web2Secrets web2SecretsMock = new Web2Secrets(ownerAddress, List.of(encryptedSecret)); - when(web2SecretsRepository.findWeb2SecretsByOwnerAddress(ownerAddress)) - .thenReturn(Optional.of(web2SecretsMock)); - when(encryptionService.decrypt(encryptedSecret.getValue())) - .thenReturn(plainSecretValue); - - Optional result = web2SecretsService.getSecret(ownerAddress, secretAddress, true); - assertThat(result).isNotEmpty(); - assertThat(result).get().extracting(Secret::getAddress).isEqualTo(secretAddress); - assertThat(result).get().extracting(Secret::getValue).isEqualTo(plainSecretValue); - assertThat(result).get().extracting(Secret::isEncryptedValue).isEqualTo(false); - } - - @Test - void shouldGetEncryptedSecret() { - Secret encryptedSecret = new Secret(secretAddress, encryptedSecretValue, true); - Web2Secrets web2Secrets = new Web2Secrets(ownerAddress, List.of(encryptedSecret)); - when(web2SecretsRepository.findWeb2SecretsByOwnerAddress(ownerAddress)) - .thenReturn(Optional.of(web2Secrets)); - - Optional oSecret1 = web2SecretsService.getSecret(ownerAddress, secretAddress); - Optional oSecret2 = web2SecretsService.getSecret(ownerAddress, secretAddress, false); - assertThat(oSecret1) - .contains(encryptedSecret) - .isEqualTo(oSecret2); - verify(web2SecretsRepository, times(2)).findWeb2SecretsByOwnerAddress(ownerAddress); - verifyNoInteractions(encryptionService); - } - - @Test - void shouldGetEmptyResultIfSecretNotPresent() { - when(web2SecretsRepository.findWeb2SecretsByOwnerAddress(ownerAddress)).thenReturn(Optional.empty()); - assertThat(web2SecretsService.getSecret(ownerAddress, secretAddress)).isEmpty(); - assertThat(web2SecretsService.getSecret(ownerAddress, secretAddress, false)).isEmpty(); - verify(web2SecretsRepository, times(2)).findWeb2SecretsByOwnerAddress(ownerAddress); - verifyNoInteractions(encryptionService); - } - - @Test - void shouldNotAddSecretIfPresent() { - Web2Secrets web2Secrets = new Web2Secrets(ownerAddress, List.of(new Secret(secretAddress, encryptedSecretValue, true))); - when(web2SecretsRepository.findWeb2SecretsByOwnerAddress(ownerAddress)).thenReturn(Optional.of(web2Secrets)); - assertThat(web2SecretsService.addSecret(ownerAddress, secretAddress, plainSecretValue)).isEmpty(); - verify(encryptionService, times(1)).encrypt(plainSecretValue); - verify(web2SecretsRepository, never()).save(any()); - } - - @Test - void shouldAddSecret() { - when(encryptionService.encrypt(plainSecretValue)).thenReturn(encryptedSecretValue); - - final Optional newSecret = web2SecretsService.addSecret(ownerAddress, secretAddress, plainSecretValue); - assertThat(newSecret).isPresent(); - assertThat(newSecret).get().extracting(Secret::getAddress).isEqualTo(secretAddress); - assertThat(newSecret).get().extracting(Secret::getValue).isEqualTo(encryptedSecretValue); - assertThat(newSecret).get().extracting(Secret::isEncryptedValue).isEqualTo(true); - - verify(encryptionService).encrypt(any()); - verify(web2SecretsRepository).save(any()); - } - - @Test - void shouldNotUpdateSecretIfMissing() { - final Secret encryptedSecret = new Secret(secretAddress, encryptedSecretValue, true); - final Web2Secrets web2Secrets = new Web2Secrets(ownerAddress, List.of(encryptedSecret)); - when(web2SecretsRepository.findWeb2SecretsByOwnerAddress(ownerAddress)) - .thenReturn(Optional.empty()) - .thenReturn(Optional.of(web2Secrets)); - assertThatThrownBy(() -> web2SecretsService.updateSecret(ownerAddress, secretAddress, plainSecretValue)) - .isInstanceOf(NoSuchElementException.class); - verify(web2SecretsRepository, never()).save(any()); - } - - @Test - void shouldNotUpdateSecretIfSameValue() throws NotAnExistingSecretException { - final Secret encryptedSecret = new Secret(secretAddress, encryptedSecretValue, true); - final Web2Secrets web2Secrets = new Web2Secrets(ownerAddress, List.of(encryptedSecret)); - when(web2SecretsService.getWeb2Secrets(ownerAddress)) - .thenReturn(Optional.of(web2Secrets)); - when(encryptionService.encrypt(plainSecretValue)) - .thenReturn(encryptedSecretValue); - - assertThat(web2SecretsService.updateSecret(ownerAddress, secretAddress, plainSecretValue)).isEmpty(); - verify(web2SecretsRepository, never()).save(web2Secrets); - } - - @Test - void shouldNotUpdateSecretIfOldSecretDoesntExist() { - final Web2Secrets web2Secrets = new Web2Secrets(ownerAddress, List.of()); - when(web2SecretsService.getWeb2Secrets(ownerAddress)) - .thenReturn(Optional.of(web2Secrets)); - when(encryptionService.encrypt(plainSecretValue)) - .thenReturn(encryptedSecretValue); - - final ThrowableAssertAlternative exception = - assertThatExceptionOfType(NotAnExistingSecretException.class) - .isThrownBy(() -> web2SecretsService.updateSecret(ownerAddress, secretAddress, plainSecretValue)); - exception.extracting(NotAnExistingSecretException::getOwnerAddress).isEqualTo(ownerAddress); - exception.extracting(NotAnExistingSecretException::getSecretAddress).isEqualTo(secretAddress); - - verify(web2SecretsRepository, never()).save(any()); - } - - @Test - void shouldUpdateSecret() throws NotAnExistingSecretException { - Secret encryptedSecret = new Secret(secretAddress, encryptedSecretValue, true); - String newSecretValue = "newSecretValue"; - String newEncryptedSecretValue = "newEncryptedSecretValue"; - Web2Secrets web2SecretsMock = new Web2Secrets(ownerAddress, List.of(encryptedSecret)); - when(web2SecretsService.getWeb2Secrets(ownerAddress)) - .thenReturn(Optional.of(web2SecretsMock)); - when(encryptionService.encrypt(newSecretValue)) - .thenReturn(newEncryptedSecretValue); - - final Optional oNewSecret = web2SecretsService.updateSecret(ownerAddress, secretAddress, newSecretValue); - assertThat(oNewSecret).isPresent(); - - final Secret newSecret = oNewSecret.get(); - assertThat(newSecret).extracting(Secret::getAddress).isEqualTo(secretAddress); - assertThat(newSecret).extracting(Secret::getValue).isEqualTo(newEncryptedSecretValue); - assertThat(newSecret).extracting(Secret::isEncryptedValue).isEqualTo(true); - - verify(web2SecretsRepository, never()).save(web2SecretsMock); // Current object should not be updated - verify(web2SecretsRepository, times(1)).save(any()); // A new object should be created with the same ID - } -} diff --git a/src/test/java/com/iexec/sms/tee/session/base/SecretSessionBaseServiceTests.java b/src/test/java/com/iexec/sms/tee/session/base/SecretSessionBaseServiceTests.java index b992c666..fd171564 100644 --- a/src/test/java/com/iexec/sms/tee/session/base/SecretSessionBaseServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/base/SecretSessionBaseServiceTests.java @@ -9,12 +9,12 @@ import com.iexec.sms.api.config.TeeAppProperties; import com.iexec.sms.api.config.TeeServicesProperties; import com.iexec.sms.secret.ReservedSecretKeyName; -import com.iexec.sms.secret.Secret; import com.iexec.sms.secret.compute.OnChainObjectType; import com.iexec.sms.secret.compute.SecretOwnerRole; import com.iexec.sms.secret.compute.TeeTaskComputeSecret; import com.iexec.sms.secret.compute.TeeTaskComputeSecretService; -import com.iexec.sms.secret.web2.Web2SecretsService; +import com.iexec.sms.secret.web2.Web2Secret; +import com.iexec.sms.secret.web2.Web2SecretService; import com.iexec.sms.secret.web3.Web3Secret; import com.iexec.sms.secret.web3.Web3SecretService; import com.iexec.sms.tee.challenge.TeeChallenge; @@ -59,7 +59,7 @@ class SecretSessionBaseServiceTests { @Mock private Web3SecretService web3SecretService; @Mock - private Web2SecretsService web2SecretsService; + private Web2SecretService web2SecretService; @Mock private TeeChallengeService teeChallengeService; @Mock @@ -86,6 +86,7 @@ void beforeEach() { void shouldGetSecretsTokens() throws Exception { TaskDescription taskDescription = createTaskDescription(enclaveConfig); TeeSessionRequest request = createSessionRequest(taskDescription); + String beneficiary = request.getTaskDescription().getBeneficiary(); // pre when(preComputeProperties.getFingerprint()) @@ -94,16 +95,16 @@ void shouldGetSecretsTokens() throws Exception { when(web3SecretService.getSecret(DATASET_ADDRESS, true)) .thenReturn(Optional.of(secret)); // post - Secret publicKeySecret = new Secret("address", ENCRYPTION_PUBLIC_KEY, true); + Web2Secret publicKeySecret = new Web2Secret(beneficiary, "address", ENCRYPTION_PUBLIC_KEY, true); when(postComputeProperties.getFingerprint()) .thenReturn(POST_COMPUTE_FINGERPRINT); - when(web2SecretsService.getSecret( - request.getTaskDescription().getBeneficiary(), + when(web2SecretService.getSecret( + beneficiary, ReservedSecretKeyName.IEXEC_RESULT_ENCRYPTION_PUBLIC_KEY, true)) .thenReturn(Optional.of(publicKeySecret)); - Secret storageSecret = new Secret("address", STORAGE_TOKEN, true); - when(web2SecretsService.getSecret(taskDescription.getRequester(), + Web2Secret storageSecret = new Web2Secret(beneficiary, "address", STORAGE_TOKEN, true); + when(web2SecretService.getSecret(taskDescription.getRequester(), ReservedSecretKeyName.IEXEC_RESULT_IEXEC_IPFS_TOKEN, true)) .thenReturn(Optional.of(storageSecret)); TeeChallenge challenge = TeeChallenge.builder() @@ -390,17 +391,18 @@ void shouldGetPostComputeTokens() throws Exception { TeeSessionRequest request = createSessionRequest(createTaskDescription(enclaveConfig)); String requesterAddress = request.getTaskDescription().getRequester(); + String beneficiary = request.getTaskDescription().getBeneficiary(); - Secret publicKeySecret = new Secret("address", ENCRYPTION_PUBLIC_KEY, true); + Web2Secret publicKeySecret = new Web2Secret(beneficiary, "address", ENCRYPTION_PUBLIC_KEY, true); when(postComputeProperties.getFingerprint()) .thenReturn(POST_COMPUTE_FINGERPRINT); - when(web2SecretsService.getSecret( + when(web2SecretService.getSecret( request.getTaskDescription().getBeneficiary(), ReservedSecretKeyName.IEXEC_RESULT_ENCRYPTION_PUBLIC_KEY, true)) .thenReturn(Optional.of(publicKeySecret)); - Secret storageSecret = new Secret("address", STORAGE_TOKEN, true); - when(web2SecretsService.getSecret( + Web2Secret storageSecret = new Web2Secret(beneficiary, "address", STORAGE_TOKEN, true); + when(web2SecretService.getSecret( requesterAddress, ReservedSecretKeyName.IEXEC_RESULT_IEXEC_IPFS_TOKEN, true)) @@ -468,9 +470,9 @@ void shouldGetPostComputeStorageTokensOnIpfs() { final TaskDescription taskDescription = sessionRequest.getTaskDescription(); final String secretValue = "Secret value"; - when(web2SecretsService.getSecret(taskDescription.getRequester(), + when(web2SecretService.getSecret(taskDescription.getRequester(), ReservedSecretKeyName.IEXEC_RESULT_IEXEC_IPFS_TOKEN, true)) - .thenReturn(Optional.of(new Secret(null, secretValue, true))); + .thenReturn(Optional.of(new Web2Secret(null, null, secretValue, true))); final Map tokens = assertDoesNotThrow( () -> teeSecretsService.getPostComputeStorageTokens(sessionRequest)); @@ -491,9 +493,9 @@ void shouldGetPostComputeStorageTokensOnDropbox() { taskDescription.setResultStorageProvider(DealParams.DROPBOX_RESULT_STORAGE_PROVIDER); final String secretValue = "Secret value"; - when(web2SecretsService.getSecret(taskDescription.getRequester(), + when(web2SecretService.getSecret(taskDescription.getRequester(), ReservedSecretKeyName.IEXEC_RESULT_DROPBOX_TOKEN, true)) - .thenReturn(Optional.of(new Secret(null, secretValue, true))); + .thenReturn(Optional.of(new Web2Secret(null, null, secretValue, true))); final Map tokens = assertDoesNotThrow( () -> teeSecretsService.getPostComputeStorageTokens(sessionRequest)); @@ -512,7 +514,7 @@ void shouldNotGetPostComputeStorageTokensSinceNoSecret() { final TeeSessionRequest sessionRequest = createSessionRequest(createTaskDescription(enclaveConfig)); final TaskDescription taskDescription = sessionRequest.getTaskDescription(); - when(web2SecretsService.getSecret(taskDescription.getRequester(), + when(web2SecretService.getSecret(taskDescription.getRequester(), ReservedSecretKeyName.IEXEC_RESULT_IEXEC_IPFS_TOKEN, true)) .thenReturn(Optional.empty()); @@ -636,9 +638,10 @@ void shouldNotGetPostComputeSignTokensSinceNoEnclaveCredentialsPrivateKey() { void shouldGetPostComputeEncryptionTokensWithEncryption() { TeeSessionRequest request = createSessionRequest(createTaskDescription(enclaveConfig)); - Secret publicKeySecret = new Secret("address", ENCRYPTION_PUBLIC_KEY, true); - when(web2SecretsService.getSecret( - request.getTaskDescription().getBeneficiary(), + String beneficiary = request.getTaskDescription().getBeneficiary(); + Web2Secret publicKeySecret = new Web2Secret(beneficiary, "address", ENCRYPTION_PUBLIC_KEY, true); + when(web2SecretService.getSecret( + beneficiary, ReservedSecretKeyName.IEXEC_RESULT_ENCRYPTION_PUBLIC_KEY, true)) .thenReturn(Optional.of(publicKeySecret)); @@ -670,7 +673,7 @@ void shouldGetPostComputeEncryptionTokensWithoutEncryption() { void shouldNotGetPostComputeEncryptionTokensSinceEmptyBeneficiaryKey() { TeeSessionRequest request = createSessionRequest(createTaskDescription(enclaveConfig)); - when(web2SecretsService.getSecret( + when(web2SecretService.getSecret( request.getTaskDescription().getBeneficiary(), ReservedSecretKeyName.IEXEC_RESULT_ENCRYPTION_PUBLIC_KEY, true)) From 8dc671b310ed9c1b2bb2f7cfc0a08d78a0f28fdc Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Wed, 16 Nov 2022 10:01:51 +0100 Subject: [PATCH 204/293] Rename `newValue` into `newEncryptedValue` or `newDecryptedValue` depending on context --- .../java/com/iexec/sms/secret/web2/Web2Secret.java | 12 ++++++------ .../java/com/iexec/sms/secret/web3/Web3Secret.java | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/iexec/sms/secret/web2/Web2Secret.java b/src/main/java/com/iexec/sms/secret/web2/Web2Secret.java index f46f3519..efd0e2ab 100644 --- a/src/main/java/com/iexec/sms/secret/web2/Web2Secret.java +++ b/src/main/java/com/iexec/sms/secret/web2/Web2Secret.java @@ -45,24 +45,24 @@ public Web2Secret(String ownerAddress, String address, String value, boolean isE * Copies the current {@link Web2Secret} object, * while replacing the old value with a new encrypted value. * - * @param newValue Value to use for new object. + * @param newEncryptedValue Value to use for new object. * @return A new {@link Web2Secret} object with new value. */ @Override - public Web2Secret withEncryptedValue(String newValue) { - return new Web2Secret(this.getId(), this.getOwnerAddress(), this.getAddress(), newValue, true); + public Web2Secret withEncryptedValue(String newEncryptedValue) { + return new Web2Secret(this.getId(), this.getOwnerAddress(), this.getAddress(), newEncryptedValue, true); } /** * Copies the current {@link Web2Secret} object, * while replacing the old value with a new decrypted value. * - * @param newValue Value to use for new object. + * @param newDecryptedValue Value to use for new object. * @return A new {@link Web2Secret} object with new value. */ @Override - public Web2Secret withDecryptedValue(String newValue) { - return new Web2Secret(this.getId(), this.getOwnerAddress(), this.getAddress(), newValue, false); + public Web2Secret withDecryptedValue(String newDecryptedValue) { + return new Web2Secret(this.getId(), this.getOwnerAddress(), this.getAddress(), newDecryptedValue, false); } @Override diff --git a/src/main/java/com/iexec/sms/secret/web3/Web3Secret.java b/src/main/java/com/iexec/sms/secret/web3/Web3Secret.java index a2a32d27..e7ce3411 100644 --- a/src/main/java/com/iexec/sms/secret/web3/Web3Secret.java +++ b/src/main/java/com/iexec/sms/secret/web3/Web3Secret.java @@ -52,23 +52,23 @@ public Web3Secret(String address, String value, boolean isEncryptedValue) { * Copies the current {@link Web3Secret} object, * while replacing the old value with a new encrypted value. * - * @param newValue Value to use for new object. + * @param newEncryptedValue Value to use for new object. * @return A new {@link Web3Secret} object with new value. */ @Override - public Web3Secret withEncryptedValue(String newValue) { - return new Web3Secret(super.getId(), this.id, this.getAddress(), newValue, true); + public Web3Secret withEncryptedValue(String newEncryptedValue) { + return new Web3Secret(super.getId(), this.id, this.getAddress(), newEncryptedValue, true); } /** * Copies the current {@link Web3Secret} object, * while replacing the old value with a new decrypted value. * - * @param newValue Value to use for new object. + * @param newDecryptedValue Value to use for new object. * @return A new {@link Web3Secret} object with new value. */ @Override - public Web3Secret withDecryptedValue(String newValue) { - return new Web3Secret(super.getId(), this.id, this.getAddress(), newValue, false); + public Web3Secret withDecryptedValue(String newDecryptedValue) { + return new Web3Secret(super.getId(), this.id, this.getAddress(), newDecryptedValue, false); } } From ce8a7b8630773e5b1bd735fef1747b0b6c3b1ef3 Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Wed, 16 Nov 2022 14:56:58 +0100 Subject: [PATCH 205/293] Move Dockerfile to project root --- src/main/resources/Dockerfile => Dockerfile | 0 Jenkinsfile | 1 - build.gradle | 2 +- 3 files changed, 1 insertion(+), 2 deletions(-) rename src/main/resources/Dockerfile => Dockerfile (100%) diff --git a/src/main/resources/Dockerfile b/Dockerfile similarity index 100% rename from src/main/resources/Dockerfile rename to Dockerfile diff --git a/Jenkinsfile b/Jenkinsfile index 093ff6eb..b84818a4 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -9,7 +9,6 @@ buildJavaProject( integrationTestsEnvVars: [], shouldPublishJars: true, shouldPublishDockerImages: true, - dockerfileDir: 'build/resources/main', buildContext: '.', preDevelopVisibility: 'iex.ec', developVisibility: 'iex.ec', diff --git a/build.gradle b/build.gradle index 31ad42f0..87e0f93a 100644 --- a/build.gradle +++ b/build.gradle @@ -168,7 +168,7 @@ task buildImage(type: Exec) { group 'Build' description 'Builds an OCI image from a Dockerfile.' dependsOn bootJar - commandLine ('sh', '-c', "docker build -f build/resources/main/Dockerfile --build-arg jar=$jarPathForOCI" + commandLine ('sh', '-c', "docker build --build-arg jar=$jarPathForOCI" + " -t $ociImageName:$gitShortCommit . && docker tag $ociImageName:$gitShortCommit $ociImageName:dev") standardOutput = new ByteArrayOutputStream() From a3c2a3eb90f70570043d72a8093bd978863e331c Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Wed, 16 Nov 2022 15:15:08 +0100 Subject: [PATCH 206/293] Restore dockerfileDir configuration property in Jenkinsfile --- Jenkinsfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Jenkinsfile b/Jenkinsfile index b84818a4..27e229f5 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -9,6 +9,7 @@ buildJavaProject( integrationTestsEnvVars: [], shouldPublishJars: true, shouldPublishDockerImages: true, + dockerfileDir: '.', buildContext: '.', preDevelopVisibility: 'iex.ec', developVisibility: 'iex.ec', From 7db8cb1581803205f20b153b686836058870d26b Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Wed, 16 Nov 2022 17:24:38 +0100 Subject: [PATCH 207/293] Introduce `WebXSecretHeader` --- .../java/com/iexec/sms/secret/Secret.java | 70 ++----------------- .../com/iexec/sms/secret/web2/Web2Secret.java | 28 ++++---- .../sms/secret/web2/Web2SecretHeader.java | 36 ++++++++++ .../sms/secret/web2/Web2SecretRepository.java | 6 +- .../sms/secret/web2/Web2SecretService.java | 2 +- .../com/iexec/sms/secret/web3/Web3Secret.java | 29 +++----- .../sms/secret/web3/Web3SecretHeader.java | 35 ++++++++++ .../sms/secret/web3/Web3SecretRepository.java | 7 +- .../sms/secret/web3/Web3SecretService.java | 4 +- .../secret/web2/Web2SecretServiceTests.java | 45 ++++++------ .../sms/secret/web2/Web2SecretTests.java | 24 ++++--- .../secret/web3/Web3SecretServiceTests.java | 18 ++--- 12 files changed, 156 insertions(+), 148 deletions(-) create mode 100644 src/main/java/com/iexec/sms/secret/web2/Web2SecretHeader.java create mode 100644 src/main/java/com/iexec/sms/secret/web3/Web3SecretHeader.java diff --git a/src/main/java/com/iexec/sms/secret/Secret.java b/src/main/java/com/iexec/sms/secret/Secret.java index c81fd493..1b90984c 100644 --- a/src/main/java/com/iexec/sms/secret/Secret.java +++ b/src/main/java/com/iexec/sms/secret/Secret.java @@ -17,63 +17,27 @@ package com.iexec.sms.secret; import lombok.AccessLevel; -import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; -import org.hibernate.annotations.GenericGenerator; import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.Id; +import javax.persistence.MappedSuperclass; import java.util.Objects; -@Entity +@MappedSuperclass @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) -@AllArgsConstructor(access = AccessLevel.PROTECTED) -public class Secret { - - @Id - @GeneratedValue(generator = "system-uuid") - @GenericGenerator(name = "system-uuid", strategy = "uuid") - private String id; - - private String address; //0xdataset1, aws.amazon.com, beneficiary.key.iex.ec (Kb) +public abstract class Secret { @Column(columnDefinition = "LONGTEXT") private String value; private boolean isEncryptedValue; /* Clear secrets at construction */ - public Secret(String address, String value, boolean isEncryptedValue) { - this.address = address; + public Secret(String value, boolean isEncryptedValue) { this.value = value; this.isEncryptedValue = isEncryptedValue; } - /** - * Copies the current {@link Secret} object, - * while replacing the old value with a new encrypted value. - * - * @param newValue Value to use for new object. - * @return A new {@link Secret} object with new value. - */ - public Secret withEncryptedValue(String newValue) { - return new Secret(this.id, this.address, newValue, true); - } - - /** - * Copies the current {@link Secret} object, - * while replacing the old value with a new decrypted value. - * - * @param newValue Value to use for new object. - * @return A new {@link Secret} object with new value. - */ - public Secret withDecryptedValue(String newValue) { - return new Secret(this.id, this.address, newValue, false); - } - - /** * Get the secret value without possible leading or trailing * newline characters. This should be used when putting @@ -89,31 +53,5 @@ public String getTrimmedValue() { Objects.requireNonNull(this.value, "Secret value must not be null"); return this.value.trim(); } - - @Override - public String toString() { - return "Secret{" + - "id='" + id + '\'' + - ", address='" + address + '\'' + - ", value='" + (isEncryptedValue ? value : "") + '\'' + - ", isEncryptedValue=" + isEncryptedValue + - '}'; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - Secret secret = (Secret) o; - return isEncryptedValue == secret.isEncryptedValue - && Objects.equals(id, secret.id) - && Objects.equals(address, secret.address) - && Objects.equals(value, secret.value); - } - - @Override - public int hashCode() { - return Objects.hash(id, address, value, isEncryptedValue); - } } diff --git a/src/main/java/com/iexec/sms/secret/web2/Web2Secret.java b/src/main/java/com/iexec/sms/secret/web2/Web2Secret.java index f46f3519..90f31514 100644 --- a/src/main/java/com/iexec/sms/secret/web2/Web2Secret.java +++ b/src/main/java/com/iexec/sms/secret/web2/Web2Secret.java @@ -21,6 +21,7 @@ import com.iexec.sms.secret.Secret; import lombok.*; +import javax.persistence.EmbeddedId; import javax.persistence.Entity; import java.util.Objects; @@ -29,16 +30,17 @@ @NoArgsConstructor(access = AccessLevel.PRIVATE) @AllArgsConstructor(access = AccessLevel.PRIVATE) public class Web2Secret extends Secret { - private String ownerAddress; + @EmbeddedId + private Web2SecretHeader header; - Web2Secret(String id, String ownerAddress, String address, String value, boolean isEncryptedValue) { - super(id, address, value, isEncryptedValue); - this.ownerAddress = ownerAddress; + public Web2Secret(String ownerAddress, String address, String value, boolean isEncryptedValue) { + super(value, isEncryptedValue); + this.header = new Web2SecretHeader(ownerAddress, address); } - public Web2Secret(String ownerAddress, String address, String value, boolean isEncryptedValue) { - super(address, value, isEncryptedValue); - this.ownerAddress = ownerAddress; + public Web2Secret(Web2SecretHeader header, String value, boolean isEncryptedValue) { + super(value, isEncryptedValue); + this.header = header; } /** @@ -48,9 +50,8 @@ public Web2Secret(String ownerAddress, String address, String value, boolean isE * @param newValue Value to use for new object. * @return A new {@link Web2Secret} object with new value. */ - @Override public Web2Secret withEncryptedValue(String newValue) { - return new Web2Secret(this.getId(), this.getOwnerAddress(), this.getAddress(), newValue, true); + return new Web2Secret(this.getHeader(), newValue, true); } /** @@ -60,9 +61,8 @@ public Web2Secret withEncryptedValue(String newValue) { * @param newValue Value to use for new object. * @return A new {@link Web2Secret} object with new value. */ - @Override public Web2Secret withDecryptedValue(String newValue) { - return new Web2Secret(this.getId(), this.getOwnerAddress(), this.getAddress(), newValue, false); + return new Web2Secret(this.getHeader(), newValue, false); } @Override @@ -70,12 +70,12 @@ public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; if (!super.equals(o)) return false; - Web2Secret that = (Web2Secret) o; - return Objects.equals(ownerAddress, that.ownerAddress); + final Web2Secret that = (Web2Secret) o; + return Objects.equals(header, that.header); } @Override public int hashCode() { - return Objects.hash(super.hashCode(), ownerAddress); + return Objects.hash(super.hashCode(), header); } } diff --git a/src/main/java/com/iexec/sms/secret/web2/Web2SecretHeader.java b/src/main/java/com/iexec/sms/secret/web2/Web2SecretHeader.java new file mode 100644 index 00000000..9100f2ac --- /dev/null +++ b/src/main/java/com/iexec/sms/secret/web2/Web2SecretHeader.java @@ -0,0 +1,36 @@ +/* + * + * * Copyright 2022 IEXEC BLOCKCHAIN TECH + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * + */ + +package com.iexec.sms.secret.web2; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import javax.persistence.Embeddable; +import java.io.Serializable; + +@Embeddable +@Getter +@NoArgsConstructor(access = AccessLevel.PRIVATE) +@AllArgsConstructor(access = AccessLevel.PACKAGE) +public class Web2SecretHeader implements Serializable { + private String ownerAddress; + private String address; //0xdataset1, aws.amazon.com, beneficiary.key.iex.ec (Kb) +} diff --git a/src/main/java/com/iexec/sms/secret/web2/Web2SecretRepository.java b/src/main/java/com/iexec/sms/secret/web2/Web2SecretRepository.java index 923cfd04..c003909d 100644 --- a/src/main/java/com/iexec/sms/secret/web2/Web2SecretRepository.java +++ b/src/main/java/com/iexec/sms/secret/web2/Web2SecretRepository.java @@ -23,5 +23,9 @@ import java.util.Optional; public interface Web2SecretRepository extends CrudRepository { - Optional findByOwnerAddressAndAddressAllIgnoreCase(String ownerAddress, String address); + Optional findByHeader(Web2SecretHeader header); + + default Optional find(String ownerAddress, String address) { + return findByHeader(new Web2SecretHeader(ownerAddress.toLowerCase(), address.toLowerCase())); + } } diff --git a/src/main/java/com/iexec/sms/secret/web2/Web2SecretService.java b/src/main/java/com/iexec/sms/secret/web2/Web2SecretService.java index d3c0e2e4..cfe8c495 100644 --- a/src/main/java/com/iexec/sms/secret/web2/Web2SecretService.java +++ b/src/main/java/com/iexec/sms/secret/web2/Web2SecretService.java @@ -38,7 +38,7 @@ protected Web2SecretService(EncryptionService encryptionService, } public Optional getSecret(String ownerAddress, String secretAddress) { - return web2SecretRepository.findByOwnerAddressAndAddressAllIgnoreCase(ownerAddress, secretAddress); + return web2SecretRepository.find(ownerAddress, secretAddress); } public Optional getSecret(String ownerAddress, String secretAddress, boolean shouldDecryptValue) { diff --git a/src/main/java/com/iexec/sms/secret/web3/Web3Secret.java b/src/main/java/com/iexec/sms/secret/web3/Web3Secret.java index a2a32d27..c6d25171 100644 --- a/src/main/java/com/iexec/sms/secret/web3/Web3Secret.java +++ b/src/main/java/com/iexec/sms/secret/web3/Web3Secret.java @@ -21,31 +21,26 @@ import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; -import org.hibernate.annotations.GenericGenerator; +import javax.persistence.EmbeddedId; import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.Id; @Entity @Getter @NoArgsConstructor(access = AccessLevel.PACKAGE) @AllArgsConstructor(access = AccessLevel.PRIVATE) public class Web3Secret extends Secret { + @EmbeddedId + private Web3SecretHeader header; - // TODO: remove this duplicate `id` field - @Id - @GeneratedValue(generator = "system-uuid") - @GenericGenerator(name = "system-uuid", strategy = "uuid") - private String id; - - private Web3Secret(String superId, String id, String address, String value, boolean isEncryptedValue) { - super(superId, address, value, isEncryptedValue); - this.id = id; + public Web3Secret(String address, String value, boolean isEncryptedValue) { + super(value, isEncryptedValue); + this.header = new Web3SecretHeader(address); } - public Web3Secret(String address, String value, boolean isEncryptedValue) { - super(address, value, isEncryptedValue); + public Web3Secret(Web3SecretHeader header, String value, boolean isEncryptedValue) { + super(value, isEncryptedValue); + this.header = header; } /** @@ -55,9 +50,8 @@ public Web3Secret(String address, String value, boolean isEncryptedValue) { * @param newValue Value to use for new object. * @return A new {@link Web3Secret} object with new value. */ - @Override public Web3Secret withEncryptedValue(String newValue) { - return new Web3Secret(super.getId(), this.id, this.getAddress(), newValue, true); + return new Web3Secret(header, newValue, true); } /** @@ -67,8 +61,7 @@ public Web3Secret withEncryptedValue(String newValue) { * @param newValue Value to use for new object. * @return A new {@link Web3Secret} object with new value. */ - @Override public Web3Secret withDecryptedValue(String newValue) { - return new Web3Secret(super.getId(), this.id, this.getAddress(), newValue, false); + return new Web3Secret(header, newValue, false); } } diff --git a/src/main/java/com/iexec/sms/secret/web3/Web3SecretHeader.java b/src/main/java/com/iexec/sms/secret/web3/Web3SecretHeader.java new file mode 100644 index 00000000..8cb9f01a --- /dev/null +++ b/src/main/java/com/iexec/sms/secret/web3/Web3SecretHeader.java @@ -0,0 +1,35 @@ +/* + * + * * Copyright 2022 IEXEC BLOCKCHAIN TECH + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * + */ + +package com.iexec.sms.secret.web3; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import javax.persistence.Embeddable; +import java.io.Serializable; + +@Embeddable +@Getter +@NoArgsConstructor(access = AccessLevel.PRIVATE) +@AllArgsConstructor(access = AccessLevel.PACKAGE) +public class Web3SecretHeader implements Serializable { + private String address; +} diff --git a/src/main/java/com/iexec/sms/secret/web3/Web3SecretRepository.java b/src/main/java/com/iexec/sms/secret/web3/Web3SecretRepository.java index 9b2d39c5..5fefae3c 100644 --- a/src/main/java/com/iexec/sms/secret/web3/Web3SecretRepository.java +++ b/src/main/java/com/iexec/sms/secret/web3/Web3SecretRepository.java @@ -16,13 +16,14 @@ package com.iexec.sms.secret.web3; - import org.springframework.data.repository.CrudRepository; import java.util.Optional; public interface Web3SecretRepository extends CrudRepository { + Optional findByHeader(Web3SecretHeader header); - Optional findWeb3SecretByAddress(String secretAddress); - + default Optional find(String secretAddress) { + return findByHeader(new Web3SecretHeader(secretAddress.toLowerCase())); + } } diff --git a/src/main/java/com/iexec/sms/secret/web3/Web3SecretService.java b/src/main/java/com/iexec/sms/secret/web3/Web3SecretService.java index 392065ef..78594881 100644 --- a/src/main/java/com/iexec/sms/secret/web3/Web3SecretService.java +++ b/src/main/java/com/iexec/sms/secret/web3/Web3SecretService.java @@ -38,7 +38,7 @@ public Web3SecretService(Web3SecretRepository web3SecretRepository, public Optional getSecret(String secretAddress) { secretAddress = secretAddress.toLowerCase(); - return web3SecretRepository.findWeb3SecretByAddress(secretAddress); + return web3SecretRepository.find(secretAddress); } public Optional getSecret(String secretAddress, boolean shouldDecryptValue) { @@ -61,7 +61,7 @@ public Optional getSecret(String secretAddress, boolean shouldDecryp public boolean addSecret(String secretAddress, String secretValue) { secretAddress = secretAddress.toLowerCase(); - if (web3SecretRepository.findWeb3SecretByAddress(secretAddress).isPresent()) { + if (web3SecretRepository.find(secretAddress).isPresent()) { log.error("Secret already exists [secretAddress:{}]", secretAddress); return false; } diff --git a/src/test/java/com/iexec/sms/secret/web2/Web2SecretServiceTests.java b/src/test/java/com/iexec/sms/secret/web2/Web2SecretServiceTests.java index 776b6c73..33017dd0 100644 --- a/src/test/java/com/iexec/sms/secret/web2/Web2SecretServiceTests.java +++ b/src/test/java/com/iexec/sms/secret/web2/Web2SecretServiceTests.java @@ -19,7 +19,6 @@ package com.iexec.sms.secret.web2; import com.iexec.sms.encryption.EncryptionService; -import com.iexec.sms.secret.Secret; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.InjectMocks; @@ -33,7 +32,6 @@ import static org.mockito.Mockito.*; class Web2SecretServiceTests { - private static final String ID = "id"; private static final String OWNER_ADDRESS = "ownerAddress"; private static final String SECRET_ADDRESS = "secretAddress"; private static final String PLAIN_SECRET_VALUE = "plainSecretValue"; @@ -58,7 +56,7 @@ void beforeEach() { void shouldGetDecryptedSecret() { final Web2Secret encryptedSecret = new Web2Secret(OWNER_ADDRESS, SECRET_ADDRESS, ENCRYPTED_SECRET_VALUE, true); - when(web2SecretRepository.findByOwnerAddressAndAddressAllIgnoreCase(OWNER_ADDRESS, SECRET_ADDRESS)) + when(web2SecretRepository.find(OWNER_ADDRESS, SECRET_ADDRESS)) .thenReturn(Optional.of(encryptedSecret)); when(encryptionService.decrypt(ENCRYPTED_SECRET_VALUE)) .thenReturn(PLAIN_SECRET_VALUE); @@ -66,9 +64,9 @@ void shouldGetDecryptedSecret() { final Optional result = web2SecretService.getSecret(OWNER_ADDRESS, SECRET_ADDRESS, true); assertThat(result).isNotEmpty(); assertAll( - () -> assertThat(result).get().extracting(Secret::getAddress).isEqualTo(SECRET_ADDRESS), - () -> assertThat(result).get().extracting(Secret::getValue).isEqualTo(PLAIN_SECRET_VALUE), - () -> assertThat(result).get().extracting(Secret::isEncryptedValue).isEqualTo(false) + () -> assertThat(result).get().extracting(Web2Secret::getHeader).usingRecursiveComparison().isEqualTo(new Web2SecretHeader(OWNER_ADDRESS, SECRET_ADDRESS)), + () -> assertThat(result).get().extracting(Web2Secret::getValue).isEqualTo(PLAIN_SECRET_VALUE), + () -> assertThat(result).get().extracting(Web2Secret::isEncryptedValue).isEqualTo(false) ); } @@ -76,7 +74,7 @@ void shouldGetDecryptedSecret() { void shouldGetEncryptedSecret() { final Web2Secret encryptedSecret = new Web2Secret(OWNER_ADDRESS, SECRET_ADDRESS, ENCRYPTED_SECRET_VALUE, true); - when(web2SecretRepository.findByOwnerAddressAndAddressAllIgnoreCase(OWNER_ADDRESS, SECRET_ADDRESS)) + when(web2SecretRepository.find(OWNER_ADDRESS, SECRET_ADDRESS)) .thenReturn(Optional.of(encryptedSecret)); final Optional oSecret1 = web2SecretService.getSecret(OWNER_ADDRESS, SECRET_ADDRESS); @@ -84,22 +82,22 @@ void shouldGetEncryptedSecret() { assertThat(oSecret1).isNotEmpty(); assertAll( () -> assertThat(oSecret1).isEqualTo(oSecret2), - () -> assertThat(oSecret1).get().extracting(Secret::getAddress).isEqualTo(SECRET_ADDRESS), - () -> assertThat(oSecret1).get().extracting(Secret::getValue).isEqualTo(ENCRYPTED_SECRET_VALUE), - () -> assertThat(oSecret1).get().extracting(Secret::isEncryptedValue).isEqualTo(true), + () -> assertThat(oSecret1).get().extracting(Web2Secret::getHeader).usingRecursiveComparison().isEqualTo(new Web2SecretHeader(OWNER_ADDRESS, SECRET_ADDRESS)), + () -> assertThat(oSecret1).get().extracting(Web2Secret::getValue).isEqualTo(ENCRYPTED_SECRET_VALUE), + () -> assertThat(oSecret1).get().extracting(Web2Secret::isEncryptedValue).isEqualTo(true), () -> verifyNoInteractions(encryptionService) ); } @Test void shouldGetEmptyResultIfSecretNotPresent() { - when(web2SecretRepository.findByOwnerAddressAndAddressAllIgnoreCase(OWNER_ADDRESS, SECRET_ADDRESS)) + when(web2SecretRepository.find(OWNER_ADDRESS, SECRET_ADDRESS)) .thenReturn(Optional.empty()); assertThat(web2SecretService.getSecret(OWNER_ADDRESS, SECRET_ADDRESS)).isEmpty(); assertThat(web2SecretService.getSecret(OWNER_ADDRESS, SECRET_ADDRESS, false)).isEmpty(); verify(web2SecretRepository, times(2)) - .findByOwnerAddressAndAddressAllIgnoreCase(OWNER_ADDRESS, SECRET_ADDRESS); + .find(OWNER_ADDRESS, SECRET_ADDRESS); verifyNoInteractions(encryptionService); } // endregion @@ -107,17 +105,16 @@ void shouldGetEmptyResultIfSecretNotPresent() { // region addSecret @Test void shouldAddSecret() throws SecretAlreadyExistsException { - when(web2SecretRepository.findByOwnerAddressAndAddressAllIgnoreCase(OWNER_ADDRESS, SECRET_ADDRESS)) + when(web2SecretRepository.find(OWNER_ADDRESS, SECRET_ADDRESS)) .thenReturn(Optional.empty()); when(encryptionService.encrypt(PLAIN_SECRET_VALUE)).thenReturn(ENCRYPTED_SECRET_VALUE); - when(web2SecretRepository.save(any())).thenReturn(new Web2Secret(ID, OWNER_ADDRESS, SECRET_ADDRESS, ENCRYPTED_SECRET_VALUE, true)); + when(web2SecretRepository.save(any())).thenReturn(new Web2Secret(OWNER_ADDRESS, SECRET_ADDRESS, ENCRYPTED_SECRET_VALUE, true)); final Web2Secret newSecret = web2SecretService.addSecret(OWNER_ADDRESS, SECRET_ADDRESS, PLAIN_SECRET_VALUE); assertAll( - () -> assertThat(newSecret).extracting(Secret::getId).isEqualTo(ID), - () -> assertThat(newSecret).extracting(Secret::getAddress).isEqualTo(SECRET_ADDRESS), - () -> assertThat(newSecret).extracting(Secret::getValue).isEqualTo(ENCRYPTED_SECRET_VALUE), - () -> assertThat(newSecret).extracting(Secret::isEncryptedValue).isEqualTo(true), + () -> assertThat(newSecret).extracting(Web2Secret::getHeader).usingRecursiveComparison().isEqualTo(new Web2SecretHeader(OWNER_ADDRESS, SECRET_ADDRESS)), + () -> assertThat(newSecret).extracting(Web2Secret::getValue).isEqualTo(ENCRYPTED_SECRET_VALUE), + () -> assertThat(newSecret).extracting(Web2Secret::isEncryptedValue).isEqualTo(true), () -> verify(encryptionService).encrypt(any()), () -> verify(web2SecretRepository).save(any()) @@ -126,8 +123,8 @@ void shouldAddSecret() throws SecretAlreadyExistsException { @Test void shouldNotAddSecretIfPresent() { - final Web2Secret secret = new Web2Secret(ID, OWNER_ADDRESS, SECRET_ADDRESS, ENCRYPTED_SECRET_VALUE, true); - when(web2SecretRepository.findByOwnerAddressAndAddressAllIgnoreCase(OWNER_ADDRESS, SECRET_ADDRESS)) + final Web2Secret secret = new Web2Secret(OWNER_ADDRESS, SECRET_ADDRESS, ENCRYPTED_SECRET_VALUE, true); + when(web2SecretRepository.find(OWNER_ADDRESS, SECRET_ADDRESS)) .thenReturn(Optional.of(secret)); final SecretAlreadyExistsException exception = assertThrows(SecretAlreadyExistsException.class, @@ -151,15 +148,13 @@ void shouldUpdateSecret() throws NotAnExistingSecretException, SameSecretExcepti .thenReturn(Optional.of(encryptedSecret)); when(encryptionService.encrypt(newSecretValue)) .thenReturn(newEncryptedSecretValue); - final Web2Secret savedSecret = new Web2Secret(ID, OWNER_ADDRESS, SECRET_ADDRESS, newEncryptedSecretValue, true); + final Web2Secret savedSecret = new Web2Secret(OWNER_ADDRESS, SECRET_ADDRESS, newEncryptedSecretValue, true); when(web2SecretRepository.save(any())) .thenReturn(savedSecret); final Web2Secret newSecret = web2SecretService.updateSecret(OWNER_ADDRESS, SECRET_ADDRESS, newSecretValue); assertAll( - () -> assertThat(newSecret).extracting(Web2Secret::getId).isEqualTo(ID), - () -> assertThat(newSecret).extracting(Web2Secret::getOwnerAddress).isEqualTo(OWNER_ADDRESS), - () -> assertThat(newSecret).extracting(Web2Secret::getAddress).isEqualTo(SECRET_ADDRESS), + () -> assertThat(newSecret).extracting(Web2Secret::getHeader).usingRecursiveComparison().isEqualTo(new Web2SecretHeader(OWNER_ADDRESS, SECRET_ADDRESS)), () -> assertThat(newSecret).extracting(Web2Secret::getValue).isEqualTo(newEncryptedSecretValue), () -> assertThat(newSecret).extracting(Web2Secret::isEncryptedValue).isEqualTo(true), @@ -170,7 +165,7 @@ void shouldUpdateSecret() throws NotAnExistingSecretException, SameSecretExcepti @Test void shouldNotUpdateSecretIfMissing() { - when(web2SecretRepository.findByOwnerAddressAndAddressAllIgnoreCase(OWNER_ADDRESS, SECRET_ADDRESS)) + when(web2SecretRepository.find(OWNER_ADDRESS, SECRET_ADDRESS)) .thenReturn(Optional.empty()); final NotAnExistingSecretException exception = assertThrows(NotAnExistingSecretException.class, diff --git a/src/test/java/com/iexec/sms/secret/web2/Web2SecretTests.java b/src/test/java/com/iexec/sms/secret/web2/Web2SecretTests.java index 6319b025..4e001e80 100644 --- a/src/test/java/com/iexec/sms/secret/web2/Web2SecretTests.java +++ b/src/test/java/com/iexec/sms/secret/web2/Web2SecretTests.java @@ -18,29 +18,35 @@ package com.iexec.sms.secret.web2; +import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; - class Web2SecretTests { - private static final String ID = "id"; private static final String OWNER_ADDRESS = "ownerAddress"; private static final String SECRET_ADDRESS = "secretAddress"; private static final String UNENCRYPTED_VALUE = "unencrypted value"; private static final String ENCRYPTED_VALUE = "encrypted value"; - private static final Web2Secret UNENCRYPTED_SECRET = new Web2Secret(ID, OWNER_ADDRESS, SECRET_ADDRESS, UNENCRYPTED_VALUE, false); - private static final Web2Secret ENCRYPTED_SECRET = new Web2Secret(ID, OWNER_ADDRESS, SECRET_ADDRESS, ENCRYPTED_VALUE, true); + private static final Web2Secret UNENCRYPTED_SECRET = new Web2Secret(OWNER_ADDRESS, SECRET_ADDRESS, UNENCRYPTED_VALUE, false); + private static final Web2Secret ENCRYPTED_SECRET = new Web2Secret(OWNER_ADDRESS, SECRET_ADDRESS, ENCRYPTED_VALUE, true); @Test void withEncryptedValue() { - assertEquals(ENCRYPTED_SECRET, UNENCRYPTED_SECRET.withEncryptedValue(ENCRYPTED_VALUE)); - assertEquals(ENCRYPTED_SECRET, ENCRYPTED_SECRET.withEncryptedValue(ENCRYPTED_VALUE)); + Assertions.assertThat(UNENCRYPTED_SECRET.withEncryptedValue(ENCRYPTED_VALUE)) + .usingRecursiveComparison() + .isEqualTo(ENCRYPTED_SECRET); + Assertions.assertThat(ENCRYPTED_SECRET.withEncryptedValue(ENCRYPTED_VALUE)) + .usingRecursiveComparison() + .isEqualTo(ENCRYPTED_SECRET); } @Test void withDecryptedValue() { - assertEquals(UNENCRYPTED_SECRET, ENCRYPTED_SECRET.withDecryptedValue(UNENCRYPTED_VALUE)); - assertEquals(UNENCRYPTED_SECRET, UNENCRYPTED_SECRET.withDecryptedValue(UNENCRYPTED_VALUE)); + Assertions.assertThat(ENCRYPTED_SECRET.withDecryptedValue(UNENCRYPTED_VALUE)) + .usingRecursiveComparison() + .isEqualTo(UNENCRYPTED_SECRET); + Assertions.assertThat(UNENCRYPTED_SECRET.withDecryptedValue(UNENCRYPTED_VALUE)) + .usingRecursiveComparison() + .isEqualTo(UNENCRYPTED_SECRET); } } diff --git a/src/test/java/com/iexec/sms/secret/web3/Web3SecretServiceTests.java b/src/test/java/com/iexec/sms/secret/web3/Web3SecretServiceTests.java index fea48d42..cf2af59b 100644 --- a/src/test/java/com/iexec/sms/secret/web3/Web3SecretServiceTests.java +++ b/src/test/java/com/iexec/sms/secret/web3/Web3SecretServiceTests.java @@ -50,7 +50,7 @@ void init() { @Test void shouldNotAddSecretIfPresent() { Web3Secret web3Secret = new Web3Secret(secretAddress, encryptedSecretValue, true); - when(web3SecretRepository.findWeb3SecretByAddress(secretAddress)).thenReturn(Optional.of(web3Secret)); + when(web3SecretRepository.find(secretAddress)).thenReturn(Optional.of(web3Secret)); assertThat(web3SecretService.addSecret(secretAddress, plainSecretValue)).isFalse(); verifyNoInteractions(encryptionService); verify(web3SecretRepository, never()).save(any()); @@ -58,7 +58,7 @@ void shouldNotAddSecretIfPresent() { @Test void shouldAddSecret() { - when(web3SecretRepository.findWeb3SecretByAddress(secretAddress)).thenReturn(Optional.empty()); + when(web3SecretRepository.find(secretAddress)).thenReturn(Optional.empty()); when(encryptionService.encrypt(plainSecretValue)).thenReturn(encryptedSecretValue); assertThat(web3SecretService.addSecret(secretAddress, plainSecretValue)).isTrue(); verify(encryptionService).encrypt(any()); @@ -68,38 +68,38 @@ void shouldAddSecret() { @Test void shouldGetDecryptedSecret() { Web3Secret encryptedSecret = new Web3Secret(secretAddress, encryptedSecretValue, true); - when(web3SecretRepository.findWeb3SecretByAddress(secretAddress)).thenReturn(Optional.of(encryptedSecret)); + when(web3SecretRepository.find(secretAddress)).thenReturn(Optional.of(encryptedSecret)); when(encryptionService.decrypt(encryptedSecretValue)).thenReturn(plainSecretValue); Optional result = web3SecretService.getSecret(secretAddress, true); assertThat(result).isPresent(); - assertThat(result).get().extracting(Web3Secret::getAddress).isEqualTo(secretAddress); + assertThat(result).get().extracting(Web3Secret::getHeader).usingRecursiveComparison().isEqualTo(new Web3SecretHeader(secretAddress)); assertThat(result).get().extracting(Web3Secret::getValue).isEqualTo(plainSecretValue); assertThat(result).get().extracting(Web3Secret::isEncryptedValue).isEqualTo(false); - verify(web3SecretRepository).findWeb3SecretByAddress(secretAddress); + verify(web3SecretRepository).find(secretAddress); verify(encryptionService).decrypt(any()); } @Test void shouldGetEncryptedSecret() { Web3Secret encryptedSecret = new Web3Secret(secretAddress, encryptedSecretValue, true); - when(web3SecretRepository.findWeb3SecretByAddress(secretAddress)).thenReturn(Optional.of(encryptedSecret)); + when(web3SecretRepository.find(secretAddress)).thenReturn(Optional.of(encryptedSecret)); Optional oSecret1 = web3SecretService.getSecret(secretAddress, false); Optional oSecret2 = web3SecretService.getSecret(secretAddress); assertThat(oSecret1) .contains(encryptedSecret) .isEqualTo(oSecret2); - verify(web3SecretRepository, times(2)).findWeb3SecretByAddress(secretAddress); + verify(web3SecretRepository, times(2)).find(secretAddress); verifyNoInteractions(encryptionService); } @Test void shouldGetEmptyResultIfSecretNotPresent() { - when(web3SecretRepository.findWeb3SecretByAddress(secretAddress)).thenReturn(Optional.empty()); + when(web3SecretRepository.find(secretAddress)).thenReturn(Optional.empty()); assertThat(web3SecretService.getSecret(secretAddress)).isEmpty(); assertThat(web3SecretService.getSecret(secretAddress, false)).isEmpty(); - verify(web3SecretRepository, times(2)).findWeb3SecretByAddress(secretAddress); + verify(web3SecretRepository, times(2)).find(secretAddress); verifyNoInteractions(encryptionService); } From ba22aeb39cd017455b6233099adda8e39519bbf9 Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Wed, 16 Nov 2022 17:41:01 +0100 Subject: [PATCH 208/293] Remove spacing in Dockerfile --- Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 1911f97b..f861ef89 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,8 +4,8 @@ ARG jar RUN test -n "$jar" -COPY $jar /app/iexec-sms.jar +COPY $jar /app/iexec-sms.jar -COPY src/main/resources/ssl-keystore-dev.p12 /app/ssl-keystore-dev.p12 +COPY src/main/resources/ssl-keystore-dev.p12 /app/ssl-keystore-dev.p12 ENTRYPOINT [ "/bin/sh", "-c", "java -jar /app/iexec-sms.jar" ] From daa1757670ea98d19e36f33c24804fba15d58775 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Thu, 17 Nov 2022 16:18:09 +0100 Subject: [PATCH 209/293] Remove unused `equals` & `hashcode` methods --- .../com/iexec/sms/secret/web2/Web2Secret.java | 20 ++++--------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/iexec/sms/secret/web2/Web2Secret.java b/src/main/java/com/iexec/sms/secret/web2/Web2Secret.java index 98c1dd95..2df5d0d7 100644 --- a/src/main/java/com/iexec/sms/secret/web2/Web2Secret.java +++ b/src/main/java/com/iexec/sms/secret/web2/Web2Secret.java @@ -19,11 +19,13 @@ package com.iexec.sms.secret.web2; import com.iexec.sms.secret.Secret; -import lombok.*; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; import javax.persistence.EmbeddedId; import javax.persistence.Entity; -import java.util.Objects; @Entity @Getter @@ -64,18 +66,4 @@ public Web2Secret withEncryptedValue(String newEncryptedValue) { public Web2Secret withDecryptedValue(String newDecryptedValue) { return new Web2Secret(this.getHeader(), newDecryptedValue, false); } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - if (!super.equals(o)) return false; - final Web2Secret that = (Web2Secret) o; - return Objects.equals(header, that.header); - } - - @Override - public int hashCode() { - return Objects.hash(super.hashCode(), header); - } } From a27dec31ba9ba4e755d2ce9aeeba457a46e05594 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Fri, 18 Nov 2022 09:31:39 +0100 Subject: [PATCH 210/293] Remove `.toLowerCase()` from `Web2SecretRepository.find()` method + move `.toLowerCase` to `Web3SecretHeader` --- .../com/iexec/sms/secret/web2/Web2SecretRepository.java | 2 +- .../java/com/iexec/sms/secret/web3/Web3SecretHeader.java | 6 ++++-- .../com/iexec/sms/secret/web3/Web3SecretRepository.java | 2 +- .../java/com/iexec/sms/secret/web3/Web3SecretService.java | 4 ---- .../java/com/iexec/sms/secret/web2/Web2SecretTests.java | 4 ++-- 5 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/iexec/sms/secret/web2/Web2SecretRepository.java b/src/main/java/com/iexec/sms/secret/web2/Web2SecretRepository.java index c003909d..9880e951 100644 --- a/src/main/java/com/iexec/sms/secret/web2/Web2SecretRepository.java +++ b/src/main/java/com/iexec/sms/secret/web2/Web2SecretRepository.java @@ -26,6 +26,6 @@ public interface Web2SecretRepository extends CrudRepository Optional findByHeader(Web2SecretHeader header); default Optional find(String ownerAddress, String address) { - return findByHeader(new Web2SecretHeader(ownerAddress.toLowerCase(), address.toLowerCase())); + return findByHeader(new Web2SecretHeader(ownerAddress, address)); } } diff --git a/src/main/java/com/iexec/sms/secret/web3/Web3SecretHeader.java b/src/main/java/com/iexec/sms/secret/web3/Web3SecretHeader.java index 8cb9f01a..ceb00215 100644 --- a/src/main/java/com/iexec/sms/secret/web3/Web3SecretHeader.java +++ b/src/main/java/com/iexec/sms/secret/web3/Web3SecretHeader.java @@ -19,7 +19,6 @@ package com.iexec.sms.secret.web3; import lombok.AccessLevel; -import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; @@ -29,7 +28,10 @@ @Embeddable @Getter @NoArgsConstructor(access = AccessLevel.PRIVATE) -@AllArgsConstructor(access = AccessLevel.PACKAGE) public class Web3SecretHeader implements Serializable { private String address; + + Web3SecretHeader(String address) { + this.address = address.toLowerCase(); + } } diff --git a/src/main/java/com/iexec/sms/secret/web3/Web3SecretRepository.java b/src/main/java/com/iexec/sms/secret/web3/Web3SecretRepository.java index 5fefae3c..e3f3f20b 100644 --- a/src/main/java/com/iexec/sms/secret/web3/Web3SecretRepository.java +++ b/src/main/java/com/iexec/sms/secret/web3/Web3SecretRepository.java @@ -24,6 +24,6 @@ public interface Web3SecretRepository extends CrudRepository Optional findByHeader(Web3SecretHeader header); default Optional find(String secretAddress) { - return findByHeader(new Web3SecretHeader(secretAddress.toLowerCase())); + return findByHeader(new Web3SecretHeader(secretAddress)); } } diff --git a/src/main/java/com/iexec/sms/secret/web3/Web3SecretService.java b/src/main/java/com/iexec/sms/secret/web3/Web3SecretService.java index 78594881..f66c73b6 100644 --- a/src/main/java/com/iexec/sms/secret/web3/Web3SecretService.java +++ b/src/main/java/com/iexec/sms/secret/web3/Web3SecretService.java @@ -37,12 +37,10 @@ public Web3SecretService(Web3SecretRepository web3SecretRepository, } public Optional getSecret(String secretAddress) { - secretAddress = secretAddress.toLowerCase(); return web3SecretRepository.find(secretAddress); } public Optional getSecret(String secretAddress, boolean shouldDecryptValue) { - secretAddress = secretAddress.toLowerCase(); Optional oSecret = getSecret(secretAddress); if (oSecret.isEmpty()) { return Optional.empty(); @@ -59,8 +57,6 @@ public Optional getSecret(String secretAddress, boolean shouldDecryp * Stores encrypted secrets * */ public boolean addSecret(String secretAddress, String secretValue) { - secretAddress = secretAddress.toLowerCase(); - if (web3SecretRepository.find(secretAddress).isPresent()) { log.error("Secret already exists [secretAddress:{}]", secretAddress); return false; diff --git a/src/test/java/com/iexec/sms/secret/web2/Web2SecretTests.java b/src/test/java/com/iexec/sms/secret/web2/Web2SecretTests.java index 4e001e80..1b01b937 100644 --- a/src/test/java/com/iexec/sms/secret/web2/Web2SecretTests.java +++ b/src/test/java/com/iexec/sms/secret/web2/Web2SecretTests.java @@ -25,8 +25,8 @@ class Web2SecretTests { private static final String OWNER_ADDRESS = "ownerAddress"; private static final String SECRET_ADDRESS = "secretAddress"; - private static final String UNENCRYPTED_VALUE = "unencrypted value"; - private static final String ENCRYPTED_VALUE = "encrypted value"; + private static final String UNENCRYPTED_VALUE = "unencryptedValue"; + private static final String ENCRYPTED_VALUE = "encryptedValue"; private static final Web2Secret UNENCRYPTED_SECRET = new Web2Secret(OWNER_ADDRESS, SECRET_ADDRESS, UNENCRYPTED_VALUE, false); private static final Web2Secret ENCRYPTED_SECRET = new Web2Secret(OWNER_ADDRESS, SECRET_ADDRESS, ENCRYPTED_VALUE, true); From 2895c6ef793446e7c7da492a6b87bc170f7c4c80 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Fri, 18 Nov 2022 14:19:46 +0100 Subject: [PATCH 211/293] Changed `Secret` constructor visibility --- src/main/java/com/iexec/sms/secret/Secret.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/iexec/sms/secret/Secret.java b/src/main/java/com/iexec/sms/secret/Secret.java index 1b90984c..7be615c2 100644 --- a/src/main/java/com/iexec/sms/secret/Secret.java +++ b/src/main/java/com/iexec/sms/secret/Secret.java @@ -17,6 +17,7 @@ package com.iexec.sms.secret; import lombok.AccessLevel; +import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; @@ -27,17 +28,12 @@ @MappedSuperclass @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor(access = AccessLevel.PROTECTED) public abstract class Secret { @Column(columnDefinition = "LONGTEXT") private String value; private boolean isEncryptedValue; - /* Clear secrets at construction */ - public Secret(String value, boolean isEncryptedValue) { - this.value = value; - this.isEncryptedValue = isEncryptedValue; - } - /** * Get the secret value without possible leading or trailing * newline characters. This should be used when putting From 17a590bbe5fa28301883a5017cbac2031a5c9570 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Fri, 18 Nov 2022 14:21:08 +0100 Subject: [PATCH 212/293] Defer Web2 & Web3 secret constructors to a single one --- src/main/java/com/iexec/sms/secret/web2/Web2Secret.java | 3 +-- src/main/java/com/iexec/sms/secret/web3/Web3Secret.java | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/iexec/sms/secret/web2/Web2Secret.java b/src/main/java/com/iexec/sms/secret/web2/Web2Secret.java index 2df5d0d7..04cf77ce 100644 --- a/src/main/java/com/iexec/sms/secret/web2/Web2Secret.java +++ b/src/main/java/com/iexec/sms/secret/web2/Web2Secret.java @@ -36,8 +36,7 @@ public class Web2Secret extends Secret { private Web2SecretHeader header; public Web2Secret(String ownerAddress, String address, String value, boolean isEncryptedValue) { - super(value, isEncryptedValue); - this.header = new Web2SecretHeader(ownerAddress, address); + this(new Web2SecretHeader(ownerAddress, address), value, isEncryptedValue); } public Web2Secret(Web2SecretHeader header, String value, boolean isEncryptedValue) { diff --git a/src/main/java/com/iexec/sms/secret/web3/Web3Secret.java b/src/main/java/com/iexec/sms/secret/web3/Web3Secret.java index 251c3b2f..1eb3d239 100644 --- a/src/main/java/com/iexec/sms/secret/web3/Web3Secret.java +++ b/src/main/java/com/iexec/sms/secret/web3/Web3Secret.java @@ -34,8 +34,7 @@ public class Web3Secret extends Secret { private Web3SecretHeader header; public Web3Secret(String address, String value, boolean isEncryptedValue) { - super(value, isEncryptedValue); - this.header = new Web3SecretHeader(address); + this(new Web3SecretHeader(address), value, isEncryptedValue); } public Web3Secret(Web3SecretHeader header, String value, boolean isEncryptedValue) { From 9e0e25ddf1284532e8dffd3da038f5333a85a186 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Fri, 18 Nov 2022 14:24:29 +0100 Subject: [PATCH 213/293] Use `WebXSecretHeader` as declared ID classes for `WebXSecretRepository`s --- .../java/com/iexec/sms/secret/web2/Web2SecretHeader.java | 3 +-- .../com/iexec/sms/secret/web2/Web2SecretRepository.java | 8 +++++--- .../java/com/iexec/sms/secret/web3/Web3SecretHeader.java | 3 +-- .../com/iexec/sms/secret/web3/Web3SecretRepository.java | 8 +++++--- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/iexec/sms/secret/web2/Web2SecretHeader.java b/src/main/java/com/iexec/sms/secret/web2/Web2SecretHeader.java index 9100f2ac..b782ad39 100644 --- a/src/main/java/com/iexec/sms/secret/web2/Web2SecretHeader.java +++ b/src/main/java/com/iexec/sms/secret/web2/Web2SecretHeader.java @@ -24,13 +24,12 @@ import lombok.NoArgsConstructor; import javax.persistence.Embeddable; -import java.io.Serializable; @Embeddable @Getter @NoArgsConstructor(access = AccessLevel.PRIVATE) @AllArgsConstructor(access = AccessLevel.PACKAGE) -public class Web2SecretHeader implements Serializable { +public class Web2SecretHeader { private String ownerAddress; private String address; //0xdataset1, aws.amazon.com, beneficiary.key.iex.ec (Kb) } diff --git a/src/main/java/com/iexec/sms/secret/web2/Web2SecretRepository.java b/src/main/java/com/iexec/sms/secret/web2/Web2SecretRepository.java index 9880e951..b74c52c8 100644 --- a/src/main/java/com/iexec/sms/secret/web2/Web2SecretRepository.java +++ b/src/main/java/com/iexec/sms/secret/web2/Web2SecretRepository.java @@ -18,14 +18,16 @@ package com.iexec.sms.secret.web2; +import org.jetbrains.annotations.NotNull; import org.springframework.data.repository.CrudRepository; import java.util.Optional; -public interface Web2SecretRepository extends CrudRepository { - Optional findByHeader(Web2SecretHeader header); +public interface Web2SecretRepository extends CrudRepository { + @NotNull + Optional findById(@NotNull Web2SecretHeader header); default Optional find(String ownerAddress, String address) { - return findByHeader(new Web2SecretHeader(ownerAddress, address)); + return findById(new Web2SecretHeader(ownerAddress, address)); } } diff --git a/src/main/java/com/iexec/sms/secret/web3/Web3SecretHeader.java b/src/main/java/com/iexec/sms/secret/web3/Web3SecretHeader.java index ceb00215..49443044 100644 --- a/src/main/java/com/iexec/sms/secret/web3/Web3SecretHeader.java +++ b/src/main/java/com/iexec/sms/secret/web3/Web3SecretHeader.java @@ -23,12 +23,11 @@ import lombok.NoArgsConstructor; import javax.persistence.Embeddable; -import java.io.Serializable; @Embeddable @Getter @NoArgsConstructor(access = AccessLevel.PRIVATE) -public class Web3SecretHeader implements Serializable { +public class Web3SecretHeader { private String address; Web3SecretHeader(String address) { diff --git a/src/main/java/com/iexec/sms/secret/web3/Web3SecretRepository.java b/src/main/java/com/iexec/sms/secret/web3/Web3SecretRepository.java index e3f3f20b..2a4b89c1 100644 --- a/src/main/java/com/iexec/sms/secret/web3/Web3SecretRepository.java +++ b/src/main/java/com/iexec/sms/secret/web3/Web3SecretRepository.java @@ -16,14 +16,16 @@ package com.iexec.sms.secret.web3; +import org.jetbrains.annotations.NotNull; import org.springframework.data.repository.CrudRepository; import java.util.Optional; -public interface Web3SecretRepository extends CrudRepository { - Optional findByHeader(Web3SecretHeader header); +public interface Web3SecretRepository extends CrudRepository { + @NotNull + Optional findById(@NotNull Web3SecretHeader header); default Optional find(String secretAddress) { - return findByHeader(new Web3SecretHeader(secretAddress)); + return findById(new Web3SecretHeader(secretAddress)); } } From 4b09776dc7a277d5c0616b8b952f159388494d43 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Fri, 18 Nov 2022 14:59:48 +0100 Subject: [PATCH 214/293] Set protected `WebXSecretHeader` no-args constructor --- src/main/java/com/iexec/sms/secret/web2/Web2SecretHeader.java | 2 +- src/main/java/com/iexec/sms/secret/web3/Web3SecretHeader.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/iexec/sms/secret/web2/Web2SecretHeader.java b/src/main/java/com/iexec/sms/secret/web2/Web2SecretHeader.java index b782ad39..4b66c995 100644 --- a/src/main/java/com/iexec/sms/secret/web2/Web2SecretHeader.java +++ b/src/main/java/com/iexec/sms/secret/web2/Web2SecretHeader.java @@ -27,7 +27,7 @@ @Embeddable @Getter -@NoArgsConstructor(access = AccessLevel.PRIVATE) +@NoArgsConstructor(access = AccessLevel.PROTECTED) @AllArgsConstructor(access = AccessLevel.PACKAGE) public class Web2SecretHeader { private String ownerAddress; diff --git a/src/main/java/com/iexec/sms/secret/web3/Web3SecretHeader.java b/src/main/java/com/iexec/sms/secret/web3/Web3SecretHeader.java index 49443044..28fc1d85 100644 --- a/src/main/java/com/iexec/sms/secret/web3/Web3SecretHeader.java +++ b/src/main/java/com/iexec/sms/secret/web3/Web3SecretHeader.java @@ -26,7 +26,7 @@ @Embeddable @Getter -@NoArgsConstructor(access = AccessLevel.PRIVATE) +@NoArgsConstructor(access = AccessLevel.PROTECTED) public class Web3SecretHeader { private String address; From b6cafb5efe2a024fdd5043f91041071566d56b16 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Fri, 18 Nov 2022 15:13:20 +0100 Subject: [PATCH 215/293] Remove useless overriden method --- .../java/com/iexec/sms/secret/web2/Web2SecretRepository.java | 4 ---- .../java/com/iexec/sms/secret/web3/Web3SecretRepository.java | 4 ---- 2 files changed, 8 deletions(-) diff --git a/src/main/java/com/iexec/sms/secret/web2/Web2SecretRepository.java b/src/main/java/com/iexec/sms/secret/web2/Web2SecretRepository.java index b74c52c8..44fe243a 100644 --- a/src/main/java/com/iexec/sms/secret/web2/Web2SecretRepository.java +++ b/src/main/java/com/iexec/sms/secret/web2/Web2SecretRepository.java @@ -18,15 +18,11 @@ package com.iexec.sms.secret.web2; -import org.jetbrains.annotations.NotNull; import org.springframework.data.repository.CrudRepository; import java.util.Optional; public interface Web2SecretRepository extends CrudRepository { - @NotNull - Optional findById(@NotNull Web2SecretHeader header); - default Optional find(String ownerAddress, String address) { return findById(new Web2SecretHeader(ownerAddress, address)); } diff --git a/src/main/java/com/iexec/sms/secret/web3/Web3SecretRepository.java b/src/main/java/com/iexec/sms/secret/web3/Web3SecretRepository.java index 2a4b89c1..ba7c1f11 100644 --- a/src/main/java/com/iexec/sms/secret/web3/Web3SecretRepository.java +++ b/src/main/java/com/iexec/sms/secret/web3/Web3SecretRepository.java @@ -16,15 +16,11 @@ package com.iexec.sms.secret.web3; -import org.jetbrains.annotations.NotNull; import org.springframework.data.repository.CrudRepository; import java.util.Optional; public interface Web3SecretRepository extends CrudRepository { - @NotNull - Optional findById(@NotNull Web3SecretHeader header); - default Optional find(String secretAddress) { return findById(new Web3SecretHeader(secretAddress)); } From 12e876ef97f029a3dc82c827781d5b22601f3d35 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Fri, 18 Nov 2022 15:15:07 +0100 Subject: [PATCH 216/293] Fix miscellaneous things --- src/main/java/com/iexec/sms/secret/web2/Web2Secret.java | 2 +- src/main/java/com/iexec/sms/secret/web2/Web2SecretHeader.java | 4 +++- src/main/java/com/iexec/sms/secret/web3/Web3Secret.java | 2 +- src/main/java/com/iexec/sms/secret/web3/Web3SecretHeader.java | 4 +++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/iexec/sms/secret/web2/Web2Secret.java b/src/main/java/com/iexec/sms/secret/web2/Web2Secret.java index 04cf77ce..d9f68137 100644 --- a/src/main/java/com/iexec/sms/secret/web2/Web2Secret.java +++ b/src/main/java/com/iexec/sms/secret/web2/Web2Secret.java @@ -29,7 +29,7 @@ @Entity @Getter -@NoArgsConstructor(access = AccessLevel.PRIVATE) +@NoArgsConstructor(access = AccessLevel.PROTECTED) @AllArgsConstructor(access = AccessLevel.PRIVATE) public class Web2Secret extends Secret { @EmbeddedId diff --git a/src/main/java/com/iexec/sms/secret/web2/Web2SecretHeader.java b/src/main/java/com/iexec/sms/secret/web2/Web2SecretHeader.java index 4b66c995..30bc4bef 100644 --- a/src/main/java/com/iexec/sms/secret/web2/Web2SecretHeader.java +++ b/src/main/java/com/iexec/sms/secret/web2/Web2SecretHeader.java @@ -24,12 +24,14 @@ import lombok.NoArgsConstructor; import javax.persistence.Embeddable; +import java.io.Serializable; @Embeddable @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) @AllArgsConstructor(access = AccessLevel.PACKAGE) -public class Web2SecretHeader { +public class Web2SecretHeader implements Serializable { + private static final long serialVersionUID = -6126999592529129002L; private String ownerAddress; private String address; //0xdataset1, aws.amazon.com, beneficiary.key.iex.ec (Kb) } diff --git a/src/main/java/com/iexec/sms/secret/web3/Web3Secret.java b/src/main/java/com/iexec/sms/secret/web3/Web3Secret.java index 1eb3d239..a082700f 100644 --- a/src/main/java/com/iexec/sms/secret/web3/Web3Secret.java +++ b/src/main/java/com/iexec/sms/secret/web3/Web3Secret.java @@ -27,7 +27,7 @@ @Entity @Getter -@NoArgsConstructor(access = AccessLevel.PACKAGE) +@NoArgsConstructor(access = AccessLevel.PROTECTED) @AllArgsConstructor(access = AccessLevel.PRIVATE) public class Web3Secret extends Secret { @EmbeddedId diff --git a/src/main/java/com/iexec/sms/secret/web3/Web3SecretHeader.java b/src/main/java/com/iexec/sms/secret/web3/Web3SecretHeader.java index 28fc1d85..fb9b6bb5 100644 --- a/src/main/java/com/iexec/sms/secret/web3/Web3SecretHeader.java +++ b/src/main/java/com/iexec/sms/secret/web3/Web3SecretHeader.java @@ -23,11 +23,13 @@ import lombok.NoArgsConstructor; import javax.persistence.Embeddable; +import java.io.Serializable; @Embeddable @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) -public class Web3SecretHeader { +public class Web3SecretHeader implements Serializable { + private static final long serialVersionUID = -6181164795694317827L; private String address; Web3SecretHeader(String address) { From a6e3dd1850eb5a9e3f091ed12feff957d8dc884e Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Fri, 18 Nov 2022 15:31:51 +0100 Subject: [PATCH 217/293] Standardize syntax --- src/main/java/com/iexec/sms/secret/web2/Web2Secret.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/iexec/sms/secret/web2/Web2Secret.java b/src/main/java/com/iexec/sms/secret/web2/Web2Secret.java index d9f68137..564d2ee1 100644 --- a/src/main/java/com/iexec/sms/secret/web2/Web2Secret.java +++ b/src/main/java/com/iexec/sms/secret/web2/Web2Secret.java @@ -52,7 +52,7 @@ public Web2Secret(Web2SecretHeader header, String value, boolean isEncryptedValu * @return A new {@link Web2Secret} object with new value. */ public Web2Secret withEncryptedValue(String newEncryptedValue) { - return new Web2Secret(this.getHeader(), newEncryptedValue, true); + return new Web2Secret(header, newEncryptedValue, true); } /** @@ -63,6 +63,6 @@ public Web2Secret withEncryptedValue(String newEncryptedValue) { * @return A new {@link Web2Secret} object with new value. */ public Web2Secret withDecryptedValue(String newDecryptedValue) { - return new Web2Secret(this.getHeader(), newDecryptedValue, false); + return new Web2Secret(header, newDecryptedValue, false); } } From 1157f62e9ab28cd0bb4fb02dea2b141ebda323a0 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Thu, 24 Nov 2022 14:16:06 +0100 Subject: [PATCH 218/293] Add protected constructor to `Web2SecretHeader` to lower fields + require non-null addresses for secrets headers --- .../com/iexec/sms/secret/web2/Web2SecretHeader.java | 11 +++++++++-- .../com/iexec/sms/secret/web3/Web3SecretHeader.java | 3 +++ .../iexec/sms/tee/session/TeeSessionTestUtils.java | 2 ++ .../session/base/SecretSessionBaseServiceTests.java | 7 +++++-- 4 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/iexec/sms/secret/web2/Web2SecretHeader.java b/src/main/java/com/iexec/sms/secret/web2/Web2SecretHeader.java index 30bc4bef..ffc84e4c 100644 --- a/src/main/java/com/iexec/sms/secret/web2/Web2SecretHeader.java +++ b/src/main/java/com/iexec/sms/secret/web2/Web2SecretHeader.java @@ -19,19 +19,26 @@ package com.iexec.sms.secret.web2; import lombok.AccessLevel; -import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import javax.persistence.Embeddable; import java.io.Serializable; +import java.util.Objects; @Embeddable @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) -@AllArgsConstructor(access = AccessLevel.PACKAGE) public class Web2SecretHeader implements Serializable { private static final long serialVersionUID = -6126999592529129002L; private String ownerAddress; private String address; //0xdataset1, aws.amazon.com, beneficiary.key.iex.ec (Kb) + + Web2SecretHeader(String ownerAddress, String address) { + Objects.requireNonNull(ownerAddress, "Web2 secret owner address can't be null."); + Objects.requireNonNull(address, "Web2 secret address can't be null."); + + this.ownerAddress = ownerAddress.toLowerCase(); + this.address = address.toLowerCase(); + } } diff --git a/src/main/java/com/iexec/sms/secret/web3/Web3SecretHeader.java b/src/main/java/com/iexec/sms/secret/web3/Web3SecretHeader.java index fb9b6bb5..1cfdf569 100644 --- a/src/main/java/com/iexec/sms/secret/web3/Web3SecretHeader.java +++ b/src/main/java/com/iexec/sms/secret/web3/Web3SecretHeader.java @@ -24,6 +24,7 @@ import javax.persistence.Embeddable; import java.io.Serializable; +import java.util.Objects; @Embeddable @Getter @@ -33,6 +34,8 @@ public class Web3SecretHeader implements Serializable { private String address; Web3SecretHeader(String address) { + Objects.requireNonNull(address, "Web3 secret address can't be null."); + this.address = address.toLowerCase(); } } diff --git a/src/test/java/com/iexec/sms/tee/session/TeeSessionTestUtils.java b/src/test/java/com/iexec/sms/tee/session/TeeSessionTestUtils.java index d17bde7c..c2a84225 100644 --- a/src/test/java/com/iexec/sms/tee/session/TeeSessionTestUtils.java +++ b/src/test/java/com/iexec/sms/tee/session/TeeSessionTestUtils.java @@ -112,6 +112,7 @@ public static TeeSessionRequest createSessionRequest(TaskDescription taskDescrip public static TaskDescription createTaskDescription(TeeEnclaveConfiguration enclaveConfig) { String appAddress = createEthereumAddress(); String requesterAddress = createEthereumAddress(); + String beneficiaryAddress = createEthereumAddress(); return TaskDescription.builder() .chainTaskId(TASK_ID) .appUri(APP_URI) @@ -122,6 +123,7 @@ public static TaskDescription createTaskDescription(TeeEnclaveConfiguration encl .datasetName(DATASET_NAME) .datasetChecksum(DATASET_CHECKSUM) .requester(requesterAddress) + .beneficiary(beneficiaryAddress) .cmd(ARGS) .inputFiles(List.of(INPUT_FILE_URL_1, INPUT_FILE_URL_2)) .isResultEncryption(true) diff --git a/src/test/java/com/iexec/sms/tee/session/base/SecretSessionBaseServiceTests.java b/src/test/java/com/iexec/sms/tee/session/base/SecretSessionBaseServiceTests.java index fd171564..fa3be8e0 100644 --- a/src/test/java/com/iexec/sms/tee/session/base/SecretSessionBaseServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/base/SecretSessionBaseServiceTests.java @@ -468,11 +468,12 @@ void shouldGetPostComputeStorageTokensWithCallback() { void shouldGetPostComputeStorageTokensOnIpfs() { final TeeSessionRequest sessionRequest = createSessionRequest(createTaskDescription(enclaveConfig)); final TaskDescription taskDescription = sessionRequest.getTaskDescription(); + final String beneficiaryAddress = taskDescription.getAppAddress(); final String secretValue = "Secret value"; when(web2SecretService.getSecret(taskDescription.getRequester(), ReservedSecretKeyName.IEXEC_RESULT_IEXEC_IPFS_TOKEN, true)) - .thenReturn(Optional.of(new Web2Secret(null, null, secretValue, true))); + .thenReturn(Optional.of(new Web2Secret(beneficiaryAddress, "address", secretValue, true))); final Map tokens = assertDoesNotThrow( () -> teeSecretsService.getPostComputeStorageTokens(sessionRequest)); @@ -492,10 +493,12 @@ void shouldGetPostComputeStorageTokensOnDropbox() { final TaskDescription taskDescription = sessionRequest.getTaskDescription(); taskDescription.setResultStorageProvider(DealParams.DROPBOX_RESULT_STORAGE_PROVIDER); + final String beneficiaryAddress = taskDescription.getAppAddress(); + final String secretValue = "Secret value"; when(web2SecretService.getSecret(taskDescription.getRequester(), ReservedSecretKeyName.IEXEC_RESULT_DROPBOX_TOKEN, true)) - .thenReturn(Optional.of(new Web2Secret(null, null, secretValue, true))); + .thenReturn(Optional.of(new Web2Secret(beneficiaryAddress, "address", secretValue, true))); final Map tokens = assertDoesNotThrow( () -> teeSecretsService.getPostComputeStorageTokens(sessionRequest)); From 84733ee4b4bcfaeb38eb82c671a8aab8f5a2494c Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Mon, 5 Dec 2022 14:13:47 +0100 Subject: [PATCH 219/293] Remove unused public visibility --- src/main/java/com/iexec/sms/secret/web2/Web2Secret.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/iexec/sms/secret/web2/Web2Secret.java b/src/main/java/com/iexec/sms/secret/web2/Web2Secret.java index 564d2ee1..a3636293 100644 --- a/src/main/java/com/iexec/sms/secret/web2/Web2Secret.java +++ b/src/main/java/com/iexec/sms/secret/web2/Web2Secret.java @@ -39,7 +39,7 @@ public Web2Secret(String ownerAddress, String address, String value, boolean isE this(new Web2SecretHeader(ownerAddress, address), value, isEncryptedValue); } - public Web2Secret(Web2SecretHeader header, String value, boolean isEncryptedValue) { + Web2Secret(Web2SecretHeader header, String value, boolean isEncryptedValue) { super(value, isEncryptedValue); this.header = header; } From 0db7faedc3bc7ef5ff2e21ba6455b186c9cf310a Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Mon, 5 Dec 2022 14:44:00 +0100 Subject: [PATCH 220/293] Set visibility of `WebXSecret` constructor to private when possible --- src/main/java/com/iexec/sms/secret/web2/Web2Secret.java | 2 +- src/main/java/com/iexec/sms/secret/web3/Web3Secret.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/iexec/sms/secret/web2/Web2Secret.java b/src/main/java/com/iexec/sms/secret/web2/Web2Secret.java index a3636293..7f676d15 100644 --- a/src/main/java/com/iexec/sms/secret/web2/Web2Secret.java +++ b/src/main/java/com/iexec/sms/secret/web2/Web2Secret.java @@ -39,7 +39,7 @@ public Web2Secret(String ownerAddress, String address, String value, boolean isE this(new Web2SecretHeader(ownerAddress, address), value, isEncryptedValue); } - Web2Secret(Web2SecretHeader header, String value, boolean isEncryptedValue) { + private Web2Secret(Web2SecretHeader header, String value, boolean isEncryptedValue) { super(value, isEncryptedValue); this.header = header; } diff --git a/src/main/java/com/iexec/sms/secret/web3/Web3Secret.java b/src/main/java/com/iexec/sms/secret/web3/Web3Secret.java index a082700f..b3bcab06 100644 --- a/src/main/java/com/iexec/sms/secret/web3/Web3Secret.java +++ b/src/main/java/com/iexec/sms/secret/web3/Web3Secret.java @@ -37,7 +37,7 @@ public Web3Secret(String address, String value, boolean isEncryptedValue) { this(new Web3SecretHeader(address), value, isEncryptedValue); } - public Web3Secret(Web3SecretHeader header, String value, boolean isEncryptedValue) { + private Web3Secret(Web3SecretHeader header, String value, boolean isEncryptedValue) { super(value, isEncryptedValue); this.header = header; } From 81250a12472400f92869e014b114d10a1eee8cce Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Mon, 5 Dec 2022 14:54:46 +0100 Subject: [PATCH 221/293] Remove unused constructors --- src/main/java/com/iexec/sms/secret/web2/Web2Secret.java | 2 -- src/main/java/com/iexec/sms/secret/web3/Web3Secret.java | 2 -- 2 files changed, 4 deletions(-) diff --git a/src/main/java/com/iexec/sms/secret/web2/Web2Secret.java b/src/main/java/com/iexec/sms/secret/web2/Web2Secret.java index 7f676d15..fba015d9 100644 --- a/src/main/java/com/iexec/sms/secret/web2/Web2Secret.java +++ b/src/main/java/com/iexec/sms/secret/web2/Web2Secret.java @@ -20,7 +20,6 @@ import com.iexec.sms.secret.Secret; import lombok.AccessLevel; -import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; @@ -30,7 +29,6 @@ @Entity @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) -@AllArgsConstructor(access = AccessLevel.PRIVATE) public class Web2Secret extends Secret { @EmbeddedId private Web2SecretHeader header; diff --git a/src/main/java/com/iexec/sms/secret/web3/Web3Secret.java b/src/main/java/com/iexec/sms/secret/web3/Web3Secret.java index b3bcab06..e2decf2c 100644 --- a/src/main/java/com/iexec/sms/secret/web3/Web3Secret.java +++ b/src/main/java/com/iexec/sms/secret/web3/Web3Secret.java @@ -18,7 +18,6 @@ import com.iexec.sms.secret.Secret; import lombok.AccessLevel; -import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; @@ -28,7 +27,6 @@ @Entity @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) -@AllArgsConstructor(access = AccessLevel.PRIVATE) public class Web3Secret extends Secret { @EmbeddedId private Web3SecretHeader header; From a16d5c847f93e6ef6e0f3e68015849527106a6af Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Mon, 5 Dec 2022 15:17:24 +0100 Subject: [PATCH 222/293] Remove default methods in `WebXSecretRepository`s --- .../sms/secret/web2/Web2SecretRepository.java | 6 +----- .../sms/secret/web2/Web2SecretService.java | 2 +- .../sms/secret/web3/Web3SecretRepository.java | 6 +----- .../sms/secret/web3/Web3SecretService.java | 4 ++-- .../secret/web2/Web2SecretServiceTests.java | 20 ++++++++++--------- .../secret/web3/Web3SecretServiceTests.java | 16 +++++++-------- 6 files changed, 24 insertions(+), 30 deletions(-) diff --git a/src/main/java/com/iexec/sms/secret/web2/Web2SecretRepository.java b/src/main/java/com/iexec/sms/secret/web2/Web2SecretRepository.java index 44fe243a..cbeacde1 100644 --- a/src/main/java/com/iexec/sms/secret/web2/Web2SecretRepository.java +++ b/src/main/java/com/iexec/sms/secret/web2/Web2SecretRepository.java @@ -20,10 +20,6 @@ import org.springframework.data.repository.CrudRepository; -import java.util.Optional; - public interface Web2SecretRepository extends CrudRepository { - default Optional find(String ownerAddress, String address) { - return findById(new Web2SecretHeader(ownerAddress, address)); - } + } diff --git a/src/main/java/com/iexec/sms/secret/web2/Web2SecretService.java b/src/main/java/com/iexec/sms/secret/web2/Web2SecretService.java index cfe8c495..f6cea2a4 100644 --- a/src/main/java/com/iexec/sms/secret/web2/Web2SecretService.java +++ b/src/main/java/com/iexec/sms/secret/web2/Web2SecretService.java @@ -38,7 +38,7 @@ protected Web2SecretService(EncryptionService encryptionService, } public Optional getSecret(String ownerAddress, String secretAddress) { - return web2SecretRepository.find(ownerAddress, secretAddress); + return web2SecretRepository.findById(new Web2SecretHeader(ownerAddress, secretAddress)); } public Optional getSecret(String ownerAddress, String secretAddress, boolean shouldDecryptValue) { diff --git a/src/main/java/com/iexec/sms/secret/web3/Web3SecretRepository.java b/src/main/java/com/iexec/sms/secret/web3/Web3SecretRepository.java index ba7c1f11..6a23e496 100644 --- a/src/main/java/com/iexec/sms/secret/web3/Web3SecretRepository.java +++ b/src/main/java/com/iexec/sms/secret/web3/Web3SecretRepository.java @@ -18,10 +18,6 @@ import org.springframework.data.repository.CrudRepository; -import java.util.Optional; - public interface Web3SecretRepository extends CrudRepository { - default Optional find(String secretAddress) { - return findById(new Web3SecretHeader(secretAddress)); - } + } diff --git a/src/main/java/com/iexec/sms/secret/web3/Web3SecretService.java b/src/main/java/com/iexec/sms/secret/web3/Web3SecretService.java index f66c73b6..9b5fafed 100644 --- a/src/main/java/com/iexec/sms/secret/web3/Web3SecretService.java +++ b/src/main/java/com/iexec/sms/secret/web3/Web3SecretService.java @@ -37,7 +37,7 @@ public Web3SecretService(Web3SecretRepository web3SecretRepository, } public Optional getSecret(String secretAddress) { - return web3SecretRepository.find(secretAddress); + return web3SecretRepository.findById(new Web3SecretHeader(secretAddress)); } public Optional getSecret(String secretAddress, boolean shouldDecryptValue) { @@ -57,7 +57,7 @@ public Optional getSecret(String secretAddress, boolean shouldDecryp * Stores encrypted secrets * */ public boolean addSecret(String secretAddress, String secretValue) { - if (web3SecretRepository.find(secretAddress).isPresent()) { + if (getSecret(secretAddress).isPresent()) { log.error("Secret already exists [secretAddress:{}]", secretAddress); return false; } diff --git a/src/test/java/com/iexec/sms/secret/web2/Web2SecretServiceTests.java b/src/test/java/com/iexec/sms/secret/web2/Web2SecretServiceTests.java index 33017dd0..49eb6bcd 100644 --- a/src/test/java/com/iexec/sms/secret/web2/Web2SecretServiceTests.java +++ b/src/test/java/com/iexec/sms/secret/web2/Web2SecretServiceTests.java @@ -24,6 +24,7 @@ import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.mockito.Spy; import java.util.Optional; @@ -44,6 +45,7 @@ class Web2SecretServiceTests { private EncryptionService encryptionService; @InjectMocks + @Spy private Web2SecretService web2SecretService; @BeforeEach @@ -56,7 +58,7 @@ void beforeEach() { void shouldGetDecryptedSecret() { final Web2Secret encryptedSecret = new Web2Secret(OWNER_ADDRESS, SECRET_ADDRESS, ENCRYPTED_SECRET_VALUE, true); - when(web2SecretRepository.find(OWNER_ADDRESS, SECRET_ADDRESS)) + when(web2SecretRepository.findById(any(Web2SecretHeader.class))) .thenReturn(Optional.of(encryptedSecret)); when(encryptionService.decrypt(ENCRYPTED_SECRET_VALUE)) .thenReturn(PLAIN_SECRET_VALUE); @@ -74,7 +76,7 @@ void shouldGetDecryptedSecret() { void shouldGetEncryptedSecret() { final Web2Secret encryptedSecret = new Web2Secret(OWNER_ADDRESS, SECRET_ADDRESS, ENCRYPTED_SECRET_VALUE, true); - when(web2SecretRepository.find(OWNER_ADDRESS, SECRET_ADDRESS)) + when(web2SecretRepository.findById(any(Web2SecretHeader.class))) .thenReturn(Optional.of(encryptedSecret)); final Optional oSecret1 = web2SecretService.getSecret(OWNER_ADDRESS, SECRET_ADDRESS); @@ -91,13 +93,13 @@ void shouldGetEncryptedSecret() { @Test void shouldGetEmptyResultIfSecretNotPresent() { - when(web2SecretRepository.find(OWNER_ADDRESS, SECRET_ADDRESS)) + when(web2SecretRepository.findById(any(Web2SecretHeader.class))) .thenReturn(Optional.empty()); assertThat(web2SecretService.getSecret(OWNER_ADDRESS, SECRET_ADDRESS)).isEmpty(); assertThat(web2SecretService.getSecret(OWNER_ADDRESS, SECRET_ADDRESS, false)).isEmpty(); verify(web2SecretRepository, times(2)) - .find(OWNER_ADDRESS, SECRET_ADDRESS); + .findById(any(Web2SecretHeader.class)); verifyNoInteractions(encryptionService); } // endregion @@ -105,7 +107,7 @@ void shouldGetEmptyResultIfSecretNotPresent() { // region addSecret @Test void shouldAddSecret() throws SecretAlreadyExistsException { - when(web2SecretRepository.find(OWNER_ADDRESS, SECRET_ADDRESS)) + when(web2SecretRepository.findById(any(Web2SecretHeader.class))) .thenReturn(Optional.empty()); when(encryptionService.encrypt(PLAIN_SECRET_VALUE)).thenReturn(ENCRYPTED_SECRET_VALUE); when(web2SecretRepository.save(any())).thenReturn(new Web2Secret(OWNER_ADDRESS, SECRET_ADDRESS, ENCRYPTED_SECRET_VALUE, true)); @@ -124,7 +126,7 @@ void shouldAddSecret() throws SecretAlreadyExistsException { @Test void shouldNotAddSecretIfPresent() { final Web2Secret secret = new Web2Secret(OWNER_ADDRESS, SECRET_ADDRESS, ENCRYPTED_SECRET_VALUE, true); - when(web2SecretRepository.find(OWNER_ADDRESS, SECRET_ADDRESS)) + when(web2SecretRepository.findById(any(Web2SecretHeader.class))) .thenReturn(Optional.of(secret)); final SecretAlreadyExistsException exception = assertThrows(SecretAlreadyExistsException.class, @@ -144,7 +146,7 @@ void shouldUpdateSecret() throws NotAnExistingSecretException, SameSecretExcepti final Web2Secret encryptedSecret = new Web2Secret(OWNER_ADDRESS, SECRET_ADDRESS, ENCRYPTED_SECRET_VALUE, true); final String newSecretValue = "newSecretValue"; final String newEncryptedSecretValue = "newEncryptedSecretValue"; - when(web2SecretService.getSecret(OWNER_ADDRESS, SECRET_ADDRESS)) + when(web2SecretRepository.findById(any(Web2SecretHeader.class))) .thenReturn(Optional.of(encryptedSecret)); when(encryptionService.encrypt(newSecretValue)) .thenReturn(newEncryptedSecretValue); @@ -165,7 +167,7 @@ void shouldUpdateSecret() throws NotAnExistingSecretException, SameSecretExcepti @Test void shouldNotUpdateSecretIfMissing() { - when(web2SecretRepository.find(OWNER_ADDRESS, SECRET_ADDRESS)) + when(web2SecretRepository.findById(any(Web2SecretHeader.class))) .thenReturn(Optional.empty()); final NotAnExistingSecretException exception = assertThrows(NotAnExistingSecretException.class, @@ -180,7 +182,7 @@ void shouldNotUpdateSecretIfMissing() { @Test void shouldNotUpdateSecretIfSameValue() { final Web2Secret encryptedSecret = new Web2Secret(OWNER_ADDRESS, SECRET_ADDRESS, ENCRYPTED_SECRET_VALUE, true); - when(web2SecretService.getSecret(OWNER_ADDRESS, SECRET_ADDRESS)) + when(web2SecretRepository.findById(any(Web2SecretHeader.class))) .thenReturn(Optional.of(encryptedSecret)); when(encryptionService.encrypt(PLAIN_SECRET_VALUE)) .thenReturn(ENCRYPTED_SECRET_VALUE); diff --git a/src/test/java/com/iexec/sms/secret/web3/Web3SecretServiceTests.java b/src/test/java/com/iexec/sms/secret/web3/Web3SecretServiceTests.java index cf2af59b..fdedb1d8 100644 --- a/src/test/java/com/iexec/sms/secret/web3/Web3SecretServiceTests.java +++ b/src/test/java/com/iexec/sms/secret/web3/Web3SecretServiceTests.java @@ -50,7 +50,7 @@ void init() { @Test void shouldNotAddSecretIfPresent() { Web3Secret web3Secret = new Web3Secret(secretAddress, encryptedSecretValue, true); - when(web3SecretRepository.find(secretAddress)).thenReturn(Optional.of(web3Secret)); + when(web3SecretRepository.findById(any(Web3SecretHeader.class))).thenReturn(Optional.of(web3Secret)); assertThat(web3SecretService.addSecret(secretAddress, plainSecretValue)).isFalse(); verifyNoInteractions(encryptionService); verify(web3SecretRepository, never()).save(any()); @@ -58,7 +58,7 @@ void shouldNotAddSecretIfPresent() { @Test void shouldAddSecret() { - when(web3SecretRepository.find(secretAddress)).thenReturn(Optional.empty()); + when(web3SecretRepository.findById(any(Web3SecretHeader.class))).thenReturn(Optional.empty()); when(encryptionService.encrypt(plainSecretValue)).thenReturn(encryptedSecretValue); assertThat(web3SecretService.addSecret(secretAddress, plainSecretValue)).isTrue(); verify(encryptionService).encrypt(any()); @@ -68,7 +68,7 @@ void shouldAddSecret() { @Test void shouldGetDecryptedSecret() { Web3Secret encryptedSecret = new Web3Secret(secretAddress, encryptedSecretValue, true); - when(web3SecretRepository.find(secretAddress)).thenReturn(Optional.of(encryptedSecret)); + when(web3SecretRepository.findById(any(Web3SecretHeader.class))).thenReturn(Optional.of(encryptedSecret)); when(encryptionService.decrypt(encryptedSecretValue)).thenReturn(plainSecretValue); Optional result = web3SecretService.getSecret(secretAddress, true); @@ -77,29 +77,29 @@ void shouldGetDecryptedSecret() { assertThat(result).get().extracting(Web3Secret::getValue).isEqualTo(plainSecretValue); assertThat(result).get().extracting(Web3Secret::isEncryptedValue).isEqualTo(false); - verify(web3SecretRepository).find(secretAddress); + verify(web3SecretRepository).findById(any(Web3SecretHeader.class)); verify(encryptionService).decrypt(any()); } @Test void shouldGetEncryptedSecret() { Web3Secret encryptedSecret = new Web3Secret(secretAddress, encryptedSecretValue, true); - when(web3SecretRepository.find(secretAddress)).thenReturn(Optional.of(encryptedSecret)); + when(web3SecretRepository.findById(any(Web3SecretHeader.class))).thenReturn(Optional.of(encryptedSecret)); Optional oSecret1 = web3SecretService.getSecret(secretAddress, false); Optional oSecret2 = web3SecretService.getSecret(secretAddress); assertThat(oSecret1) .contains(encryptedSecret) .isEqualTo(oSecret2); - verify(web3SecretRepository, times(2)).find(secretAddress); + verify(web3SecretRepository, times(2)).findById(any(Web3SecretHeader.class)); verifyNoInteractions(encryptionService); } @Test void shouldGetEmptyResultIfSecretNotPresent() { - when(web3SecretRepository.find(secretAddress)).thenReturn(Optional.empty()); + when(web3SecretRepository.findById(any(Web3SecretHeader.class))).thenReturn(Optional.empty()); assertThat(web3SecretService.getSecret(secretAddress)).isEmpty(); assertThat(web3SecretService.getSecret(secretAddress, false)).isEmpty(); - verify(web3SecretRepository, times(2)).find(secretAddress); + verify(web3SecretRepository, times(2)).findById(any(Web3SecretHeader.class)); verifyNoInteractions(encryptionService); } From 50a3804c3a06222a675dca5a4ce811ce2a8a1754 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Mon, 5 Dec 2022 15:29:44 +0100 Subject: [PATCH 223/293] Remove unused `@Spy` --- .../java/com/iexec/sms/secret/web2/Web2SecretServiceTests.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/test/java/com/iexec/sms/secret/web2/Web2SecretServiceTests.java b/src/test/java/com/iexec/sms/secret/web2/Web2SecretServiceTests.java index 49eb6bcd..26b886a2 100644 --- a/src/test/java/com/iexec/sms/secret/web2/Web2SecretServiceTests.java +++ b/src/test/java/com/iexec/sms/secret/web2/Web2SecretServiceTests.java @@ -24,7 +24,6 @@ import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import org.mockito.Spy; import java.util.Optional; @@ -45,7 +44,6 @@ class Web2SecretServiceTests { private EncryptionService encryptionService; @InjectMocks - @Spy private Web2SecretService web2SecretService; @BeforeEach From e7cf74168c6972668f678154d855c33d21df9964 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton <87655102+mcornaton@users.noreply.github.com> Date: Mon, 5 Dec 2022 15:39:42 +0100 Subject: [PATCH 224/293] Fix copyrights MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jérémy James Toussaint <33313130+jeremyjams@users.noreply.github.com> --- .../sms/secret/web2/Web2SecretHeader.java | 24 +++++++++---------- .../sms/secret/web3/Web3SecretHeader.java | 24 +++++++++---------- 2 files changed, 22 insertions(+), 26 deletions(-) diff --git a/src/main/java/com/iexec/sms/secret/web2/Web2SecretHeader.java b/src/main/java/com/iexec/sms/secret/web2/Web2SecretHeader.java index ffc84e4c..4afebe95 100644 --- a/src/main/java/com/iexec/sms/secret/web2/Web2SecretHeader.java +++ b/src/main/java/com/iexec/sms/secret/web2/Web2SecretHeader.java @@ -1,19 +1,17 @@ /* + * Copyright 2022 IEXEC BLOCKCHAIN TECH * - * * Copyright 2022 IEXEC BLOCKCHAIN TECH - * * - * * Licensed under the Apache License, Version 2.0 (the "License"); - * * you may not use this file except in compliance with the License. - * * You may obtain a copy of the License at - * * - * * http://www.apache.org/licenses/LICENSE-2.0 - * * - * * Unless required by applicable law or agreed to in writing, software - * * distributed under the License is distributed on an "AS IS" BASIS, - * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * * See the License for the specific language governing permissions and - * * limitations under the License. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package com.iexec.sms.secret.web2; diff --git a/src/main/java/com/iexec/sms/secret/web3/Web3SecretHeader.java b/src/main/java/com/iexec/sms/secret/web3/Web3SecretHeader.java index 1cfdf569..be856cb2 100644 --- a/src/main/java/com/iexec/sms/secret/web3/Web3SecretHeader.java +++ b/src/main/java/com/iexec/sms/secret/web3/Web3SecretHeader.java @@ -1,19 +1,17 @@ /* + * Copyright 2022 IEXEC BLOCKCHAIN TECH * - * * Copyright 2022 IEXEC BLOCKCHAIN TECH - * * - * * Licensed under the Apache License, Version 2.0 (the "License"); - * * you may not use this file except in compliance with the License. - * * You may obtain a copy of the License at - * * - * * http://www.apache.org/licenses/LICENSE-2.0 - * * - * * Unless required by applicable law or agreed to in writing, software - * * distributed under the License is distributed on an "AS IS" BASIS, - * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * * See the License for the specific language governing permissions and - * * limitations under the License. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package com.iexec.sms.secret.web3; From d1895f90f81072bde705ff2e605abea9bbbe9775 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Wed, 14 Dec 2022 15:59:23 +0100 Subject: [PATCH 225/293] Introduce TEE task compute secret header --- .../TeeTaskComputeSecretIntegrationTests.java | 17 +-- .../compute/AppComputeSecretController.java | 4 +- .../secret/compute/TeeTaskComputeSecret.java | 74 ++++++----- .../compute/TeeTaskComputeSecretHeader.java | 81 ++++++++++++ .../TeeTaskComputeSecretRepository.java | 2 +- .../compute/TeeTaskComputeSecretService.java | 29 ++--- .../TeeTaskComputeSecretHeaderTests.java | 115 ++++++++++++++++++ .../TeeTaskComputeSecretServiceTest.java | 11 +- .../compute/TeeTaskComputeSecretTest.java | 104 +--------------- .../sms/tee/session/TeeSessionTestUtils.java | 1 + 10 files changed, 265 insertions(+), 173 deletions(-) create mode 100644 src/main/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretHeader.java create mode 100644 src/test/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretHeaderTests.java diff --git a/src/itest/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretIntegrationTests.java b/src/itest/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretIntegrationTests.java index c4c110a3..92372783 100644 --- a/src/itest/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretIntegrationTests.java +++ b/src/itest/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretIntegrationTests.java @@ -145,9 +145,8 @@ void shouldAddNewComputeSecrets() { Assertions.fail("An app developer secret was expected but none has been retrieved."); return; } - Assertions.assertThat(appDeveloperSecret.get().getId()).isNotBlank(); - Assertions.assertThat(appDeveloperSecret.get().getOnChainObjectAddress()).isEqualToIgnoringCase(appAddress); - Assertions.assertThat(appDeveloperSecret.get().getKey()).isEqualTo(appDeveloperSecretIndex); + Assertions.assertThat(appDeveloperSecret.get().getHeader().getOnChainObjectAddress()).isEqualToIgnoringCase(appAddress); + Assertions.assertThat(appDeveloperSecret.get().getHeader().getKey()).isEqualTo(appDeveloperSecretIndex); Assertions.assertThat(appDeveloperSecret.get().getValue()).isNotEqualTo(secretValue); Assertions.assertThat(appDeveloperSecret.get().getValue()).isEqualTo(encryptionService.encrypt(secretValue)); @@ -168,9 +167,8 @@ void shouldAddNewComputeSecrets() { Assertions.fail("An app requester secret was expected but none has been retrieved."); return; } - Assertions.assertThat(requesterSecret.get().getId()).isNotBlank(); - Assertions.assertThat(requesterSecret.get().getOnChainObjectAddress()).isEqualToIgnoringCase(""); - Assertions.assertThat(requesterSecret.get().getKey()).isEqualTo(requesterSecretKey); + Assertions.assertThat(requesterSecret.get().getHeader().getOnChainObjectAddress()).isEqualToIgnoringCase(""); + Assertions.assertThat(requesterSecret.get().getHeader().getKey()).isEqualTo(requesterSecretKey); Assertions.assertThat(requesterSecret.get().getValue()).isNotEqualTo(secretValue); Assertions.assertThat(requesterSecret.get().getValue()).isEqualTo(encryptionService.encrypt(secretValue)); @@ -212,7 +210,12 @@ void addMultipleRequesterSecrets() { } Assertions.assertThat(repository.count()).isEqualTo(keys.size()); List secrets = repository.findAll(); - Assertions.assertThat(secrets.stream().map(TeeTaskComputeSecret::getKey).collect(Collectors.toList())) + final List retrievedKeys = secrets + .stream() + .map(TeeTaskComputeSecret::getHeader) + .map(TeeTaskComputeSecretHeader::getKey) + .collect(Collectors.toList()); + Assertions.assertThat(retrievedKeys) .containsExactlyInAnyOrder("secret-key-1", "secret-key-2", "secret-key-3"); } diff --git a/src/main/java/com/iexec/sms/secret/compute/AppComputeSecretController.java b/src/main/java/com/iexec/sms/secret/compute/AppComputeSecretController.java index f52a3810..7bd4cfbd 100644 --- a/src/main/java/com/iexec/sms/secret/compute/AppComputeSecretController.java +++ b/src/main/java/com/iexec/sms/secret/compute/AppComputeSecretController.java @@ -42,8 +42,8 @@ public class AppComputeSecretController { static final String INVALID_SECRET_KEY_FORMAT_MSG = "Secret key should contain at most 64 characters from [0-9A-Za-z-_]"; private static final Pattern secretKeyPattern = Pattern.compile("^[\\p{Alnum}-_]{" - + TeeTaskComputeSecret.SECRET_KEY_MIN_LENGTH + "," - + TeeTaskComputeSecret.SECRET_KEY_MAX_LENGTH + "}$"); + + TeeTaskComputeSecretHeader.SECRET_KEY_MIN_LENGTH + "," + + TeeTaskComputeSecretHeader.SECRET_KEY_MAX_LENGTH + "}$"); public AppComputeSecretController(AuthorizationService authorizationService, TeeTaskComputeSecretService teeTaskComputeSecretService) { diff --git a/src/main/java/com/iexec/sms/secret/compute/TeeTaskComputeSecret.java b/src/main/java/com/iexec/sms/secret/compute/TeeTaskComputeSecret.java index 7658abb1..77b62f91 100644 --- a/src/main/java/com/iexec/sms/secret/compute/TeeTaskComputeSecret.java +++ b/src/main/java/com/iexec/sms/secret/compute/TeeTaskComputeSecret.java @@ -17,15 +17,14 @@ package com.iexec.sms.secret.compute; import com.iexec.sms.secret.SecretUtils; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.hibernate.annotations.GenericGenerator; +import lombok.*; -import javax.persistence.*; +import javax.persistence.Column; +import javax.persistence.EmbeddedId; +import javax.persistence.Entity; import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; import java.io.Serializable; +import java.util.Objects; /** * Define a secret that can be used during the execution of a TEE task. @@ -47,37 +46,16 @@ *

  • For requesters, it must be a String of at most 64 characters from [0-9A-Za-z-_]. * */ -@Data -@NoArgsConstructor @Entity -@Table(uniqueConstraints = { @UniqueConstraint(columnNames = {"onChainObjectAddress", "fixedSecretOwner", "key"}) }) +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor(access = AccessLevel.PRIVATE) public class TeeTaskComputeSecret implements Serializable { - public static final int SECRET_KEY_MIN_LENGTH = 1; - public static final int SECRET_KEY_MAX_LENGTH = 64; - - @Id - @GeneratedValue(generator = "system-uuid") - @GenericGenerator(name = "system-uuid", strategy = "uuid") - private String id; - - /** - * Represents the blockchain address of the deployed object - * (0xapplication, 0xdataset, 0xworkerpool) - *

    - * In a future release, it should also handle ENS names. - */ - @NotNull - private String onChainObjectAddress; // Will be empty for a secret belonging to a requester - @NotNull - private OnChainObjectType onChainObjectType; - @NotNull - private SecretOwnerRole secretOwnerRole; - @NotNull - private String fixedSecretOwner; // Will be empty for a secret belonging to an application developer @NotNull - @Size(min = SECRET_KEY_MIN_LENGTH, max = SECRET_KEY_MAX_LENGTH) - private String key; + @EmbeddedId + private TeeTaskComputeSecretHeader header; + @NotNull /* * Expected behavior of AES encryption is to not expand the data very much. @@ -102,11 +80,31 @@ public TeeTaskComputeSecret( String fixedSecretOwner, String key, String value) { - this.onChainObjectType = onChainObjectType; - this.onChainObjectAddress = onChainObjectAddress; - this.secretOwnerRole = secretOwnerRole; - this.fixedSecretOwner = fixedSecretOwner; - this.key = key; + this.header = new TeeTaskComputeSecretHeader( + onChainObjectType, + onChainObjectAddress, + secretOwnerRole, + fixedSecretOwner, + key + ); this.value = value; } + + public TeeTaskComputeSecret withValue(String newValue) { + return new TeeTaskComputeSecret(header, newValue); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + final TeeTaskComputeSecret that = (TeeTaskComputeSecret) o; + return Objects.equals(header, that.header) + && Objects.equals(value, that.value); + } + + @Override + public int hashCode() { + return Objects.hash(header, value); + } } diff --git a/src/main/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretHeader.java b/src/main/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretHeader.java new file mode 100644 index 00000000..477cd03d --- /dev/null +++ b/src/main/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretHeader.java @@ -0,0 +1,81 @@ +/* + * Copyright 2022 IEXEC BLOCKCHAIN TECH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.iexec.sms.secret.compute; + +import lombok.AccessLevel; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.apache.commons.lang3.StringUtils; + +import javax.persistence.Embeddable; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.io.Serializable; +import java.util.Objects; + +@Embeddable +@Getter +@EqualsAndHashCode +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class TeeTaskComputeSecretHeader implements Serializable { + public static final int SECRET_KEY_MIN_LENGTH = 1; + public static final int SECRET_KEY_MAX_LENGTH = 64; + + @NotNull + private OnChainObjectType onChainObjectType; + /** + * Represents the blockchain address of the deployed object + * (0xapplication, 0xdataset, 0xworkerpool) + * as a lower case string. + *

    + * In a future release, it should also handle ENS names. + */ + @NotNull + private String onChainObjectAddress; // Will be empty for a secret belonging to a requester + @NotNull + private SecretOwnerRole secretOwnerRole; + @NotNull + private String fixedSecretOwner; // Will be empty for a secret belonging to an application developer + @NotNull + @Size(min = SECRET_KEY_MIN_LENGTH, max = SECRET_KEY_MAX_LENGTH) + private String key; + + public TeeTaskComputeSecretHeader(OnChainObjectType onChainObjectType, + String onChainObjectAddress, + SecretOwnerRole secretOwnerRole, + String fixedSecretOwner, + String key) { + Objects.requireNonNull(onChainObjectType, "On-chain object type can't be null."); + Objects.requireNonNull(secretOwnerRole, "Secret owner role can't be null."); + Objects.requireNonNull(key, "key can't be null."); + + if (secretOwnerRole == SecretOwnerRole.REQUESTER && !StringUtils.isEmpty(onChainObjectAddress)) { + throw new IllegalArgumentException("On-chain object address should be empty for a requester secret."); + } + + if (secretOwnerRole == SecretOwnerRole.APPLICATION_DEVELOPER && !StringUtils.isEmpty(fixedSecretOwner)) { + throw new IllegalArgumentException("Fixed secret owner should be empty for an application developer secret."); + } + + this.onChainObjectAddress = onChainObjectAddress == null ? "" : onChainObjectAddress.toLowerCase(); + this.onChainObjectType = onChainObjectType; + this.secretOwnerRole = secretOwnerRole; + this.fixedSecretOwner = fixedSecretOwner == null ? "" : fixedSecretOwner; + this.key = key; + } +} diff --git a/src/main/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretRepository.java b/src/main/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretRepository.java index 88180feb..2803b6b3 100644 --- a/src/main/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretRepository.java +++ b/src/main/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretRepository.java @@ -18,5 +18,5 @@ import org.springframework.data.jpa.repository.JpaRepository; -public interface TeeTaskComputeSecretRepository extends JpaRepository { +public interface TeeTaskComputeSecretRepository extends JpaRepository { } diff --git a/src/main/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretService.java b/src/main/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretService.java index 0c321b04..3969b44d 100644 --- a/src/main/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretService.java +++ b/src/main/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretService.java @@ -18,9 +18,6 @@ import com.iexec.sms.encryption.EncryptionService; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.SerializationUtils; -import org.springframework.data.domain.Example; -import org.springframework.data.domain.ExampleMatcher; import org.springframework.stereotype.Service; import java.util.Optional; @@ -48,28 +45,21 @@ public Optional getSecret( SecretOwnerRole secretOwnerRole, String secretOwner, String secretKey) { - onChainObjectAddress = onChainObjectAddress.toLowerCase(); - final TeeTaskComputeSecret wantedSecret = TeeTaskComputeSecret - .builder() - .onChainObjectType(onChainObjectType) - .onChainObjectAddress(onChainObjectAddress) - .secretOwnerRole(secretOwnerRole) - .fixedSecretOwner(secretOwner) - .key(secretKey) - .build(); - final ExampleMatcher exampleMatcher = ExampleMatcher.matching() - .withIgnorePaths("value"); + final TeeTaskComputeSecretHeader header = new TeeTaskComputeSecretHeader( + onChainObjectType, + onChainObjectAddress, + secretOwnerRole, + secretOwner, + secretKey + ); final Optional oSecret = teeTaskComputeSecretRepository - .findOne(Example.of(wantedSecret, exampleMatcher)); + .findById(header); if (oSecret.isEmpty()) { return Optional.empty(); } final TeeTaskComputeSecret secret = oSecret.get(); final String decryptedValue = encryptionService.decrypt(secret.getValue()); - // deep copy to avoid altering original object - //TODO: Improve this out-of-the box cloning to get better performances - TeeTaskComputeSecret decryptedSecret = SerializationUtils.clone(secret); - decryptedSecret.setValue(decryptedValue); + TeeTaskComputeSecret decryptedSecret = secret.withValue(decryptedValue); return Optional.of(decryptedSecret); } @@ -116,7 +106,6 @@ public boolean encryptAndSaveSecret(OnChainObjectType onChainObjectType, " [secret:{}]", secret); return false; } - onChainObjectAddress = onChainObjectAddress.toLowerCase(); final TeeTaskComputeSecret secret = TeeTaskComputeSecret .builder() .onChainObjectType(onChainObjectType) diff --git a/src/test/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretHeaderTests.java b/src/test/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretHeaderTests.java new file mode 100644 index 00000000..f69d42ca --- /dev/null +++ b/src/test/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretHeaderTests.java @@ -0,0 +1,115 @@ +/* + * Copyright 2022 IEXEC BLOCKCHAIN TECH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.iexec.sms.secret.compute; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; + +class TeeTaskComputeSecretHeaderTests { + private final static String ON_CHAIN_OBJECT_ADDRESS = "onChainObjectAddress"; + private final static String FIXED_SECRET_OWNER = "fixedSecretOwner"; + private final static String KEY = "key"; + + // region Valid constructions + @ParameterizedTest + @EnumSource(OnChainObjectType.class) + void shouldConstructNewApplicationDeveloperSecretHeader(OnChainObjectType objectType) { + Assertions.assertThatNoException().isThrownBy(() -> new TeeTaskComputeSecretHeader( + objectType, + ON_CHAIN_OBJECT_ADDRESS, + SecretOwnerRole.APPLICATION_DEVELOPER, + "", + KEY + )); + } + + @ParameterizedTest + @EnumSource(OnChainObjectType.class) + void shouldConstructNewRequesterSecretHeader(OnChainObjectType objectType) { + Assertions.assertThatNoException().isThrownBy(() -> new TeeTaskComputeSecretHeader( + objectType, + "", + SecretOwnerRole.REQUESTER, + FIXED_SECRET_OWNER, + KEY + )); + } + // endregion + + // region Invalid construction + @Test + void shouldNotConstructNewSecretHeaderBecauseOnChainObjectTypeIsNull() { + Assertions.assertThatThrownBy(() -> new TeeTaskComputeSecretHeader( + null, + ON_CHAIN_OBJECT_ADDRESS, + SecretOwnerRole.APPLICATION_DEVELOPER, + FIXED_SECRET_OWNER, + KEY + )).isInstanceOf(NullPointerException.class); + } + + @ParameterizedTest + @EnumSource(OnChainObjectType.class) + void shouldNotConstructSecretHeaderBecauseSecretOwnerRoleIsNull(OnChainObjectType objectType) { + Assertions.assertThatThrownBy(() -> new TeeTaskComputeSecretHeader( + objectType, + ON_CHAIN_OBJECT_ADDRESS, + null, + FIXED_SECRET_OWNER, + KEY + )).isInstanceOf(NullPointerException.class); + } + + @ParameterizedTest + @EnumSource(OnChainObjectType.class) + void shouldNotConstructSecretHeaderBecauseKeyIsNull(OnChainObjectType objectType) { + Assertions.assertThatThrownBy(() -> new TeeTaskComputeSecretHeader( + objectType, + ON_CHAIN_OBJECT_ADDRESS, + SecretOwnerRole.APPLICATION_DEVELOPER, + FIXED_SECRET_OWNER, + null + )).isInstanceOf(NullPointerException.class); + } + + @ParameterizedTest + @EnumSource(OnChainObjectType.class) + void shouldNotConstructNewApplicationDeveloperSecretHeaderBecauseFixedSecretOwnerNotEmpty(OnChainObjectType objectType) { + Assertions.assertThatThrownBy(() -> new TeeTaskComputeSecretHeader( + objectType, + ON_CHAIN_OBJECT_ADDRESS, + SecretOwnerRole.APPLICATION_DEVELOPER, + FIXED_SECRET_OWNER, + KEY + )).isInstanceOf(IllegalArgumentException.class); + } + + @ParameterizedTest + @EnumSource(OnChainObjectType.class) + void shouldNotConstructNewRequesterSecretHeaderBecauseOnChainObjectAddressNotEmpty(OnChainObjectType objectType) { + Assertions.assertThatThrownBy(() -> new TeeTaskComputeSecretHeader( + objectType, + ON_CHAIN_OBJECT_ADDRESS, + SecretOwnerRole.REQUESTER, + "", + KEY + )).isInstanceOf(IllegalArgumentException.class); + } + // endregion +} \ No newline at end of file diff --git a/src/test/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretServiceTest.java b/src/test/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretServiceTest.java index f586952a..a9434c58 100644 --- a/src/test/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretServiceTest.java +++ b/src/test/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretServiceTest.java @@ -19,6 +19,7 @@ class TeeTaskComputeSecretServiceTest { .onChainObjectType(OnChainObjectType.APPLICATION) .onChainObjectAddress(APP_ADDRESS.toLowerCase()) .secretOwnerRole(SecretOwnerRole.APPLICATION_DEVELOPER) + .fixedSecretOwner("") .key("0") .value(ENCRYPTED_SECRET_VALUE) .build(); @@ -53,8 +54,8 @@ void shouldAddSecret() { verify(teeTaskComputeSecretRepository, times(1)).save(computeSecretCaptor.capture()); final TeeTaskComputeSecret savedTeeTaskComputeSecret = computeSecretCaptor.getValue(); - Assertions.assertThat(savedTeeTaskComputeSecret.getKey()).isEqualTo("0"); - Assertions.assertThat(savedTeeTaskComputeSecret.getOnChainObjectAddress()).isEqualTo(APP_ADDRESS.toLowerCase()); + Assertions.assertThat(savedTeeTaskComputeSecret.getHeader().getKey()).isEqualTo("0"); + Assertions.assertThat(savedTeeTaskComputeSecret.getHeader().getOnChainObjectAddress()).isEqualTo(APP_ADDRESS.toLowerCase()); Assertions.assertThat(savedTeeTaskComputeSecret.getValue()).isEqualTo(ENCRYPTED_SECRET_VALUE); } @@ -72,15 +73,15 @@ void shouldNotAddSecretSinceAlreadyExist() { // region getSecret @Test void shouldGetSecret() { - when(teeTaskComputeSecretRepository.findOne(any())) + when(teeTaskComputeSecretRepository.findById(any())) .thenReturn(Optional.of(COMPUTE_SECRET)); when(encryptionService.decrypt(ENCRYPTED_SECRET_VALUE)) .thenReturn(DECRYPTED_SECRET_VALUE); Optional decryptedSecret = teeTaskComputeSecretService.getSecret(OnChainObjectType.APPLICATION, APP_ADDRESS, SecretOwnerRole.APPLICATION_DEVELOPER, "", "0"); Assertions.assertThat(decryptedSecret).isPresent(); - Assertions.assertThat(decryptedSecret.get().getKey()).isEqualTo("0"); - Assertions.assertThat(decryptedSecret.get().getOnChainObjectAddress()).isEqualTo(APP_ADDRESS.toLowerCase()); + Assertions.assertThat(decryptedSecret.get().getHeader().getKey()).isEqualTo("0"); + Assertions.assertThat(decryptedSecret.get().getHeader().getOnChainObjectAddress()).isEqualTo(APP_ADDRESS.toLowerCase()); Assertions.assertThat(decryptedSecret.get().getValue()).isEqualTo(DECRYPTED_SECRET_VALUE); verify(encryptionService, Mockito.times(1)).decrypt(any()); } diff --git a/src/test/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretTest.java b/src/test/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretTest.java index 8fff237f..5fc466f4 100644 --- a/src/test/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretTest.java +++ b/src/test/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretTest.java @@ -4,7 +4,6 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; -import org.springframework.dao.DataIntegrityViolationException; import javax.validation.ConstraintViolationException; @@ -43,85 +42,6 @@ private TeeTaskComputeSecret getRequesterSecret() { .build(); } - @Test - void shouldNotSaveSecretFromDefaultBuilder() { - log.info("shouldNotSaveEntity"); - TeeTaskComputeSecret secret = TeeTaskComputeSecret.builder().build(); - assertThat(secret).hasAllNullFieldsOrProperties(); - assertThatThrownBy(() -> teeTaskComputeSecretRepository.saveAndFlush(secret)) - .isInstanceOf(ConstraintViolationException.class); - } - - @Test - void shouldNotSaveSecretWhenOnChainObjectAddressIsNull() { - TeeTaskComputeSecret secret = TeeTaskComputeSecret.builder() - //.onChainObjectAddress("") - .onChainObjectType(OnChainObjectType.APPLICATION) - .secretOwnerRole(SecretOwnerRole.APPLICATION_DEVELOPER) - .fixedSecretOwner("") - .key("") - .value("") - .build(); - assertThatThrownBy(() -> teeTaskComputeSecretRepository.saveAndFlush(secret)) - .isInstanceOf(ConstraintViolationException.class); - } - - @Test - void shouldNotSaveSecretWhenOnChainObjectTypeIsNull() { - TeeTaskComputeSecret secret = TeeTaskComputeSecret.builder() - .onChainObjectAddress("") - //.onChainObjectType(OnChainObjectType.APPLICATION) - .secretOwnerRole(SecretOwnerRole.APPLICATION_DEVELOPER) - .fixedSecretOwner("") - .key("") - .value("") - .build(); - assertThatThrownBy(() -> teeTaskComputeSecretRepository.saveAndFlush(secret)) - .isInstanceOf(ConstraintViolationException.class); - } - - @Test - void shouldNotSaveSecretWhenSecretOwnerRoleIsNull() { - TeeTaskComputeSecret secret = TeeTaskComputeSecret.builder() - .onChainObjectAddress("") - .onChainObjectType(OnChainObjectType.APPLICATION) - //.secretOwnerRole(SecretOwnerRole.APPLICATION_DEVELOPER) - .fixedSecretOwner("") - .key("") - .value("") - .build(); - assertThatThrownBy(() -> teeTaskComputeSecretRepository.saveAndFlush(secret)) - .isInstanceOf(ConstraintViolationException.class); - } - - @Test - void shouldNotSaveSecretWhenFixedSecretOwnerIsNull() { - TeeTaskComputeSecret secret = TeeTaskComputeSecret.builder() - .onChainObjectAddress("") - .onChainObjectType(OnChainObjectType.APPLICATION) - .secretOwnerRole(SecretOwnerRole.APPLICATION_DEVELOPER) - //.fixedSecretOwner("") - .key("") - .value("") - .build(); - assertThatThrownBy(() -> teeTaskComputeSecretRepository.saveAndFlush(secret)) - .isInstanceOf(ConstraintViolationException.class); - } - - @Test - void shouldNotSaveSecretWhenKeyIsNull() { - TeeTaskComputeSecret secret = TeeTaskComputeSecret.builder() - .onChainObjectAddress("") - .onChainObjectType(OnChainObjectType.APPLICATION) - .secretOwnerRole(SecretOwnerRole.APPLICATION_DEVELOPER) - .fixedSecretOwner("") - //.key("") - .value("") - .build(); - assertThatThrownBy(() -> teeTaskComputeSecretRepository.saveAndFlush(secret)) - .isInstanceOf(ConstraintViolationException.class); - } - @Test void shouldNotSaveSecretWhenValueIsNull() { TeeTaskComputeSecret secret = TeeTaskComputeSecret.builder() @@ -136,34 +56,18 @@ void shouldNotSaveSecretWhenValueIsNull() { .isInstanceOf(ConstraintViolationException.class); } - @Test - void shouldFailToSaveSameAppDeveloperSecretTwice() { - log.info("AppDeveloperSecret"); - teeTaskComputeSecretRepository.saveAndFlush(getAppDeveloperSecret()); - assertThatThrownBy(() -> teeTaskComputeSecretRepository.saveAndFlush(getAppDeveloperSecret())) - .isInstanceOf(DataIntegrityViolationException.class); - } - - @Test - void shouldFailToSaveSameRequesterSecretTwice() { - log.info("RequesterSecret"); - teeTaskComputeSecretRepository.saveAndFlush(getRequesterSecret()); - assertThatThrownBy(() -> teeTaskComputeSecretRepository.saveAndFlush(getRequesterSecret())) - .isInstanceOf(DataIntegrityViolationException.class); - } - @Test void shouldSaveAppDeveloperAndRequesterSecrets() { TeeTaskComputeSecret appDeveloperSecret = getAppDeveloperSecret(); teeTaskComputeSecretRepository.save(appDeveloperSecret); - String appDeveloperSecretId = appDeveloperSecret.getId(); + final TeeTaskComputeSecretHeader appDeveloperSecretHeader = appDeveloperSecret.getHeader(); TeeTaskComputeSecret requesterSecret = getRequesterSecret(); teeTaskComputeSecretRepository.save(requesterSecret); - String requesterSecretId = requesterSecret.getId(); + final TeeTaskComputeSecretHeader requesterSecretHeader = requesterSecret.getHeader(); assertThat(teeTaskComputeSecretRepository.count()).isEqualTo(2); - assertThat(teeTaskComputeSecretRepository.getById(appDeveloperSecretId)) + assertThat(teeTaskComputeSecretRepository.getById(appDeveloperSecretHeader)) .isEqualTo(appDeveloperSecret); - assertThat(teeTaskComputeSecretRepository.getById(requesterSecretId)) + assertThat(teeTaskComputeSecretRepository.getById(requesterSecretHeader)) .isEqualTo(requesterSecret); } diff --git a/src/test/java/com/iexec/sms/tee/session/TeeSessionTestUtils.java b/src/test/java/com/iexec/sms/tee/session/TeeSessionTestUtils.java index c2a84225..ad3cfdf2 100644 --- a/src/test/java/com/iexec/sms/tee/session/TeeSessionTestUtils.java +++ b/src/test/java/com/iexec/sms/tee/session/TeeSessionTestUtils.java @@ -84,6 +84,7 @@ public static TeeTaskComputeSecret getApplicationDeveloperSecret(String appAddre .onChainObjectType(OnChainObjectType.APPLICATION) .onChainObjectAddress(appAddress) .secretOwnerRole(SecretOwnerRole.APPLICATION_DEVELOPER) + .fixedSecretOwner("") .key(APP_DEVELOPER_SECRET_INDEX) .value(APP_DEVELOPER_SECRET_VALUE) .build(); From cdc8475b2f58a2abafc7802c436a40c0edfa7159 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Fri, 16 Dec 2022 08:38:43 +0100 Subject: [PATCH 226/293] Add missing new line at end of file --- .../sms/secret/compute/TeeTaskComputeSecretHeaderTests.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretHeaderTests.java b/src/test/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretHeaderTests.java index f69d42ca..92a7d62e 100644 --- a/src/test/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretHeaderTests.java +++ b/src/test/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretHeaderTests.java @@ -112,4 +112,4 @@ void shouldNotConstructNewRequesterSecretHeaderBecauseOnChainObjectAddressNotEmp )).isInstanceOf(IllegalArgumentException.class); } // endregion -} \ No newline at end of file +} From d63954fca3b60e6d55abd555f9cd9972509c8ea3 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Tue, 20 Dec 2022 11:50:35 +0100 Subject: [PATCH 227/293] Replace `IllegalArgumentException` with `ValidationException` --- .../sms/secret/compute/TeeTaskComputeSecretHeader.java | 5 +++-- .../sms/secret/compute/TeeTaskComputeSecretHeaderTests.java | 6 ++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretHeader.java b/src/main/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretHeader.java index 477cd03d..95921828 100644 --- a/src/main/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretHeader.java +++ b/src/main/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretHeader.java @@ -23,6 +23,7 @@ import org.apache.commons.lang3.StringUtils; import javax.persistence.Embeddable; +import javax.validation.ValidationException; import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; import java.io.Serializable; @@ -65,11 +66,11 @@ public TeeTaskComputeSecretHeader(OnChainObjectType onChainObjectType, Objects.requireNonNull(key, "key can't be null."); if (secretOwnerRole == SecretOwnerRole.REQUESTER && !StringUtils.isEmpty(onChainObjectAddress)) { - throw new IllegalArgumentException("On-chain object address should be empty for a requester secret."); + throw new ValidationException("On-chain object address should be empty for a requester secret."); } if (secretOwnerRole == SecretOwnerRole.APPLICATION_DEVELOPER && !StringUtils.isEmpty(fixedSecretOwner)) { - throw new IllegalArgumentException("Fixed secret owner should be empty for an application developer secret."); + throw new ValidationException("Fixed secret owner should be empty for an application developer secret."); } this.onChainObjectAddress = onChainObjectAddress == null ? "" : onChainObjectAddress.toLowerCase(); diff --git a/src/test/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretHeaderTests.java b/src/test/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretHeaderTests.java index 92a7d62e..436179b3 100644 --- a/src/test/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretHeaderTests.java +++ b/src/test/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretHeaderTests.java @@ -21,6 +21,8 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.EnumSource; +import javax.validation.ValidationException; + class TeeTaskComputeSecretHeaderTests { private final static String ON_CHAIN_OBJECT_ADDRESS = "onChainObjectAddress"; private final static String FIXED_SECRET_OWNER = "fixedSecretOwner"; @@ -97,7 +99,7 @@ void shouldNotConstructNewApplicationDeveloperSecretHeaderBecauseFixedSecretOwne SecretOwnerRole.APPLICATION_DEVELOPER, FIXED_SECRET_OWNER, KEY - )).isInstanceOf(IllegalArgumentException.class); + )).isInstanceOf(ValidationException.class); } @ParameterizedTest @@ -109,7 +111,7 @@ void shouldNotConstructNewRequesterSecretHeaderBecauseOnChainObjectAddressNotEmp SecretOwnerRole.REQUESTER, "", KEY - )).isInstanceOf(IllegalArgumentException.class); + )).isInstanceOf(ValidationException.class); } // endregion } From 8b7fdd0a2d7612c268c611b075549d8393b9a40e Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Wed, 21 Dec 2022 10:13:55 +0100 Subject: [PATCH 228/293] Use iexec-common 6.2.1-NEXT-SNAPSHOT --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index b1a61815..ac5603e2 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ version=7.1.1 -iexecCommonVersion=6.0.1-NEXT-SNAPSHOT +iexecCommonVersion=6.2.1-NEXT-SNAPSHOT nexusUser nexusPassword From 63be7db27cc28747fba00deff7a81fc47f516dcf Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Wed, 21 Dec 2022 10:15:35 +0100 Subject: [PATCH 229/293] Use okhttp version 4.9.0 to keep the one used in web3j --- build.gradle | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index d133e561..c5b1cae2 100644 --- a/build.gradle +++ b/build.gradle @@ -76,8 +76,10 @@ dependencies { implementation 'org.apache.httpcomponents:httpclient:4.5.9' // Web3j issues, see core build.gradle - implementation 'com.squareup.okhttp3:okhttp:4.3.1' - implementation 'org.jetbrains.kotlin:kotlin-stdlib:1.3.50' + // NoSuchMethodError: 'okhttp3.RequestBody okhttp3.RequestBody.create(java.lang.String, okhttp3.MediaType)' + // Spring Boot dependencies BOM enforces okhttp3 3.14.9 in 2.6.X + // It is required to define the dependency version required by web3j until migration to at least Spring Boot 2.7.X + implementation 'com.squareup.okhttp3:okhttp:4.9.0' // Web3j issue: https://github.com/web3j/web3j/issues/1180 // velocity for templating implementation 'org.apache.velocity:velocity-engine-core:2.0' From ada5841a688eaecbdb1cae2be5d638f024a8055b Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Wed, 21 Dec 2022 13:41:01 +0100 Subject: [PATCH 230/293] Replace explicit checks with `Validator` --- .../compute/TeeTaskComputeSecretHeader.java | 25 ++++++++++++++----- .../TeeTaskComputeSecretHeaderTests.java | 10 ++++---- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretHeader.java b/src/main/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretHeader.java index 95921828..cd607bd2 100644 --- a/src/main/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretHeader.java +++ b/src/main/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretHeader.java @@ -20,16 +20,18 @@ import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import javax.persistence.Embeddable; -import javax.validation.ValidationException; +import javax.validation.*; import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; import java.io.Serializable; -import java.util.Objects; +import java.util.Set; @Embeddable +@Slf4j @Getter @EqualsAndHashCode @NoArgsConstructor(access = AccessLevel.PROTECTED) @@ -61,10 +63,6 @@ public TeeTaskComputeSecretHeader(OnChainObjectType onChainObjectType, SecretOwnerRole secretOwnerRole, String fixedSecretOwner, String key) { - Objects.requireNonNull(onChainObjectType, "On-chain object type can't be null."); - Objects.requireNonNull(secretOwnerRole, "Secret owner role can't be null."); - Objects.requireNonNull(key, "key can't be null."); - if (secretOwnerRole == SecretOwnerRole.REQUESTER && !StringUtils.isEmpty(onChainObjectAddress)) { throw new ValidationException("On-chain object address should be empty for a requester secret."); } @@ -78,5 +76,20 @@ public TeeTaskComputeSecretHeader(OnChainObjectType onChainObjectType, this.secretOwnerRole = secretOwnerRole; this.fixedSecretOwner = fixedSecretOwner == null ? "" : fixedSecretOwner; this.key = key; + + validateFields(); + } + + private void validateFields() { + try (ValidatorFactory factory = Validation.buildDefaultValidatorFactory()) { + final Validator validator = factory.getValidator(); + final Set> issues = validator.validate(this); + if (!issues.isEmpty()) { + for (final ConstraintViolation issue : issues) { + log.warn(issue.getMessage()); + } + throw new ValidationException("Can't create TeeTaskComputeSecretHeader."); + } + } } } diff --git a/src/test/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretHeaderTests.java b/src/test/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretHeaderTests.java index 436179b3..c6088d3c 100644 --- a/src/test/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretHeaderTests.java +++ b/src/test/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretHeaderTests.java @@ -61,9 +61,9 @@ void shouldNotConstructNewSecretHeaderBecauseOnChainObjectTypeIsNull() { null, ON_CHAIN_OBJECT_ADDRESS, SecretOwnerRole.APPLICATION_DEVELOPER, - FIXED_SECRET_OWNER, + "", KEY - )).isInstanceOf(NullPointerException.class); + )).isInstanceOf(ValidationException.class); } @ParameterizedTest @@ -75,7 +75,7 @@ void shouldNotConstructSecretHeaderBecauseSecretOwnerRoleIsNull(OnChainObjectTyp null, FIXED_SECRET_OWNER, KEY - )).isInstanceOf(NullPointerException.class); + )).isInstanceOf(ValidationException.class); } @ParameterizedTest @@ -85,9 +85,9 @@ void shouldNotConstructSecretHeaderBecauseKeyIsNull(OnChainObjectType objectType objectType, ON_CHAIN_OBJECT_ADDRESS, SecretOwnerRole.APPLICATION_DEVELOPER, - FIXED_SECRET_OWNER, + "", null - )).isInstanceOf(NullPointerException.class); + )).isInstanceOf(ValidationException.class); } @ParameterizedTest From c6ca2579a98668aae8238b772a21f0bb7531f027 Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Wed, 21 Dec 2022 17:00:20 +0100 Subject: [PATCH 231/293] Use domain hash instead of plain domain in challenge for getWeb3Secret endpoint --- .../java/com/iexec/sms/authorization/AuthorizationService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/iexec/sms/authorization/AuthorizationService.java b/src/main/java/com/iexec/sms/authorization/AuthorizationService.java index 31399575..a31edad6 100644 --- a/src/main/java/com/iexec/sms/authorization/AuthorizationService.java +++ b/src/main/java/com/iexec/sms/authorization/AuthorizationService.java @@ -114,7 +114,7 @@ public boolean isSignedByOwner(String message, String signature, String address) public String getChallengeForGetWeb3Secret(String secretAddress) { return HashUtils.concatenateAndHash( - DOMAIN, + Hash.sha3(DOMAIN), secretAddress); } From 8766e3d4bb85fee4ac9517164de13f8e1fc4888f Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Thu, 22 Dec 2022 09:12:15 +0100 Subject: [PATCH 232/293] Fix `shouldNotSaveSecretWhenValueIsNull` --- .../com/iexec/sms/secret/compute/TeeTaskComputeSecretTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretTest.java b/src/test/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretTest.java index 5fc466f4..0e838d1f 100644 --- a/src/test/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretTest.java +++ b/src/test/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretTest.java @@ -49,7 +49,7 @@ void shouldNotSaveSecretWhenValueIsNull() { .onChainObjectType(OnChainObjectType.APPLICATION) .secretOwnerRole(SecretOwnerRole.APPLICATION_DEVELOPER) .fixedSecretOwner("") - .key("") + .key("key") //.value("") .build(); assertThatThrownBy(() -> teeTaskComputeSecretRepository.saveAndFlush(secret)) From 015438d1d56bd1eef2e8cc8271c88c65dcf49f60 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Thu, 22 Dec 2022 16:26:00 +0100 Subject: [PATCH 233/293] Remove Lombok `@EqualsAndHashCode` on `TeeTaskComputeSecretHeader` --- .../compute/TeeTaskComputeSecretHeader.java | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretHeader.java b/src/main/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretHeader.java index cd607bd2..86d71a0b 100644 --- a/src/main/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretHeader.java +++ b/src/main/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretHeader.java @@ -17,7 +17,6 @@ package com.iexec.sms.secret.compute; import lombok.AccessLevel; -import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -28,12 +27,12 @@ import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; import java.io.Serializable; +import java.util.Objects; import java.util.Set; @Embeddable @Slf4j @Getter -@EqualsAndHashCode @NoArgsConstructor(access = AccessLevel.PROTECTED) public class TeeTaskComputeSecretHeader implements Serializable { public static final int SECRET_KEY_MIN_LENGTH = 1; @@ -92,4 +91,21 @@ private void validateFields() { } } } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + final TeeTaskComputeSecretHeader that = (TeeTaskComputeSecretHeader) o; + return onChainObjectType == that.onChainObjectType + && Objects.equals(onChainObjectAddress, that.onChainObjectAddress) + && secretOwnerRole == that.secretOwnerRole + && Objects.equals(fixedSecretOwner, that.fixedSecretOwner) + && Objects.equals(key, that.key); + } + + @Override + public int hashCode() { + return Objects.hash(onChainObjectType, onChainObjectAddress, secretOwnerRole, fixedSecretOwner, key); + } } From 409f4aaffa58c093ee96be1d8614d774ae365264 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton <87655102+mcornaton@users.noreply.github.com> Date: Fri, 23 Dec 2022 09:37:20 +0100 Subject: [PATCH 234/293] Set `fixedSecretOwner` to lower case MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jérémy James Toussaint <33313130+jeremyjams@users.noreply.github.com> --- .../iexec/sms/secret/compute/TeeTaskComputeSecretHeader.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretHeader.java b/src/main/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretHeader.java index 86d71a0b..b3e75eaa 100644 --- a/src/main/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretHeader.java +++ b/src/main/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretHeader.java @@ -73,7 +73,7 @@ public TeeTaskComputeSecretHeader(OnChainObjectType onChainObjectType, this.onChainObjectAddress = onChainObjectAddress == null ? "" : onChainObjectAddress.toLowerCase(); this.onChainObjectType = onChainObjectType; this.secretOwnerRole = secretOwnerRole; - this.fixedSecretOwner = fixedSecretOwner == null ? "" : fixedSecretOwner; + this.fixedSecretOwner = fixedSecretOwner == null ? "" : fixedSecretOwner.toLowerCase(); this.key = key; validateFields(); From 05da2e2ca38eabaca33fc5c830ea250ca059b53e Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Fri, 23 Dec 2022 09:48:24 +0100 Subject: [PATCH 235/293] Log all issues at once --- .../iexec/sms/secret/compute/TeeTaskComputeSecretHeader.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretHeader.java b/src/main/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretHeader.java index b3e75eaa..3457eb26 100644 --- a/src/main/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretHeader.java +++ b/src/main/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretHeader.java @@ -29,6 +29,7 @@ import java.io.Serializable; import java.util.Objects; import java.util.Set; +import java.util.stream.Collectors; @Embeddable @Slf4j @@ -84,9 +85,7 @@ private void validateFields() { final Validator validator = factory.getValidator(); final Set> issues = validator.validate(this); if (!issues.isEmpty()) { - for (final ConstraintViolation issue : issues) { - log.warn(issue.getMessage()); - } + log.warn("{}", issues.stream().map(ConstraintViolation::getMessage).collect(Collectors.toList())); throw new ValidationException("Can't create TeeTaskComputeSecretHeader."); } } From 3e51299584533eb46d23f5f02f85f1701b034740 Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Tue, 27 Dec 2022 10:17:10 +0100 Subject: [PATCH 236/293] Use gradle 7.6 --- gradle/wrapper/gradle-wrapper.jar | Bin 55616 -> 61574 bytes gradle/wrapper/gradle-wrapper.properties | 3 +- gradlew | 274 ++++++++++++++--------- gradlew.bat | 38 ++-- 4 files changed, 182 insertions(+), 133 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 5c2d1cf016b3885f6930543d57b744ea8c220a1a..943f0cbfa754578e88a3dae77fce6e3dea56edbf 100644 GIT binary patch delta 41329 zcmaI7Q*Td!I-v?`;`vDt%y5>m*3j$(*l^jdP2JpjMA^0+&|2TRW5uH`Rl*t)xVuObX z8is+1yIO~&Kuk+s4o%X#jAkG`%UPmPu(FoL%5_`#;kGEuRVc~{{IR+C!``~k7pe0l zFXh?Sv#G{;-2u>dboTrE^TlrtNyz)gAA~dd3D%(Ez-7BcWF-3N-lU^jY(Q3BP09(v z08qAf4D0ZGh!N1O0%}ltu;LX<)c$&>15vN4OoeiB>*M_jiP3(*3DI7ybrif?aUk#2 zZ1#cK(XGztsOk*$n=#$<^-e+Pcj5{+!C$eb zN~?2cjlp%m7T~9W%6~LA1S?1-B*cW&S8#yh*9dDkSPV;;oMD(o5Ay}vOPgL_`O4c{ zc#!>?7VKF4YmW~!y6b(Dmo!%rNrLYq&g13!f`8Mups(Ds?W3 z48Eq$A>}K@X%nJ+7A53jKO5ziu79Dlo2a#`KniJ`T<~DWx3*+QhUVcXjS@OJjaRtL z%jHp$NjJ1+5c_bN<3)n;D0{)AuFf67lPOR$ zHNRwEISZtoGb>zjEKL+DOt}ycwmuCce>^IekE8o38o7Esv(qZOzvTR~n8e|*DXSG8 zsx23%fasBiHT&(|kP%fK9)Q2>guZ6W9nFRtcL<-$tczpwDj4wd8w=q1gYrs`7eQ2b zSqIDBGz*?9u0ezSFS3xzEijzukZPERLMecjfXyz5;af7-_LU}}Z2#mnEZETI6(eAV zK1*TNL4aeB*ya@>pnA^}Hy~cfiaYYehC7x8!I@uifQaKS3}E#Z>u;+5kh)P!m43yZ zBkormKnm(h)u>YQZXEE29FNuMdVU+|5Z_X&A`whuCQbRBG=&BlOE~VkPNT}nwdg%9 zxYh|cl>WgWRB4qj+hN_gA=CD){EIp?qdbyTLg!VigOXN^CwqxQ4%IgHr@COIQfR(g zkqSx`WmRa|ueYoUOpd6E6|r1s>LLR)xM2~>HTYw(b~!33LtcRO7^=jz(!F6xo4M3d$AZYj*2<0`phJlRYN*R+YrfjFM^H>z9pLcHW> zEmv)@MZ)v=y3}Ij;FFOACiNIYUuKF%&mInXG!<7`F##I-Wn;RZO0GCJ2toHvFdqlb zH!OwhjfC+T38NjzfIzdn*)vvUS*BL3-&Cs+-|2W^njiNfskM_0FL=)x*14CKrp!xi zu4Cp5EfJO(KBYLyuxE*c-NgJ`xrduL$J1T}_q+^NXK^4SPW)3&_;)hqiYV9fxBL&d zU~xH+iU8GUrkfc;`sfoYu4Z0Frs}5{g|n-=_43k*>y%7~Msc9GR_0bSa+yrs?M}hC z*!;1&c5}=EkdcX9BkFZ)&=sbQYHqY6agmN=NvZt1t8B?CyEr6r)40>IXhn6h99xCX zBHx~7bc2OMArE!PJ>GAi1B*-WO9rTrpR}7)4&XKAqAZuXuFLL%=>nr@Dt77@TUWDR z!eJNBxHsq~-_`ykOXHzrYK!wUdo2nf3x7ypQ7C=lCTL+M+Rbg`%c`RU-BK2@+-vjo z`u+tKt9gX!GcO~*O_OEzXJRT?)lRL{Zr#a3xlmda^AB0FdjYyksXf~Vp*yR3aFnI7 zG+?gWkQ=W2Pf_`(+n55=Ys~{W7th)ZLb4(uZQdtYsOHNRtyjE++=H1^+lIAd>KyDa#5C>D|<_GKcm(3PYc~bzGZ@N7+!Mj!=bDV^^CMiVdv+$p{@93{c0Z z!5ur-V5s0!EDG8y;Edz|BPSf&bgs!3BlC`6v&woFBf@mDFF71)>490%iXT}I#903o z-3YS-O!xu(mA4sex(*ALz6am7zhN~ZzaE+02-j}JrrL>&BFBh5ZeWmE0-FX5X4r`UeKO|0 z%r}Ol7l*(PlVbb|b5e28ti)lg6nliGY+B!n*gYz-m0$zZI`4rYRXz&)E&Z-N$iaqi z9a&2V@!gG#;2LE0!G7_e85}#Dv5}F>BJWGgll8mU zT=N(1T;BM;&mWXatMH5ydyDXG`rcH3Bq4h)_AKCM^IAgG>+VC(;qlJ~` zqck?#sKZyK6&3>^E8I!-|cbPHHvkpP4Ds9-P-#Js$IgY(Nd~Ch}UtjkaKZ(-F z*-14NMe9Q;hslQ*PQ-<-o#CCfv9d^D@Q3h`xFyKF?v#Q!H1^6tUQJ1JY)$n;R z0>#YiFav|LtDPn_;}<+h;7L9@v$d1qw9gQQlJn+3?&n3d80nSq>?ytr2r0A~ zfMLv~DJ_;EJG{yq?KsK7@{jrY@BjmzwzIRj*WUw1#V(u+FMyObcse)T1>+^BIcgu_y=@!0)y= z^RN;rIpZMX*%-1J{z^e}i1||LsH3g&tZNhIZC*qAct~9jZTJsOA_2j)dZ1%%$uEse zBM(qzYYaz-S_qaBY{;+5(W=OaXYMvSJQ-`bRCIq!CfrH?6M9|_7(22_HlAFK`?ozM zCUa{5M%aRV`dM7%9}_k8qCpvOfZD9~h}kLqHFo6_0);(c9s{N`y~-{v%+-~2&ma8B zM&Oy6ZnvxYQ;*F;0Qat=^j99Fo|V)0g$b#pusGl6eD>+u+~0tOI;-PwSvRJ6#YB&# z7SE+ixG z)e;Qu?WjBgNkh7Vb-6@3t$?Gb;_Uv+R#@%3X!VTk$d6bZYyqI$19yjgiKPafw8OmL z64`!T;O*K%BsV0Ihvt+3;&t4__r+C zv|@_-!5!B0xJ6OZMZhsTc2oPBzpkL)Azz--c@lD)o||{Eak9--EPf;oIY~s(2hD|F zZl7VZrXS;HSz@7M%VSpGaoUvljLuytnazV~H9QQXEp11ecsQY=7&3s@0^29sg^iZs zU2Vt)$|XYUPQ0aY<;~al3rCUO_dt;&vyWBlR87~f+lrhZ9VZRZY3y$OtN^K{mWD%V z4S~Q6E~N3melp5`PT7B9_YYeo?KEjf4Q`#;0)pt6dU%J{J6a=2w`bAN3c_W3iOKXi zFm1$rnne!3>Icp!k}KdDo-M)=;oa|0G1a)_O5&xfUL=QTC_*9jiwKu;GvYhTL09kH z&%4#fb1J=idPm+jAFCh+R3P2jNAwIuNkCi$i+#n??2P0}&>D9JC;93pTeM-qI;Hv$ z3T`~HFkgOgbWh-b0jXr$R~g?uHzat{AnW@-w4ifKwY{w);{gmBQFccBgY!D@vGi1+ zqaX?qF;FcbMPx4o6PDr+Y^bzDb&9@$7e5;2-Ryt3k|;@AN-atWMn91Fkko7_Egxu> zOzT$_YOF&pPREwmw2Vt6=V*o*LVJ6TOO7aJju13l3E&9Enq}BHt6;;&$xCCgpqsJd zUv`UeL1efo@-oNv9Jwd`QI&qWu{^+^fq)nLDcR<|6Mh_$>sObpLuNICKX(RJpr|?P4}Py5>L{ThsOt#yhlsv|AZL z5^K+2+wz-vN$YZ7a;VF7;-v|>emyT*UD>MBT9w7eGqikDsiEKARMKOX5#BTHWV@*Q>5d@Ty;PK* zyJ?cJYQx7nghR4!rzYF!Zpff6g*v;!-r7{E6TZ$BmJ~R}+)^b}rTs2HRJ8>Nlc=;# z7Va?3>TK0ezHrZ7Ud$sd)<;k-5x!Dth2zO>WQJd!4zAVl_=>b&mWzwWf!t}mh(@$; zY8A-ztqCYDqpi|bz_6QQp4w2DNa1=!+zK72*D)8?j}UnG;E>Fha>2U(VgF#irB)w@ z1dr6FlTv_8Qp|~;QZ`!mC-Xig7_3S5?X_ex$-o%G7i~%Rg?A}j zZD60oNlX|b;9Uy#g*ag;GQvLLzGfp=9IgcZ{W*Xsxc{mqjIsrf!X${nKWqsfotH{DMM*Y;FRcNPVmhESGBfEG zWSK$cm0R^YYpmPAH>6QgMkVA3hnP#?jDxlUegrkhj+lJ)VMG{!bTDe>Ri*t#Jgo@n zNbd9SG5dYyV|M_QfyWb2FEJoWt+B~6sFz$~djv8*-R70+86s>|lvH5<8l0yrsM1)q z509>8-jVZmZ&!EwWuy!s#=e0V;Doxvu`_+ya;WJJT3pg;@I7XK{f6^O|M-sX9G0#j73o<*Zq=hlM;*!52zV7^fEwCr>5}&q znvtRZBJ*qXGC}&fvA!ANW6#61v?KJl`yre*+C`36#f8 zdR(Zv7Ns3UvqSRFZY0|C4f-0Ebs`E7B_@lN>N8!%$bU!N_a7hOwhv)h)XcjvEx;CJ z_>5r_2Q=M+77D9Hkqp$4O=(mz=y?_x zdI%Hz)MN>g4yFfasJ7gbNC{P9qnf#*b0rM3bCl9hN$u{AyGY>&HIpC*HP0wLl+Z0q z6I`#8czzBtcO7uYb=dlc#?*?8k9Z64fcjOT;Ya@|z`CL!7U2k}DKLhTL=>lQ#QYUv=LZ#~Xhb&cjFR z^SF64uO8q5vMlhW#=efVOf{U6D_Hd%Yu*n^mlt8#t~}fm!{F<**Td|MkvK)KJ!#>l zv{;0D1wVEHoSzl@J*#o=`yc1*P5b|-=WYlNM7sGUMX=NOI>eF-BpS;nq}0v*PS zSQ6@wGZe;F`KM+J6J_JnWs~{FenqiC^tINxW+y-eUpi1D81E=KU2H5m5h|KLbSrG+ zSrqK#{-#pRg++FNLP;F zBj2Ve#>SI{DY|QlOy_2TF>sUE0nn4+2tl$%xMzLZV@kA&ggy>i@Nt zbuw2oVGbt2VX;eYB=CHg5ny%b?}_m;1b<;W3S!;<1?BB6H8|w=32i8(6Fznu7&?~u z2m_-i<0bR65mIl6wM&1CITk!@FyNTmd3uq{Z<+HFDU3-EK-K+uE_Jk~UEB)X)dzRlULl>sytpTQ; zFW80jffMCSm18{N;}p} zoKi5tBpGe@umKBlZ|1?wy7D;N(o+#Pvc8HjpH(=&{-?XzOMq?H0F62BB7CW{%TiRP zV`^81cE$EJh|(f>ul;GiKP8F^Eg>}tw>hCF6y3zP58py3u%=88_f1w?Dh6qHi_=ps z1{zKT3L#)T-CHtS&YwCVV7i$hOXFt+doDFc<`MndcjpeR_V#?~+=e|BdnS5C#8DCu z@>*3!I9V90`#WJf((HL5H@8Cn}2785z<$gM>-9QzkIFpq?-y&ZG;z`CfJDo9A}G6 z^Ot5zx6dW7CS z%CI6TuW$9`)#F}}>ZZm?_H-DQXzUIAx*V~b340UbCu_t$Dyfn)d&||;<1z?7fkbQo zJ2kmSt9>cdDqfC-E2ZXN?z7Y6AEkZ^eIVyo1 zw;KO5iZg~7HCM5Jk&G}NQwK`~bXb=f#j!xIJJ#ETt7@1qhw9lR(hEuxbrv?Ct!{87 z(9=Xd%+o|ax*N?__cB*&7kQ_BKkH|g0C`v=ptGnr!Eh|tl=`ApNyN}p!_oQCHMFa* z|FW3-aBH1mgsnX zI9mTRZMe<`*tH~w>N9+i1#h^sZpf>kHavl=APRCt+>y+ojJc$-aUSf^8qCY4ef}f(#S6=tveiuU`=132nDf#KB)Cf3!4ggf(JETHuKO(IvTb(s6;Rk ztYFXlcsofjf#oh@u|;rIFWKDeg%l>%*I;u@iH7^D8QiG=N0e*#(CB<`4BYGtxViCH zK}_P>g0_%^NAkM28@J&eAN_e0N6bMm0POqgxLKQDf`=o{(*v@;Ga7?*IqTo1^w^?v zIcM@Q@~%nUD210hId^wYwE*;*WM5&f4n%ofbA0UbB8e0^2qWr8GUr#+{S!zLVlM4DyW|>h(t4HO*B1bmF_098 z4$HepU8YS-9gl<+Jt4+VCtJtvcUTT}1QYa=dtF@74d&Cn0)jpv1WUzjFfq8f{014v|G1;he z76hAgD&1IT-dQsl`jfn*ZmGI%JJ^~+NI?156SJJ}aqymBc2)EUtesH3bzUGkE>BOU zjiilBZdFgHdrbKru<~*cLcJxjI#t~}RB_zhRU&TJz&fD*F1e&^ zASpZ}3ppRY={cnp``a?AB|@w55$%pZ!_*FuGrqYzLh!y&70vS1j+=c~|zjkE7i4Y4E(NTKXd-je8>=6q<+#B7yc*NLp6XBE( zs>jG~xBpI-ljN3WLT@-~1>TEAk)dHU%i@jw-oY^D2AAbV59ve1769bo`!T=fs=;eSB?Ur}e23z;mmjG63^1VapT zJ^+%ZaOzE#rj%fn+b{m4>2adL5XUGah7hN9%pOioPhtS{_h27L+0G{>cCo|~9^z6m zR}TEt7)gP|V54=xHOWv{R&vfIF>ue4cUX%`vuBOLBv77PfvD%0)@wCB&U4w%YF!b^ zpa}ozLBfP;v#}!^mV5J)dZ^$J^ zv(Hyed#^O5=y({EIo9Z{OF9+iq{Ine$lY^BbK(F2Ig8F{L$rU~w+Dlx#0g}zEHdDx z&5pw?qc~)N29@e}L+~Lz+bUO_LyvddFBjqn%Y5<^!p&TO!8}&EPg#5QZF6j-yoX0S z-?-v5-}&Rjf`Rh7JDsZmJjGj9$Cl|nIgO6&D%o7z*=qGA_a#^F&XG*hZCRd1-S6Ws z!gc`Xg}x2d2`<7Y4cTMI@|h^^U_p)}ab^mdVjeR(ZqX0s9Fl6OU(B`AWLSu_F@vsB>y{Mq`)wzzv{<& zfNo`_G-R4&%8bV;CZaoB@3s17HMBWlrCK+##Fn(-5RVRm44J}Qv&=6O$U5r#Z&RZz zWEPzVa+hNL=u^l41{J<3*`Vtms8#QC2{sGHFPjy-O?`j)F@~l5qvQaL4vQri^;41ad$`%D#T%3N9 zkU84ckT z_3+LH{7IYY>1@RWK*VVp8cDs*jNb{UU=qwlreT-e=Q`)+4f2NQ+}U!9`fS`?rsj^8 z5p*AB*D=t(sbAMU^rLueRZ8e8j2qQV1~Xu@8hYmusOb@gbMEL&1t_(j|ETY1Q+Fq* zKH$RLu8u@?^hVwkzBUu&NT}LcfTObO{CffGsFXYPCekhefLbLr_2P*#-0EE$(pjvcDgV9tRl70x2=D#$2{f zBYGy%jl=p4xYOinzp`n)kZ1)!=(h>Uu z!u}9h+W0v!f592#lTRX^@m*2>QYApnMFyI_OqNgru6^c^*Pnwr`G(`&)Z{?F1xCv) zsvqbLV)_E?!c=(&SLqH*LCM{3Q#(QNh_k>60B8NI9v7B&fPo3QayiD3*xHAk&=3?sc3KByr z*8HY4^=sBurq?+vda~|8r(qXWjJ(DL3p_e zBn*I?YtG*$&&lZB_{U=;D( zxZ+Dj`A%#$CJkmf&T1BLGSl#$k97)AY1E<*U#MO-$vFR3oTqT6Z^yWnoC|l@H0xv2 zD)1~1F-|b3gk=mXwfaSxOiz}bApixCL>&8@~99w!b|jzLU9r zTOEW6^%I%%J5EvJkxL~%`#ti^dCz)p?E(V6K%D~9V%e)WSt~5=h9wXb87{Rd&{&xS z&cy4XD}4?_jXZ)2Wwow+76rPoU-X}ZAN^+mDV+m9U#UdAdGp9;PN(5uI!p^iG@nRO zoLRpOWHjCVP{JAe?A*aPTqI=R{nv0_^Oj&nO-Uj;MO8GjX&upEP47x?TuO?H;}fx@ z26cLT83kd+uw0HFNslL#yPRdlefBBHDVC+Ga|Tc}KzT+i3WcdDzc_ZvU9+aGyS#D$ zI1Z}`a7V_(Oe4LSTyu-Qut(@ewfH*g6qn0b5B!c7#hijdWXoSr@(sQNVYt8>e*g0e zwv4nqN+dY#V08ci=d-Rn+zkJ-QcHv4x~>H$;nl83-22HjF)2QMpNEM1ozq$th2#KR zj5s^@lA)tHN{IHpAsv{%HuEFwPv8h3aVTxQ%oEW6IvV#QJ0B;vgw^Hp1Px?Mz2A(2 zdQ^;}4MsY<8eV>fzO;AfuTO{tS(&yXF^v3Wsx#DZs4Wl=ZFh+B1m>lFnd30yCVR52 zEJayFdp-q;DvW6zH@VRwYD(2-QPXG9E3_6^gL+7G$hjq7@;bw*A(u_p);K`=92Ab# z1o-jasBEQv2krbr#TE(#MCgA|$zCN)9w_30sl_vd<8s(O#cBpCt^|cGdhfk9L|QytS{v+6Q(M+%1Hlofd~SQ8Vq4uNSlg>%xb@;Et66K0q5aPH&y}=D zijMp=z2$$)fLOS^q5p68lSW1#m3yq5Sk|@8ceL2rNmjk2J%f=$-}y#AAr@z7}J@q znC9s0tH!IM142|WcJIzvgeRMUrxSw*j0!Zj_bp5^psleDWe zDY$ccM9=xzR&NE;|Z?L-|)xilhIAhkZZWk#w6L6SSqli=BV@qsfaoHuDkj>&m z!zI_AX0#lYT5Y4TY+qAdr{Csm{#2zt#aM*~cuo7~3ldhG#z2W;C^xTcYc#SVm#gh} z1f!tnu8-(T6Ot`f*n$z1OjIJZg@fJAQgi5~@$k(BAV3V(VsM6ZOpz_DMy*;E@R(_^ zhXrH6?4&^rl`&jyLmct2BEyQetwOeE&cL|Bq?k);AL4u+OjlIW@)oUbEgI3!W3yTV z#OAtdpy+g1{qG$O)Z_fo3FExgDGRWHK@biXmlPbTt7 z>g?@cFRqmY1~$SjAkTG|^Fvx|cw&)wjyRusR0yCrLH#${DA{m$@gSPvmMUycnJ8Z8 z+t}!X(9$q+I4Y7Fm;>@IC^-}m$?K=_!4}T zgVd*|Ox+=pIq1u^VUaa-M0!1PBco=JVw#ey)H(Fm$Op865sBKWe5(CARTJjH$D#&; zkK zVb&kzzhhhnGBe2@!a-?puNTM*NJDT(nBpLG&J+zhC9C*&vFANdQ5a*SAl>5P#Ik3s zSS>G=DfA?l?HctG@F!%^9K4y!j%FOVx_+UiLy6>WFWZM7DnIp3JHWA$xK?r0Xo&M3 z(qa-&m<`?quG{UqQAWEa4VB;k@<`ajTqCT|+BUMmw!l^2w-#8E%AZwF$<17Imz@Ry zV=K*&LR|Q(){7O=$&}!}Yh_XiKe+0dV;7R7sLeRFf9#WDpchEoGx!W`RHO7}_kBJs8dd=lFv@uxIHs(zH(jHHlgHMJoAx zrK*{gP+3{iT6X6(IBeicuuzggq=XCFTNaPCIkg&jJSnMQlTqZ+JW*kugy|dQ9R@^a zF`SK@D!=$GK+0W4#`vB+FYj0 zs|)Pr36|g#TTz+~>F9Jl&;BA%gu6+XlW2~ohU-yi;&S);&nRL7v4 zKZ$n?B;XxWiaKb7zb4sn9bvvTk#w1rll+^Z5bY&39Bv|MpCX{I!8cMF z8Fj@8(8u7Ae^+-JMV>0^y$EH!$~|{ZCoxR!N|vE)VB2=!qymlC<`Mhz$;1+VnI?c! zr6yS%#27XWAF0v@2r@jd7rjo*24_CHaH%g?shSsM0d&tiK0x0|>imsu@#v<5D#GFckLxwAK|CD~2MAlXfVs$5_P&|wprbdUZGXzfpMNS!v# zQC3fOq)V&;zv z#fWE$XrJvk8SPnB8u;M8)HacogF=OUeW@|1wC;PhU6vL4{N0>$=}4W|Or z_w;hZkX*8V_@!oW43l2pZPgQjrbfj0%ei}{!Nw@UhbTaD{i<1CijYztB$G45Yj?$_35c-!{BK`IReuw{0Fl%hQ)Ov@uR z49L}NfcBAEChD3?J>v^=H{(QA@0@m?`IU<6?FFyd+u||ghy}~ z8%XR^Lrud&p55iLzZu1|En+p8=&RhAQ$uRp<&_Pq!eM~p;LBGCb1xG%bF&NC$rzID z^$-7=`QUvE*X+*Dt_qb{7t7dYn@$Kp4P01E0AI(ShwI#I?pPD73b;BdBXer!p~M&I zNr9%jQL;)~kHX^9A>A2nx^lrg_pWo;OxSXM61Htz$L7Hl$nn_F3)1}(um}3d65Od2 zzl~a09R<%Qf%5*@KNHh?*0B=2e5>Fqf^TQq^}W&++}VO&DpaIRL{{XA0=Bb5GgYF6 zfVrQTWf2MxDxU9&IA^v166I$do6)SIfg{T{#3vTxwvb6t_TciJ%O+%RuU#|ypEyIc z2eB3}I=dY7xJ>Pa_JFI~23yI9&z_>2sJ!caVGy3r>`|}s;j3s0PuU8#)ii$Ycbs^t zJ!DZfXW{&Z4zrmUZOPl>2={9Gn2p2~fQQid>tkMUZH2r4wP{OesX>o=I#(tRXH)vx zX7nFkr#kt2yu?xY&svdjD^AmaijADk@=EZVqtMmi(-y|f{KO?h0RA3(OEF;}UU@}T zdJnxjUc{cP#y94d7fbtldljc+PN(R-Ken}(?#Y8kFT+nx-yB9k5KU*MZ3L)2fH$o6 zM@_2dZDlir#X#5wFj-)zY)tE5w)k+x=PJ?&kQ$VOw%woc+U6jV0YquV>u)H0-z1U-BkI5=|$N(I4>DS0lIK z2P!;)DDD&y31fJnQzyKkiNQPffT;6hxV)hXTF=b6osfmDW959lz5*yy53+hJQ@rIx zXZIZ!rU-ulZgVaLlF~W(165z<-pRvs>YfpdV2ut6z@T*^F?NruWIrnN?D0oztWpyYso0d<@5THYPMl zbpj*b9OUri7{yC;8MBqw0RDaw+DNn1{@YQ=7>XatlP6)=5z)+HkxH@Z+(cLp9k@Sg zj9v7C8QG2aR#`DtS*}+Ph3)#2f#~1iv0e!2`P+J~70hgfLxml^5Ds9RJ*(p(9g%T@!MXOd2yKf_Oc~D3uyk!GV=}uwT}%za6sd}6{aM*iq%M6d4m35FCp|z@qI^m zQ4)s2aHr*ey)Z`3eA?Ul{RcYyVT9RXz{;-C#wS=uL?a7(fVBR`zKo_vX;;7g-sY4V zqtjf?eF~-P{WLxPptiPF^U@3u(Ef;Q0dqcShdj961P-ZAYesuDu(3n+o9R0Gc;XS& z3X92}H4(@aVo%}kNn&b>;NO$ht9hR%K0!q)v_Av)#upfJB+R3#)tMJeP5;D-mM6i) zq3}LW=p9Z5usNY|$~B_)VQ;bZ(ik!p4Eytntr}mo;4jIX7u~B^$&hR&G+B9 z9cFSYL}6$Yg*2t?gc%NraC67es|%{0MzsOxmV1~W0HY3ydE>+#v|N-sV!D&1(y`NM z?=dpM@AqFfB@zrlZxpXrK4b2(dO z02Gyy;^7o$Vk@#zRTw~wadmt#{nG5lqO=-pUZ;7I_OF*!pcf8Lg5gMrMmc4TNmcREY#=tRN238%O{m|?e`9yMnBO9r;m<<}3v zQAHFs0A;ZS#WM=a3)!^a&ZJvcG>)r~>mTOgTY}NmdK~?mL+!tbWRlptV|QQ+ccKU9 z4+lfhtb|Mxq<^*24$ZZL@{y+u5(!=_w?j0K0q)(5j(aEfvVRAop7gO5zGNd;#00M2 znFIQ*R)IHHuOtD(Rslq+cl?&Fz+LceqlMZM^qrK^A%A!{7LIEd8iV0@b-}5v34Y@n z^S_~mxn%YG7=Kf=_mfX<*{%~~GZ$kuBi9&Z{?gxhF+E&2ihXS)b>}4=oeXpPMi@Fx z1OD8}MUCOLR7|$vvHS(ELfv@2!L`tZd7)f_A3iakhf=VrXnA+k7L#Pj&+q{+M-`4Y z?hdOjZc?0=x(<;2F&mxQKYe73Dd>7NNtRJMuc=8?k9NE%X(wPecQc|BKGUhQ7Mz5& zKOqG0z9XqotS@F}P?l8hpt=-Rpb@nh0%WPUa~f9pY`}FYc8_3hu18oO!_rg7VmUg` zwbPvPg=QN*EC-~&J`>(uacPC_ny>^&ety%1IhNKS?hXJd*rHC}>VcpdH~Q}?#_J|^ zpNg{a;ztd1pD|6RfGG`W7Q{MJ>`LQW{4figAc^YlP?z=c*_&T4JKJlcAH@FU0D5O& zN!#OX@TH7qknNy>9Rq{YOpS{!@r^=?YOjIbY66i|Nq*NCF)mU;qaC^# zifF$*MeJCi2e&skxECbrj=m;Jz&oDKt*72d$Hgtom1n5;7tO*6b@8*-BwX==MJ}tu zEMoJ$R4!|TYWej3FimrGui9H0ziP|jtq#{`q9rXGLhS+WrSI5fL5(`TzYvWzOX8W^Km=_Me#_0M7r%iM4~9 zxr>AGzmWemu+ZIwVHNPN0UY~3U3dR~7j>+iRPC&t7)|YrU0uV}WIdN8(7z~~$VN20 zpj8HoD{%>>(Gzrt!^i>b5F%FA@?IIClqJ!TY}}&e6RD#mXJy%6k*`Q@Lq%@JE}N>I zH}U6Z1RLO3)56i29q}EzolFRxI;9wd>wAb1CbwCEb4(lbB||9 zVN*W&ZOp}=77Tg|_a{0T&9`A;)jGWv`<-Fla9s5C=uT*ch}7<|C;C`cPVgi$UIMq!83)Yl}0suK_y2m#Ac97 z1cf~X9t?*jQH&p6!@LK7@|}JtC`Aa9oKcK+!{CUcGr*$zF;wVSc)Zv~Nh30*su|6( z8k%bIZ>~YxKoj5~^~UkRCt}GslTqB!6ya%5$DG?Bl5E60<#$44MTORfP^x;J89odA z_+w!V=Rqwy9r7F2q%&FNuWS|5joe2+g3VDFKPyvwG_}Mvt@c4BHE%D5N=_S66*wUc zu^s|Hw@WwPKa%QC9V2p2TqS-?{@8`x~q^{!Gc~bvLk=cDa9_bMIy`Z zi_8x0FMHgx@PD{^$L`F+rE5F3Z9BPQ+qP}nPOgq^+qT*1I325_j&0j-Klk2W-aW?p z2j{3cYSlby)&(odZgI5SZMyW4&tHzqO+kUX;jxFv`#B>b`B{uQatg>+wz@~d9|9F( z#Dc|bLTX4uWlN5H%8@F6p`Fnxcr&z&E!$C@umga6IA7?a(J7OkVIR@EXC&*XobilY zIH%rRQW4DJ+M8@6L3uR+p)Iep4q~nRPR3~H=T5Mku_Bz~%?n&%PkwQ%jhI)*$OtL4 zxTFE8gcE=fQ%rv5x!@4X;#=NFJkWa1+3L{8%H{ZXxkFi_Pq{_03pwVJl`#E~6Zd4% zouTBN@)YH;mXhBw+akZk>%E(&BlC?T<{?-XwndIZ3t7fK@L~^VYMNkYN12Oc*{IYZXb5jMAIl}bIP1zmV%Hf z!2cJhRQ}jRXbRl}c1h30sQg{>;BYNUncM$&TOkc`9u3gwHPUUr8^USBkNKj@+QP%O z{B&`0)>2otKb&!9#Iy5LnG)GK z&x;#$j&WXBznxIPf8Ut^xUPn-h4W45w${iH$wC(u+$1Ukg3i>Y z*{B&uGY1I(b!h#|I8IvY=y_^cGG}{T_mlrQsN)OviE@>-Z85{M9GJ5Iz}F)qW7^w4 zwbruz_-w%SE%^D#@}uNMMiK;_)o=(B7F#Scm6_5E?|R}!B#oKeL{kzW!(4yVkM$@K zh&k39i-KjYKcL~#ODw9WTp#9aFbIvN%1YKrYDU0C>AxCf=uaU6Z=$j~5mQ2f#AqTj z8VE`fUL5+5yqRF{%42DD&C0+Hu5efLQe=BU8>dJ3iq+UbSl8G*Xh~Zj>o{(c2%#}q zny?$ioL(OBi#zd3_h?R12lQkz{?#1-?wt0tw>J-7KJZMsP9Xi9vhL3EU|-*T;ub4p zs7C;gIzIzk#;0?#w`9)nwmV{t2}C=VF`YmWd)-=lCh=d`lTVTOF;dr|nVdRmTAti= zE@ms7+^3)3XpAB1wY7p#oBmm3?n*JtRKwR6?GmpvKpTpO+GdpL#QMO!V$g#GhHHoX zn9e}R_gWxIpzz|Nc62Dq@0G4uQyZ#~>5Fkq`z26P*J+C8?#kJeeM}$km}LRmQOPUU zt)tu)on>^?j&B4kru3*ASB?d^z}dV%T0uUH+;=O?0sP|hE$gE5j)P^QY_%p+nG20U zLf{nl2`2_Mx!o`q=jA?ts|e^o+!|Aiz4F6h#EFQZf89!gkvly`gISDHL0-(cWuE@r zctxK!D%PG@$YBwN*lc==TucW{UFbR-LMjB>UCS{KWf=%Q4;(|S^ow>7;zU(RVK5)u zRkRsM4can>f3Onf#!$cnW1H8+dAT~F-2^x-TJa8>zhWJoZm{aQss<#`Xh#mxXxHwn z)OUd`T;r&?53X;(m{7kCk3B{m0rWr*a(g!@`1s@eTRV96cTLgJ1*D z=B`~E@$kYXPg0jcF5O_kx><=TKW}OD_VG;9Y5pi`Ye`b8Ht2^LU`iorTfEuDx?(iv zoL3`7y&y?F>^6Pk4<9*D^+3_H?&3!E-dCDJkJ{Z%AaTNC`iN>Ir`D;tyW-e7iW~2a z^OwC_9NI=&!|I^&r@+F&atYjx#g+MAh9>Pj$SYoi?v?gc%C3|L-F zB@h{e#S{~W5(~E zC0tjuqA87ryF($+Z|WOnz2u9|xA^NOo^H@A$eN@#rIeh<$XlyDdedycI?)G9>Lg%x zsq&lYp^5dzeQ0=7DjY(uP0_mZsAdowjJRU)!LG^>n1%)#Dr|A4PIU?#t zDYh_x+l5cuGt*CQpBWObpDuoGTB?0!9=X`;K!I`spIZ^wn{%+QkXsn~Q$sFoj8CSQ zrC7Z2684R9IDaoZG%++%+*7eD6L+h;K>XpdYH81^`1QocAH8YA+4~ymsft|Vq0a0F z(dYRI{@U=@2GpJgK_>1ezClUC=PzNrN5X*LMBQbWHj$_}%G`PCRWwVsiNY1IPb^?` zqVXvkB;795P*$}3uE$Vt$;9O#$mlqr{18tNV=&y~<{N$7N~hrFd)HoSVc#Grc2Kv7 zB$F6vtp8wv)qgIq$p0xQ5E>R*+``ht!`?mR9ES*4rm?MtuYvL9$eDwfqaZCNS~Lfy zYYUTFsEM(#+%C+{o+?WdshLOFrO
    CzJPg&1&C#S}14UBT4n{?E;je=leIwEK80 zX7l8KMhkR@<0ecQ@8WviaO=D7IlkDmng#lU?Ew6X$fKTh=fYV`M#IKW&1WK9M8+g~ ziA8{L8N(A6gj&p~0~F=#2OR!|eo_W1_SQ%f3G7BLH1W-wZv(>3L@xHCkpE(-=;_A9me&l}Za=a0o2&t2qV2@Ssf z)2{fBn*tm3Zev!)kb^=_Jn6usUE4Ppum&ImPh&qyt~32`Tbnh{hpw4Lmf!tRvjTlo zu^#6oH&Vq?N|t& z2c=jz*{_3uUSontjGHMoE-W;I^8noFtuxu`M`Wh`N)kZFyb{4Jw>;ACT6~3=W z@4rHelELn8x}&zieuL|1`;trgEL5#n{Cs1X;dIZMH?u?E$`z7~g?YyRU{e%f+tZCe zJ}sGS{m0NS3b?kTm~{;G#KSnbS z-OJ49#;7n8YJ1H-u9u5Q#9DWo$}FZ$#k{XSDH0WVNNhG$S?iAHW_wt0$b`5J3l2TO z>Hb11wy{Qt>?>lC{&LKv@QeNeEOv{Uv9`db<8BC(u(g6xme`ZLNJ~B@Iz-4mX+?h` z0$vDNK18H}XhbK}`|}Ztcff81S$!%iFdkvIvuUcW4w!jtoNI@!Z;p72zKA>c2YDwy zXLP!?cVv{Z5n-|i@K%Z4FI*QEgyegcK~fmaXmbxZytQ8^&EGkVU!)$h^RqbN+8|~O zG;0=-Y(IJP=|e_*)__^x174=$2BsqIw`J#^*}4%H_myqmCL`C z*{Z}l2rTgBf1I3EofWI}=At}%zgfsY87x)l^7h19<7PjU} ztE!GOae|2`8R|ZdIIr=CL#kTboz+m~?doyEEyeoh{SsEZ1L^Ii0B5AAgyZB!}9{5jb*#E0EWIzoEH#G^2z$dB) zst$ZS(=zp1^{C8Jhh(z8IWlEcW#)h;CuQBB%V|a5TVJQ%uBHd%S6o5`6-xr4Qv~1- zTxjJnH>hGblo2V^T&?>sNB!Z@csW!Ivdlj&Yr@F&IMO?2hnMJt zS|0jlCwD7#wyd+v%I-g1>o1~`0dDyDmFlG#IqqBp>zHLOVEHWslR~r1nP-vmOe~@B zjxwwd7yv27l|KEHtzhjI8%h;-1rsLNSyf*%mRixmpE|QYJAgbY_bX-ldgV6;2|-34 z1gDtxDs{4h2YiHi8|Odvu9)P2=~G<#4S!m#x{!v()w{j5`~j}<4{q-vzr|{cKd$U+ zD8TUbxDPjauXPl&gi*m>>rek8%!B;WPQw7&Z($!{s}-XiRPU>W!{@!8XYN`HH+V8N zgsX(3Ll@%4`T#qQvhJeGGUG4pEi|AA8g{wISRUxBezSz(61ET&n8ceA!SiDAq&pjo zA;w#5n4j3qeyC12%Ps6{56}^&Zz|;NyIFY0>~mf*53eKQB3Z3_Lms*bb8tf}tG7~( z$xz@ne>V{0#9!slwX@76$%HG*st{K=W~Ue}nWx2KaRTY1|8NQ{ZKwkxDD)E5a}OqW zaFC{FrZ==LxgVPYbBZadv5%u${}5o-p+s|?BW#`(UvRoyBlWdSCwLi0oiWL)Y1WL- z^K)1~{aYJa518(_AlO8H9Ha>qbCgu|OW49!D0%#|dB2%g9^J-WR;{8cuHQ10)z-7{ zphv)&9ti~B2Gqhk4c-q^3CLGH$OdHx7C39dol+t!@NGyram0)*0mx_}6b$Ij4pwCN z#Ihw@l5pQZbuHnGoMaZ6h0U-{evEmCND}>qQrrP#4^_9|6MazvS!@R*Lla;ZQut-aq5Vif5S zQfJ;4@IRkvSGBI8VXKUl=CL7P@ zM%K+S$sPc`Vrb+!E~V0{p?~nI%1^&xT927M9_+urz!O5a32d2}WuQn$v@EUR?f=2l z9b%}66|#8cwvEDgBAk_?jEz(K3N+WG)f+f#HW-YbBjgx{#N|v+zy4=Z7SX8ww)qbU z`#}o=Li*oYh5`QP?|NDn*8l&JVSQ7sPE=f^xFpPx%ye>3Fl5GHDrjgh<^%FzQ0l!D zT;u)bR5KeUE_LvZ8Z}GHb@fXN%VpLUV3H$@#cg$a3krJgPkk#-I@@1wh7NB+$6IU3 zEDO(X?`=N=~&cbiX;)*hB8AC49oAbh;(Nr4Jf`a(J^n} z3{Q)=UK!HP`SoXOhKrWKnss-f!e*b8$@$a;rTkYSi&PG&ZVhT&TVAjt@%1nasaFk{ z!Zlg!QHCU0TBC{#5D4MC=z3)i-30y&0Yrg67}LOs@QxhQ{M5H<@324xl&o7<#6Ej9 z4jqWzC<_|yAmNN?gx59tq%91JGBCDwcLlGs)=<0V4`Vdqs|nQB)OqUf99^6f2K_L%#!B15ha_8ROUFzlV{N{4&4d#orrMGOc9ntR z*V`Cz2$FHywE!G8L=sjX(7!!S3L6BhgO-g-T;w2%=clWy^Ic_T??*@V!gf~BbALV0 zdLI8K5)suRX3iUXH|AG0(xSy@`L1r%M(l-8WH1A?*EgEWE9(6Gq}-metA)ZGOdXzavrW98z+OWd^#%h&fRZGaWdKn~W)@ z)cILuZqD?d{d4o3-CXR6kA_x3i*Ygj=2_BGIzoxHUB1C2-hmGcG&+u!81De5E;cn% zIJj{ae(*&PhIdh;Z7vZKaFV&87dOC#hggEEnXO?o7yN!a%*o1CND36YAws|>yxk>~ zY}MOFWetrY5Ad~aAwrC9Lv+s;6Os14Q=b5vRrofV(S@{Yc_Z81RCY8@F2~NWpke!| zVk9^Y#@OkC5wv65-pAI$f+Y=PzTqdwUCB7=Bdm@YV+{5n;f_@2Y6|`xdrpHcZToAQKsM=e{;I;%}a~<$1emQ{c0tY=Jhi{WG0BXk0};V#K4K zhRnILHmeSZR*rNm0sSXY;Z!FLb%wk27=5a{O0@oIgIe_d3UEBX*`0z-CaCGY4;X}v zjaL6WTiz02ucQw8#`!X=a?PVpxZwphCx^m&zp2`BCp7BXd6NVK+btuA*wUHoke(yeQQ_McAtEu%l8E7|f+%m);k2J^JE zYSl>y4+gWdgwiYzr`U@|5bt=Plee_UO*GKU+4wPDZ$T$Aei{?uzIY;Iv-f9Xc>+t% zmXTqd!~-IuIPV8LaI5y*oSS)?X3{4_s-F{oH*g*aOB=o?gHFb&%=k)r>a6>Yyh(m1 z+j=|EdgSd5g%LhIH;`9NVdf+KjFL+0q4y{EA*}e`yr9@HU$rG#kK~T6J9U8K?kAqn z*oxf)vq15@fV(on?COT@O5KW?Sf{Ez!NLnvpUQ3y`xpB*u=W<;yPjEoOmmF4 zJ=0Pdhw!qWKmp*)iXSx2ec%@rm&pUa&|8dg#L^PEgLv+MR2& zaK6PIMv%iio1BB3>>19@)*pL2ZiAw*i5=%HKl<+A$OxrJYS)jWFX30=?dQjjQDjlR z2e3HX2eG##;3)F#ko5OB!5^>N_v)QwxBl4;W&F(0} z9h*`waf z6lUENGPuIu!tAUUD=!j)bm18&VPBwxyr&KKIm>xptWEcb2lKnyT|1XKzs0gx>Tf$j zj|21&nBXx9&|9>IZ|Is;!2IqKC}+2&jRAnX_Q& z=IS?>-@g=n%YPB~5g}eh!sp_BmnR1KGsTYtD_05Sli^f~yuiCAS>K@b^mhWN*nJBE z>u;Z5-tm6TIFY=<7uku^tguhq72Uc7q6elk0^wjXVPCcOJ6;^tfo!vk(s?w^(V||% ztUU_UE$lQO@uNaJ#G*ifO~4X8#~121H$0P%yKlVjzybE$PY%BbF%G`q-LLGn?y4Mb zS9YCQ@>4VN&i+T z;Lwrh$)=q}5*}ZS_GuYAe&={S=U^GI__l|v-r}`#%>f&I+Hg(6G`o#JQ7l!ucC^}n zXsWrtn}M1d5WB<}`#Om=dUgmr#8r#i-Y+2IJCydVvs3$dGOl(wOnI`b>;l&U2U@Ds zpl1Shj!nttDzK2eYiIR~VmZ_isd{n~2xCFj>I~&;sc1dvns-%XZJzK*keAhx_xnlU zwLAO=Oo)8BRffg#R;^Vd9q|$<_@}507MAd%PIWT3Epu7n0>eY;o_Gsy=@@V9&vJiS zdkJ{L^q31ziY1$_fpbZ4!TRi~Mm5lub)T`wlWeVY1wmfiq!dmStEG=DWGb*o@esFtzCKxSo>VDBQYnX`7u4AEd4Yj*URb*An2FxL*M;V*U3j` zlvdyD5NE2Bi`nd2gYu|y!rwLX1cav}W5BUf@M4C!*GDFiR(X}`q;r(f+ygn2<6mYE zT_3(&r0!+mv`6vkc@jrmiPV=~r1Lm>U(E~x6Ga`atYN~4ih6EeMc6+Bo}v48t<|Z2 zLVOU2u%iMQYk5XINB-0&%a*EUy)xSsI{ii|lOFI7ps>_!QJ_h9lE+@gsyf-|B#m|k zEeEIsIBWOSODg{6aQonW`1X`{zLfMnDO!afmZ^5E8L6#B9GuIVNbdKYyl;t)aAM8= zln+Y|{a#%Gd_e3|!NQCHsR~w)54c+#7P6-Fs09960XK+JQ4y}=FM>a3CW>Mm)Os}O zgy6$CuGkKlqTOU@0>julYHjF#p&KRz4)s8j&6{lI_G=*R3N7!RpJLDzk+2wu5Z%pl zxC4&fqi7Q9hu(agzZDeyD>T$yH6BeS_~heNTm=Eh0iY$&M#XH-_PCn~I$>do z$a5ig4L*w$_zYITN&GzMwcHd%5%!`XrHL=^Mlw)ESu-lG3KVU@(KcliZBx97WE#o; z_nD@kv5^*_13UQT6O56?*MbNKuF6?lpW~AkG?PdkVGh~avS?j$5ICxC$M4p1Qo8X zbPuU*s?sI=JcLAJMHh$>Z9(6GF#?mIeN=TWbE*gikanGb7A=kUTtThzJ=1lpcmzH6 zfeX7b21G1h#TIzrq#Vx=@E!G4 z7oT*bH4)>T)_&Rs@AOr_1=Q>uXeRoknv}ycAdUiliO)|=e%X8E6d{0SlKHNFwj3y3 z3DJ0;MB|3#x65g&j~l$S_jzUA0+FjWRh8@anHX zJ2PQZ-7`Vl?!kRBjvCHAcJeTRUlHtW#I{>!$hm%6gpEir)^gXFwaPUP;0kiLS%vNz zc+-Whu5w&k`9KP)KIpIE5j}fa_e2X@ealmXWE5w+)^-F~~1?CNXf%Os71V@~d=?O@H>)id~o}DT8FYe?F&&lZ8L*X#A(J zc^tXG~=)m>DCgg?M+vF z(wQ6O$;FvjYaOr1F+t%KuLKG~iR3{h)%9Np4tQ9--gD*_bM0$~5q=ST{|OogeqAoW zb69le9M|Q^;v5i_umagS?&Z$k`W;+QA`sx!i5;luPWljt>aPH;NjzNwYMu-vtrm^b zk>yKD^Ca~ZyLmP_3omP*hq)|_*$q=M9gNn*SW zaHFZaFhaZ&D>KK6{Z1%JLQSZC324Z3VvNX_K&l}sX*c}S=Q%nTRG|1_KRDaK9JQzLz>c`%DILe%0hwIbz;`c^8( z$NAUKc@p`eNupG>6oCQRXU;3bee$24G=nQ39DZi7`$Fq|zYl3>CC7?jA&{~)^_r>-X z)A>~brtK*yTQC{)Ao#hlKpk<>>;wO&T|fl8P0QyI;_~K+$FLCi1%XSbu?5;hu$(g8~4`p9^JY6BK=&OnfvL(69ittxUVUQats{x7&Ox3$==!pi5Vo}3= zQP5id3;mnjhO!v2Vt(8B2*R8bt$%wUSZuBdvIlPI`1+KX`CPR471DB0%2DR@4XaA) zVON^$TlyPK6mK^iC*a=-& zh1N+6hOUcBUdj6;DWzrs7>=b&leLN1}P-Z?%+#=oZKx`Cmf>?@^%ekP|<)Lk;n1(|1DakT#w_mtm4$b zrMLpl5CKrNh6evatCRl?&B*>UFk?go`uJmL5q|ewuuPhR+0Yc>TjSHV%aQ1acA+7` z!;VKF-SthS#d3dG^3skn->N%aKEx!-a(T!N5M{{mL>z)V1ESK2+JSToq z8+m)5zM$&Kp`<*zANRZ8df)tYef_+Z|9&lo46YppoDqR%AX4S;&4kX0U`LJz#%h{V z5G0`vHink4nwxvO#Qt(b+@<9ImFi_UIyC9SJu~FMn(Q4G>)4wdv3|UR)EoWF5U|hD znIdzQ?80S;KX{(`@JQMlWbspFH0Q>0%SVp#YCtdR#-Z2WkJ8jzigM4J8kwAQV{-j@ z+#7ofP*PAQy(hrmt2Ov8>J5Ye62t6TWQlL=dOkxWH0V z`imC6McOiO)MnaVtf+CFg;OzixG4)1OM1{xoFjsz$)m3XFjkM#wEa zAXL^Y*ItfOK-%(KgxgXT3y2$2MUtK%oSc@?Lt?f;yD9Y-Re3QK0H&VA)X;H7R*oog zqugDx6T5-Zh4{Sn_|aB%#xYmbwg~oh@&;B8K)z!~xWbU?{%~hOW4b1?-DR1!8Ug)M z72!O>;6K0nQl`R<{I5(aMQ1y=`cGF}|aEBWezY{n4&Zr^o=7y~bR) zC**n(rA}BiMyv@iqkm8}(sBAkQojW=c0V>a!a4o!uQ?*^3qnK3ehVDYXlU^4?TydY zJ6K=kj@(OgaKlawT3`9jId{bl{!4kN6ox;10^JKI6@|alfY+@+kg%F;8zJQO81nB* zeh_Id0s4=kP-5B_7Pn6bp|l$|NTD$%jNCCM%n!H(+7}LBV98EL?YEaSisfGpF}KXT z8!6O|3p0unmk+~1VvG+|C7KuXui71^7kbnTP%6^u=?R=$-$mCmwxc@V>U_A$ttM+U z1+XGV1qD4zdYMmrz7MYtv4NCKl**iFL$6Wyhf+@3R5J<2ivtp-{3>l3KUzzO`dn0Y zuoVN-sG}5MzMa9J_L#|_?3q835hW`7%@_Wu`Y~|D>Rv8op?@>$s^ax}zyKC}4r@d_ zbwaOX8x%EY*)4Jw4L^AktvAc4+7{??yAie9WgJRbRLd_F*Cz&Yam3;e9bom*X;+@) z-o4859cRI(IWpcfm6iNFXUO?F9x4Fj`_?_`RzJXiC8MUg*^Jd`?i!Sq0g#wIEHN{= zYU@+BT2rO%nJGWV@9Rys?z$Le^|B|y%%2J5`0xx41*hBLnIa7ivc$e@Y@7Sf&UNm~ zb?g|!hd)?(VPt3xaYK(G4--XUkw&|Ulv%OURD?W?Wc;-*n>@PX$VZSvEy|oqdi81w zI0_GeZW}g~XpGu1{dqmcmSA2l#e+2H;c1zy4v0DJE>Gni2jI=SWC4zJ#zij&$4iu` z^iW9Dq~dK#kA3UK85S}+SfcKiEjb2*{GYcd3)J{V4y8Bz+bB_zc*=_ge^t&L0vGe{ zplZ#)@vO}HzwR!3^t~S5WOn^3cVxH-4bRtr={bx8>7v6%vXhha)+UhnU)NTx^w9)= zMVkLWU}_(#r(`=|yvEEQ%D$A(8yCiI zlq8XPa_%co#PKY8SMX!IBWn4}h2cyW$RAvUtDwzqBU&SLF&l-p-^nVa>xPNSZt22- zYN2vXC>Svk@oCjK9MQO);;G=Ywdca%;GtANKZgecJ+q@5glfOna1J5BBvv&%q#M$MBbA%-=nL;Sh88@(YCR?&V7fz$>iD=sBdYDEeUY|uFc z1aw)rB@KeLYuKaG_68=C5d2=>E%9ck2yJw8luhqkUhul))>IQ*KDbj^Id{zGjcE(` z@EE~aRuGO1A){4&DA~F;J$Ga%a)Boc-Nq7iqTcO@U~WrLURSb~ott6y+~M9m_Y_@~ z*$7=c87&ci#PM82@5ELzDbS7t3N{hFk7yF0tUJeWM~acb#<5ooO8)93W^qAsxrGs^ zn>7>WM>61#61inUh_W(PhcNDX5k$yhXCwpkz)n-cKKfNId{6*+o))wcO9@Hx-eLAb zZ}bVphtW?;)PhW0h?mwt_XHTP2By{X1oYVrr?LZ_Ho6F8rGAaviOAUrd`rrd%2nKOj%{pI-gGU(%f0NEg1 zp$9*(e?~m+Kh*s{;3SX{1}Nj`=5AtdFJ^6FX7?X6FD>=|5{|>SZ8{9PH%05VUo^_3 z_2Bg2vQb8GWFn~~m~69mHX9KvOl-y-Yre>xI_JcT=ZEE(K2%28TGo+e5!n@Hr`GbG zd9K&8Hva`UeSj$sn1Q=sSY#?G(~LKgEJ_es@G#;^7Z#gk0SBzT{l_qw^df>yn!9JW z-6m~x@Z;(8=fVuGIti8R;kJ(vb(3HP?xAI6gVOHXj8{h$~xZ zdp$DV`)+WT@2r->Y$xrsgJ91?#uDN~t-?|_NaD_{&+7>3ST#Jd_dJfB^}L;4+iUdO z?5~!)j(_v_0xO9<70v_4+G$O+rwgu}bI)!o6c=rT%rbFjW>4 zLgfjHj63R8HyD=7Hbw~v=@Hzp-Ocx) z94BrfNjIOLEd7jD9l}q)&Hhj=C6#f}i7**L;GX`l#I=bSg*ZGwau=o53zB5(e~Eg* zq7MxD(y3xpi=E`N$I`NPgsO4YU_n?rpb<@qBf(Ha1>-_pGnQU0W{};-NGqV3DG;Vl zS48<-01lZ~LTJO{=?Mn|Op|rsvJlNPM*+gq6uDJd_MDw&q~f> zdldr&1PA~DA^C3?4gFu+xlZT*+0IKs)GfW^H>+Tv;nOOx=9Cwc5JjXAu;D*K%YwRl zDVWB8Gq@ZfQY`$9UjEru*9KVLYQR`2+O5S)qOId{ z=ZKPB*qg26V-qct!$K&#?U)&@H+nMwZWigEF84#yx11@AD6-=H-qOQc1_F+Jb)NZN(?X;q1#R*%qae)x=p0 zN1yoq>>DjDKAL~kMYlYA--gn4Bol9`PejAqi)>tj>B70G%w(jvE$>vi!x@Jql`WYh zE6|223yj`YOVg=#+j%Csdld2fJl$zSxubnI*JBA^lLhlnft5WM9l2!f&*pjAP_s)7 z`60VKQ6@_VRx;YfF)cP9^4lj*wgL7k!F=lmdnKGY)D~B%!IKMi^t4A?G`@hkTf!#k z4Qq?+v(`pO317obcRWog4)It{sn9!GMIiq2Vf{dPl%QfKIA0tR8dplpd-rTh_Q*y5(+EuF8DjGKnpM{?4 z{_GGS(_Tixc#9xNiIzyZY?#&;2e{`-*tnEyYlp6V zKw{Hgie^&NGOT09_0v zRRw4zN0#6NN-Wm#O4N4c_wCrff+hXfzsMFlFD=P7mhl(bmv182!S~d)!rE4_*~4!-F$2!=mf1U zM0fgFpwHN&#eZpYZj8W)+-bnJAFq9b;Q%cBMvcQa;C!33~%4ygE--1>L&a)U=Tr)1R#Qk$CB4Se@k3 zfrX1}vEun=Qyx*BrH6-A&co%Q=xL(}1|)1pKb*C5;{I0GelNv$197yeRP&g9uab8; z6K(hAD^bNhPPH+VN=p>??MxP&UER3D%@De~qvhI#>%5x>P<9SGvQgC*90msjwJRyr z&b)(Cz3g$C!ngkBy2vDpaxjqK7l?ImrblP5FL-q8??=ET zD>k_0$^dBjvQNvYhW?DY!QE`Fu(wmE6T6)nkca!ab{VLLDb6Bp` zk-v0NuMrjTU{lj2iA&UZLWgQvVTweOXTPubO?3948Tl0qrO~3difO_{yYO zViZxM8cUcox$a+7K=>>&FHY)65zy{CqObOu?cM9M4}q`f8Lyk?q{iGyoH$_NJ@Tt! z-t(OS@AmYwbc@n4QJ=`Mp>NXZ#$sCUz=kS0cL@y-kbD)7D`h}?1Fm?lE!LUAdbqoZ zA!wh6k;mDxkuyLOy3V^1ky>Q#Vz7zm6lrFr{yaa5uFR;jZTi?m`}ose_}H&Y>6rM| zK;DW_Ba;1^LVGx5K7lG|=K1y$kND3kXkenvV-p9~3N9>Z_L9I!BYY}w3i;F>f3yC6 z=mR|uh&)ib(Ihib?i@3*H{hMKxNMvQdfc9`k3k>J0lE=yS1jq(IJD{rm7~Ch)f#JE zfq^Kv67GGt@YjIe;6#jl>q57sbt~yD4%q59qaz)GQ_CWfMRSfhr4z z3r|tzBV7)e)U%MAlNN4uCxYn4=y`ZD)*~YVh6U7$)6wQP#&l&BYcqEUBNg|-L&hXa zG|7u1%6ibLJvlFD08V+?N_)Xr2W&MMkh11pQTsq2RfPJMD@--HZ7t7nV7sMMG#;$B z&%_5$(lKi9%^r$p67JD?g=m$O27=tRO$WCL;>-56Vff?d_N*~iLENqS==cGI^Z!nS zQmqWW-g|t}nj)&_&%auI)XoTD_b0g3BV>UgMRW*M+%vsoh@NOIeE9xQU7Juj-j0;m zFjb0b-nL9ftOfB1R7_X+ydhKGKlb<{{8e~wGM={|ag^B#D{Hq`C0!FukUAbYAfHEY zalw=t;&3ZYL-Tqp5eICzCmv?e<>z4ohDWRHXSjcn|Ej$$a1RXouDv&UX~^6%S;^r2 zH33|FVmfsYv{AS_*x7WO7LJ~nZ*z`&;*Y)^DXjFyXHM4U0K3GMb-7yG@m^h{ds9( z^iyyfmttIn(!K0VbE~KLDfuP`Z1{Vdqp%BB!O$OxEL_tJH3-`YrH`{_0ggcc1(^ob zgk{aWzKd6UfU_d*SXirZ)8^q5wZUJ;tA{9O%Z#v^c;70%Cll+fw}`sS$e3hTH4olW z)-6eBIimHrO@)cI!ejb7=DOOmM$AOdJNoh<#aGp3dhT%zzVfcb?znXWXf?v-YQ1aj z(7HId($Jxhhj0dO3)5652DqRJZ1*exw7uKJn-YF|<@4e8fh>Crq=+%3Keni?G9`=w zLVwJ6K|$)2SWqzB_Dj>gpT(&ojEI=F1tnF@bntzuBrjPhzOB2?-R-Z8*ySg5i@WMK zg#Zpkhx?$LTGTw;ScznSI_1Ofg@CSGQ_nSAAtT0Lnt!!)OF#!mZ9`M&SveRlY+Auo zDu~{{P#GjeGV#c<5{e|_Ru^LFJv+Ts<`XgGVmiCx&wg1fc;cAAKSCpcW9IN=`THvd z<9Xxr4ZJ3czQmmt$Zn^PS1J{^8yZ9bct|ObyR=gZL7F*Cn z@K4rh8vzz@RF52f`a#)U&F}<|-JHg6qYFpzIooYvu!iNKOTykX&yzWj|Am{z`q7 z2b+|f&KoW~&)+OG2b89zUz0o8j0oa2X}P@c|BX73;KS#mw_%tLLU6O8n=Vna5i|(- zcUy-lAgE8eG+&%bQ;AF?-xsY*ALkRzAO{n}Tgk-%4TXoR`5nfQlJgHaz zrWhn?g1eb0&@dJm+56qvUd^T-|0Xp<<3ZH~InM9L=r)h^jKrJ^3yqe@G9`PIVu_k{ zR!hY|FGABOBu#%+Pqyb2%9<0_cT1YfWQmqN%W*U%!*Rfo z%X2GQ;HA9dakq!%XlTj<68%ZdSbniO1G&K=x&i6$98Nkl4gUeA9QSN}`ZC+`8PieU2c3@+|^{EKMgEp!I z1)8A(Y&$cUu+OPPx%8}T1E=o>&4b_B%X3EyNVc4-sLW*??lWLM8d+_Nv7K)SHpAcf zJMC=8Mz9Xs=>hJH4Qi`pe1Z2^P>DzdC_H^Ye4~m*2bp%7C(3L_pWO~G;`j@O5&+$@ z*L~hx-xc2nFGgM~eCX#Mk^HIpCin@$$~AWid=OK133*rTPI(I6GFW9xXeB2(U$U-{ z+~?^2cf&`!Bp}qOzKWjX>^4BSd*q2)eTwJFyk~5XRb9{7cn)Zc*9g zhb8k3b9>=x0C5_7*988v+G!wN4?5f7Z!IpfYSWw4bCBsNa$)tk-U2$}fnuEytnuLs zAYU57Ud(A~!jtaFr-ijYAtdOes&I33A5xuDVcUsbLrRA0N;$r@X5EjDLd<=z9?tOD*6Li7+MgbSGeuFN-F}R(md@xy#`d0v|Wv zTy{U5PA?0(kpo+xYbcBITzAr~U!N zZr=QSHDe%6Owj*V)>S}N(e!V)ba#5`?(XimBArswB_ST)G?SM!EzfB(Ahb zhbSN*NGty}F#=CVY_t zgD7Y=N|g(@C_D3DPB@O?%Y|j+M6@lQWQm*~qnR?J(Bw{er|SgPDg1ymN?psn((U%w z#Ze}^qnPihp-$}#0idgyS2A+jhDoOzdt8pK-a9`7NQ(Tw&!q~kq2*OD)|c~>sCiB{ z)v(DZGF2Drj(E&wo0hv9O55Uw%t2hmL~2-G?#4q*qZ`TU0+*?t)sIwIo`}>2#3{pe z(VIoIBs(!!I+Pj?yF!-7Q6FL${7N*B^vBXF7!up;gLdh>K8zvkWOx3~e%Zj^n&vCo zx?Bp1`_-qrjFKpMQK8d@>W6<2%-P!ZQhf6SPh^!-Ml&HGq%2L5vP#T@rXxhuy-z((WD;1v2hq=e(Yvv!U6Ep%Uuu^})eR-(ZWkri@`co-) zbHzCK5$DT0iEUC|E^D;Wl z@{IeZNRZ;EXueQKn1hIVYb5`?&yy+8*_@-Ie+2s~_q^w(cZdf&p{C&tU#XK0HzSW` z9t;Z38@^Xf8Iv7! zpiOs%B{iZ#)8pymGGmpRMQ!3p5&zf%TDGUpsh*537l484LLdkxXod;3PY> zHW?GLEZbrY7w#;Wnc(n4*8Y-beDmq2+Ocx}(XN%B`OanWi`ox+Yl&#EgOimuS5SXQ z;*?tbYA{jn0AYS1v`mYKGhZBl09p+hsP>}zTUmUm%%Zp|*sNbS$GKJoIsOW<9I+fL zJ8M|i8S`kKP z_$pD<#UeREd}}L#KbWoh@GzF6%tPc0qxXUpIe(LsNvTb1_K>L6A#Q={>!pM@CSfMR z>UHHPLIV}~=&mGg!V#G9{yHo9mn1m45ShqHoL~(`3*GIkz(*HXRmNWn4JV^})IJ%I zzz~BcUI~pIC-hcENw-jca5sC;2d%uZpvK^1m#3ZyD}17$M~K>-ZjJ=5SW1aV zN&leoXKWvmFaF1iDsQb>0vWyt!+{Iu8@ip&mL4O5CL4T#-kTwjvgTqK-9Q;otF0p% zz^LOKCRM{o5-n0}eon$E@k2QqVO*7R6i^kgO6mXd0K*xJ>qtW$1p*(Ki0z6lwKIiy;9=|#(r3uDf6_v)^AU7}}P)UrM;ng$61-v7o2=QzQ zD0y}zp=Hs2lCi>-hcUe=6k!9J60!Kz-@gk{&nlYY72aFH-gtQKL%#ATO0?@<-&xp3Zh29)<%~sd~ zV{HcC9Ba+{6spjl33AQ+aQwv4RESGqY$2uG844=;tyFHLCaf_)Tzj*(mwr_Cd@G{$ z`NGz4`d-QOe=gdSI7IVttr-)lg-V*2i)LtOAUiP_dOne)SB zQ@pU8V_R!yWm<`;-r!7ul?mw5j74{NG1AFQ)Amgl^NsAcwto`3!m%o zXc=|*mJH4{p7V_Z{Akl=hJm;N`rA04^1!IM`>SYJN{JY$ziso&3jWP?(Cdm zV$j^NcW-K6hpzmKfmd?5aJdu7VoaO2Kwq6qUgL1f^YU;?SG9ANQZwt8ozKNkjciwY zx8y@Q;nzkTC2B$=TkiboOl10FudB>pC(iNWHw8;L+X7;)X^Sb_9qXq9EgZPPy$7lC z{gFPTJ2_NwJp0q8zLk#o2VUDrYk{;`mhZ$Zo8&j=$S!XRZZH+@u-C z6f#7X)RazwyAUq1wc_-#b;>&}q#y3ay^ z_MYY}epWmlixa-)r3k(WbltE@C|qQ+S?`%*!zsHseYW7qx#R1Cipa$WsKP-Ei-Bh@ z$KI7T*1GOUOAx8h97~*lx!u+u^r{=QTO!1-%N7fvmgErTjsyWrOh53l2E`zW{nT`v_TmLezE3|GLIQeL3>3BPFDK5*iYx& zue=z@Qh(J#y5&UfYp!yGq_!ttv_JZKf=b06X3eKv;ww=Ce#&({afsfba^?3~wdgbH z(*|U}cV4e1FNG(&H(7MhoJ8lni(+=3`XC`e65o0ms7QOz(-bUzr;C|OI6$PFm^71) z<5mv}Nx&l#K5oxsM28mO35aT*KW2o@@j(Lc0I4W{mdr%)D*{f@J+fh3`Jw0GQ+-hD zmp^Pj4l~VVM}IONfL&cJ%hA^59RASf8=|~uPTCa{Z;3*;#oTY~)~;UiZgdTND@QbJ zjX{P!{Pri_$1lzOhKP7)7$1lE0@O;4gojl;PrPJ8S>}MBzaUV3Y@x|B?ZG@SQc|uW zg^%_Ff{}a=lTL5cPCw$81j+~jb$i5sA`O}6k(j9o-8C5jL24SVnS`YHgf2PhH$8g! z@K$pVtZ>1m*i?TbXnM4T@e z{VZtXI8VBYGA1Fo_aT9ZmPa-;#Au3haT;3A^-#bIR9Nh})j+>n&P9{_A`_WD`-j

    y@x`+Tbra}}5^vb;M@BwAEuLYd4TN!#) zOGK*#`o*O&x5pXU>$RO0!ec+JMa=Ek*0$ngpnt4YCJd(C&~pTHlqlzRYUBo$7$ZaZ znch~8dh3=6>0Nx#?_wA_Uo=tLrs|6}TaGx?(8LO=%YY_DRaw(;VjOEdi2>Ml9HjFR zs}RB9Bl&Q2MJ3e_+XFY(O>|$!-0{jke=WoDJ#5F`P~qx9@a~^MDE58QH>$={3hj{G zw(ai$qsrG{ZU{>2d*oVnar{K4A3$AP1+0DvqmPTPRzB15;`)2tljfc&klG*#Wd_NuxRt-TJej=B0 zL5oOgLnhQJP0NO-xE+RUoFK(Lq#&)DfZ`vQArd4zD4C!l+GC!uR)akxC{1QVLVXr; z-#e(ETa`j6S(^3)?-_N+w!`e7ZOCw9G<5g_gCK|S#wg2w5d#6Ck_1RJ=Y`9+5O0y( zXw+veU;~!IjQHqnR!O$LbTQia_*>|n9yba;#k9oLnn$FZFe&Biab&@lJ~uc6g9fMWN1#$kEMTg z5SMyocoWUvM>O2`=o}xqOw||Q zC)t-9rQpZ&^1ynzP%=Pq@Jitvp~5RxJ5*` zVKiIGYD=64{1C+MSQL<) zUx7=^tt`$h$nY}Kee!N-e&{^muyAym^q6AdsEP2aaQZ?=mF@mxlaf4$kr8UGheG+( zGpz@Ei@dcn3Z`1h_a84oc{{$BS48PPTO!;(P(8&dMSXfD!9gIEq~4M<9=hN8Qv?@} zv0Wkn4Na1f$v$0dsUAm)Cx4+1zNa?*v};}3*uY}_qm|82Bb;25chO%1EaWI4VHXS6 z(Xut!*xyJI&VVhR8JWb7H@W!^YJ`^_Xtzr8vHOWVg6uF5<#!qfqTmxnpmK;hs4++;{ zH!KhvGry4g3lvLY?cc5wUYSOv$MQTbbo^M9o3cAQ&plS}4TbcxCfY2 zj(RjxnCT4~RSRfrt(KrKrKBo*G-u@*&E6n`Eib`FzMO;aJHIYw;x&GwC^@pL?YNM5oDkq(KCLFIz)QvhB zJ`L&xQdm54v?w0;$|){hPv0?w#Zi-V?&$LMwmFe&9|=JNv%_Pbe)TI%nbQwMTG8|1 za5X&QO3@pHl`asmca4Ep9$5jYX&I9{s1Oon{lK~2`I_~B_a)0tn>xfOONoa;C2*1A zRfL-a3>hnVsiu0Vk|yU6QwP$a6PgW{Sih*4+;w}s9_gwS$&O)88|4VH)^4TKbJ0)y zED>)FYgwSsYOAcEBP`Nu$hG=FjsNMrSgq81T)RCKq|nTmc8|pcnH@0XWXC|~Ar?2rT3o?GVxa$GcDb)1k@!aVNxBcef+DGVCgSHkn zGLqu{{6NEa*7x<5fy%{027XDNlxbwA9jlyamz%-${iz2e=OVSt-Egh%?QM>l@<@jZ zvtiRX5;DqCw&cKRLp|%|m#u_hL{Eil8rt*1-WZ80j^qMGlVw!O;{>Ifomf%pA??KW zFxez%PQ5yzd1=z)p@|aY0<}}+y)X9y`J}>koz&#nrSgwa^xn;pOPSR-Pg%d=H`};oqeV!{HH`4@<7T3*~p6mzG zur#F|7>SpLkq7uzYSPkoi|JwXHw7BJx?IL97PTb(u_;;FA^TMHyl2h3X~Ur-IB5sWkj2 zTL}-tjg_qLi8Xb;kPNyY%F;}Nyqgq_;Bc^K+L|V=mZao~5a*s9TA%o( zSpc~@-pf%XEoU_YUF~lXN%eWgToF|{HsNg9nGU9^)*PV?)CBp9RwBp#gQ3tzMgF|* z4I+vfVEXu%v1Z_c`x@FyYL~E$cU2R~g7w~XEL3xbvuDxokm%-+2=8xxI^O?wL7Q76 z>Eefr_9DtHAKN1^neJH__$r*?XPZ#y))DDQ>@E!(y%=ITBaJ=Vfkx>3S{D1Z6S@Dq zygE6`9w`OUAoX5x17=z0OE4*vRh(AN>#0l|YNcm`5S$PVk$qGB9;YU0WDKE#U(QZ- zES#RdF(RRyswkZ1gR3UKJ;Tx7g3l6tWmiT_N7EM!&C$poZAR7!9kY!-;#R43}9KcZcxM+H$; z!_Sb%9A|pZ`;Bp~10Tzs%=XKYV)r|uyygP#$4X`&O&R=sSh6<}xcXl>@X*#9%Ke}S zxBWy?$yD9`;?dW_%T?W~0*EVSo7ofA9*wO%DV?>{0I7UuuCE`yex+X<2)oI-0ReU6 z;D%@KC=hWXcjkOq;NOJiWC#fCK-mx@P{Ke4n2zFu7YDgLc;Fw30`P+Ye*6tZp|M!N zp*<6TJ^=>C#&JQ{Sb&xT2RzFTQo;rVCnP{#*nr1`8R!NV9#H@;&Wr%gBs-{<2!KU_ z0a|x5zy+RFCb`Y-IpD!-@qwvHN>B;uZ4nks7_yLu`zaUq}ThLC(z1!9fA0HAz;H@3N$uO1wqTq2+=m6_2@bH5W7`~oMHuakwo&c^0 zdk5sj0mw~hg8x^r{x7B|v;Z#03BSULDGub{BH+NUDN<0L5FnSq2ABV42LG?#^1p_~ zqCn`h+8>?e@o7>}lf$9f5i&I7sOB!tSWp{%sZ>7ll^J!a+R1rx{w5 zTis9qah3#>rEq(mnt233$P_;EZEa+VZyq;y-JIm-?HR}d0D5_ekUP=kZ$0kk<@ z(D*}uu7@6Y2v06r!;{?by8s^;oudTZ*a4sC>_AfvfaW{|IDCgq_nW`}Prygmmn(7l zFS+SIZ2kbj5Y;W0|G%i&|BvGN53|1(1QA4x^zXmV|1$gk?XD;k&-wp#_HQ$Hc>Zq( z^FPeu@LTHl)ABbIg~D8cLT2Ddz1!z#{>3GXHGePTIR+BuHi4DKfWpdxTf3zqLuywM92PbPZeNoh!lLsHQ?AE0c^SO5S3 delta 35491 zcmZ6SQ+uEd(4;f5lZkEHwryJz+kPgtolI=onAo;$+sW*^-|n95b@e~!gRZ`-Ds&I5 zw*jn<_6Kamn)xai1PI7EOwx@bJD{tHs)_a;n_*^z2Vp7{6dA;c!VuBCtWnn_(@pe) z{)esD2I3fTw1WBk*r4nUrq35t&vUV&ex)BwQ_cF)%6HUvlz`Ps#+VRFU?tsh2J6S= z#>h*H8(8PsCkU*nJ`*OgA z$h|w%v6n-3-Z_>V^IB zldB5M`mT?GV+$|%-Fn9g??9kkCwiKJx$D4qN5_G)#UEn5pSq!@5yg}EUpYA(Zk6fN z9kIsfBYqLarHt4VgfI7V*(Bnt8xk49ccKRMvdI(I=BA+v{~jx@m7cveoZrAa<`-#G zqN_2vU=DghhPEF2^-A`nu+pe(6bI`{iCZX9@`v8wJv6UCMGb=j2LMgE9FK)>Y^!Gu z)R#KEcuX5NAA8HdM~|PHZ=I~(YpO~0B7F=3qYn)>s~X}G2^EbdS|QN}&G(g?cehWJ zI%PKGqB_jMjq1*+&6Nr{aNNqXH8Rx3mHW`K6Rc!z9^bFT$0jCQ}0eHY*SeOX^|%daAdpdtxX z(bjO3@qY=CwRZ?hKCG8|OU^MUJ5n>`62?&cKxZQ6`ccoUgU!%#2ki zdN>^9Qma~L(GKA(NrW+X`eqK9)n?4&lJIr0 zhC6S$7*0%|ikghIf(+uRoK$CsD->F1&X2nNdzA-qc)lhb&(`$L6}K>5HrB+xNoW!~ zQ*ua2QJcwH9zc&0*8Qk5))B31B(wirCBZkOGs$jP+;AUak4Jue4E`d=FRkO9)Y<0b(=hmreM*A7w8vRw{78;F-!@quEzlw=Loc)uzYKXQao94Ad6vW{ zv}1mU35rS@zij%LT0&W9;c1C*skwgH>!d@P<0z;wTk#HyB^H>oSdB$O&teW%M41$g z6jNn9a)}!3JWm+!oIi)t&o0(*5pQ#_a!{FNzc-rEs6f8=#=`LG}8h-wAo(aZWJCU$5Vo zPH4ccUndVW;S*i3&->nlGx{eI@(7g*IGM;_-1#QBgdvDOgR*ExY}KW=ECCn-iU;WP zJgTMrf<7tJ2Bgx0t1hq<6Ik(c^o1)QNMomoXTS>_)A6qV{XZ`V|8f6tIW`m*%oA75X-UX$Ri zHGbGi-q%@*#_WP@IZPrOD8Edd;`}#!ABL-CQDHtVD!7)VyaO`p)m$H+Qs+?(bBXNKNJ<( zEO3u9oLfwf$3aQ5mQq3)SeR8Fn;Krg)!dw z2|SD-@OLPlZX(mDO$)~KuA{q?bP=})Re7*-lqRmF4R)%XQ0`n}wO}(e(Pyi<#Xejs zOueSq#L;lLUg;>jRVR>XC{pbyuf~%eMOgCAT(xXB|Ku(`MqlsvS&V-{EJMoJxb zG=#-m>+vDwjJ)+&?KUEppB<&|rxD+Y){FN#)x%d~XbSS5Squ)YMD_ zm~alNWH08*ka~Z+ViC2MinwaXxP1)gU{yUW3%V|bH>>QT?ulLQF$e=r2iSZ&sTF7m^HQ3>Oy$zcQ0T`v2f>f`p2=&T5}zhq{!jRtM;YBkZ-TVF-OPYr zDgcO*EEqT}2naMZ2ndKU2zv`(Rxct5$RGTqK7bO))`s!b8`1s;%wPAEE-mamwf8hA zTxu;_@y6m$M4-y{m`x;Br5ujC@AFA3&aYSMA6@Bg$jFGwAQY1a7qU&w6$xz!QSUZA zjmNB0fS(HmIIHFzQ7KI;U1M14ya+aixffSUT^O=C9A`Nkcm88-eA{d_c!&R;eZNe! ze6Rupp7vQ(u6E{UuBbg+RJ)C0vJ=)IXhPXa@=1w)mo+^p9qqV2f9YEy>TuMO|tZpbrx4uP+_ zzT)hFrnnX0uumBHD*2fd0C3!SBWK+)`U7Ra)9;8{$h+FtR_jmRZ_;p!yIhKIS>!6AWvDoevw$gLp}>wiYa5TtG+)q&YTz~uCj)iV zHVE1l193qBPmo3r`fmYNPoYaKHim{%=r+3A*1 z-u86N^@>Uh8FEE@yn6_1cTJ`;jX+*Y?cW!vfBBY=dMC>EB=I#eM>fK4BfEP8Ved2I zoeG2%;5bsSgGs2Uh)2~I3LU6+s5Sf;9_tM4&yP(9Ep8Xmk<47z^`&_4Y2Cyl@7HLZ#i=;RQtp2s1F)KH%;=in$W&;GCL`7UfzsLN04tIj_k*# z8m*d|%CMKnQqwk?O-g&!ivbE6c4s;iz4;S`(@mL&`|n+oHNhusFuV#!^Y*@dHCuWb zSqj|O0Wg$lxB#WK9LLP%m9O-cKVgfq$19| ziBu)AU8pUmSr{>Ixx+Yt2jo_|(E+HTgYKy!51IKWezJV7$7=cNX}_mEEpE+_L|HF{ zB%Eoe9(OY>a}HTa^eVN*OO0rRvi^@&&g8KwXAl*^JA;J_Reg zHST-eSo7%zoV9#iSU|Cx^rT%%Tz~HR(hX_Np0A`$1H%a&g?gr~G@Ln)bYl9v03C;= z^9j7LLAEYhoIf*mBZpP%cCh*gOvSq8Sxd+wAHB}NHmVC*UvSbRD3&5MZT5U}Tmv&cXP0+YY z@~dya3(jguZ;%{rCvN1lM|vj9K3l^mpN;cSLDv0%G;o=G*Xm*4CCu3@j@U!HL35pc zjnYHcIqtIcmZ58)U-7_#u3ht*ROslUNEEZ4RYOmnZop)cDo5pmP)Rt)9DA1?Kn&)A1U65M@@Z{swMZ6*`PckGeuE#+$$;N zx0sCgmn~o+(lRK!-4^+V>3^dqO}kVpvNWz#Nu5ypLegO&D~0!pA|G&GPh@r00Fk{; z`yor9WLy`CI+N&<-gqdyv???6a|u^{3Jdr8LTl7W1K8D^lhtNnKnitosGziw%sO63!V(AnlM#E2)Fn8IM6wBt)RZrLb5%;` zu1Vs3ACXy<3wb$~lwr@Ic4XTH9zW>!dp|0r7;PB1P`3q@5U zCk-xj5D0lws$FhTvF&OW9Y`jJF)oKZ=?fG3n>S6Lks9XQuGZ!5Vk~Zl;R~6l9pda9 zNj!?Yl9*f<`4t2frklQE)vnc_X4ugM&j3Rb>D~Txuh!*8mWpM=Z|T#*$$EvHeCFqe zL!WgFX`s=JNRV|6|I^jK(Vsx4p1Ra>=HsEg1nAPIU@9LiPUmbF+chnhA~_RRIXgQe zbHj>?=Meo2$HV2xe|SPkpwnfkZckKh9s(;%UQHX|M{k=*oh+kS6k7IXhO*JHPY$Z= zxOBA6F(Ff})<#2U&=hH5udCijwBAUJWV4mNTKH#2d#-a|$0tHZt-7ZV1?Q20AWOW8 z2xuHX`)(cGhKB23N0+`G#Vwi0NukwaV!C)p2g1vBjLELau5|22#!Zv)eK;$ZX{Pdb z$UHcNdWgzYno}dkS!Ht;&eV}lEo%mN`CxS62U3slo8zUTVajaYVZtJ3=RkZwt3ZP|AyE55as zVIoTVhRwSA_GFwaBa(K7cgv89{zI7D-B6=qzO-=C(XY|uTH>(EasB(`nZE}vK**fh z0Jyk4qroP(Rj2aN#$cJMvoTLzyLydkR>{qNwdmD7CGrln0gw342$)|N_Yg0QrX$JI z-?H|Trl2^FcA9AgYWG$$@0NTSDk~JjWIQ})R8`EYf|+t&YX*eEOe>A*Wpd97CHNr& z6=jH>&x6T5qw;^t^|a;A-nUb!0bJ0>a(qR4X!UFFs*3U>`K<*P$?A?)?~nn7wQ^ ziHo5C=_^9w3yb-xz~mg!=k1;D(kj^$ePcZ46GxooFl1tbw-ER5&dLLZ8E$mDY7;p`$Ekeq540kwv&PK<0?}VNKJYL^Mn#N>((j9 zTxPdWN)o;*A1*o8UYy!U-+Dp3?u`24edKjid5(hEVwON)K&2_h0WgLr6Q@`Mrv1G!a%WTEnVB#!hV?7XEGQr*a!RN zJFboz*{!Dab-4cn8X$egZ8?`L2d<5la?UIG*^PnKNuz_?>x#$|W;gs+Gh{DVTES5H zd|lQyJH)IoQC)MVkBLfa4GsPJm&K}z<(+f&CE7Z-igW&%{PH{0GI+a*yt`xy9-j(n zm`x!mzf29t+Nz2-vP@7*n5-1qN)}81z2nZO%v5-tfp1)ZY2X`vUB^BzA^D1Nx8=Fx z{vk9IX{GzKK%ryiz^&ub%~u_0B=%!mfL)z<^E+${yWW`rZ%^@1o!ygU9-PC9t$&YY&F;w9=7*PM%pn?C;EF&hAS5I|8Dajd=@i+ZcmT&0#JES- z6Ag8X{-+SYD7|x=-|p4^$w%b>Cy8d|AfH%=u>rz_CoKoV;)+Y=*>)d@kSr@x&t zodKy~8HfhdlixW$xqO7jeZd6-a>dx)x}sm|G(~L;1{CKsa%G}@W$M#psh=CD)rprp zQEo(w%bKQZZlfYfEt3o>Un@?cTeFv^@(@?-F5`tZKH6mT{Eb8_E=*sGgG{J&o4Y4B9P+7c?~4;~9> zYUN#4nK#q>6pUS<{<+`XD12WX@8oE2x-~1c{^;Hn`H5)TKQmwaKq4SDjkGtw{qt{n z(8?DOBj32Xv2c&$%NV+zMMWFrr#LV#?aP_e#_c+T_lz{Nzdh@Rjb}-Q=5d=POj+qd z5ZADpUPQ3qx+Lmq23r~7^0Q!@f3Vx@&$eN2!WRVIS{x>p5f6;V-U%B=kG`q<5N?@y zv<6!AsvJenO`{UE6D)$`u~Wx^5oDMGTNol>;YjA%biZ&qzN@9^a@vOD@xet<1D_q9 zxO#2#bNa<>cH8DB%s+v}P7rYn<3RU)4Q0kwjPNkFiK5d!~%BU`j`JRNDwV z_To5yf=;w1ZniR86Bgq>C%((R{*rJ^6queTFkP(O7k_?-K_N6%G=4sSFchr$8mEOm z0`PM4V#f#M%i5&xQg}GEVOP{-BpvSc?$D*kENRlrn6h|_a*m}STqG^i!xkfEty=h} zI33{(2S9e?9~J)#+3XB5b-DbMl?8wD&40slQ?xzQi|p7w-5 z+)v{j!Y}x;7Gr44C^W6vd}ufn+#{iGr1#HI9`*d6xB|(m-T(f4lRhtS8V?dHVG%M+ zIXFvUKtK>MKtO1cW_>V{6n@|Uo@gWJ-%#02rAs9Fs8^N(rb3j;!PJmZ=EN}4jzmJB zB#yt2nxvpST1_0{61n&l$cKv7BNkA3@l_NW(22Uax?j#8w?$D##soV{7g8Y3CSLN} zvpF5UHBY*+3A{e{XhAe0AYgOyO;~fvMTQy=Z*93Zt9Q9+Xvo?@XVh;2K8Tr@0|@^v zC6wt(&z}aDBeI{K<$*qGi!#GHdht<=s&~#^B7L;#ldfa6DtFeKw8l3{12%`ZI_NJ4 zZms#DKdwi>Uk)qa@WowK2Q>b(DQc!^!oXH?fK5}LDgYin){P7OC~&-Cu;*Vm9eavQZCR(yX(boIH6 zbBck|;I)Z8%s%u?CPhJdGR8B+E3{L`}Nk=D4Rg%V@zb9X>z+S+i8OP;CmFi zv^AU+)p8Et;FW_l`_iG6Zsfb1zlDImU6s(;*`SXTTqA@s);gj>m!kPhf>_OGvI(7i z^D#%;xkp1PKn@HkoZ~@`#s2&Y=ea;~05xIRh_rZ*>U3pRtW;!x^N#-g@2e6^7=_C% zHf)1}%UWtFOq*}KcHZ8`Yi!_+^(#S-VvZ{4QRzIuJbo@_2=*eee?kjt+@d1H z?Uzm#+=(uhmqKETAqWo4pnr-CFy7H3F!PBIAS+mL1(edfHiz!)wt~9wO`aznaS@#C zxnoW%9i`0Y|D}E0#rkKzMPMsk91Y$$oap;EZGaH`oIky_L8I7Kq3CbAV~sE{mtyql-9Txz{T^;#F9l^4#QWWb|Sg8(8IECd3HArC3O&nWQ`AnOXJ%3kR+5N)=|Hb++Ra`4ItdAXuWDMk`*O?n{a8&K8hMx z9Z>gIujSYnkgp`TM4hOYtU|;P#1Gk3Bw?eaX*Tkd91nVw%nv%N=(Kv`ZKZ1-AIo*r zKQeTY)0(XnPw=LiV~aZJZ(~-Wy{&{%qU$qGzK_`zYg!MND^$D5m(FoaumKn1S!X>U z7_rp3CQ{Yuel_Lk76V#mJq%$N1aAgTH{!nM$$7E0C=Sn0%UW;YXk+^1E|~JIo{}7B z7!S~J>2^Hg-QlVRycQ?Cl^(M!GowC*2l&`MIj4DhdK)pSR{RQ3Q==yyA8VnZL1w#i zil^|KR|MOFhxH@0&a8aTGJyPMY>L_O*zhGDM}-Q95trNF*&=4RhYT2es$vzZjme&# zKXNHW`#q{EhG&@1+4Tg6<;+|4b5R1uSJQ6g`Lw)GBtJ+`|-ANaiaQDqfQCsIZpWE zHO$9fyMoA%DTWfi47KwrN@p-aT##Yka`Wyqqg;_{7Q)+W#>|;~zWg`fl`o!(7 zlvu5)lPMjnHUx`$0!2~Q>tTsM7SRkwa5Z^LPFwL81bF?~3c#hr8y}CHhXzRy>1U=0 zOj@`r*01CTB3C@p6#}xK;)44A$$F5ntay;w0>6c+lHH(cW5cjV9v1h(6;Q4~pQ1?n z9LeyxK`H*eJ&#Io%T!U%v+y{h?ez=`4KU$I)+Gx}CZ--I4CAZF5B;_)6NO5h^|e}* z!-U01`TgLw$PCD&F!ogSHm@~Rn0%(T|6{-)Uy1EHtoTn9imY;nr_$}vN$$a?J~)Wy zQP;5q>4w!;VAb#<*=r!i*3Qvw7P@9Hc5>#K*YO0gV^>Y>w%{WfS(~9xMdwsPmK^5!<4-VF6z`kj!BwuLV<)+PUbe{E=5;wfSYnmsGLSV|;Dr zbbpL!WNS+QAtn9JenoH;+IupE0s(MySQX)z5#f@@cp+h znHQ#lO9CL%T9Aupr&7&)W|vE#=%r~B_qRV#iMl!e2N*M8&s3xJ+KOkdh_WZBt%8Sgy!@ZEg)_3U^&Hv@lfNq)eY~|MQqKsKf(6pG#(lv}mkOz|ga5*Py-u+zbbS@^sRpby~!;2#hLS_Cl zNR9q7o)Y)pl)tvAy@|oU>?JuLsZPDJ36Mfur!CBI954y2L_7H!a2P7xiMM|iWA#MW z4my^)ruJ$6diWh!TmIS+38n5UI>c#uI@o$R473(E-wb;G4nyOsGLq;c1+5-&v#CBZ zbG6x=yy2u5-Hm)?{%Xr%$xi-rgKU|~qTRUrlu^^0l9FMgfX2U2FR52qVTNm9ZB~{m zLtCUZTpyR&UQj8^9WdQ=aIC_uIin+S9$b0y5SoPp_r9&8d_Hoq1+RFX)nbd!pa9nd z0Zh|vO&5n!8=aIPKT%BeuOom~;(DF6!sXa&tJs%XWo_FBe4xt0Fmwe=G>&UCz9~g1 zd&I&9`()EO_<5~2#q{kz2JaEfQ<~we&$G}KcG!%2c`?%|Qs+Hwa7^iX=NmbCU!hQH zcP4}(E}#@HW}a3d*-vIoYl;$%k3+-70vZ}e??{)t8O--bb%P~t9^;N+cNiN?4Iu(2 z!FJr#cX0NM`M zR*!li1dw|kRagCiXO-?Qt+SdRIjeQ5uB;M{nmXKgTPo3e+ZGmdr9vq1SldNO>bFIq zH~T&~?gtnMx^?OU9BW;K8|;rpVWHWp#l}cIin`4;Y@Z-spqeX57s~}!zYsJBknTtk z6!+K$Hm>BXJawjDc1Ljh19PoC0SOMlBpbnzM%ZafPsABGv5tq13#-?VO@SzF?`rVO zVcw#l#6TCEV@HDlxVF6AG#vjBO!lteH1+{*`+k^Zk`=S(~SdNFn4w*l)c|G3ITb z#%@FIu0||~rp2;+lAopm$U&up(aW_|6Tg@+Zqz=lj2{S_$V6d>`!Rhq*zQrVt0g|e zRpyh_g~gx53|sYqtM#^!ray;^XZl^E!Op~Cc!{QcDxsIO#94nUd|Cy-6>5+9m=at` zM6@_z(OTm6q*zg=J=D4hV~syql`{=8T1R`>az{^(O9bF&hjmE<^ZRe$IvN%IoM$j-!doZH^n|)~SRCr6vI24A_-|EeWj3=L- zCjXg{<(oI02S(xWzx=DRSGwFdlBj6UoD?fFB4iGk;;Icc82M&=d{K@p1R3IF*m2V& znS4-3+%g>bX?Dr)y^xRfb|*OWMuY+&ucT)Ywdua)ZIXh3yaOr8S9mLf5dR;(s1lS^ zeWA-+ZZ;^^>fqEC+STN`PdvejHXIt`A^7Dg#(X=-D?Maq=G8W5M9pj%whe*+6oD8= zOU#o!?kYSz{-AR5uO`i}$KZoKlp2Dh<&)c-220&Pp!(!`qWLHq5LuPQZ=SDw%fZM< zP|G#=mA#q3fE)ieL+(wE6rVG}4SISX1Gjf>?}U<1ftx~2X_9BM1q)c1>;Oi_Qu&JlHZ3(+cp>U9sBb9wdCJzZ+eAn{S$EKFE-PCIwqmw2k7Ph4x z;8_$%Iyi;vbrDeOX@*Fhxy6JL_a^|k+e9k*_C_06wFrw*|IVEO*Y3!slTXT$9G#%! z=9bnFkWvs3)5sxLH6YjACX)OXp7NNbTsF$p3i~37*brm1#}ws~ny_LH{c#5ZIn>BS zlrs|V2{EwmhKJ%{vS_jQldf<}_g2_kI6Zawz&*BLu`}u$YV^N9dvY$=6EbKMor^?a z9|RFdEY?mK!570NNd!!w2cQ>5VDSp{z)2V9sR%D)<_EAe?SH=`&ciOI^6%?=iu7gQ zm=p&Nzz+Wl**1mc*`cWGq{2y^)_GwezeZF6r4|(L{iHEI$Oz3Sh5-GwsLpCDcsK!I zy}WkE!T^i|xZ5+z(JEP=dV|1^{}VJo|9?pXwK6(@9t{MJ}4g#QT~s4XoC zQZ{yt-L8TX!(W7hH-zECga?yJvB5}bMWgNgIwr@?AfN6chH18@*RW}>)}_~3sjw_o zS3)6*v{};Gtf*d>uWVVa$Zh$;_=+s~_pm)_mIx1ePx{jBk>)aUFF4Wtu!#wU^m7jH zdsKeItBsAc2%CC}%1XilC>%>LkM@mqQzbs3;hUEDJU6v>cFBp3NgF;mhT&7rl(x^A zRNZt1Q%o7Iyp^`cnOHFU9)nf%aO%k-*u{pOaa{msa9ki@NX{X#ibQ8{T2PyIbD>Ua zFHf8}a!F-tEY4t!M!eSxIcfLo>4!5L7U7&aR4oD$qG%7>wN~{364TNS>bSIyS2iz( ziDMaq>tmW4_k(JQJ#>4W@NOpe4mR52a&%Y==nz(YJxcy3SWc?0@u5n6-&EHsrv(=K zWb^7Qga61+t)^#CSI$+5j=l4OjDX}`jC}>>IqjPb!!{Y=i43dc-ju!dAw8^(y}fxZ zn?GlD62X?d{GSV8AH%CfhIM4h4$twg*$bZ{$6e8nQz9%H0EfaLwFZv#~EsmlmKI5Yt#@MCiSO0 zMKcH9a-q5~{eO5}wj*}kU6POr1X{jH<9xe^E9sIAfKOr$Qo=CjMvAXx0L zK8lfGL$=qSWb2|qiN)4g)vAR!=!jx8c7`OauJ%s0GSMen*V)Ed`V{W&BCTj{y_mb_ zaY3fl|CW;E!kYV(Q)Q8_s#b`eV7SVh(}2Mcof6LHqhAPII&-PB4BS408#WEFdyf=S zs(pNW)T#mu;A|)yjxwkg@!Wola;Jg!|1hOqXooN)SxJ+1wrzo1VO^^v@z1t0((^pgaXF)*l5&UkF8VRDjAH!sz#>{I*S6m_!h0iG$2MxbJ4bF~c!VK)R54>tJtA zPs|c1u9weZ1%yrc2HAM13N%X*Xg=v(R}ikvGd<+!6$u+)d1)J5+=wzwDh$n+Hb4Ie zb^3~?^+s$nOqjsl{MKeVje^SGW(zGvhc8k|AM>%b^QJ_Fy48e}ZAm|D6mg6gTYgNx zj*!67=pmd(niD`8QPut7+tp~20z+BzvgOx*Z{!HDaVgz_E47I5nJ4TDI%dFb z+n67MH4Hu4pnFEm(OxR~Xc-=~e}D^R@s$hMZIT&nKz^)zi*CbUQ;x@v8Y~pp8hmH! zZq$Fl?%2U|f}n2`=5a7Ddz7ubJtA7dvP7_v;HyAdy4yt;H47~^?NDBT;leH`S@H(h z(87nn`yC7V7Ks#6du@Cxc0@w14GV4jX>o?(0W$j{B1`*j5)=fhP-BHUsGr?JrQO&G zT=Ksv3x7sbP8N6erib_G7r_3g{+8XDIKfGMEdT>fZ4LDre3;u(-KO<yIRQ2)T^$X(X*ZnJ52hCC{}qHdJm48F_RUdp?&YSrH? z9wD8D|BbWX)%}D%D^H(lI&xJ-bnxci&CVdqI(w3QOy|U7?xGSzphteT-eZu9BFUE^ z%S`dIL0Ma}5$mFdJ~RNjQ6sokkFv8fSJXpQ3V?s=Qz!YlN4XDQ1*K4G+XF95c04qw z5#6S%B>M<{?1*aH6G#=Vv|AI>@tclJP32EEZs|s7%6e>F?+#X z`soBs;>77In-A%9C!06;=G5MyB{`{Erl$!ISaXkh|4e2pQ45#2H5K64e+Mq0 zNX$!EJ&6s{X?AsW+Z;kdC2k9MGNbv1d5f&%rE_HQs+|H*OW~!pfA%x;i%K*PtNF(Q zz*KG7X9aj?SAGI< zeqcd`6yGUlHdZs$A5!gT?~RX2Wd~U@oxPN@JKPYU^4{hX1m*5LuVx5b!GQZR@}jTB zu}UZkrWujmHhf`-S<)!gG1{&9)`J{{7OpT-_07#+bZ@8p)8{*A95@s-t{R|uRr62U zQF)vB1UO))qse1sZXS4P{?bCf!u?~n$|QD6AHR_<`pDWfoj1Cu#!iO`!fgWXg=qe(Z1< z>|F;d-W%>4S~(^DW)b>l#ZJAjD)+Px;=j@&4v^w6VLEgJ%(wU>=8v##R%u4E=a+<&slj=L>4+x7 zUr6h#wvY)uOrGY!w+fa6=`k_5MAqF1(==rRh+}YQFb4f9TcjUh!a}Nnbx0`F(~jGW ze8BKg6#nW1Tn`5WV-&NDd`YIIA;Z*pYswT#QBTG+X$Y$mM9E6A?1scxgDYz zyZ&JCXW5b^D>J=M#PlHuZ+)Ki>F45+{McOaINR1Qu|!|004@2ltzPYgHIrkw2Rydm z)#3cisZoD>3W>v5R*Y4KSXf>71pZ&trGUS{zOOBE%AvcnNGsxT>VXEw2uWXCeiSXd zT$_Fw%WgKuVa+3M$kJ}fKRrGQQO?CV21DWY$a!9{5@C9?#6qBb!r$~g3`J99{sQH18S9N->K|nD&`knqOB z=55#RJs3?ze|#A5`RN!TrFG3hz=>J0)Xs1_nUwI#B5Vk*tpQ6#+o}4Y&rAAg&B?s`=*Q! z;;aPQlb5YQK59v_z*}AksSgt5yRL5AicA0sm-J`~cJbF%DYvL@wU54{V05S+SW4*x z&u-0yrKj6#;Lo|lLNI0B(j-e>bd-c3KGz?9LFo*Gni%?G+|D8+KCyT!QvfC6`Y~#$ zJ>Q7Y_0c1KljiP)iBjDGcXwG>LzMT}Rx+zC8~=vrxd4uVT31|hL89Lw9nF>`>2o@- zFXk1vb3t}!iUE!+Wl-1|Tgd$#M^Me6RDyU?O~K9242OQyEQfye)He#>wb>89_aEND zSzm_~5HrO?TWk#kQ)QtAVSpvLfrREN|Fivgx#Os*TnOsd0ROZB&W75dlQ$muP%(e< zhWr6RVHXtSoi;Rflu$c(SL(bN4cJMeoPefIXYs3^jOGIS?x=9osZIx?+9q3EO_;x( zmadp!QFgp7$zfN5eSeh|TZDf!C*@Z3l6zGbgpK28^Wh%c?8)$GF~EKBl2qE0M!|;u zGCK&l0s3*O{8(4npI|f7kwTH;jkm>S6~MpZFS|oYP7p?qDWb5w^kOf~DPR6OSvAXh zR5yPWqs>{L;3S{da@q3yfy+hTg>h4nQr*m_q0=h!iv#CaSz_wEB#F}#?JTp$I4sKJ zse4zsgW7P>gmtMQ5RfR`0&kfqPH4iOT?Iw8W=qMmqIk=r63iBV#IWY-jR z{X>u&t}8yi zaZ+`WlVBflB;k-HO#fJQ#NK@0Kns{!syNK#+5*!`Kntpg`;QYtsC|Y!8c)l=4s1oq z3q~dpQ>}hVCIE&;O_BY1fb(;qCObMMKh!L#^=L^IDVu(NkSb*Osw@(vm@fLHb#t+V$fiFSx7;}ojcbn8ti zgpW!cHA}rO49BMMfYD-oI2FNQGWP9GyJrsQjyB}qav(HU&&oRq)sKcBv>Z>XJ{)mR zzNl7O+E6qub53@9FsWg(bwn<%b0^y2(*ap7?ZL^Lg!rV=GZIYmd0vETlp2K@W0yWZ~elWQbRq{*DW2Hj!?@jPslviTy`N0xcrd+wIwQuUjP~p~_ius(Ym&A1*`nXR zO8J!7GU=bx;Qr(AhJSl^79OL~OBzE>3vC|>Aukog;nx>rz2t|uWqnSYyzNhmf5}fv zmNkr}HsV1}l?QSgFP#q)RMhVu!w$-0Jw9eP6#!`(98W5CNxr#rq886e*<$J5RCW0x zKM|^}D;)Xdy$HxHnnOI|D(kbR*MEDG1(?YXFl3q~=tpUa9e*|TWN}E1tRei?BQ|NA zmzB@+RG1#Nf6pX>kF#H2ls_3anl|sc3t%TpNPQi;e=R)T zfeEl)gN?eYLhScBiv=Sn9b&8pjW%H_9}!pGKor|sRzf*mLNtFtZ$cTx1~F|6 zxu=% z7m%_+`1vKKEl~cX*DSk(4_QWF1YcV@ixGo#7)bM+3jRa?A-y3xwRKoYJALPol;cLp zec5T(sY>w2wBdtH3y2*4VRG<;NqLwnN<;)cMPl|wt`;p-KRBMpfNL}{7Zj!QIt(De z^JJjo;IDv>OZDEEA0r=?r$o;{!s~d`PY)Fd_%PHla&8g!;+Bh;@COlI_HUaOiIK;+Xp3LJsqgVYMLd{E8B$(xn z{3A5!$^|EXc7yMY6?rT%mjmVP?H6FnVDBc+*eqji-)Mv%U*(u%76M|>!a{`Fgh$ns zbT8J1@&+y1WgpqgXmD2S&b9O=4>s&gwJyq>OheG=icMgFG&I!La#gUGT50z{6?c8! zslag+uaNe3?8M&zC1Nj<857t^g?+q$kS7b_fnCu$p#p0QvI?E*B+6cx2MZu2GiPsy z-f!ot5}&bnBPDM`RU^fB2!aHEwV?iG2o|XU*$L?i@u+z)k$DoT>M!;W!fFr=hdOtG zDnvk|>8WANa1ty1%nt=8NTWh*y!)|lQtOX1P+WWs?W;7<+BQY9}z}KHl z_S}x#IV=;zcU-JiOPNLq!~2Y7i~}YoPV~dR3UoD6;B=+hzkeCnL6BL<(3Fy+pPJRv zqvC&DqZXN3NQz8V=BwhvL@|_Mhe2=TL?>4@Or;bYf|6G{ItkBc?CqPBVxKLrO~ZDw zWU|sea2VQ8XU$K-R5@~VvQh`JE(k=jP(_7}`D!Sa%fya~Ah&#P^(LK34mR%fbb%r` z*kk`}`2hlA1O@`a^*^|=w~qo)(Urv&M*E&NZ>&7iIH>4elPwS!d}k$F^B6EIe62-;7a@EHdoPrkkrQFofc8sgJ$cT)$r|{4|2m-j?Poh#7>-Hq zsl~c2YijW3c~B^FyI~y7t6xt6i@O>|nly0vxUiIocON%d5eKt(H>Ct;HGOx^9N9JP4>=Q))frf-aSMhG!6hi30^MgG?XM10i$~ScdudSDUb;MI9l< zdv{{4*y1dbZ?2)8!H%H*jZN?`15~6ipnDb?bo>|ToQ7wT=cIc;Ap>5UZ>`t{sgf%k zT4vfy;JZLAJ3sn&LV0IogDj(y<)dut@|`l?B(Rcc|)8ea@V*mgb#VKhA?) zN8}s=tR`T^m$m5b%4DA&O~L1fe7Ox}C;;MqJGp*Rg|$58S?kkv znqS7(MfF1QDvFheK=?%+pXx`gM3vkix~6Ygqy+Xg?O?*|VNSPJBe#L%ebZC=an0@F z^)e;+?_pRFF!DV{TZxG6s<>I!MH{b+oev1kZDz5$_)rp|{i49>k)FHRG(H>wva zG$g;)Lq1RvSq&Y#hx*f3P`9Frk32r#bc-BH~ z1F-H^WtnXW>esnYBhk1`EJukCDCjR|KQVhZ3(IE-NgjOULsauyaD5!qqd1sdFgujA zu1xB!EsJ}&-r6ZcZKF6wtgRc+!s29FL6;GARis5@>w{uX&sR~ltcQSZ)pe)P0FJ23HP@_JE%1e^^UlLX>8vs_fdY!< zrd7#y3u`iFPoMH1f6r1#m)2Zdbpu2QJD)VO*L7JV{Cq^nF$1CQV|v_33o$=LtXiX^ z`{hln7nrLOaG(4SC1j0UlGsd6Gy*XP{B{7S6Amho&ZnXxM7w%T_ss>{OC`4?6GB6X zXkwP`S<=p^^8gS3GfWa9?xVhcB5V4rrinwnwN(-a!9ZocvfTl$+PzR5ikk-D$Zaq% z)JaN+OdAY_p9ASd?^f6NL_-kD;}QGU3ZGgQhH6K ziZa$Y=_>iF88k_IQhq(1Oh2;8^z^>Qt4wv=$Xxk%a9OL2d4VP+J57Uz)c9@2CAHt+ zrUS@ZW?2@|=?=#5J#>;Sk#7(L2RA^WXrocHpF8`7NQ-CkKfb``Sh0W zi$R~d8u0PE8hV{tWn$`g!2!1odWIEQ)uLf^yJ)=$(|3_o*jpYyj`RKo>9QNeog-dq zQT{VQEy6n@@Fp1vZSxYe2ytdo4!O&y^a?NuW}OZFaWy1KWtD>>5WzfcY`DpJ!^AGm zNdkc~#%o!j!!4ry*Imt@O=tF6o9D{vEkz7PTf`V7v1jTFMf%W(Hy%)x*B&86!K^Co zK*5|E6OkZa3@BO}ol6#MXCacR|VrG=Dsagn?7&E^3ZGC0F5+eygOt zzC-~QX>E-Rt-%(B!*+iT^V{Z=GR5GZiT0gr5+Fw<0m;V)2T~7%dYg&FhR>5ob6#!^ zPTWEg-D(f6aHc8C^S9Zt>$}5eM>CILJrdS_Zsj`#2I-=);4Ur`(`!F>qVo3jZ zJE#IzjeOJ`0B@|)Hx|)^i~v|)Fv4|$Ggv;gz7N-j{RgZEW~nbWuT|mPf`|N^>KvRP z0={r`W3ai9(oLCpkM>~M#))F^@m^%Ld{}(H&KDQ`JZ$JqQx+ag;XU$T)Y?KTUTpb} zN`!XYx%^J78e>zPhT~Khx_N_$ry~NRF z6mbU0j+fqDj8pa!-SMPridwXd*{>gso#O=HFctjeh;`qo0fLagtv$C(|2-k*6O6FfzK=KmUj93>bEi3dqSd&uqbrGv95j`EQ= zmh~k-%wS>BJLG_qu&(vIL!=tS?P=-UqE#h&B$AWTE%q2nCy-?q!$(5uUCZB96a~{+RRunBk$Whg6k8jk>@$ORZ zy0%`e+H=eKQg!!A=5IhHgsEX#Uz$kA?(5Ir%~(a#EDy>5AWV%`{rS>C(ut*T;|i&N zef?7-8W|$B<%qfX_(5?~o6!HIf%j@jBHNg>$r&YOx*TqpQvlV_Mw(S979c_b51P$&=JfTSCWdx9;|I!J-x zRRNzSDD>qfK*s=vxfkGkYlnrohkkKYXz%=r_5h2mZ?io|Dt8g&ASxQ+GWIDxy+`g zVc6nu=A*8=Tz9`&94tI}Zu1r;a#4K|zg-;jci&xO8bH*6e6$;aKr{&L+xg>Y#0B9+pf;TP^3x=b!OQvG$fv0LOJ&K^dLmMK8_^( zyDMGd#}tfs`;M0Dlcu2z_OHh`sIu%jw0;)xn{SR*;co9I9b?cSrf2M6kXuq5M-gA@m3V9FR|%)w{x24 zNqKv8`rj2;Gh3Uhe5EGPT%e=Pe&D|)=n(`v85{5X6-IRQ#Afz%*cnZ++mK8U?M6w# zKUIh#gM5SRpg{)kC&6%$TcmSuHNf*T8kHA%^>MIVhVOBg_vQ_{{uzz?gvC=Bus!B? zTr8TrNMmL&5{I(6Cjb zdq;h`3qnBymz~?xycn)ef4p6}W?~BOT^sy}uKn6+KR^tPqF4D$Ccbi-l;g~gR7VNt zucX zlUplGd7M7qVzZLR6{xy86oya1z8O}pf-2v_WCy^3(N zlfd;w_+GzE!>eEs1!NkPlEqEZ=+l_7r8kN0b!!^91^&1R8h9>)XTHVu{Rsv@_mHX#Ik)mn{9U)dzq zcAc*k;^$w})JHc@ba}6#PQw^gN9PIYl=4fg6Y{*zY`z>DMaB z#4&iA+lmTEI2xd!r@lJfMqz%}%Y>=l@NRIpch)anslx4LlC9Tvq(9LU09Ac(ck+kz z8ax4cam~@v-I~@Y+Ira}LmpF+RB%o`pWSm(&&Pw(q?$j zQ#nevq(?8zsOQ~-2f-4I$_-5Adz1*nR_FjhGmb}M($pfVlbGOK=Eq|*Fvu57xfgQO zGoKD}&$t5AA3W>y#QuETwO_p|j!||W?4Vx|y=u3-`X2<6<;ukq8J0kF z3c}nFUsA2j80p$lPIo@vSn+q^A;Mcqbik1u)`&7TK>1eVU4D2+?H%+hsjhY=DhwbN zo5gYwJ__wS9_}GfS{lVHswf#%RZGq36qH~TqLF`~y1cC5{jPGnkT~JP#buOUn)O^c zxN$A4sj5|lvi#EX+iWY)%iJ|-1Sh`9v%a{aCjZz)rSZc%q_vYL{BpyhuXx%X`3c<97rby42{Rf^la}DLoYid^tiXn(Cv*Yk6{#2BhN!=l21h-yN z7BrMhX#Q^LM4phWyn_gO1XaR9v9aiJZjop!huljqU@Nx1dAiak&++0a(F?Fhc^Kd5 z@4(oJjerrY&-f&sECh%&TmI4ClBwswb2f3H;GL5;+ndbc0=?EZ;W-zF3U%sWrDQwKu{Z~cX*@&afU*eDKN*lYw|xY zoiox61&gk5hW?E-+l)m85(5y$Xj)!{6PYpohi4r+AoG`e61OIXyjCcC=)IDTPMx7p zdsI`16^S&8D`WO3e(5YD9<56SRsO+{N2K`eRK#DQ#H3ME=npKk$DA2mOtZcO7e;SX z2bYyIf#R@Et)cV!aY8egjMqr zkApYV2FxVVxn-GKhjMz^K*%K5VE|$T-qB5TgU(okG2s)LFT?`L6@NBBoXwuZW_k8& zXi8J$D;@U)(F|;Zs$?VF33135@@hmu&KQ$m$iAaD73t|O-_;N-+E=iHk^hsdBUEUJ zZ0YGR6OsCblynuBXayixHnreP5KKkBFHxC%p;tYl&}F=qFZ#PDVyd*XCq5qX9xbe1 z;r>l!!H{ncVdv5i?_>dSxp1o@H9*3W9o$Cv4m~G#hZ-X`?DPn;$H3>$nV?@K4>ezD znKE|8ImaMWN;>FURW=5?2S)<7dsBjK+k-%kvCS4qAA0QYTnEs!&mL+SpFAT+e^ru% zNn){St_;l7awSNI0i3k4Z9@Z2r z9;j9qE71{28zrbII+ISxALuTVlDO!cnse21F-0|j6-s%Es?HGay^KmZhdpEzbeKF8 zGD5Z@w9Za0hXArvH`TO8M)(Mz+6m&Aehzf+Tx}!XeT+}+=S=kN9qx1OzS4+7fO9`p z$2@Fxg4o?cj7RZfMoK9NDa6IHYRa`whUsMM4C%t7+NnrElfwQomBZrZlX6E_*&qo8 zk3a}R$rk9*1$}B;!-*Iw{(){=49~5I0gONqr3zyhmjY1g6@dn;UJ^CG60hYDZAT4O z{%Wc~Nh{TxJhsF{YZk+n3u*M!$Rl=uXNM0sUABR0QK;pMUDwP)@zSOtcVsmRU_z5q zcJ~PLaRkzFMIL&jC7dD`2p-*<$SS9%6fn@&Fmz>*fIXRzZp&Hxj5md;Fc8-qPB)}? z%%=BZ73Q;=Y|RiO?c_Y+XxRO+@)_NtzneP3Phd}THh*wNvP&QMwfhC~pV?50W|6Rj z-zib}iG{HIa0fIrQ?z4~^38`JKjLs2G2mv9q0?uFs};Tl*2Bare0hMGPM)f87pZ!1 z%PcGjQ5Z&2BpQsc^vzB~m23V*!X-&h;LI+pVSz9?^C#=AvJZqwR-;ayrXeix?F_fG z`H_$FTKd}k{mjbmAM~%mRFkSIL-m^H5A}KHhi*yWx@e3V?A zv7e#Ugu#(28wb}%t*0?nAE--LQM7b@W^zD<7r~l`XGsvBF%FQzI)nG^OOU5+HL?Ou zGY`)m%*IfoXa_$wuy)e)#-oC3%}`>{{aUyeP0nI)pP{WAgRHeZ65pe_Ihnw25#UzC z(5@NeJ>B5tArWdQsG1tZeJcIy(O>7rp!S!*X1oS%W}`?`#aNnEtfGB{h#o7mq#(wo zz(=BQidKOwH;ydi303(`iXDI?AG2!2ke(xh(s>VrW)bfZ1uHvcmXs zi{8R%)#o z5vDqT*HHs9>ZuFJA7KLc(UUR0vUKB+c@x1Jb^ z$n#qx|ESO@R2e?!)cI|=X||zY_}fCr+hR=7g+gVvZiVvzpSH&SVyutB3vW@3iwaXB z_u==S64el1aFXCP69=qmIdMs<1Poll)dj&V!cggO=$l7eXYQSlIGF!Z=7kK5Ahthl z+ZaCSGh3G&vjycJ)(&?Lddd`lb_W+5RpeAT3H1mmW)i#mafwL0{hK=Kl`pM?|2*;Y ze=WmeY_Y<`XkvLlQyGzf23P>CgMS3cu-FYT8M=I&gojZ>lLdG8Rr+QA3-UWdPn;O} z+#urLP?l-^8K?OKP?L;{>B;F&b8~n5xBHb=!XM_28~!oMpjJ_?iEK56mPFywpug%| zkU0jF#uC{pDLj{&t0T@e729oBmx_G>x!}M>d`YfPJz#vj$MY?V zsMA;_3STK4?Z%_Lj=+8dGd@+;bn*)x7k?DrcnEWDSpE1qlIiETVf`<=+uMS8 z7hMxgfqwiE6N^BBS+|lUAw5o?Bzm~vidK5sCsE1AA)(Bfqza};xCZOC9C1!Kd`_$* zlT(|$=9}$s1PxA))r1J<(tUG`R;C#y&ngJhG_GmD8tWuMFZ;=Tw4fSrt_7F>q6fy& z4~~$B{S{!DW=Z&I(_!a$dVjcd7KCqb$Ku|4DXQWY^koV zy=MZ5OeVoyjf4`lVPK!}LhbSGPhJhC8D1?uG@{Gk0=H|t{e)0tRF z`dE5is>ffJ*o(PpO=)pYqiE8%B42$KV}3Hc$hv7%A~8!N!~ntbc}#LhF@1=?ZVME< zMw~^inTr|@e59m^77Kv|2ii@)I1@y!gEE_KSm2IF^nR`A^_kT%{wNUSVBrDM(imj; z_kYqx(a6Z(pI|?JWWxUV!Ix-+j-QA~0GW8RhYJ`|KUdk1K>J+As3MIVY)cDnDMDcX z>C?BFV3`)s%ZgKv4XpRsswkpO=}=o* z&|Z?NUAAFg+8oC%@sn)E=}0DhNHD^ALI>g|Zr`jR$9Pu4r)I7j#;Kp{@C;BJY5raw z?{L+i*BC>YUSV(U$kzsHwnio7O(1E_5ds$JKRS%qFN_;E@5b^rS>(60t1F^`3U%U& z3H3EGCq=?`gzMs2(~V4Ui&F*F+HSk?c8l^cGguH??YNN~c6ZI(>3}l7+LFo&Eon@< z2`1Whg^482M}(chzFKW`V!cqoS2tHkMUr+@_n?#z&yqU3$RQPrZEtedoj`w8qIVA^>mD;Lfiqma{e7hC^Wp?G`32nQ)jc@9ntudW_er>wR=7)S=%C722v}tmYA%_(KD_drzX1B(8}{oK zamaAP-bQs}!d?)FWpARKYTF{GR*b9N);M0-(831V&3^fJ>=_a zPO1TdFX(H+{x5R-J1%|X;wu^vd2HAaG0)O;LILH=z8i*W`}uXnLKMY!5CgvW&44dT z?YA2Oe#HoWj#z;ff1*zRXTTVToOkdD)juF>p|var5Ye&c@R1R0R-*Cr(9af*Xde<=Yw(qV`dFg)f!)RK3L(;l=W4 zk93gkipPo9C*JWq!;_iihgEQ46=RQ7P8q<`5lPUKh|w!PavaL<1^h+XD6BOBNfgtW zEU`QiMam2#l@^ec&Os|Fca`UbeEbN)3mrtpf(a1Ivcqo`(hQflIvII-JjaY#%R=S4 z5_tk~woX#y4d6b)2OqNiiJ8UdGI#3;O*q>oVvV5O>XSmpj59($CvOp-SK=wr1_Msi zajF)k&mFlD969?^PIfS$!RALl_P;f|CYnlZ`EMcm`g_xm_@50!d!HOo{NGWw?r-%< zttu0t5hP)1mckew%q78P@^TrAu|>hp`S@pl-BKs*!vRBIe`J_ z#BKIOkEb`epEtb~ECc~xH^_e|IAH6PsSPLTxHs7+_;F<^x@`;1zXNP(hT994HjS7kZKL31XcM`oMFFdoTTLWWm+(OikvM3toXwgxQa7mKn1(W>BNLz&nngnohjtFFnT1YzE@LY_N77w?qg$r+DByuF?PzSf*C!ioA9#Ur31 z3%5w*O0G=-l$KBLLb40FOul`Y%#5b*aPpd1;xqQE?;(!p0B0@DVM+mRA17{<5#3Av zD)+8>r33cg2@l|@p4VhQdrksi=J zdBg*H`tk{xZRpG8w5IHFSRG4QYVM}@u<>*UT#wRiA}OWeg#YR1!k*suzEDtOlfmIdIq@d^7elHr?RMhGx`0zHaz&>*^Ja zd-{+(C}Z>o*nct=#0d*D*td_M5BbLr{{I2q^gbS7OY_YgZ3+Kt(=>6-76K{&3>8g6 zUaG+p-x@SY%?)**J`bPjplC>4M4T?&hT5NN5 zD4_88;X(0aw`}Kn^1?nrZ*`FH<8b=f@A}!bcc$}gX$A0s>#raeIt$humGVIxjGTys zNc;m3%^Z81@YgI1GdmSj4xl8$5@rM~0oB?MCp-)#8VhNZJOCUJD@Vd%8sA`s4i(W1 zp$zh%3C7^V?`QQ$QOtog;`AF27KGh9j`HlmL;Q=`)kU-`F7QcC_*H?|JA99#Z@ipJ z-bJ#j_Hzx-(PiPpoo-7?$|IYJ*TTqh!v+hGv6QH4r_%_&PFj*|si05 z%~yqU8)k3WsXDP-)v@;eJ@@g#0kdyMs2mYpJglc<5r~Y}l(Cg`W&2iNS}jBb zNx{}(Hh3a)%SpICIlx-WOnE)-8vMlXsY=!*P@9aj|I;zF2HCgcjym6fe zmYP;op)0UGliT;eQjm-;40Cz*cI*MvBO=XNWgJ&=)FAlLk<0CD`P>_-yxxg>!zGYg z6UfI>DkhA{ZPaqfhCHGf%?phDo`difUYUu8+;dNjBK?^t+X*)YJuUL5!E4_=;5*#vU&2<3Q{7vh zrg^2`oK%j#8qo(_&?NcGs4Mb|P`jhojXCDruLSdkMjLka@Hu{q3?t*AuWs5=t>1(> zQw@|vmA9}Mrx$wZM$*Qnr=S2jfoB}hBc@%E`z&rGB>P|mED9tvyY3*Zm@b~V_8UoR z`bV?LA1%tsm@^z-IYkmv*T!X0zqsgk`LVC}qoM@=mPH}niP?4tfGR>B@j8%+9xzf%tYz_>8f)f_X? z&ji`%sRkigYRS36R_SQ!6sBZXH|R??s*W^S%3#)52LSu+X0M4Cv#jWgH4!TpD>)C- zdAv#QVIv@vbBt7ye;e1|6q%D{5o>5LPKCDDqKH)9zVKZ&;bh<@vng~WN;}iBDqFtG zbaaQDKX+IiZv8U62FU`%^TuGF{c&Q)Sg`H1{}@I%8|H^yPR2g<t0vYcy}jTZ6q>r!iNHR zAR0%s<~^+C2!OjXV@#n|)}L;%Mr3k2LjF~dHlz)`0})%#df58QpP0tyvZEcDaaO!AAh|t=e zF=QB>tz~A2VZY)Atr|Xkt57Xw$pwUJUuL_7n@jnfg8)=5`Kh)W3JyQSZB~%FK#_OW zeS=XSswsW@s8!|jfb27Q+J+#q48}`Do&SK&&e59VF-U~SOWag@CK~k@(0Ay+-K|1I zq`XF7)_G1R#Dont*5qtuuoWX30t0)9`eqc|d}e@fff*Ee}WI#_q! zS5SWmipG!4Z^f0^gf$3@t$Q40ej#Cv^E4;gBRE3S4w{XRC{kDC?keAM4-aBKsD43G z45o5Xe1^#G?YxNiga9IFYkK<+5?iTZ-IcQ<9RcBd?!CF?8a{+>yK3)PAAT5BC6gTy z_$Y1$;_1PVpRwzeae9ACU?{ftLnjLAr10V#oMmm~^GZx{_TIbVx(_qzrV1y>vZHd9 z{=s14Jitl~2lZ&NJiUUG?Gv~9V|ii4wjF+!RT>el>!v2D#77sR6K_iFY=FK)j&u2m zq0xg@m3_BbO#qO0!YM9&*x(-U|71?G!JdNR@0RTW;{Sif<37LzWGCAxE-0ame7WOp zEu&-8gvH8Mf(teuRY!>~D zlNeqr7SQ13PL@Fr@T-Qd3OWP_fS@ z9yb#`bU&aN$RkA{TJ9w35PCcJ8%L&%Sw&3dVcLP*a=OMpGW2gE<&h%@=UK{`svcq< zxhbg)e}1BV(?R~Hq>{=qaNwwm^`KTt&N(%bvYs$U%E4NJ4FQZ(Pu+lU$zoxOWd=p3 z!)gnYg}5>V@WqG&|9z%}8NHHyn5FT1f?`v6wFViTVGTgzWY=wefX{ze{a!19`8A&7 zq2tnvUR^@X2b5#9Fg>|UE_%k{m$t?svkEJNo*QGbQk06E1<=eqA&p`Bk#vY!2Tuwg zDc^1O|L{i4md?s=ocn`kAsxs_O;@JQVOV&PwH7$O7-W^9(L1gq2e zrWyF?;%*$a^S`?iYW9H!b4l0f#Tfz6gO*(6Sj>;$v_@cOZ)*MM^OR^r*)Nd)iD*?Y zS%HdgL=S!=`v2<%ci72^iX8Xa$dWj8$H|MR<+o(lg{Zq7sL{pI^NGO4X@295B$9E^ z0|vXfP)5sVnP}WsRK23gM@@7?VxYkjY0%_osmj7k)PcCDolRoF1OuHG!NhidPENC2`Go0Ebg05Sz+8c?9_X$(Aj`EJh^4(1) zxs|D@sabjg{^9N<)XqnPt7}IaK;w3?n^TP~6GKA&OtA#vJQBpA4`_K(md9N%ay~K6 zj{)oknP8}ejCo48K9?tSVqYiBUByqWS*?ghI#rH9vI(OwAFGHtZ0#A)%j`uc_=tHf!&69FT zRw`JLop^Gf6r{z_BLDlEV-^qNs%9l~D%6Wy{a?~r8u{PJ&To)be1nwpdouIe$%4_s z$;i|;(GDH?|Hy1R>=21(T$12l!(|51jU3$3An*s~qG_eyPWZzA>lb1BN<3Ig@FHck)xXql5L_$;`G(zw9oz2#2z@bA;XV!>d?ODVS_l;^b85fcE^qB_4bU47nqV2LVPfN* zw3Y8_rK%agOViEQ!mPCCH2C*R z$#Ixmz*M&@L5Ik1>?MzhXsjr;^g3wKGuR#X{)myn(fnUF+)y^^^apA)^|mw3G{W7} z9~Dx!8KLp0M+(Egex7Ea3OW}8M+9qccn;gs7+q)pO#u3%r%;V9;#14EnYf6cqk14D z9OI0tySty+8t&mj6_Oe85tfrhxXHK=UlymFa0XC-EliDkZBXh zL@ENOD>N*G5hTLL#^evj%$N*EXBcmE0N5<$tBc9eAi@!Zm9U0+uJMYs2^AQs1yGm(iaN$R4QMMEi>`K(9 z7Uys6#h4Uk808f;^4(Mzty0nHOW3LHg7P9|)*-B*wIL@($tF*I%gh}KZ54qCV@&9V z4_;}3`YA#g6! z){JY|^pLZ?#t$cX*Nc4&LzHBt1OY>AV*{3ZEgrhXy%1)1)e?jh6j$Pr{^FGmav6|J zZn2d%B-oU33GzizW$zNS9?5qVAZu9+1R`s^_%S;yo3AH0d+dq2K2!2SU32iCg1Fu$!q4 z?YZQj-JYwz5kL6{C$Z#8-@6w^R0q|ne*a#w_Au0Ak`6z@0qsq;>AQB3egir&qi0Y) zna5rbmN9)`6S^ms7UPg<4ykoDjaK0@99fY}_Qvq%@QEZG3D3h%itFi45+Jmu%8wSU zp*ZNscbPoQ>m902O6P6?qXr*|+;&`7+>n&jt8X~^0h^KEYtN~N{4LF&1B@47>_*^7X5N4i#Q0 zemM+7NU>!cNg^F-W?J_TfF!~QQnhsY0nGdXF8&XD!(h6^yTMRF(R{u-HNMb-o`8~` zkP6$$51i_j{KJ z76=WE&mNXp*YATQ<75nDo?7gm4$pC~ny_frE)tQ8dm?EIcrLi<#pMuTz&tFlUl3z_;g-!xqEugsstc3GMNJR|nKJUa$VF`h)9B=G!i`bM z#G-0&)IB@@ntRKT1=*>Hm(2B1)iYEnBa9I=l@uM{H>yhrWf`}d^;VjzC(fjlkXkW@ zcM4Tx8JAYXF5H6+;WfUzlgd#udMZ+a`(u$?@a?jBm(559y92XkUh4kjN%_n!<-@PGR-9Hunkx4xO#=3A;1 z{2yj!lF)!o#x;QDwBI~oY>bmA2Z1-$&RoPm`SHV+`oHc){l82P@!$8NvbC%Xb%)|V zWirw^y}Vk?)*AQ?ZFfP>Q%?_H_K$hCY4LSPh_yQTgtbADxo|0>;8{PzMcu#&$I zi|_fOGGK&HdVB1H*Ei>LF~Yorw-St|5&1$cIf6B|G+1cTh#KosS+boL0#5L(JYA*n-KGm@TyOxWhj3N&#tLPx7 zDkEG*G4eXehmSFF^=}zPqU)kmJw@qR8tpH(^olVy{Cl&G7;SEO<>}cXu@Pf0VHwxO z@?@OvA*Akz6Zwr@`avp;mpILmOtL}65(BH6a|c7?0UUcq^;niqRSHgTR{5ANdsb;n z)#HRu@iPFVmrk`8)2cyJk`;Uc1@BPm%mZw^${f3POr@9ZmmB>`y_$O2oR%NAj^{C+ z-kDi3!|^yxFPjo-PAJ=1gZA>vAzyQwdLl)DGGTaHz1glIpZzfSzPdZP$eh$K5{!r@ z#>lG^nBl;1OSweXz_E!y$3_7ZPSRT?5|{9Fc`^W1UHihnX-qjT!3KVmE$n*C6)+P= z*5xE93OV^@=MiVcx)x!kb+cCxVP#P&g5%{UYrU#1?E-pNJ7`w(nPGM-jHqVwX_%qC z@RBRLMH@+`d6}QGQ!SR0lNl?fCgVR{d4rf)O?Ko1-=o5(Hkr0`0+}mUswxe(+M4TY zjE26Qx31^Q)tVbrP*rDe`Y2Ub3c>wL%#B-{YTXoRdFt{10+p3@){6P1u?y$Ra0B&< z#%y4kB?H5+u;_K;+dKYzVk1bbSK9r&*AO?kT)M0`v{|jPhYqd4-%t-BDXG4A7f<5m z!9tL9=LmL7ua4;i8-Hb9_8IncG@E2Y$7cqduiPo|wb9$ohxdTzOHtKJ#p$SwJ3r7x zwq(cvt`=9jO){}{N}<3*DhufQZe9)Piu`yJbHpUW5=wnSI$9dbt6F8F!7Ng2acqBE zwSYxdv&$opAGE@~7jZKfhe^}AHK&cuu92kaBuJ>u+^a+&{^lJ}S-q_?e2SA$z(oTb zC+)G4R!7+p$nggeWkj(ZDq%j7lg-)|ER5m0K25{ZK$~pI8KJqD(Ox@|*h8FQ6ehZ= ziDsr+t+q}2pPb4-gk+BBiRgmgK*89oO{3LmvbQVMS+8CU@C=TDQj3H+fKcgUVoRl2 zkq3dbht%3bYfrt~;M&7=hGTCfWRC$1vIP`cN(%yEFcDCYXTY*3ScQSCEEX7WkSc5! zbEcIMaN0>+f&{k5o)GhjMKzU?KkX=ycl*Q4g^pJ(tCph3oriPO#$AUdInJRHSi!Bv zt6_$cd)haq2nq(t`y4nqA2Z^`NSvutVami7rS%h+}68j`Q99Fo*S_d$+%IOgsaOeNCe4 zDhi0@04p;OMjr_rFpot4Vb6RCqM~2W!*l5Zrqf-WD1x@F6?wauZhGCv8lG9MGSFJx zSuKx09W0DX->kmqW_K1i(*+2C1Y@B3m7{fGAFqv9qHMrh{42d2Qb&8z!)HA!ofUjR z7AO&*qCdyoX^!A9t(Ij07wW8}6_3WO7=FV@l|Y-KMC-hjxLG(AUIVBoA0`4{|93w(3sB ztwh_nmbUS-uh~m!x?!Qjml5kZF(Z?|-N1!I4=|NB%*O@0z|w?nGI!so;_8X4R#$Dh z?Do?i0xy!W?Pq43Eg_lpsR`YTvOdx$k?3V!1_CF{z2G%YVRXb;)7 zg{VcbYP1(uL^c z>Gt?@u~_1_d&WbCqXRTU!|f*76yE3`0_tE^NfG*=U2 z7<@D+LO(>0&sUED)Xcgqe`@HcX07O9F}xgDIdBwx0?>+6q}b~F{5z_dIO|XH9x7QZ zb2?9HP!Y|EqdZ+CHVG$xP9P2k`UuS6stktf&kuyVKfAXWF0TNx;UI$*ZzOVA`RMQ; zObP7;ECe^f(G8A0S@7y+d>&GB)3(VUVIckcyb3gr1xN}NOqnm#6V2nakT_Wy9li&< zKP;J@0ls~0-5mUdGL8{7^L;~2Gc<)`-1$WhVy>Eh!PN39&PO^0Gus<{vCPJ25gYRf zGfQdvev?{8=VH*hXyVzD<8o(aiOye>;(WvM zjX9sK?)&TwD!&>px7R>*APT3hS#BOwAr^on!|OeztwNw-ORg>lTgjl+Ccm!SVH}g= zdv+X-Kr46Z|87~tj3Z587$Ba`W)d>b*s3QyVP#)`jIr9@m5$AKS#RmS0*qTPW#T_y zN(Di;UR-9P3QDDgh{ani_ zKXow^Lr=kW+!{wj4&p&0;e`+3Y9lxS9b3PB?dmMwH~qRl;QL4N@$sKDf&)UGU!f6y zj-DFeP;`)A3DJ3O^l#n991O)D@@@MMz{wx4@m<@TW?(ng{2f7Eu5MtmmsHVS%DENh z1J_|bSLP+M#Fp)*=r6^#VrKO*ZRA{)yVoP*Bs+|jNi6wX6CSl>-_K85%kbg{l!IL# z1uplWH0AUf#4j-9-aFFp)MNN#QkGYw7UDfh0RK|hyxV==w%bPkR`cxxdu-UhMlRaL z&A4>`XM^m-z2~&{(_{Q~*G}Na4(q6A|6W&6^)x{mDB{tcLJV9cf%~rglg4ekFCukP zRmcUpoxavTVax8DYenc=Ejd~`z|VbK5=noY%VC0=or(I;kLQ0QoP6kovzwfj#sWhg zukkCJh~4cMRtFEn1`a=le@0oJjEo*Nz;OF3M<4o9{e|sEy?HQdGHmUtkq8Ow?N8JG zZT4p)vcB`M-oLf340GSDFpqFQ6a74R*w=}$6ttVmic^8a?2qhTqBnE>G63`DaSshe zS0PXuLs;#PPF)>lqKyxS88USQdNsx@$opaY=pKKvoJFEl#E?sc`1vhQ5gP8ztBOlv z?%*On70Dx;%C)ecV97m|f_DHNS;ZrDBWRDnWib1VU-nye=PA5?#sZ>|}gXn0U=2OKD zedR2j#8t8=2Ssbi!!GB7_j6Bxu7n|>rlzq6aUpbG7Ws5Je#&;!-PYWUQK5GAw|H1Y zDW!7X6Q7(Rikvv=Ssencqrk=^lrd<_KFC8JwuUk3f+4Dj9V@{w27oUb_I718!eF1I zOLqLZ4nDUKd}NM>)NtIRX^h%3)!0Rfn&(i?HkBgS4Ao7FvS2=hp&bNsLOyIvfACQG z(+`68ko#eDqD^&skn=!Pmm2Vg{SLb(QE=aj8;I-dl$JvC^c}r)b~u3OAh^-Vg#B$k z#p91sUe1!3g7Z%90Ia&;xMv1J-Xgh#n=t!{#qe1-Pia3o@936P_JtUF?rmHc+Sg;$05MraPh@kn#oQGI5rUzr9eiPYs!jxwMw~4bSaoY5515 zP_4w3?pnjY#Tv!{nTHxJq67m`Vqyw%s)2fvWphS!Jd>910F=@rJYeiV6J2Y-8FWnU z;4cKcsof|MnCi)UIH!pxi~QMY)z20-w0S(%VA>iI)3`8RsyzivWDRDHoOw+G7}kzL|Bkm=*%+gi;%5vB?`@j(KU(|tgj?x?pNwFje^y!v?v z;;32|rZNd)z%Oye=}q_dpoRd=oc>=RAG?%C@_Xe|rUnCTT(QSp0mnV@79|ha@>7)g zv)ohnFDtTe4^;fWG&`^%>FFL>QD1N9=oNDE`4?ueU4g%Lxu=yLtWFkhvVg~HFk83a zCHTsXZ-^!&=?J^v8|3XX4!r$!?-hj3nG=YH1dgpK01v+2^qcm-KQK7dOZ?jrBTpjz z=t{0r7QJZb-4{{b@j}1XRg9!hOBxTkIrWexl1!Oq3R**!h&mDqn~sb=(M)`Uel(u# z3i_+6H^HAI{~h?OR|kxc%YlP{!-Bqvk!Oha5DUUV?#&RI|EH^Sk80w|<2cTmf=D1O zkB~5mJVGJiC6DrmfYhV1pde6L6$Qg9P_(>6l2V9S6!d^#xu7iw^w3z0t41DCDPUxy zL>?ljtI(AMLP9WrBv>n`lpSWFJ<~a7&b@Qz^ZR9zxw(Jb@9%f-Q(B{ojjX&w_rO?i zC<|h*=`d1pCaCYeFVV{uUyb;THuDXY>^Nh`|Mth4D8=5pQF#QsXG~X7TngOxxH4}4 zwf2D`PqQ}RLbvHD6}wjQ%fvz9fNiq+zAxEBV4d=4!Q;~DYn*10|jAyJxdSf+kg7dXK@$$2RRq)e|YMSjP+@t$I=TTuEuS63BP6YgjoA zl|wcTxjr+Lo(##((~lpy>E=YV)r}KNq(-iImrT#H+?s!0aQxYmH{1(rGAzZP2c2y@ zc=`h8OhJ|YvxJ!RUqjlv_Vfdy){9lMpKz{0OPf>0oqtj6wa=G*S^Js=_N#yEtaj+#C=T!WZ2oBR zq@LL)+lEwP=p*dX?eZU4364PJGCTr#QOjoIE8_9Lh7#GWkWVHg1Zn&Fhj% z@)HB9NNyGuTZ(&Pxq@`%l_viq!Gdbn5q|ZT9SzfgF*tF`>q7l(Vp{l*FSfrg6^Z9t z({;pGOuPs31EliWw8+66Jr|MEX))|xbIuv2Nc@TPW{B3MWogl*cJB@Hhn2N@&OnCqoC=7L73MG?1ptW;60l}!Ge6T2u`GJ4Co)aG*1iBNw| z2|xC3uF3W&4|m%Jvw7|8ypbyDdXm5}wAK6V;MH557hCAVy+>623BQMZxUfDe^f&Rp zYZgR@a?UfR`yRZndup6=MhLCdr{^}-5V=gtEv;dUFB$Wjj&H$bX`=ZjcFx_VI7{|f zU;Hp&y`UGqK6U5EVGRC03G*PaE}ht1wzaYDk$=B`=bdV~GeZO}whg^y9h*BYck3@> za(v#?hByUNHp8*qzgJHS<`kM1dItWbAd$1-Wt6c)j8?fA(A*zAVMtya3aB?lBqw9! zTuur?Wv4`^_#-Lc_WF$mN=$Z;Aq7j=8(0E&DY-digtP{KWjJZ*Z-~gGM$)vMK$+AQ z7^+PGN9_uwegqoTp0Gsuif@6;ckM#rK|K&hs|Sx8stYovcEEpbTCbyHwR#sRdEB;j zU@&(B&`h~PKbwQGa(9q3N&tz|WatVBaHnIT#!U!difr|VNLtgjFlG}#jHhgy6_5ye zqy%6!LxvKZ(58qPOBl1&48|_h8HJFYX8?c39LB7Aj{&uwDmctwQ{2BVkNuV5In zbQQ)%Z#N3v?W6$wECI%>gM(Cb+zw0xV=y$Rin;8_QA$>5xUJ1`ujLSCszl>|JDkWPWTxS~-qG?@m*>|r1p4TSPD(CWr9A4r;s zR;6YJfUF^acQCD4P#OpFcAL)3Tfmt92(9HHjSG?YfmAKL4Y$(fH9$_7)xOhYS};T zh(n`lz!G9Z98 z2L|cBK%^kxP#GB1DNP|t73zLj{Z%T>aHx`2K4A)3)vUDJ!KiM5{Ajn4f2teCBjE@1 z3;cK6$ID(}%oH{TOsGde*Bu*C5Hp310c$TIpf$))xkB@|fI8Y9^s1;3?k-Zb2BgW) zAO|rBpG<-l?}6E5`f~TN|Ld5w>W{}A=)#O(AIUbu%R|=c!Q)y>Fu*@#8%%JB=)T-H P+;zlAyf701baeg)J&AD9 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 8cf6eb5a..f398c33c 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip +networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 8e25e6c1..65dcd68d 100755 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,78 +17,113 @@ # ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -97,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" + JAVACMD=java which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the @@ -105,84 +140,105 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=$((i+1)) + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=$(save "$@") +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then - cd "$(dirname "$0")" -fi +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index 24467a14..6689b85b 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -14,7 +14,7 @@ @rem limitations under the License. @rem -@if "%DEBUG%" == "" @echo off +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -25,10 +25,14 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @@ -37,7 +41,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init +if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -51,7 +55,7 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto init +if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% @@ -61,38 +65,26 @@ echo location of your Java installation. goto fail -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd +if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal From a7746fbab0dd267cf4389bfc4572a17c72485386 Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Tue, 27 Dec 2022 10:27:46 +0100 Subject: [PATCH 237/293] Replace Report.enabled property with Report.required --- build.gradle | 2 +- iexec-sms-library/build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index c5b1cae2..3a2fc914 100644 --- a/build.gradle +++ b/build.gradle @@ -141,7 +141,7 @@ jacoco { // sonarqube code coverage requires jacoco XML report jacocoTestReport { reports { - xml.enabled true + xml.required = true } } tasks.test.finalizedBy tasks.jacocoTestReport diff --git a/iexec-sms-library/build.gradle b/iexec-sms-library/build.gradle index c6736157..e5d0a14a 100644 --- a/iexec-sms-library/build.gradle +++ b/iexec-sms-library/build.gradle @@ -27,7 +27,7 @@ jacoco { // sonarqube code coverage requires jacoco XML report jacocoTestReport { reports { - xml.enabled true + xml.required = true } } tasks.test.finalizedBy tasks.jacocoTestReport From 675946eb7056271eb189a7afcbfbef757c07ad05 Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Tue, 27 Dec 2022 10:46:39 +0100 Subject: [PATCH 238/293] Use freefair lombok gradle plugin 6.6.1 --- build.gradle | 2 +- iexec-sms-library/build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 3a2fc914..800bf6b2 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'io.freefair.lombok' version '5.3.0' + id 'io.freefair.lombok' version '6.6.1' id 'org.springframework.boot' version '2.6.2' id 'io.spring.dependency-management' version '1.0.11.RELEASE' id 'jacoco' diff --git a/iexec-sms-library/build.gradle b/iexec-sms-library/build.gradle index e5d0a14a..00f55e4d 100644 --- a/iexec-sms-library/build.gradle +++ b/iexec-sms-library/build.gradle @@ -1,8 +1,8 @@ plugins { id 'java-library' + id 'io.freefair.lombok' id 'jacoco' id 'maven-publish' - id 'io.freefair.lombok' } dependencies { From 6fc9cfc46566fad023675faa4b947b37f0c28fbb Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Tue, 27 Dec 2022 11:20:40 +0100 Subject: [PATCH 239/293] Use Spring dependency management gradle plugin 1.1.0 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 800bf6b2..16a30fa5 100644 --- a/build.gradle +++ b/build.gradle @@ -2,7 +2,7 @@ plugins { id 'java' id 'io.freefair.lombok' version '6.6.1' id 'org.springframework.boot' version '2.6.2' - id 'io.spring.dependency-management' version '1.0.11.RELEASE' + id 'io.spring.dependency-management' version '1.1.0' id 'jacoco' id 'org.sonarqube' version '3.3' id 'maven-publish' From 74d5be35c0f21956fdeab5fc9ae07cf5b091222e Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Wed, 28 Dec 2022 15:20:28 +0100 Subject: [PATCH 240/293] Configure java toolchain in build.gradle --- build.gradle | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 16a30fa5..de0ea072 100644 --- a/build.gradle +++ b/build.gradle @@ -19,8 +19,6 @@ if (!project.hasProperty('gitBranch')) { allprojects { group = 'com.iexec.sms' - sourceCompatibility = 11 - targetCompatibility = 11 if (gitBranch != 'main' && gitBranch != 'master' && !(gitBranch ==~ '(release|hotfix|support)/.*')) { version += '-NEXT-SNAPSHOT' } @@ -41,6 +39,11 @@ allprojects { url 'https://jitpack.io' } } + java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(11)) + } + } } configurations { From cae6a47fa846f78878667696437c8e07d712225c Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Mon, 2 Jan 2023 14:54:00 +0100 Subject: [PATCH 241/293] Remove `isEncryptedValue` from `WebXSecret`s --- .../java/com/iexec/sms/secret/Secret.java | 13 +--- .../iexec/sms/secret/SecretController.java | 15 ++-- .../com/iexec/sms/secret/web2/Web2Secret.java | 27 ++----- .../sms/secret/web2/Web2SecretService.java | 22 +++--- .../com/iexec/sms/secret/web3/Web3Secret.java | 27 ++----- .../sms/secret/web3/Web3SecretService.java | 19 ++--- .../base/SecretSessionBaseService.java | 20 ++--- .../sms/secret/SecretControllerTests.java | 20 +++-- .../secret/web2/Web2SecretServiceTests.java | 56 ++++++------- .../sms/secret/web2/Web2SecretTests.java | 12 +-- .../secret/web3/Web3SecretServiceTests.java | 40 +++++----- .../base/SecretSessionBaseServiceTests.java | 78 +++++++------------ 12 files changed, 154 insertions(+), 195 deletions(-) diff --git a/src/main/java/com/iexec/sms/secret/Secret.java b/src/main/java/com/iexec/sms/secret/Secret.java index 7be615c2..02db3df4 100644 --- a/src/main/java/com/iexec/sms/secret/Secret.java +++ b/src/main/java/com/iexec/sms/secret/Secret.java @@ -17,37 +17,30 @@ package com.iexec.sms.secret; import lombok.AccessLevel; -import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import javax.persistence.Column; import javax.persistence.MappedSuperclass; -import java.util.Objects; @MappedSuperclass @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) -@AllArgsConstructor(access = AccessLevel.PROTECTED) public abstract class Secret { @Column(columnDefinition = "LONGTEXT") private String value; - private boolean isEncryptedValue; /** - * Get the secret value without possible leading or trailing + * Create the secret without possible leading or trailing * newline characters. This should be used when putting * the secret in the palaemon session. We decided to handle * this specific case because it has a good probability to occur * (when reading the secret from a file and uploading it to the * SMS without any trimming) and it can break the workflow even * though everything is correctly setup. - * - * @return trimmed secret value */ - public String getTrimmedValue() { - Objects.requireNonNull(this.value, "Secret value must not be null"); - return this.value.trim(); + protected Secret(String value) { + this.value = value != null ? value.trim() : null; } } diff --git a/src/main/java/com/iexec/sms/secret/SecretController.java b/src/main/java/com/iexec/sms/secret/SecretController.java index 3bec3086..ef971810 100644 --- a/src/main/java/com/iexec/sms/secret/SecretController.java +++ b/src/main/java/com/iexec/sms/secret/SecretController.java @@ -18,8 +18,10 @@ import com.iexec.sms.authorization.AuthorizationService; -import com.iexec.sms.secret.web2.*; -import com.iexec.sms.secret.web3.Web3Secret; +import com.iexec.sms.secret.web2.NotAnExistingSecretException; +import com.iexec.sms.secret.web2.SameSecretException; +import com.iexec.sms.secret.web2.SecretAlreadyExistsException; +import com.iexec.sms.secret.web2.Web2SecretService; import com.iexec.sms.secret.web3.Web3SecretService; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; @@ -27,7 +29,6 @@ import org.springframework.web.bind.annotation.*; import java.util.NoSuchElementException; -import java.util.Optional; @Slf4j @CrossOrigin @@ -51,8 +52,8 @@ public SecretController(AuthorizationService authorizationService, @RequestMapping(path = "/web3", method = RequestMethod.HEAD) public ResponseEntity isWeb3SecretSet(@RequestParam String secretAddress) { - Optional secret = web3SecretService.getSecret(secretAddress); - return secret.isPresent() ? ResponseEntity.noContent().build() : ResponseEntity.notFound().build(); + boolean isSecretPresent = web3SecretService.isSecretPresent(secretAddress); + return isSecretPresent ? ResponseEntity.noContent().build() : ResponseEntity.notFound().build(); } @PostMapping("/web3") @@ -82,8 +83,8 @@ public ResponseEntity addWeb3Secret(@RequestHeader String authorization, @RequestMapping(path = "/web2", method = RequestMethod.HEAD) public ResponseEntity isWeb2SecretSet(@RequestParam String ownerAddress, @RequestParam String secretName) { - Optional secret = web2SecretService.getSecret(ownerAddress, secretName); - return secret.isPresent() ? ResponseEntity.noContent().build() : ResponseEntity.notFound().build(); + boolean isSecretPresent = web2SecretService.isSecretPresent(ownerAddress, secretName); + return isSecretPresent ? ResponseEntity.noContent().build() : ResponseEntity.notFound().build(); } @PostMapping("/web2") diff --git a/src/main/java/com/iexec/sms/secret/web2/Web2Secret.java b/src/main/java/com/iexec/sms/secret/web2/Web2Secret.java index fba015d9..95030797 100644 --- a/src/main/java/com/iexec/sms/secret/web2/Web2Secret.java +++ b/src/main/java/com/iexec/sms/secret/web2/Web2Secret.java @@ -33,34 +33,23 @@ public class Web2Secret extends Secret { @EmbeddedId private Web2SecretHeader header; - public Web2Secret(String ownerAddress, String address, String value, boolean isEncryptedValue) { - this(new Web2SecretHeader(ownerAddress, address), value, isEncryptedValue); + public Web2Secret(String ownerAddress, String address, String value) { + this(new Web2SecretHeader(ownerAddress, address), value); } - private Web2Secret(Web2SecretHeader header, String value, boolean isEncryptedValue) { - super(value, isEncryptedValue); + private Web2Secret(Web2SecretHeader header, String value) { + super(value); this.header = header; } /** * Copies the current {@link Web2Secret} object, - * while replacing the old value with a new encrypted value. + * while replacing the old value with a new value. * - * @param newEncryptedValue Value to use for new object. + * @param newValue Value to use for new object. * @return A new {@link Web2Secret} object with new value. */ - public Web2Secret withEncryptedValue(String newEncryptedValue) { - return new Web2Secret(header, newEncryptedValue, true); - } - - /** - * Copies the current {@link Web2Secret} object, - * while replacing the old value with a new decrypted value. - * - * @param newDecryptedValue Value to use for new object. - * @return A new {@link Web2Secret} object with new value. - */ - public Web2Secret withDecryptedValue(String newDecryptedValue) { - return new Web2Secret(header, newDecryptedValue, false); + public Web2Secret withValue(String newValue) { + return new Web2Secret(header, newValue); } } diff --git a/src/main/java/com/iexec/sms/secret/web2/Web2SecretService.java b/src/main/java/com/iexec/sms/secret/web2/Web2SecretService.java index f6cea2a4..9dae7ccf 100644 --- a/src/main/java/com/iexec/sms/secret/web2/Web2SecretService.java +++ b/src/main/java/com/iexec/sms/secret/web2/Web2SecretService.java @@ -37,20 +37,24 @@ protected Web2SecretService(EncryptionService encryptionService, this.web2SecretRepository = web2SecretRepository; } - public Optional getSecret(String ownerAddress, String secretAddress) { + Optional getSecret(String ownerAddress, String secretAddress) { return web2SecretRepository.findById(new Web2SecretHeader(ownerAddress, secretAddress)); } - public Optional getSecret(String ownerAddress, String secretAddress, boolean shouldDecryptValue) { + public Optional getDecryptedValue(String ownerAddress, String secretAddress) { final Optional oSecret = getSecret(ownerAddress, secretAddress); - if (oSecret.isEmpty() || !shouldDecryptValue) { - return oSecret; + if (oSecret.isEmpty()) { + return Optional.empty(); } final Web2Secret secret = oSecret.get(); final String decryptedValue = encryptionService.decrypt(secret.getValue()); - return Optional.of(secret.withDecryptedValue(decryptedValue)); + return Optional.ofNullable(decryptedValue); + } + + public boolean isSecretPresent(String ownerAddress, String secretAddress) { + return getSecret(ownerAddress, secretAddress).isPresent(); } /** @@ -65,14 +69,14 @@ public Optional getSecret(String ownerAddress, String secretAddress, * with same {@code ownerAddress}/{@code secretAddress} couple already exists */ public Web2Secret addSecret(String ownerAddress, String secretAddress, String secretValue) throws SecretAlreadyExistsException { - final Optional oSecret = getSecret(ownerAddress, secretAddress); - if (oSecret.isPresent()) { + final boolean isSecretPresent = isSecretPresent(ownerAddress, secretAddress); + if (isSecretPresent) { log.error("Secret already exists [ownerAddress:{}, secretAddress:{}]", ownerAddress, secretAddress); throw new SecretAlreadyExistsException(ownerAddress, secretAddress); } final String encryptedValue = encryptionService.encrypt(secretValue); - final Web2Secret newSecret = new Web2Secret(ownerAddress, secretAddress, encryptedValue, true); + final Web2Secret newSecret = new Web2Secret(ownerAddress, secretAddress, encryptedValue); return web2SecretRepository.save(newSecret); } @@ -104,7 +108,7 @@ public Web2Secret updateSecret(String ownerAddress, String secretAddress, String throw new SameSecretException(ownerAddress, secretAddress); } - final Web2Secret newSecret = secret.withEncryptedValue(encryptedValue); + final Web2Secret newSecret = secret.withValue(encryptedValue); return web2SecretRepository.save(newSecret); } } diff --git a/src/main/java/com/iexec/sms/secret/web3/Web3Secret.java b/src/main/java/com/iexec/sms/secret/web3/Web3Secret.java index e2decf2c..6e3f5de6 100644 --- a/src/main/java/com/iexec/sms/secret/web3/Web3Secret.java +++ b/src/main/java/com/iexec/sms/secret/web3/Web3Secret.java @@ -31,34 +31,23 @@ public class Web3Secret extends Secret { @EmbeddedId private Web3SecretHeader header; - public Web3Secret(String address, String value, boolean isEncryptedValue) { - this(new Web3SecretHeader(address), value, isEncryptedValue); + public Web3Secret(String address, String value) { + this(new Web3SecretHeader(address), value); } - private Web3Secret(Web3SecretHeader header, String value, boolean isEncryptedValue) { - super(value, isEncryptedValue); + private Web3Secret(Web3SecretHeader header, String value) { + super(value); this.header = header; } /** * Copies the current {@link Web3Secret} object, - * while replacing the old value with a new encrypted value. + * while replacing the old value with a new value. * - * @param newEncryptedValue Value to use for new object. + * @param newValue Value to use for new object. * @return A new {@link Web3Secret} object with new value. */ - public Web3Secret withEncryptedValue(String newEncryptedValue) { - return new Web3Secret(header, newEncryptedValue, true); - } - - /** - * Copies the current {@link Web3Secret} object, - * while replacing the old value with a new decrypted value. - * - * @param newDecryptedValue Value to use for new object. - * @return A new {@link Web3Secret} object with new value. - */ - public Web3Secret withDecryptedValue(String newDecryptedValue) { - return new Web3Secret(header, newDecryptedValue, false); + public Web3Secret withValue(String newValue) { + return new Web3Secret(header, newValue); } } diff --git a/src/main/java/com/iexec/sms/secret/web3/Web3SecretService.java b/src/main/java/com/iexec/sms/secret/web3/Web3SecretService.java index 9b5fafed..ccdb0233 100644 --- a/src/main/java/com/iexec/sms/secret/web3/Web3SecretService.java +++ b/src/main/java/com/iexec/sms/secret/web3/Web3SecretService.java @@ -36,20 +36,21 @@ public Web3SecretService(Web3SecretRepository web3SecretRepository, this.web3SecretRepository = web3SecretRepository; } - public Optional getSecret(String secretAddress) { + Optional getSecret(String secretAddress) { return web3SecretRepository.findById(new Web3SecretHeader(secretAddress)); } - public Optional getSecret(String secretAddress, boolean shouldDecryptValue) { + public Optional getDecryptedValue(String secretAddress) { Optional oSecret = getSecret(secretAddress); if (oSecret.isEmpty()) { return Optional.empty(); } - if (shouldDecryptValue) { - final String decryptedValue = encryptionService.decrypt(oSecret.get().getValue()); - return oSecret.map(secret -> secret.withDecryptedValue(decryptedValue)); - } - return oSecret; + final String decryptedValue = encryptionService.decrypt(oSecret.get().getValue()); + return Optional.ofNullable(decryptedValue); + } + + public boolean isSecretPresent(String secretAddress) { + return getSecret(secretAddress).isPresent(); } /* @@ -57,7 +58,7 @@ public Optional getSecret(String secretAddress, boolean shouldDecryp * Stores encrypted secrets * */ public boolean addSecret(String secretAddress, String secretValue) { - if (getSecret(secretAddress).isPresent()) { + if (isSecretPresent(secretAddress)) { log.error("Secret already exists [secretAddress:{}]", secretAddress); return false; } @@ -66,7 +67,7 @@ public boolean addSecret(String secretAddress, String secretValue) { log.info("Adding new web3 secret [secretAddress:{}, encryptedSecretValue:{}]", secretAddress, encryptedValue); - final Web3Secret web3Secret = new Web3Secret(secretAddress, encryptedValue, true); + final Web3Secret web3Secret = new Web3Secret(secretAddress, encryptedValue); web3SecretRepository.save(web3Secret); return true; } diff --git a/src/main/java/com/iexec/sms/tee/session/base/SecretSessionBaseService.java b/src/main/java/com/iexec/sms/tee/session/base/SecretSessionBaseService.java index 0ef10712..c6d561d1 100644 --- a/src/main/java/com/iexec/sms/tee/session/base/SecretSessionBaseService.java +++ b/src/main/java/com/iexec/sms/tee/session/base/SecretSessionBaseService.java @@ -25,7 +25,6 @@ import com.iexec.sms.secret.compute.SecretOwnerRole; import com.iexec.sms.secret.compute.TeeTaskComputeSecret; import com.iexec.sms.secret.compute.TeeTaskComputeSecretService; -import com.iexec.sms.secret.web2.Web2Secret; import com.iexec.sms.secret.web2.Web2SecretService; import com.iexec.sms.secret.web3.Web3SecretService; import com.iexec.sms.tee.challenge.TeeChallenge; @@ -138,11 +137,10 @@ public SecretEnclaveBase getPreComputeTokens(TeeSessionRequest request) List trustedEnv = new ArrayList<>(); if (taskDescription.containsDataset()) { String datasetKey = web3SecretService - .getSecret(taskDescription.getDatasetAddress(), true) + .getDecryptedValue(taskDescription.getDatasetAddress()) .orElseThrow(() -> new TeeSessionGenerationException( PRE_COMPUTE_GET_DATASET_SECRET_FAILED, - "Empty dataset secret - taskId: " + taskId)) - .getTrimmedValue(); + "Empty dataset secret - taskId: " + taskId)); tokens.put(IEXEC_DATASET_KEY, datasetKey); trustedEnv.addAll(List.of( IexecEnvUtils.IEXEC_DATASET_URL, @@ -316,16 +314,15 @@ public Map getPostComputeEncryptionTokens(TeeSessionRequest requ if (!shouldEncrypt) { return tokens; } - Optional beneficiaryResultEncryptionKeySecret = web2SecretService.getSecret( + Optional beneficiaryResultEncryptionKeySecret = web2SecretService.getDecryptedValue( taskDescription.getBeneficiary(), - IEXEC_RESULT_ENCRYPTION_PUBLIC_KEY, - true); + IEXEC_RESULT_ENCRYPTION_PUBLIC_KEY); if (beneficiaryResultEncryptionKeySecret.isEmpty()) { throw new TeeSessionGenerationException( POST_COMPUTE_GET_ENCRYPTION_TOKENS_FAILED_EMPTY_BENEFICIARY_KEY, "Empty beneficiary encryption key - taskId: " + taskId); } - String publicKeyValue = beneficiaryResultEncryptionKeySecret.get().getTrimmedValue(); + String publicKeyValue = beneficiaryResultEncryptionKeySecret.get(); tokens.put(RESULT_ENCRYPTION_PUBLIC_KEY, publicKeyValue); // base64 encoded by client return tokens; } @@ -352,10 +349,9 @@ public Map getPostComputeStorageTokens(TeeSessionRequest request String keyName = storageProvider.equals(DROPBOX_RESULT_STORAGE_PROVIDER) ? IEXEC_RESULT_DROPBOX_TOKEN : IEXEC_RESULT_IEXEC_IPFS_TOKEN; - Optional requesterStorageTokenSecret = web2SecretService.getSecret( + Optional requesterStorageTokenSecret = web2SecretService.getDecryptedValue( taskDescription.getRequester(), - keyName, - true); + keyName); if (requesterStorageTokenSecret.isEmpty()) { log.error("Failed to get storage token [taskId:{}, storageProvider:{}, requester:{}]", taskId, storageProvider, taskDescription.getRequester()); @@ -363,7 +359,7 @@ public Map getPostComputeStorageTokens(TeeSessionRequest request POST_COMPUTE_GET_STORAGE_TOKENS_FAILED, "Empty requester storage token - taskId: " + taskId); } - String requesterStorageToken = requesterStorageTokenSecret.get().getTrimmedValue(); + String requesterStorageToken = requesterStorageTokenSecret.get(); tokens.put(RESULT_STORAGE_PROVIDER, storageProvider); tokens.put(RESULT_STORAGE_PROXY, storageProxy); tokens.put(RESULT_STORAGE_TOKEN, requesterStorageToken); diff --git a/src/test/java/com/iexec/sms/secret/SecretControllerTests.java b/src/test/java/com/iexec/sms/secret/SecretControllerTests.java index 9b36e4bf..e644d7c1 100644 --- a/src/test/java/com/iexec/sms/secret/SecretControllerTests.java +++ b/src/test/java/com/iexec/sms/secret/SecretControllerTests.java @@ -18,7 +18,6 @@ import com.iexec.sms.authorization.AuthorizationService; import com.iexec.sms.secret.web2.*; -import com.iexec.sms.secret.web3.Web3Secret; import com.iexec.sms.secret.web3.Web3SecretService; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -30,7 +29,6 @@ import java.nio.charset.StandardCharsets; import java.security.SecureRandom; -import java.util.Optional; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.*; @@ -67,8 +65,8 @@ public void init() { //region isWeb3SecretSet @Test void shouldReturnNoContentWhenWeb3SecretExists() { - when(web3SecretService.getSecret(WEB3_SECRET_ADDRESS)) - .thenReturn(Optional.of(mock(Web3Secret.class))); + when(web3SecretService.isSecretPresent(WEB3_SECRET_ADDRESS)) + .thenReturn(true); assertThat(secretController.isWeb3SecretSet(WEB3_SECRET_ADDRESS)) .isEqualTo(ResponseEntity.noContent().build()); verifyNoInteractions(authorizationService, web2SecretService); @@ -76,8 +74,8 @@ void shouldReturnNoContentWhenWeb3SecretExists() { @Test void shouldReturnNotFoundWhenWeb3SecretDoesNotExist() { - when(web3SecretService.getSecret(WEB3_SECRET_ADDRESS)) - .thenReturn(Optional.empty()); + when(web3SecretService.isSecretPresent(WEB3_SECRET_ADDRESS)) + .thenReturn(false); assertThat(secretController.isWeb3SecretSet(WEB3_SECRET_ADDRESS)) .isEqualTo(ResponseEntity.notFound().build()); verifyNoInteractions(authorizationService, web2SecretService); @@ -135,8 +133,8 @@ void addWeb3Secret() { //region isWeb2SecretSet @Test void shouldReturnNoContentWhenWeb2SecretExists() { - when(web2SecretService.getSecret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME)) - .thenReturn(Optional.of(new Web2Secret(WEB2_OWNER_ADDRESS, WEB3_SECRET_ADDRESS, WEB2_SECRET_VALUE, true))); + when(web2SecretService.isSecretPresent(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME)) + .thenReturn(true); assertThat(secretController.isWeb2SecretSet(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME)) .isEqualTo(ResponseEntity.noContent().build()); verifyNoInteractions(authorizationService, web3SecretService); @@ -144,8 +142,8 @@ void shouldReturnNoContentWhenWeb2SecretExists() { @Test void shouldReturnNotFoundWhenWeb2SecretDoesNotExist() { - when(web2SecretService.getSecret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME)) - .thenReturn(Optional.empty()); + when(web2SecretService.isSecretPresent(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME)) + .thenReturn(false); assertThat(secretController.isWeb2SecretSet(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME)) .isEqualTo(ResponseEntity.notFound().build()); verifyNoInteractions(authorizationService, web3SecretService); @@ -191,7 +189,7 @@ void addWeb2Secret() throws SecretAlreadyExistsException { when(authorizationService.isSignedByHimself(CHALLENGE, AUTHORIZATION, WEB2_OWNER_ADDRESS)) .thenReturn(true); when(web2SecretService.addSecret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, WEB2_SECRET_VALUE)) - .thenReturn(new Web2Secret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, WEB2_SECRET_VALUE, true)); + .thenReturn(new Web2Secret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, WEB2_SECRET_VALUE)); assertThat(secretController.addWeb2Secret(AUTHORIZATION, WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, WEB2_SECRET_VALUE)) .isEqualTo(ResponseEntity.noContent().build()); verify(web2SecretService).addSecret(WEB2_OWNER_ADDRESS, WEB2_SECRET_NAME, WEB2_SECRET_VALUE); diff --git a/src/test/java/com/iexec/sms/secret/web2/Web2SecretServiceTests.java b/src/test/java/com/iexec/sms/secret/web2/Web2SecretServiceTests.java index 26b886a2..8b5e0e4d 100644 --- a/src/test/java/com/iexec/sms/secret/web2/Web2SecretServiceTests.java +++ b/src/test/java/com/iexec/sms/secret/web2/Web2SecretServiceTests.java @@ -53,50 +53,54 @@ void beforeEach() { // region getSecret @Test - void shouldGetDecryptedSecret() { - final Web2Secret encryptedSecret = new Web2Secret(OWNER_ADDRESS, SECRET_ADDRESS, ENCRYPTED_SECRET_VALUE, true); + void shouldGetDecryptedValue() { + final Web2Secret encryptedSecret = new Web2Secret(OWNER_ADDRESS, SECRET_ADDRESS, ENCRYPTED_SECRET_VALUE); when(web2SecretRepository.findById(any(Web2SecretHeader.class))) .thenReturn(Optional.of(encryptedSecret)); when(encryptionService.decrypt(ENCRYPTED_SECRET_VALUE)) .thenReturn(PLAIN_SECRET_VALUE); - final Optional result = web2SecretService.getSecret(OWNER_ADDRESS, SECRET_ADDRESS, true); - assertThat(result).isNotEmpty(); - assertAll( - () -> assertThat(result).get().extracting(Web2Secret::getHeader).usingRecursiveComparison().isEqualTo(new Web2SecretHeader(OWNER_ADDRESS, SECRET_ADDRESS)), - () -> assertThat(result).get().extracting(Web2Secret::getValue).isEqualTo(PLAIN_SECRET_VALUE), - () -> assertThat(result).get().extracting(Web2Secret::isEncryptedValue).isEqualTo(false) - ); + final Optional result = web2SecretService.getDecryptedValue(OWNER_ADDRESS, SECRET_ADDRESS); + assertThat(result) + .isNotEmpty() + .get().isEqualTo(PLAIN_SECRET_VALUE); } @Test void shouldGetEncryptedSecret() { - final Web2Secret encryptedSecret = new Web2Secret(OWNER_ADDRESS, SECRET_ADDRESS, ENCRYPTED_SECRET_VALUE, true); + final Web2Secret encryptedSecret = new Web2Secret(OWNER_ADDRESS, SECRET_ADDRESS, ENCRYPTED_SECRET_VALUE); when(web2SecretRepository.findById(any(Web2SecretHeader.class))) .thenReturn(Optional.of(encryptedSecret)); - final Optional oSecret1 = web2SecretService.getSecret(OWNER_ADDRESS, SECRET_ADDRESS); - final Optional oSecret2 = web2SecretService.getSecret(OWNER_ADDRESS, SECRET_ADDRESS, false); - assertThat(oSecret1).isNotEmpty(); + final Optional result = web2SecretService.getSecret(OWNER_ADDRESS, SECRET_ADDRESS); + assertThat(result).isNotEmpty(); assertAll( - () -> assertThat(oSecret1).isEqualTo(oSecret2), - () -> assertThat(oSecret1).get().extracting(Web2Secret::getHeader).usingRecursiveComparison().isEqualTo(new Web2SecretHeader(OWNER_ADDRESS, SECRET_ADDRESS)), - () -> assertThat(oSecret1).get().extracting(Web2Secret::getValue).isEqualTo(ENCRYPTED_SECRET_VALUE), - () -> assertThat(oSecret1).get().extracting(Web2Secret::isEncryptedValue).isEqualTo(true), + () -> assertThat(result).get().extracting(Web2Secret::getHeader).usingRecursiveComparison().isEqualTo(new Web2SecretHeader(OWNER_ADDRESS, SECRET_ADDRESS)), + () -> assertThat(result).get().extracting(Web2Secret::getValue).isEqualTo(ENCRYPTED_SECRET_VALUE), () -> verifyNoInteractions(encryptionService) ); } @Test - void shouldGetEmptyResultIfSecretNotPresent() { + void shouldGetEmptySecretIfSecretNotPresent() { when(web2SecretRepository.findById(any(Web2SecretHeader.class))) .thenReturn(Optional.empty()); assertThat(web2SecretService.getSecret(OWNER_ADDRESS, SECRET_ADDRESS)).isEmpty(); - assertThat(web2SecretService.getSecret(OWNER_ADDRESS, SECRET_ADDRESS, false)).isEmpty(); - verify(web2SecretRepository, times(2)) + verify(web2SecretRepository, times(1)) + .findById(any(Web2SecretHeader.class)); + verifyNoInteractions(encryptionService); + } + + @Test + void shouldGetEmptyDecryptedValueIfSecretNotPresent() { + when(web2SecretRepository.findById(any(Web2SecretHeader.class))) + .thenReturn(Optional.empty()); + + assertThat(web2SecretService.getDecryptedValue(OWNER_ADDRESS, SECRET_ADDRESS)).isEmpty(); + verify(web2SecretRepository, times(1)) .findById(any(Web2SecretHeader.class)); verifyNoInteractions(encryptionService); } @@ -108,13 +112,12 @@ void shouldAddSecret() throws SecretAlreadyExistsException { when(web2SecretRepository.findById(any(Web2SecretHeader.class))) .thenReturn(Optional.empty()); when(encryptionService.encrypt(PLAIN_SECRET_VALUE)).thenReturn(ENCRYPTED_SECRET_VALUE); - when(web2SecretRepository.save(any())).thenReturn(new Web2Secret(OWNER_ADDRESS, SECRET_ADDRESS, ENCRYPTED_SECRET_VALUE, true)); + when(web2SecretRepository.save(any())).thenReturn(new Web2Secret(OWNER_ADDRESS, SECRET_ADDRESS, ENCRYPTED_SECRET_VALUE)); final Web2Secret newSecret = web2SecretService.addSecret(OWNER_ADDRESS, SECRET_ADDRESS, PLAIN_SECRET_VALUE); assertAll( () -> assertThat(newSecret).extracting(Web2Secret::getHeader).usingRecursiveComparison().isEqualTo(new Web2SecretHeader(OWNER_ADDRESS, SECRET_ADDRESS)), () -> assertThat(newSecret).extracting(Web2Secret::getValue).isEqualTo(ENCRYPTED_SECRET_VALUE), - () -> assertThat(newSecret).extracting(Web2Secret::isEncryptedValue).isEqualTo(true), () -> verify(encryptionService).encrypt(any()), () -> verify(web2SecretRepository).save(any()) @@ -123,7 +126,7 @@ void shouldAddSecret() throws SecretAlreadyExistsException { @Test void shouldNotAddSecretIfPresent() { - final Web2Secret secret = new Web2Secret(OWNER_ADDRESS, SECRET_ADDRESS, ENCRYPTED_SECRET_VALUE, true); + final Web2Secret secret = new Web2Secret(OWNER_ADDRESS, SECRET_ADDRESS, ENCRYPTED_SECRET_VALUE); when(web2SecretRepository.findById(any(Web2SecretHeader.class))) .thenReturn(Optional.of(secret)); @@ -141,14 +144,14 @@ void shouldNotAddSecretIfPresent() { // region updateSecret @Test void shouldUpdateSecret() throws NotAnExistingSecretException, SameSecretException { - final Web2Secret encryptedSecret = new Web2Secret(OWNER_ADDRESS, SECRET_ADDRESS, ENCRYPTED_SECRET_VALUE, true); + final Web2Secret encryptedSecret = new Web2Secret(OWNER_ADDRESS, SECRET_ADDRESS, ENCRYPTED_SECRET_VALUE); final String newSecretValue = "newSecretValue"; final String newEncryptedSecretValue = "newEncryptedSecretValue"; when(web2SecretRepository.findById(any(Web2SecretHeader.class))) .thenReturn(Optional.of(encryptedSecret)); when(encryptionService.encrypt(newSecretValue)) .thenReturn(newEncryptedSecretValue); - final Web2Secret savedSecret = new Web2Secret(OWNER_ADDRESS, SECRET_ADDRESS, newEncryptedSecretValue, true); + final Web2Secret savedSecret = new Web2Secret(OWNER_ADDRESS, SECRET_ADDRESS, newEncryptedSecretValue); when(web2SecretRepository.save(any())) .thenReturn(savedSecret); @@ -156,7 +159,6 @@ void shouldUpdateSecret() throws NotAnExistingSecretException, SameSecretExcepti assertAll( () -> assertThat(newSecret).extracting(Web2Secret::getHeader).usingRecursiveComparison().isEqualTo(new Web2SecretHeader(OWNER_ADDRESS, SECRET_ADDRESS)), () -> assertThat(newSecret).extracting(Web2Secret::getValue).isEqualTo(newEncryptedSecretValue), - () -> assertThat(newSecret).extracting(Web2Secret::isEncryptedValue).isEqualTo(true), () -> verify(web2SecretRepository, never()).save(encryptedSecret), // Current object should not be updated () -> verify(web2SecretRepository, times(1)).save(any()) // A new object should be created with the same ID @@ -179,7 +181,7 @@ void shouldNotUpdateSecretIfMissing() { @Test void shouldNotUpdateSecretIfSameValue() { - final Web2Secret encryptedSecret = new Web2Secret(OWNER_ADDRESS, SECRET_ADDRESS, ENCRYPTED_SECRET_VALUE, true); + final Web2Secret encryptedSecret = new Web2Secret(OWNER_ADDRESS, SECRET_ADDRESS, ENCRYPTED_SECRET_VALUE); when(web2SecretRepository.findById(any(Web2SecretHeader.class))) .thenReturn(Optional.of(encryptedSecret)); when(encryptionService.encrypt(PLAIN_SECRET_VALUE)) diff --git a/src/test/java/com/iexec/sms/secret/web2/Web2SecretTests.java b/src/test/java/com/iexec/sms/secret/web2/Web2SecretTests.java index 1b01b937..6f75b6f5 100644 --- a/src/test/java/com/iexec/sms/secret/web2/Web2SecretTests.java +++ b/src/test/java/com/iexec/sms/secret/web2/Web2SecretTests.java @@ -27,25 +27,25 @@ class Web2SecretTests { private static final String UNENCRYPTED_VALUE = "unencryptedValue"; private static final String ENCRYPTED_VALUE = "encryptedValue"; - private static final Web2Secret UNENCRYPTED_SECRET = new Web2Secret(OWNER_ADDRESS, SECRET_ADDRESS, UNENCRYPTED_VALUE, false); - private static final Web2Secret ENCRYPTED_SECRET = new Web2Secret(OWNER_ADDRESS, SECRET_ADDRESS, ENCRYPTED_VALUE, true); + private static final Web2Secret UNENCRYPTED_SECRET = new Web2Secret(OWNER_ADDRESS, SECRET_ADDRESS, UNENCRYPTED_VALUE); + private static final Web2Secret ENCRYPTED_SECRET = new Web2Secret(OWNER_ADDRESS, SECRET_ADDRESS, ENCRYPTED_VALUE); @Test void withEncryptedValue() { - Assertions.assertThat(UNENCRYPTED_SECRET.withEncryptedValue(ENCRYPTED_VALUE)) + Assertions.assertThat(UNENCRYPTED_SECRET.withValue(ENCRYPTED_VALUE)) .usingRecursiveComparison() .isEqualTo(ENCRYPTED_SECRET); - Assertions.assertThat(ENCRYPTED_SECRET.withEncryptedValue(ENCRYPTED_VALUE)) + Assertions.assertThat(ENCRYPTED_SECRET.withValue(ENCRYPTED_VALUE)) .usingRecursiveComparison() .isEqualTo(ENCRYPTED_SECRET); } @Test void withDecryptedValue() { - Assertions.assertThat(ENCRYPTED_SECRET.withDecryptedValue(UNENCRYPTED_VALUE)) + Assertions.assertThat(ENCRYPTED_SECRET.withValue(UNENCRYPTED_VALUE)) .usingRecursiveComparison() .isEqualTo(UNENCRYPTED_SECRET); - Assertions.assertThat(UNENCRYPTED_SECRET.withDecryptedValue(UNENCRYPTED_VALUE)) + Assertions.assertThat(UNENCRYPTED_SECRET.withValue(UNENCRYPTED_VALUE)) .usingRecursiveComparison() .isEqualTo(UNENCRYPTED_SECRET); } diff --git a/src/test/java/com/iexec/sms/secret/web3/Web3SecretServiceTests.java b/src/test/java/com/iexec/sms/secret/web3/Web3SecretServiceTests.java index fdedb1d8..42b73461 100644 --- a/src/test/java/com/iexec/sms/secret/web3/Web3SecretServiceTests.java +++ b/src/test/java/com/iexec/sms/secret/web3/Web3SecretServiceTests.java @@ -49,7 +49,7 @@ void init() { @Test void shouldNotAddSecretIfPresent() { - Web3Secret web3Secret = new Web3Secret(secretAddress, encryptedSecretValue, true); + Web3Secret web3Secret = new Web3Secret(secretAddress, encryptedSecretValue); when(web3SecretRepository.findById(any(Web3SecretHeader.class))).thenReturn(Optional.of(web3Secret)); assertThat(web3SecretService.addSecret(secretAddress, plainSecretValue)).isFalse(); verifyNoInteractions(encryptionService); @@ -66,16 +66,15 @@ void shouldAddSecret() { } @Test - void shouldGetDecryptedSecret() { - Web3Secret encryptedSecret = new Web3Secret(secretAddress, encryptedSecretValue, true); + void shouldGetDecryptedValue() { + Web3Secret encryptedSecret = new Web3Secret(secretAddress, encryptedSecretValue); when(web3SecretRepository.findById(any(Web3SecretHeader.class))).thenReturn(Optional.of(encryptedSecret)); when(encryptionService.decrypt(encryptedSecretValue)).thenReturn(plainSecretValue); - Optional result = web3SecretService.getSecret(secretAddress, true); - assertThat(result).isPresent(); - assertThat(result).get().extracting(Web3Secret::getHeader).usingRecursiveComparison().isEqualTo(new Web3SecretHeader(secretAddress)); - assertThat(result).get().extracting(Web3Secret::getValue).isEqualTo(plainSecretValue); - assertThat(result).get().extracting(Web3Secret::isEncryptedValue).isEqualTo(false); + Optional result = web3SecretService.getDecryptedValue(secretAddress); + assertThat(result) + .isPresent() + .get().isEqualTo(plainSecretValue); verify(web3SecretRepository).findById(any(Web3SecretHeader.class)); verify(encryptionService).decrypt(any()); @@ -83,23 +82,28 @@ void shouldGetDecryptedSecret() { @Test void shouldGetEncryptedSecret() { - Web3Secret encryptedSecret = new Web3Secret(secretAddress, encryptedSecretValue, true); + Web3Secret encryptedSecret = new Web3Secret(secretAddress, encryptedSecretValue); when(web3SecretRepository.findById(any(Web3SecretHeader.class))).thenReturn(Optional.of(encryptedSecret)); - Optional oSecret1 = web3SecretService.getSecret(secretAddress, false); - Optional oSecret2 = web3SecretService.getSecret(secretAddress); - assertThat(oSecret1) - .contains(encryptedSecret) - .isEqualTo(oSecret2); - verify(web3SecretRepository, times(2)).findById(any(Web3SecretHeader.class)); + Optional result = web3SecretService.getSecret(secretAddress); + assertThat(result) + .contains(encryptedSecret); + verify(web3SecretRepository, times(1)).findById(any(Web3SecretHeader.class)); verifyNoInteractions(encryptionService); } @Test - void shouldGetEmptyResultIfSecretNotPresent() { + void shouldGetEmptySecretIfSecretNotPresent() { when(web3SecretRepository.findById(any(Web3SecretHeader.class))).thenReturn(Optional.empty()); assertThat(web3SecretService.getSecret(secretAddress)).isEmpty(); - assertThat(web3SecretService.getSecret(secretAddress, false)).isEmpty(); - verify(web3SecretRepository, times(2)).findById(any(Web3SecretHeader.class)); + verify(web3SecretRepository, times(1)).findById(any(Web3SecretHeader.class)); + verifyNoInteractions(encryptionService); + } + + @Test + void shouldGetEmptyValueIfSecretNotPresent() { + when(web3SecretRepository.findById(any(Web3SecretHeader.class))).thenReturn(Optional.empty()); + assertThat(web3SecretService.getDecryptedValue(secretAddress)).isEmpty(); + verify(web3SecretRepository, times(1)).findById(any(Web3SecretHeader.class)); verifyNoInteractions(encryptionService); } diff --git a/src/test/java/com/iexec/sms/tee/session/base/SecretSessionBaseServiceTests.java b/src/test/java/com/iexec/sms/tee/session/base/SecretSessionBaseServiceTests.java index fa3be8e0..9030e295 100644 --- a/src/test/java/com/iexec/sms/tee/session/base/SecretSessionBaseServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/base/SecretSessionBaseServiceTests.java @@ -13,9 +13,7 @@ import com.iexec.sms.secret.compute.SecretOwnerRole; import com.iexec.sms.secret.compute.TeeTaskComputeSecret; import com.iexec.sms.secret.compute.TeeTaskComputeSecretService; -import com.iexec.sms.secret.web2.Web2Secret; import com.iexec.sms.secret.web2.Web2SecretService; -import com.iexec.sms.secret.web3.Web3Secret; import com.iexec.sms.secret.web3.Web3SecretService; import com.iexec.sms.tee.challenge.TeeChallenge; import com.iexec.sms.tee.challenge.TeeChallengeService; @@ -91,22 +89,18 @@ void shouldGetSecretsTokens() throws Exception { // pre when(preComputeProperties.getFingerprint()) .thenReturn(PRE_COMPUTE_FINGERPRINT); - Web3Secret secret = new Web3Secret(DATASET_ADDRESS, DATASET_KEY, true); - when(web3SecretService.getSecret(DATASET_ADDRESS, true)) - .thenReturn(Optional.of(secret)); + when(web3SecretService.getDecryptedValue(DATASET_ADDRESS)) + .thenReturn(Optional.of(DATASET_KEY)); // post - Web2Secret publicKeySecret = new Web2Secret(beneficiary, "address", ENCRYPTION_PUBLIC_KEY, true); when(postComputeProperties.getFingerprint()) .thenReturn(POST_COMPUTE_FINGERPRINT); - when(web2SecretService.getSecret( + when(web2SecretService.getDecryptedValue( beneficiary, - ReservedSecretKeyName.IEXEC_RESULT_ENCRYPTION_PUBLIC_KEY, - true)) - .thenReturn(Optional.of(publicKeySecret)); - Web2Secret storageSecret = new Web2Secret(beneficiary, "address", STORAGE_TOKEN, true); - when(web2SecretService.getSecret(taskDescription.getRequester(), - ReservedSecretKeyName.IEXEC_RESULT_IEXEC_IPFS_TOKEN, true)) - .thenReturn(Optional.of(storageSecret)); + ReservedSecretKeyName.IEXEC_RESULT_ENCRYPTION_PUBLIC_KEY)) + .thenReturn(Optional.of(ENCRYPTION_PUBLIC_KEY)); + when(web2SecretService.getDecryptedValue(taskDescription.getRequester(), + ReservedSecretKeyName.IEXEC_RESULT_IEXEC_IPFS_TOKEN)) + .thenReturn(Optional.of(STORAGE_TOKEN)); TeeChallenge challenge = TeeChallenge.builder() .credentials(EthereumCredentials.generate()) .build(); @@ -165,9 +159,8 @@ void shouldGetPreComputeTokens() throws Exception { TeeSessionRequest request = createSessionRequest(taskDescription); when(preComputeProperties.getFingerprint()) .thenReturn(PRE_COMPUTE_FINGERPRINT); - Web3Secret secret = new Web3Secret(DATASET_ADDRESS, DATASET_KEY, true); - when(web3SecretService.getSecret(DATASET_ADDRESS, true)) - .thenReturn(Optional.of(secret)); + when(web3SecretService.getDecryptedValue(DATASET_ADDRESS)) + .thenReturn(Optional.of(DATASET_KEY)); SecretEnclaveBase enclaveBase = teeSecretsService.getPreComputeTokens(request); assertThat(enclaveBase.getName()).isEqualTo("pre-compute"); @@ -176,7 +169,7 @@ void shouldGetPreComputeTokens() throws Exception { expectedTokens.put("IEXEC_TASK_ID", TASK_ID); expectedTokens.put("IEXEC_PRE_COMPUTE_OUT", "/iexec_in"); expectedTokens.put("IS_DATASET_REQUIRED", true); - expectedTokens.put("IEXEC_DATASET_KEY", secret.getTrimmedValue()); + expectedTokens.put("IEXEC_DATASET_KEY", DATASET_KEY); expectedTokens.put("IEXEC_DATASET_URL", DATASET_URL); expectedTokens.put("IEXEC_DATASET_FILENAME", DATASET_NAME); expectedTokens.put("IEXEC_DATASET_CHECKSUM", DATASET_CHECKSUM); @@ -391,22 +384,17 @@ void shouldGetPostComputeTokens() throws Exception { TeeSessionRequest request = createSessionRequest(createTaskDescription(enclaveConfig)); String requesterAddress = request.getTaskDescription().getRequester(); - String beneficiary = request.getTaskDescription().getBeneficiary(); - Web2Secret publicKeySecret = new Web2Secret(beneficiary, "address", ENCRYPTION_PUBLIC_KEY, true); when(postComputeProperties.getFingerprint()) .thenReturn(POST_COMPUTE_FINGERPRINT); - when(web2SecretService.getSecret( + when(web2SecretService.getDecryptedValue( request.getTaskDescription().getBeneficiary(), - ReservedSecretKeyName.IEXEC_RESULT_ENCRYPTION_PUBLIC_KEY, - true)) - .thenReturn(Optional.of(publicKeySecret)); - Web2Secret storageSecret = new Web2Secret(beneficiary, "address", STORAGE_TOKEN, true); - when(web2SecretService.getSecret( + ReservedSecretKeyName.IEXEC_RESULT_ENCRYPTION_PUBLIC_KEY)) + .thenReturn(Optional.of(ENCRYPTION_PUBLIC_KEY)); + when(web2SecretService.getDecryptedValue( requesterAddress, - ReservedSecretKeyName.IEXEC_RESULT_IEXEC_IPFS_TOKEN, - true)) - .thenReturn(Optional.of(storageSecret)); + ReservedSecretKeyName.IEXEC_RESULT_IEXEC_IPFS_TOKEN)) + .thenReturn(Optional.of(STORAGE_TOKEN)); TeeChallenge challenge = TeeChallenge.builder() .credentials(EthereumCredentials.generate()) @@ -468,12 +456,11 @@ void shouldGetPostComputeStorageTokensWithCallback() { void shouldGetPostComputeStorageTokensOnIpfs() { final TeeSessionRequest sessionRequest = createSessionRequest(createTaskDescription(enclaveConfig)); final TaskDescription taskDescription = sessionRequest.getTaskDescription(); - final String beneficiaryAddress = taskDescription.getAppAddress(); final String secretValue = "Secret value"; - when(web2SecretService.getSecret(taskDescription.getRequester(), - ReservedSecretKeyName.IEXEC_RESULT_IEXEC_IPFS_TOKEN, true)) - .thenReturn(Optional.of(new Web2Secret(beneficiaryAddress, "address", secretValue, true))); + when(web2SecretService.getDecryptedValue(taskDescription.getRequester(), + ReservedSecretKeyName.IEXEC_RESULT_IEXEC_IPFS_TOKEN)) + .thenReturn(Optional.of(secretValue)); final Map tokens = assertDoesNotThrow( () -> teeSecretsService.getPostComputeStorageTokens(sessionRequest)); @@ -493,12 +480,10 @@ void shouldGetPostComputeStorageTokensOnDropbox() { final TaskDescription taskDescription = sessionRequest.getTaskDescription(); taskDescription.setResultStorageProvider(DealParams.DROPBOX_RESULT_STORAGE_PROVIDER); - final String beneficiaryAddress = taskDescription.getAppAddress(); - final String secretValue = "Secret value"; - when(web2SecretService.getSecret(taskDescription.getRequester(), - ReservedSecretKeyName.IEXEC_RESULT_DROPBOX_TOKEN, true)) - .thenReturn(Optional.of(new Web2Secret(beneficiaryAddress, "address", secretValue, true))); + when(web2SecretService.getDecryptedValue(taskDescription.getRequester(), + ReservedSecretKeyName.IEXEC_RESULT_DROPBOX_TOKEN)) + .thenReturn(Optional.of(secretValue)); final Map tokens = assertDoesNotThrow( () -> teeSecretsService.getPostComputeStorageTokens(sessionRequest)); @@ -517,8 +502,8 @@ void shouldNotGetPostComputeStorageTokensSinceNoSecret() { final TeeSessionRequest sessionRequest = createSessionRequest(createTaskDescription(enclaveConfig)); final TaskDescription taskDescription = sessionRequest.getTaskDescription(); - when(web2SecretService.getSecret(taskDescription.getRequester(), - ReservedSecretKeyName.IEXEC_RESULT_IEXEC_IPFS_TOKEN, true)) + when(web2SecretService.getDecryptedValue(taskDescription.getRequester(), + ReservedSecretKeyName.IEXEC_RESULT_IEXEC_IPFS_TOKEN)) .thenReturn(Optional.empty()); final TeeSessionGenerationException exception = assertThrows( @@ -642,12 +627,10 @@ void shouldGetPostComputeEncryptionTokensWithEncryption() { TeeSessionRequest request = createSessionRequest(createTaskDescription(enclaveConfig)); String beneficiary = request.getTaskDescription().getBeneficiary(); - Web2Secret publicKeySecret = new Web2Secret(beneficiary, "address", ENCRYPTION_PUBLIC_KEY, true); - when(web2SecretService.getSecret( + when(web2SecretService.getDecryptedValue( beneficiary, - ReservedSecretKeyName.IEXEC_RESULT_ENCRYPTION_PUBLIC_KEY, - true)) - .thenReturn(Optional.of(publicKeySecret)); + ReservedSecretKeyName.IEXEC_RESULT_ENCRYPTION_PUBLIC_KEY)) + .thenReturn(Optional.of(ENCRYPTION_PUBLIC_KEY)); final Map encryptionTokens = assertDoesNotThrow( () -> teeSecretsService.getPostComputeEncryptionTokens(request)); @@ -676,10 +659,9 @@ void shouldGetPostComputeEncryptionTokensWithoutEncryption() { void shouldNotGetPostComputeEncryptionTokensSinceEmptyBeneficiaryKey() { TeeSessionRequest request = createSessionRequest(createTaskDescription(enclaveConfig)); - when(web2SecretService.getSecret( + when(web2SecretService.getDecryptedValue( request.getTaskDescription().getBeneficiary(), - ReservedSecretKeyName.IEXEC_RESULT_ENCRYPTION_PUBLIC_KEY, - true)) + ReservedSecretKeyName.IEXEC_RESULT_ENCRYPTION_PUBLIC_KEY)) .thenReturn(Optional.empty()); final TeeSessionGenerationException exception = assertThrows( From d3b7022e31c798c62bef4cbf78da4c4f108de373 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Mon, 2 Jan 2023 14:56:48 +0100 Subject: [PATCH 242/293] Require non-null Secret value --- src/main/java/com/iexec/sms/secret/Secret.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/iexec/sms/secret/Secret.java b/src/main/java/com/iexec/sms/secret/Secret.java index 02db3df4..d7cc55ad 100644 --- a/src/main/java/com/iexec/sms/secret/Secret.java +++ b/src/main/java/com/iexec/sms/secret/Secret.java @@ -22,6 +22,7 @@ import javax.persistence.Column; import javax.persistence.MappedSuperclass; +import java.util.Objects; @MappedSuperclass @Getter @@ -40,7 +41,8 @@ public abstract class Secret { * though everything is correctly setup. */ protected Secret(String value) { - this.value = value != null ? value.trim() : null; + Objects.requireNonNull(value, "Secret value must not be null"); + this.value = value.trim(); } } From 96fd617df9bc0af7d3f624b3e550741c6c657929 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Mon, 2 Jan 2023 14:59:28 +0100 Subject: [PATCH 243/293] Replace `ofNullable` with `of` in `WebXSecretService`s --- src/main/java/com/iexec/sms/secret/web2/Web2SecretService.java | 2 +- src/main/java/com/iexec/sms/secret/web3/Web3SecretService.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/iexec/sms/secret/web2/Web2SecretService.java b/src/main/java/com/iexec/sms/secret/web2/Web2SecretService.java index 9dae7ccf..c673181e 100644 --- a/src/main/java/com/iexec/sms/secret/web2/Web2SecretService.java +++ b/src/main/java/com/iexec/sms/secret/web2/Web2SecretService.java @@ -50,7 +50,7 @@ public Optional getDecryptedValue(String ownerAddress, String secretAddr final Web2Secret secret = oSecret.get(); final String decryptedValue = encryptionService.decrypt(secret.getValue()); - return Optional.ofNullable(decryptedValue); + return Optional.of(decryptedValue); } public boolean isSecretPresent(String ownerAddress, String secretAddress) { diff --git a/src/main/java/com/iexec/sms/secret/web3/Web3SecretService.java b/src/main/java/com/iexec/sms/secret/web3/Web3SecretService.java index ccdb0233..3ce02a9c 100644 --- a/src/main/java/com/iexec/sms/secret/web3/Web3SecretService.java +++ b/src/main/java/com/iexec/sms/secret/web3/Web3SecretService.java @@ -46,7 +46,7 @@ public Optional getDecryptedValue(String secretAddress) { return Optional.empty(); } final String decryptedValue = encryptionService.decrypt(oSecret.get().getValue()); - return Optional.ofNullable(decryptedValue); + return Optional.of(decryptedValue); } public boolean isSecretPresent(String secretAddress) { From 202cfc747cc0f6257f3f7c56517ff4283dbd47d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20James=20Toussaint?= <33313130+jeremyjams@users.noreply.github.com> Date: Mon, 2 Jan 2023 15:47:38 +0100 Subject: [PATCH 244/293] Remove unused references --- .../com/iexec/sms/api/SmsClientProvider.java | 2 -- .../api/config/TeeServicesPropertiesTests.java | 2 -- .../sms/tee/session/TeeSessionService.java | 2 -- .../scone/SconeSessionMakerService.java | 2 -- .../AuthorizationServiceTests.java | 18 ++++++++---------- .../compute/TeeTaskComputeSecretTest.java | 2 -- .../scone/SconeSessionMakerServiceTests.java | 2 -- 7 files changed, 8 insertions(+), 22 deletions(-) diff --git a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java index a8f32986..af10880d 100644 --- a/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java +++ b/iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClientProvider.java @@ -1,7 +1,6 @@ package com.iexec.sms.api; import feign.Logger; -import lombok.extern.slf4j.Slf4j; import java.util.HashMap; import java.util.Map; @@ -10,7 +9,6 @@ * Manages the {@link SmsClient}, providing an easy way to access SMS * and avoiding the need to create a new {@link SmsClient} instance each time. */ -@Slf4j public class SmsClientProvider { private final Map urlToSmsClient = new HashMap<>(); diff --git a/iexec-sms-library/src/test/java/com/iexec/sms/api/config/TeeServicesPropertiesTests.java b/iexec-sms-library/src/test/java/com/iexec/sms/api/config/TeeServicesPropertiesTests.java index 7dfd36b0..89a3fad1 100644 --- a/iexec-sms-library/src/test/java/com/iexec/sms/api/config/TeeServicesPropertiesTests.java +++ b/iexec-sms-library/src/test/java/com/iexec/sms/api/config/TeeServicesPropertiesTests.java @@ -3,7 +3,6 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; -import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Test; import java.util.ArrayList; @@ -11,7 +10,6 @@ import static org.assertj.core.api.Assertions.assertThat; -@Slf4j class TeeServicesPropertiesTests { private static final ObjectMapper mapper = new ObjectMapper(); diff --git a/src/main/java/com/iexec/sms/tee/session/TeeSessionService.java b/src/main/java/com/iexec/sms/tee/session/TeeSessionService.java index d86b1339..b2b26390 100644 --- a/src/main/java/com/iexec/sms/tee/session/TeeSessionService.java +++ b/src/main/java/com/iexec/sms/tee/session/TeeSessionService.java @@ -23,14 +23,12 @@ import com.iexec.sms.tee.session.generic.TeeSessionGenerationException; import com.iexec.sms.tee.session.generic.TeeSessionHandler; import com.iexec.sms.tee.session.generic.TeeSessionRequest; -import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.RandomStringUtils; import org.springframework.stereotype.Service; import static com.iexec.sms.api.TeeSessionGenerationError.GET_TASK_DESCRIPTION_FAILED; import static com.iexec.sms.api.TeeSessionGenerationError.SECURE_SESSION_NO_TEE_PROVIDER; -@Slf4j @Service public class TeeSessionService { diff --git a/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionMakerService.java b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionMakerService.java index a2161f04..52b48cf1 100644 --- a/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionMakerService.java +++ b/src/main/java/com/iexec/sms/tee/session/scone/SconeSessionMakerService.java @@ -32,13 +32,11 @@ import com.iexec.sms.tee.session.scone.cas.SconeSession.Security; import com.iexec.sms.tee.session.scone.cas.SconeSession.Volumes; import lombok.NonNull; -import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import java.util.*; //TODO Rename and move -@Slf4j @Service @ConditionalOnTeeFramework(frameworks = TeeFramework.SCONE) public class SconeSessionMakerService { diff --git a/src/test/java/com/iexec/sms/authorization/AuthorizationServiceTests.java b/src/test/java/com/iexec/sms/authorization/AuthorizationServiceTests.java index 67322d33..0ff228b8 100644 --- a/src/test/java/com/iexec/sms/authorization/AuthorizationServiceTests.java +++ b/src/test/java/com/iexec/sms/authorization/AuthorizationServiceTests.java @@ -16,21 +16,12 @@ package com.iexec.sms.authorization; -import static com.iexec.common.chain.ChainTaskStatus.ACTIVE; -import static com.iexec.common.chain.ChainTaskStatus.UNSET; -import static com.iexec.sms.authorization.AuthorizationError.*; -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.when; - -import java.util.Optional; - import com.iexec.common.chain.ChainDeal; import com.iexec.common.chain.ChainTask; import com.iexec.common.chain.WorkerpoolAuthorization; import com.iexec.common.security.Signature; import com.iexec.common.utils.TestUtils; import com.iexec.sms.blockchain.IexecHubService; - import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -38,6 +29,14 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.Optional; + +import static com.iexec.common.chain.ChainTaskStatus.ACTIVE; +import static com.iexec.common.chain.ChainTaskStatus.UNSET; +import static com.iexec.sms.authorization.AuthorizationError.*; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.when; + class AuthorizationServiceTests { @Mock @@ -169,7 +168,6 @@ void shouldNotBeAuthorizedOnExecutionOfTeeTaskWhenTaskNotActiveWithDetails() { @Test void shouldNotBeAuthorizedOnExecutionOfTeeTaskWhenGetDealFailedWithDetails() { - ChainDeal chainDeal = TestUtils.getChainDeal(); ChainTask chainTask = TestUtils.getChainTask(ACTIVE); WorkerpoolAuthorization auth = TestUtils.getTeeWorkerpoolAuth(); auth.setSignature(new Signature(TestUtils.POOL_WRONG_SIGNATURE)); diff --git a/src/test/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretTest.java b/src/test/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretTest.java index 0e838d1f..c4a2be1f 100644 --- a/src/test/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretTest.java +++ b/src/test/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretTest.java @@ -1,6 +1,5 @@ package com.iexec.sms.secret.compute; -import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; @@ -10,7 +9,6 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; -@Slf4j @DataJpaTest public class TeeTaskComputeSecretTest { diff --git a/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionMakerServiceTests.java b/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionMakerServiceTests.java index 816984dd..1f7e77df 100644 --- a/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionMakerServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/scone/SconeSessionMakerServiceTests.java @@ -25,7 +25,6 @@ import com.iexec.sms.tee.session.base.SecretSessionBaseService; import com.iexec.sms.tee.session.generic.TeeSessionRequest; import com.iexec.sms.tee.session.scone.cas.SconeSession; -import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.InjectMocks; @@ -39,7 +38,6 @@ import static com.iexec.sms.tee.session.TeeSessionTestUtils.*; import static org.mockito.Mockito.when; -@Slf4j class SconeSessionMakerServiceTests { private static final String PRE_COMPUTE_ENTRYPOINT = "entrypoint1"; From f018681066c920854033167e73c67470febdf6a0 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton <87655102+mcornaton@users.noreply.github.com> Date: Tue, 3 Jan 2023 09:38:16 +0100 Subject: [PATCH 245/293] Set variables final Co-authored-by: Jeremy Bernard --- src/main/java/com/iexec/sms/secret/SecretController.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/iexec/sms/secret/SecretController.java b/src/main/java/com/iexec/sms/secret/SecretController.java index ef971810..add66101 100644 --- a/src/main/java/com/iexec/sms/secret/SecretController.java +++ b/src/main/java/com/iexec/sms/secret/SecretController.java @@ -52,7 +52,7 @@ public SecretController(AuthorizationService authorizationService, @RequestMapping(path = "/web3", method = RequestMethod.HEAD) public ResponseEntity isWeb3SecretSet(@RequestParam String secretAddress) { - boolean isSecretPresent = web3SecretService.isSecretPresent(secretAddress); + final boolean isSecretPresent = web3SecretService.isSecretPresent(secretAddress); return isSecretPresent ? ResponseEntity.noContent().build() : ResponseEntity.notFound().build(); } @@ -83,7 +83,7 @@ public ResponseEntity addWeb3Secret(@RequestHeader String authorization, @RequestMapping(path = "/web2", method = RequestMethod.HEAD) public ResponseEntity isWeb2SecretSet(@RequestParam String ownerAddress, @RequestParam String secretName) { - boolean isSecretPresent = web2SecretService.isSecretPresent(ownerAddress, secretName); + final boolean isSecretPresent = web2SecretService.isSecretPresent(ownerAddress, secretName); return isSecretPresent ? ResponseEntity.noContent().build() : ResponseEntity.notFound().build(); } From 287ada21bd99bb94cbd34276d9c0154137fd85a1 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Tue, 3 Jan 2023 09:38:54 +0100 Subject: [PATCH 246/293] Remove `Web3Secret#withValue` --- .../java/com/iexec/sms/secret/web3/Web3Secret.java | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/main/java/com/iexec/sms/secret/web3/Web3Secret.java b/src/main/java/com/iexec/sms/secret/web3/Web3Secret.java index 6e3f5de6..75f35292 100644 --- a/src/main/java/com/iexec/sms/secret/web3/Web3Secret.java +++ b/src/main/java/com/iexec/sms/secret/web3/Web3Secret.java @@ -39,15 +39,4 @@ private Web3Secret(Web3SecretHeader header, String value) { super(value); this.header = header; } - - /** - * Copies the current {@link Web3Secret} object, - * while replacing the old value with a new value. - * - * @param newValue Value to use for new object. - * @return A new {@link Web3Secret} object with new value. - */ - public Web3Secret withValue(String newValue) { - return new Web3Secret(header, newValue); - } } From 033113dab23ff039bbf8c037205b896ca04d4f25 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Tue, 3 Jan 2023 09:42:05 +0100 Subject: [PATCH 247/293] Update `Web2SecretTests` to remove encryption notion --- .../sms/secret/web2/Web2SecretTests.java | 27 +++++-------------- 1 file changed, 7 insertions(+), 20 deletions(-) diff --git a/src/test/java/com/iexec/sms/secret/web2/Web2SecretTests.java b/src/test/java/com/iexec/sms/secret/web2/Web2SecretTests.java index 6f75b6f5..6be72f64 100644 --- a/src/test/java/com/iexec/sms/secret/web2/Web2SecretTests.java +++ b/src/test/java/com/iexec/sms/secret/web2/Web2SecretTests.java @@ -25,28 +25,15 @@ class Web2SecretTests { private static final String OWNER_ADDRESS = "ownerAddress"; private static final String SECRET_ADDRESS = "secretAddress"; - private static final String UNENCRYPTED_VALUE = "unencryptedValue"; - private static final String ENCRYPTED_VALUE = "encryptedValue"; - private static final Web2Secret UNENCRYPTED_SECRET = new Web2Secret(OWNER_ADDRESS, SECRET_ADDRESS, UNENCRYPTED_VALUE); - private static final Web2Secret ENCRYPTED_SECRET = new Web2Secret(OWNER_ADDRESS, SECRET_ADDRESS, ENCRYPTED_VALUE); + private static final String VALUE = "value"; + private static final String NEW_VALUE = "newValue"; + private static final Web2Secret SECRET = new Web2Secret(OWNER_ADDRESS, SECRET_ADDRESS, VALUE); + private static final Web2Secret NEW_SECRET = new Web2Secret(OWNER_ADDRESS, SECRET_ADDRESS, NEW_VALUE); @Test - void withEncryptedValue() { - Assertions.assertThat(UNENCRYPTED_SECRET.withValue(ENCRYPTED_VALUE)) + void withValue() { + Assertions.assertThat(SECRET.withValue(NEW_VALUE)) .usingRecursiveComparison() - .isEqualTo(ENCRYPTED_SECRET); - Assertions.assertThat(ENCRYPTED_SECRET.withValue(ENCRYPTED_VALUE)) - .usingRecursiveComparison() - .isEqualTo(ENCRYPTED_SECRET); - } - - @Test - void withDecryptedValue() { - Assertions.assertThat(ENCRYPTED_SECRET.withValue(UNENCRYPTED_VALUE)) - .usingRecursiveComparison() - .isEqualTo(UNENCRYPTED_SECRET); - Assertions.assertThat(UNENCRYPTED_SECRET.withValue(UNENCRYPTED_VALUE)) - .usingRecursiveComparison() - .isEqualTo(UNENCRYPTED_SECRET); + .isEqualTo(NEW_SECRET); } } From f6555d8a0a9cd7124ca9d2287254be8a0be74b08 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Tue, 3 Jan 2023 09:45:41 +0100 Subject: [PATCH 248/293] Add JavaDoc to `WebXSecretService#getSecret` --- .../com/iexec/sms/secret/web2/Web2SecretService.java | 9 +++++++++ .../com/iexec/sms/secret/web3/Web3SecretService.java | 8 ++++++++ 2 files changed, 17 insertions(+) diff --git a/src/main/java/com/iexec/sms/secret/web2/Web2SecretService.java b/src/main/java/com/iexec/sms/secret/web2/Web2SecretService.java index c673181e..9b43ebcb 100644 --- a/src/main/java/com/iexec/sms/secret/web2/Web2SecretService.java +++ b/src/main/java/com/iexec/sms/secret/web2/Web2SecretService.java @@ -37,6 +37,15 @@ protected Web2SecretService(EncryptionService encryptionService, this.web2SecretRepository = web2SecretRepository; } + /** + * Get the secret as it was saved in DB. + * Its value should then be encrypted. + * + * @param ownerAddress Address of the secret owner. + * @param secretAddress Address of the secret. + * @return An empty {@link Optional} if no secret is found, + * an {@link Optional} containing the secret if it exists. + */ Optional getSecret(String ownerAddress, String secretAddress) { return web2SecretRepository.findById(new Web2SecretHeader(ownerAddress, secretAddress)); } diff --git a/src/main/java/com/iexec/sms/secret/web3/Web3SecretService.java b/src/main/java/com/iexec/sms/secret/web3/Web3SecretService.java index 3ce02a9c..3859cfe0 100644 --- a/src/main/java/com/iexec/sms/secret/web3/Web3SecretService.java +++ b/src/main/java/com/iexec/sms/secret/web3/Web3SecretService.java @@ -36,6 +36,14 @@ public Web3SecretService(Web3SecretRepository web3SecretRepository, this.web3SecretRepository = web3SecretRepository; } + /** + * Get the secret as it was saved in DB. + * Its value should then be encrypted. + * + * @param secretAddress Address of the secret. + * @return An empty {@link Optional} if no secret is found, + * an {@link Optional} containing the secret if it exists. + */ Optional getSecret(String secretAddress) { return web3SecretRepository.findById(new Web3SecretHeader(secretAddress)); } From f907d82e4c2b9f00ae0bad997b186f3b3164e44a Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Tue, 3 Jan 2023 10:53:56 +0100 Subject: [PATCH 249/293] Update SpringBoot@2.6.14 --- build.gradle | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index de0ea072..da76feff 100644 --- a/build.gradle +++ b/build.gradle @@ -1,7 +1,7 @@ plugins { id 'java' id 'io.freefair.lombok' version '6.6.1' - id 'org.springframework.boot' version '2.6.2' + id 'org.springframework.boot' version '2.6.14' id 'io.spring.dependency-management' version '1.1.0' id 'jacoco' id 'org.sonarqube' version '3.3' @@ -9,7 +9,7 @@ plugins { } ext { - springCloudVersion = '2021.0.0' + springCloudVersion = '2021.0.5' openFeignVersion = '11.7' } @@ -76,7 +76,7 @@ dependencies { implementation 'org.springdoc:springdoc-openapi-ui:1.6.3' //ssl - implementation 'org.apache.httpcomponents:httpclient:4.5.9' + implementation 'org.apache.httpcomponents:httpclient' // Web3j issues, see core build.gradle // NoSuchMethodError: 'okhttp3.RequestBody okhttp3.RequestBody.create(java.lang.String, okhttp3.MediaType)' From 5c99954f92e65d2882c065cf4653cf1d37ae43af Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Tue, 3 Jan 2023 14:39:27 +0100 Subject: [PATCH 250/293] Use `.map` to simplify methods --- .../com/iexec/sms/secret/web2/Web2SecretService.java | 11 ++--------- .../com/iexec/sms/secret/web3/Web3SecretService.java | 8 ++------ 2 files changed, 4 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/iexec/sms/secret/web2/Web2SecretService.java b/src/main/java/com/iexec/sms/secret/web2/Web2SecretService.java index 9b43ebcb..434dfae8 100644 --- a/src/main/java/com/iexec/sms/secret/web2/Web2SecretService.java +++ b/src/main/java/com/iexec/sms/secret/web2/Web2SecretService.java @@ -51,15 +51,8 @@ Optional getSecret(String ownerAddress, String secretAddress) { } public Optional getDecryptedValue(String ownerAddress, String secretAddress) { - final Optional oSecret = getSecret(ownerAddress, secretAddress); - - if (oSecret.isEmpty()) { - return Optional.empty(); - } - - final Web2Secret secret = oSecret.get(); - final String decryptedValue = encryptionService.decrypt(secret.getValue()); - return Optional.of(decryptedValue); + return getSecret(ownerAddress, secretAddress) + .map(secret -> encryptionService.decrypt(secret.getValue())); } public boolean isSecretPresent(String ownerAddress, String secretAddress) { diff --git a/src/main/java/com/iexec/sms/secret/web3/Web3SecretService.java b/src/main/java/com/iexec/sms/secret/web3/Web3SecretService.java index 3859cfe0..fbd3f5c1 100644 --- a/src/main/java/com/iexec/sms/secret/web3/Web3SecretService.java +++ b/src/main/java/com/iexec/sms/secret/web3/Web3SecretService.java @@ -49,12 +49,8 @@ Optional getSecret(String secretAddress) { } public Optional getDecryptedValue(String secretAddress) { - Optional oSecret = getSecret(secretAddress); - if (oSecret.isEmpty()) { - return Optional.empty(); - } - final String decryptedValue = encryptionService.decrypt(oSecret.get().getValue()); - return Optional.of(decryptedValue); + return getSecret(secretAddress) + .map(secret -> encryptionService.decrypt(secret.getValue())); } public boolean isSecretPresent(String secretAddress) { From 5759ec2812187cbfbd5be50ab5a874b01802e210 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Tue, 3 Jan 2023 14:40:30 +0100 Subject: [PATCH 251/293] Remove useless `isSecretPresent` variable --- src/main/java/com/iexec/sms/secret/web2/Web2SecretService.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/com/iexec/sms/secret/web2/Web2SecretService.java b/src/main/java/com/iexec/sms/secret/web2/Web2SecretService.java index 434dfae8..112f5268 100644 --- a/src/main/java/com/iexec/sms/secret/web2/Web2SecretService.java +++ b/src/main/java/com/iexec/sms/secret/web2/Web2SecretService.java @@ -71,8 +71,7 @@ public boolean isSecretPresent(String ownerAddress, String secretAddress) { * with same {@code ownerAddress}/{@code secretAddress} couple already exists */ public Web2Secret addSecret(String ownerAddress, String secretAddress, String secretValue) throws SecretAlreadyExistsException { - final boolean isSecretPresent = isSecretPresent(ownerAddress, secretAddress); - if (isSecretPresent) { + if (isSecretPresent(ownerAddress, secretAddress)) { log.error("Secret already exists [ownerAddress:{}, secretAddress:{}]", ownerAddress, secretAddress); throw new SecretAlreadyExistsException(ownerAddress, secretAddress); } From 719454665940ee0c9e19b289c5b082f5353610f7 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Tue, 3 Jan 2023 14:43:15 +0100 Subject: [PATCH 252/293] Remove useless `isSecretPresent` variable --- .../java/com/iexec/sms/secret/SecretController.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/iexec/sms/secret/SecretController.java b/src/main/java/com/iexec/sms/secret/SecretController.java index add66101..28347000 100644 --- a/src/main/java/com/iexec/sms/secret/SecretController.java +++ b/src/main/java/com/iexec/sms/secret/SecretController.java @@ -52,8 +52,9 @@ public SecretController(AuthorizationService authorizationService, @RequestMapping(path = "/web3", method = RequestMethod.HEAD) public ResponseEntity isWeb3SecretSet(@RequestParam String secretAddress) { - final boolean isSecretPresent = web3SecretService.isSecretPresent(secretAddress); - return isSecretPresent ? ResponseEntity.noContent().build() : ResponseEntity.notFound().build(); + return web3SecretService.isSecretPresent(secretAddress) + ? ResponseEntity.noContent().build() + : ResponseEntity.notFound().build(); } @PostMapping("/web3") @@ -83,8 +84,9 @@ public ResponseEntity addWeb3Secret(@RequestHeader String authorization, @RequestMapping(path = "/web2", method = RequestMethod.HEAD) public ResponseEntity isWeb2SecretSet(@RequestParam String ownerAddress, @RequestParam String secretName) { - final boolean isSecretPresent = web2SecretService.isSecretPresent(ownerAddress, secretName); - return isSecretPresent ? ResponseEntity.noContent().build() : ResponseEntity.notFound().build(); + return web2SecretService.isSecretPresent(ownerAddress, secretName) + ? ResponseEntity.noContent().build() + : ResponseEntity.notFound().build(); } @PostMapping("/web2") From a242e7d516799c006f5c809a30a3e318fcee901f Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Mon, 9 Jan 2023 15:02:00 +0100 Subject: [PATCH 253/293] Import Spring Boot dependencies --- iexec-sms-library/build.gradle | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/iexec-sms-library/build.gradle b/iexec-sms-library/build.gradle index 00f55e4d..0b9ca423 100644 --- a/iexec-sms-library/build.gradle +++ b/iexec-sms-library/build.gradle @@ -5,7 +5,13 @@ plugins { id 'maven-publish' } +ext { + springBootVersion = '2.6.14' +} + dependencies { + implementation platform("org.springframework.boot:spring-boot-dependencies:${springBootVersion}") + implementation "com.iexec.common:iexec-common:$iexecCommonVersion" testImplementation "org.assertj:assertj-core:3.22.0" testImplementation 'org.junit.jupiter:junit-jupiter:5.8.2' From 734e525f85cf3502ff1bb4c991a3bf58d3083ef9 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Mon, 9 Jan 2023 16:51:24 +0100 Subject: [PATCH 254/293] Remove Spring cloud dependencies --- build.gradle | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/build.gradle b/build.gradle index da76feff..d5c3dfd3 100644 --- a/build.gradle +++ b/build.gradle @@ -9,7 +9,7 @@ plugins { } ext { - springCloudVersion = '2021.0.5' +// springCloudVersion = '2021.0.5' openFeignVersion = '11.7' } @@ -51,12 +51,6 @@ configurations { integrationTestRuntimeOnly.extendsFrom runtimeOnly } -dependencyManagement { - imports { - mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}" - } -} - dependencies { // iexec implementation "com.iexec.common:iexec-common:$iexecCommonVersion" @@ -64,9 +58,7 @@ dependencies { // spring implementation 'org.springframework.boot:spring-boot-starter-web' - implementation 'org.springframework.cloud:spring-cloud-starter-openfeign' implementation 'org.springframework.retry:spring-retry' - implementation 'org.springframework.cloud:spring-cloud-starter-openfeign' implementation 'org.springframework.boot:spring-boot-starter-validation' // H2 implementation 'org.springframework.boot:spring-boot-starter-data-jpa' From 83a8f95fece6753b88342ad20ffdf114fa9965ce Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Mon, 9 Jan 2023 17:18:50 +0100 Subject: [PATCH 255/293] Remove explicit Junit version --- iexec-sms-library/build.gradle | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iexec-sms-library/build.gradle b/iexec-sms-library/build.gradle index 0b9ca423..882af307 100644 --- a/iexec-sms-library/build.gradle +++ b/iexec-sms-library/build.gradle @@ -13,9 +13,9 @@ dependencies { implementation platform("org.springframework.boot:spring-boot-dependencies:${springBootVersion}") implementation "com.iexec.common:iexec-common:$iexecCommonVersion" - testImplementation "org.assertj:assertj-core:3.22.0" - testImplementation 'org.junit.jupiter:junit-jupiter:5.8.2' - testImplementation 'org.mockito:mockito-junit-jupiter:4.7.0' + testImplementation "org.assertj:assertj-core" + testImplementation 'org.junit.jupiter:junit-jupiter' + testImplementation 'org.mockito:mockito-junit-jupiter' } java { From f31caf12d313806765cd5b2f3ff832790d75fcc5 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Tue, 10 Jan 2023 11:44:01 +0100 Subject: [PATCH 256/293] Rollback library dependency on Spring Boot --- iexec-sms-library/build.gradle | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/iexec-sms-library/build.gradle b/iexec-sms-library/build.gradle index 882af307..00f55e4d 100644 --- a/iexec-sms-library/build.gradle +++ b/iexec-sms-library/build.gradle @@ -5,17 +5,11 @@ plugins { id 'maven-publish' } -ext { - springBootVersion = '2.6.14' -} - dependencies { - implementation platform("org.springframework.boot:spring-boot-dependencies:${springBootVersion}") - implementation "com.iexec.common:iexec-common:$iexecCommonVersion" - testImplementation "org.assertj:assertj-core" - testImplementation 'org.junit.jupiter:junit-jupiter' - testImplementation 'org.mockito:mockito-junit-jupiter' + testImplementation "org.assertj:assertj-core:3.22.0" + testImplementation 'org.junit.jupiter:junit-jupiter:5.8.2' + testImplementation 'org.mockito:mockito-junit-jupiter:4.7.0' } java { From 53d189e309693f30b03c8b3ec68291450299f6d0 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Tue, 10 Jan 2023 11:45:50 +0100 Subject: [PATCH 257/293] Remove commented Spring Cloud version --- build.gradle | 1 - 1 file changed, 1 deletion(-) diff --git a/build.gradle b/build.gradle index d5c3dfd3..acc1cc6b 100644 --- a/build.gradle +++ b/build.gradle @@ -9,7 +9,6 @@ plugins { } ext { -// springCloudVersion = '2021.0.5' openFeignVersion = '11.7' } From 192d8ff4f3c4a487f4a9f7c2334f8cf0619e9a87 Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Tue, 10 Jan 2023 17:25:50 +0100 Subject: [PATCH 258/293] Remove fork option from sconify.args --- docker/sconify.args | 1 - 1 file changed, 1 deletion(-) diff --git a/docker/sconify.args b/docker/sconify.args index 37d6d374..a4a436f2 100644 --- a/docker/sconify.args +++ b/docker/sconify.args @@ -6,7 +6,6 @@ --binary=/usr/local/openjdk-11/bin/java \ --heap="8G" \ --stack="8M" \ ---fork="1" \ --binary-fs \ --fs-dir=/app \ --host-path=/etc/hosts \ From dc679507bde7ad9afdeb266e8e1e99eaa5e23abf Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Wed, 11 Jan 2023 16:44:21 +0100 Subject: [PATCH 259/293] Add banner.txt --- src/main/resources/banner.txt | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 src/main/resources/banner.txt diff --git a/src/main/resources/banner.txt b/src/main/resources/banner.txt new file mode 100644 index 00000000..9dd0c73d --- /dev/null +++ b/src/main/resources/banner.txt @@ -0,0 +1,7 @@ +${Ansi.YELLOW} _ _____ ______ +${Ansi.YELLOW} __/\__ (_) ____|_ _____ ___ \ \ \ \ +${Ansi.YELLOW} \ / | | _| \ \/ / _ \/ __| \ \ \ \ +${Ansi.YELLOW} /_ _\ | | |___ > < __/ (__ / / / / +${Ansi.YELLOW} \/ |_|_____/_/\_\___|\___| /_/_/_/ +${Ansi.YELLOW} ========= +${Ansi.YELLOW} :: Spring Boot${spring-boot.formatted-version} :: ${Ansi.DEFAULT} \ No newline at end of file From e3814223a1045cae0791e4bf8b85f05b9ae315e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20James=20Toussaint?= <33313130+jeremyjams@users.noreply.github.com> Date: Mon, 23 Jan 2023 15:46:09 +0100 Subject: [PATCH 260/293] Init changelog for next version --- CHANGELOG.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c7bd033e..8984042e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,22 @@ All notable changes to this project will be documented in this file. +## [[8.0.0]](https://github.com/iExecBlockchainComputing/iexec-sms/releases/tag/v8.0.0) 2023 + +* Add iExec banner at startup. +* Support SMS in enclave for Scone TEE tasks. +* Upgrade to Spring Boot 2.6.14. +* Refactor secret model. +* Upgrade to Gradle 7.6. +* Update web3 secret challenge. +* Remove TLS context on server. +* Remove `GET /secrets` endpoints. +* Support Gramine framework for TEE tasks. +* Add `GET /up` client method in iexec-sms-library. +* Remove non-TEE workflow. +* Return a same `SmsClient` from the `SmsClientProvider` of iexec-sms-library when calling a same SMS URL. +* Improve code quality. + ## [[7.3.0]](https://github.com/iExecBlockchainComputing/iexec-sms/releases/tag/v7.3.0) 2023-01-18 * Add endpoint to allow health checks. From dc2cc2729c3c0682e02562be0057a90776b512ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20James=20Toussaint?= <33313130+jeremyjams@users.noreply.github.com> Date: Mon, 23 Jan 2023 15:47:00 +0100 Subject: [PATCH 261/293] Update readme for next version --- README.md | 80 ++++++++++++------- .../java/com/iexec/sms/AppController.java | 1 + .../authorization/AuthorizationService.java | 1 + src/main/resources/application.yml | 2 +- 4 files changed, 53 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index d6dddc5b..ed3c822b 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,12 @@ ## Overview -The iExec Secret Management Service (SMS) stores user secrets and provisions them to authorized Trusted Execution Environment (TEE) applications running on the iExec network. +The _iExec Secret Management Service_ (SMS) stores user secrets and provisions them to authorized Trusted Execution Environment (TEE) applications running on the iExec network. + +Two TEE frameworks for TEE tasks can be supported on the iExec platform: + +- Scone +- Gramine ### Details @@ -16,29 +21,35 @@ The iExec Secret Management Service (SMS) stores user secrets and provisions the ## Configuration -The iExec Secret Management Service is available as an OCI image on [Docker Hub](https://hub.docker.com/r/iexechub/iexec-sms/tags). +The _iExec Secret Management Service_ is available as an OCI image on [Docker Hub](https://hub.docker.com/r/iexechub/iexec-sms/tags). -To run properly, the iExec Secret Management Service requires: +One _iExec Secret Management Service_ instance supports only one TEE framework kind of iExec TEE tasks. +To support both Scone and Gramine TEE tasks, two instances of _iExec SMS_ must be configured. + +To run properly, the _iExec Secret Management Service_ requires: * A blockchain node. iExec smart contracts must be deployed on the blockchain network. -* A Scontain Configuration and Attestation Service (CAS) to provision secrets to remote enclaves. -* Valid OCI images configurations for pre-compute and post-compute stages of TEE tasks executions. -* A valid OCI image configuration of a Scontain Local Attestation Service (LAS). +* Valid OCI images configurations for pre-compute and post-compute stages of TEE tasks executions. Exposed images depend on the type of TEE framework supported. +* A Secret Provisioner instance, in charge of provisioning secrets to remote enclaves. Each TEE framework requires its own type of Secret Provisioner. + * for Scone TEE tasks: + * a Scontain _Configuration and Attestation Service_ (CAS). + * a valid OCI image configuration of a Scontain Local Attestation Service (LAS). This service will be deployed by an iExec Worker to compute TEE tasks. + * for Gramine TEE tasks: + * an _iExec SPS_ instance. -The iExec SMS can be started locally for development purpose. +The _iExec Secret Management Service_ can be started locally for development purpose. It is not advised to use an instance with such configuration in production. -You can configure the SMS with the following properties: +To support: +* Scone TEE tasks, set `IEXEC_SMS_TEE_RUNTIME_FRAMEWORK=scone`, then configure the SMS with properties of all following tables. +* Gramine TEE tasks, set `IEXEC_SMS_TEE_RUNTIME_FRAMEWORK=gramine`, then configure the SMS with properties of following table. -| Environment variable | Description | Type | Default value | -| --- | --- | --- | --- | -| IEXEC_SMS_PORT | Server HTTPS port. | Positive integer | `15443` | -| IEXEC_SMS_HTTP_ENABLED | Whether to start an http context when starting the SMS. | Boolean | `true` | -| IEXEC_SMS_HTTP_PORT | Server HTTP port. | Positive integer | `13300` | -| IEXEC_SMS_SSL_KEYSTORE | Path to the key store that holds the SSL certificate. | String | `src/main/resources/ssl-keystore-dev.p12` | -| IEXEC_SMS_SSL_KEYSTORE_PASSWORD | Password used to access the key store. | String | `whatever` | -| IEXEC_SMS_SSL_KEYSTORE_TYPE | Type of the key store. | Positive integer | `PKCS12` | -| IEXEC_SMS_SSL_KEYSTORE_ALIAS | Alias that identifies the key in the key store. | String | `iexec-core` | +### Environment variables (Scone or Gramine TEE framework) + +| Environment variable | Description | Type | Default shared value | Default Scone value | Default Gramine value | +| --- | --- | --- | --- | --- | --- | +| IEXEC_SMS_PORT | Server HTTP port. | Positive integer | `13300` | +| `IEXEC_SMS_TEE_RUNTIME_FRAMEWORK` | Define which TEE framework this _iExec SMS_ supports. | `scone` or `gramine` | | | IEXEC_SMS_H2_URL | JDBC URL of the database. | URL | `jdbc:h2:file:/tmp/h2/sms-h2` | | IEXEC_SMS_H2_CONSOLE | Whether to enable the H2 console. | Boolean | `false` | | IEXEC_SMS_STORAGE_ENCRYPTION_AES_KEY_PATH | Path to the key created and used to encrypt secrets. | String | `src/main/resources/iexec-sms-aes.key` | @@ -48,23 +59,32 @@ You can configure the SMS with the following properties: | IEXEC_GAS_PRICE_MULTIPLIER | Transactions will be sent with `networkGasPrice * IEXEC_GAS_PRICE_MULTIPLIER`. | Float | `1.0` | | IEXEC_GAS_PRICE_CAP | In Wei, will be used for transactions if `networkGasPrice * IEXEC_GAS_PRICE_MULTIPLIER > IEXEC_GAS_PRICE_CAP`. | Integer | `22000000000` | | IEXEC_IS_SIDECHAIN | Define if iExec on-chain protocol is built on top of token (`false`) or native currency (`true`). | Boolean | `false` | -| IEXEC_SCONE_CAS_HOST | CAS service host. | String | `localhost` | -| IEXEC_SCONE_CAS_PORT | Server port of the CAS client API (session management). | Positive integer | `8081` | -| IEXEC_SCONE_CAS_PUBLIC_HOST | Server port of the CAS enclave API (remote attestation). Typically used by workers to execute TEE tasks. | Positive integer | `localhost` | -| IEXEC_SCONE_CAS_ENCLAVE_PORT | Scontain CAS service enclave port, used from worker host to attest applications running within enclaves. | Positive integer | `18765` | -| IEXEC_PALAEMON_TEMPLATE | Path to the template file used to generate configurations of TEE enclave sessions. | String | `src/main/resources/palaemonTemplate.vm` | -| IEXEC_SCONE_TOLERATED_INSECURE_OPTIONS | List of hardware or software Scone vulnerabilities to ignore. | String | | -| IEXEC_IGNORED_SGX_ADVISORIES | List of hardware or software Intel vulnerabilities to ignore. | String | | -| IEXEC_SMS_IMAGE_LAS_IMAGE | Scontain LAS OCI image to be used by workers to execute TEE tasks. LAS performs local attestation which creates a quote that CAS can verify. | String | | +| IEXEC_SMS_DISPLAY_DEBUG_SESSION | Whether to display TEE enclaves sessions configuration in SMS logs. | Boolean | `false` | +| `IEXEC_SECRET_PROVISIONER_WEB_HOSTNAME` | Secret provisioner server host for session management. Used to post sessions of secrets. | String | `localhost` | +| `IEXEC_SECRET_PROVISIONER_WEB_PORT` | Secret provisioner server port for session management. | Positive integer | | `8081` | `8080` | +| `IEXEC_SECRET_PROVISIONER_ENCLAVE_HOSTNAME` | Secret provisioner server host for retrieving secrets from attested enclaves. Typically used by workers to execute TEE tasks. | Positive integer | `localhost` | +| `IEXEC_SECRET_PROVISIONER_ENCLAVE_PORT`| Secret provisioner server port for retrieving secrets from attested enclaves. | Positive integer | | `18765` | `4433` | | IEXEC_TEE_WORKER_PRE_COMPUTE_IMAGE | TEE enabled OCI image name for worker pre-compute stage of TEE tasks. | String | | | IEXEC_TEE_WORKER_PRE_COMPUTE_FINGERPRINT | Fingerprint (aka mrenclave) of the TEE enabled worker pre-compute image. | String | | -| IEXEC_TEE_WORKER_PRE_COMPUTE_HEAP_SIZE_GB | Required heap size for a worker pre-compute enclave (in Giga Bytes). | Positive integer | `4` | -| IEXEC_TEE_WORKER_PRE_COMPUTE_ENTRYPOINT | Command executed when starting a container from the TEE enabled worker pre-compute image. | String | `java -jar /app/app.jar` | +| IEXEC_TEE_WORKER_PRE_COMPUTE_HEAP_SIZE_GB | Required heap size for a worker pre-compute enclave (in Giga Bytes). | Positive integer | `3` | +| IEXEC_TEE_WORKER_PRE_COMPUTE_ENTRYPOINT | Command executed when starting a container from the TEE enabled worker pre-compute image. | String | | `java -jar /app/app.jar` | `/bin/bash /apploader.sh` | | IEXEC_TEE_WORKER_POST_COMPUTE_IMAGE | TEE enabled OCI image name for worker post-compute stage of TEE tasks. | String | | | IEXEC_TEE_WORKER_POST_COMPUTE_FINGERPRINT | Fingerprint (aka mrenclave) of the TEE enabled worker post-compute image. | String | | -| IEXEC_TEE_WORKER_POST_COMPUTE_HEAP_SIZE_GB | Required heap size for a worker post-compute enclave (in Giga Bytes). | Positive integer | `4` | -| IEXEC_TEE_WORKER_POST_COMPUTE_ENTRYPOINT | Command executed when starting a container from the TEE enabled worker post-compute image. | String | `java -jar /app/app.jar` | -| IEXEC_SMS_DISPLAY_DEBUG_SESSION | Whether to display TEE enclaves sessions configuration in SMS logs. | Boolean | `false` | +| IEXEC_TEE_WORKER_POST_COMPUTE_HEAP_SIZE_GB | Required heap size for a worker post-compute enclave (in Giga Bytes). | Positive integer | `3` | +| IEXEC_TEE_WORKER_POST_COMPUTE_ENTRYPOINT | Command executed when starting a container from the TEE enabled worker post-compute image. | String | | `java -jar /app/app.jar` | `/bin/bash /apploader.sh` | + +### Scone specific environment variables (Scone framework only) +Only set following properties if `IEXEC_SMS_TEE_RUNTIME_FRAMEWORK=scone` is set. +| Environment variable | Description | Type | Default value | +| --- | --- | --- | --- | +| IEXEC_SMS_SSL_KEYSTORE | Path to the key store that holds the SSL certificate. | String | `src/main/resources/ssl-keystore-dev.p12` | +| IEXEC_SMS_SSL_KEYSTORE_PASSWORD | Password used to access the key store. | String | `whatever` | +| IEXEC_SMS_SSL_KEYSTORE_TYPE | Type of the key store. | Positive integer | `PKCS12` | +| IEXEC_SMS_SSL_KEYSTORE_ALIAS | Alias that identifies the key in the key store. | String | `iexec-core` | +| IEXEC_SCONE_TOLERATED_INSECURE_OPTIONS | List of hardware or software Scone vulnerabilities to ignore. | String | | +| IEXEC_IGNORED_SGX_ADVISORIES | List of hardware or software Intel vulnerabilities to ignore. | String | | +| IEXEC_SMS_IMAGE_LAS_IMAGE | Scontain LAS OCI image to be used by workers to execute TEE tasks. LAS performs local attestation which creates a quote that CAS can verify. | String | | + ## Health checks diff --git a/src/main/java/com/iexec/sms/AppController.java b/src/main/java/com/iexec/sms/AppController.java index ba2b2583..a6735a53 100644 --- a/src/main/java/com/iexec/sms/AppController.java +++ b/src/main/java/com/iexec/sms/AppController.java @@ -26,6 +26,7 @@ @RestController public class AppController { + //TODO: Remove this endpoint, use actuator endpoints instead. Update client too. @GetMapping(value = "/up") public ResponseEntity isUp() { String message = String.format("Up! (%s)", new Date()); diff --git a/src/main/java/com/iexec/sms/authorization/AuthorizationService.java b/src/main/java/com/iexec/sms/authorization/AuthorizationService.java index a31edad6..17687382 100644 --- a/src/main/java/com/iexec/sms/authorization/AuthorizationService.java +++ b/src/main/java/com/iexec/sms/authorization/AuthorizationService.java @@ -112,6 +112,7 @@ public boolean isSignedByOwner(String message, String signature, String address) return !owner.isEmpty() && isSignedByHimself(message, signature, owner); } + //TODO: Remove getChallengeForGetSecret methods public String getChallengeForGetWeb3Secret(String secretAddress) { return HashUtils.concatenateAndHash( Hash.sha3(DOMAIN), diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 8a9e3dc0..63c00e9c 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,5 +1,5 @@ server: - port: ${IEXEC_SMS_PORT:13300} # TODO document variable name modification for release + port: ${IEXEC_SMS_PORT:13300} # Not sure it's a good idea but here is a link for an embedded mongodb # https://www.baeldung.com/spring-boot-embedded-mongodb From 5a5d198daa61f234b664707188aa176469205086 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20James=20Toussaint?= <33313130+jeremyjams@users.noreply.github.com> Date: Mon, 23 Jan 2023 16:00:49 +0100 Subject: [PATCH 262/293] Add missing code blocs formatting on env vars --- README.md | 77 +++++++++++++++++++++++++++---------------------------- 1 file changed, 38 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index ed3c822b..1fd49c99 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,8 @@ The _iExec Secret Management Service_ (SMS) stores user secrets and provisions t Two TEE frameworks for TEE tasks can be supported on the iExec platform: -- Scone -- Gramine +* Scone +* Gramine ### Details @@ -46,44 +46,43 @@ To support: ### Environment variables (Scone or Gramine TEE framework) -| Environment variable | Description | Type | Default shared value | Default Scone value | Default Gramine value | -| --- | --- | --- | --- | --- | --- | -| IEXEC_SMS_PORT | Server HTTP port. | Positive integer | `13300` | -| `IEXEC_SMS_TEE_RUNTIME_FRAMEWORK` | Define which TEE framework this _iExec SMS_ supports. | `scone` or `gramine` | | -| IEXEC_SMS_H2_URL | JDBC URL of the database. | URL | `jdbc:h2:file:/tmp/h2/sms-h2` | -| IEXEC_SMS_H2_CONSOLE | Whether to enable the H2 console. | Boolean | `false` | -| IEXEC_SMS_STORAGE_ENCRYPTION_AES_KEY_PATH | Path to the key created and used to encrypt secrets. | String | `src/main/resources/iexec-sms-aes.key` | -| IEXEC_CHAIN_ID | Chain ID of the blockchain network to connect. | Positive integer | `17` | -| IEXEC_SMS_BLOCKCHAIN_NODE_ADDRESS | URL to connect to the blockchain node. | URL | `http://localhost:8545` | -| IEXEC_HUB_ADDRESS | Proxy contract address to interact with the iExec on-chain protocol. | String | `0xBF6B2B07e47326B7c8bfCb4A5460bef9f0Fd2002` | -| IEXEC_GAS_PRICE_MULTIPLIER | Transactions will be sent with `networkGasPrice * IEXEC_GAS_PRICE_MULTIPLIER`. | Float | `1.0` | -| IEXEC_GAS_PRICE_CAP | In Wei, will be used for transactions if `networkGasPrice * IEXEC_GAS_PRICE_MULTIPLIER > IEXEC_GAS_PRICE_CAP`. | Integer | `22000000000` | -| IEXEC_IS_SIDECHAIN | Define if iExec on-chain protocol is built on top of token (`false`) or native currency (`true`). | Boolean | `false` | -| IEXEC_SMS_DISPLAY_DEBUG_SESSION | Whether to display TEE enclaves sessions configuration in SMS logs. | Boolean | `false` | -| `IEXEC_SECRET_PROVISIONER_WEB_HOSTNAME` | Secret provisioner server host for session management. Used to post sessions of secrets. | String | `localhost` | -| `IEXEC_SECRET_PROVISIONER_WEB_PORT` | Secret provisioner server port for session management. | Positive integer | | `8081` | `8080` | -| `IEXEC_SECRET_PROVISIONER_ENCLAVE_HOSTNAME` | Secret provisioner server host for retrieving secrets from attested enclaves. Typically used by workers to execute TEE tasks. | Positive integer | `localhost` | -| `IEXEC_SECRET_PROVISIONER_ENCLAVE_PORT`| Secret provisioner server port for retrieving secrets from attested enclaves. | Positive integer | | `18765` | `4433` | -| IEXEC_TEE_WORKER_PRE_COMPUTE_IMAGE | TEE enabled OCI image name for worker pre-compute stage of TEE tasks. | String | | -| IEXEC_TEE_WORKER_PRE_COMPUTE_FINGERPRINT | Fingerprint (aka mrenclave) of the TEE enabled worker pre-compute image. | String | | -| IEXEC_TEE_WORKER_PRE_COMPUTE_HEAP_SIZE_GB | Required heap size for a worker pre-compute enclave (in Giga Bytes). | Positive integer | `3` | -| IEXEC_TEE_WORKER_PRE_COMPUTE_ENTRYPOINT | Command executed when starting a container from the TEE enabled worker pre-compute image. | String | | `java -jar /app/app.jar` | `/bin/bash /apploader.sh` | -| IEXEC_TEE_WORKER_POST_COMPUTE_IMAGE | TEE enabled OCI image name for worker post-compute stage of TEE tasks. | String | | -| IEXEC_TEE_WORKER_POST_COMPUTE_FINGERPRINT | Fingerprint (aka mrenclave) of the TEE enabled worker post-compute image. | String | | -| IEXEC_TEE_WORKER_POST_COMPUTE_HEAP_SIZE_GB | Required heap size for a worker post-compute enclave (in Giga Bytes). | Positive integer | `3` | -| IEXEC_TEE_WORKER_POST_COMPUTE_ENTRYPOINT | Command executed when starting a container from the TEE enabled worker post-compute image. | String | | `java -jar /app/app.jar` | `/bin/bash /apploader.sh` | - -### Scone specific environment variables (Scone framework only) -Only set following properties if `IEXEC_SMS_TEE_RUNTIME_FRAMEWORK=scone` is set. -| Environment variable | Description | Type | Default value | +| Environment variable | Description | Type | Default Scone value | Default Gramine value | +| --- | --- | --- | --- | --- | +| `IEXEC_SMS_TEE_RUNTIME_FRAMEWORK` | Define which TEE framework this _iExec SMS_ supports. | `scone` or `gramine` | | | +| `IEXEC_SMS_PORT` | Server HTTP port. | Positive integer | `13300` | `13300` | +| `IEXEC_SMS_H2_URL` | JDBC URL of the database. | URL | `jdbc:h2:file:/tmp/h2/sms-h2` | `jdbc:h2:file:/tmp/h2/sms-h2` | +| `IEXEC_SMS_H2_CONSOLE` | Whether to enable the H2 console. | Boolean | `false` | `false` | +| `IEXEC_SMS_STORAGE_ENCRYPTION_AES_KEY_PATH` | Path to the key created and used to encrypt secrets. | String | `src/main/resources/iexec-sms-aes.key` | `src/main/resources/iexec-sms-aes.key` | +| `IEXEC_CHAIN_ID` | Chain ID of the blockchain network to connect. | Positive integer | `17` | `17` | +| `IEXEC_SMS_BLOCKCHAIN_NODE_ADDRESS` | URL to connect to the blockchain node. | URL | `http://localhost:8545` | `http://localhost:8545` | +| `IEXEC_HUB_ADDRESS` | Proxy contract address to interact with the iExec on-chain protocol. | String | `0xBF6B2B07e47326B7c8bfCb4A5460bef9f0Fd2002` | `0xBF6B2B07e47326B7c8bfCb4A5460bef9f0Fd2002` | +| `IEXEC_GAS_PRICE_MULTIPLIER` | Transactions will be sent with `networkGasPrice * IEXEC_GAS_PRICE_MULTIPLIER`. | Float | `1.0` | `1.0` | +| `IEXEC_GAS_PRICE_CAP` | In Wei, will be used for transactions if `networkGasPrice * IEXEC_GAS_PRICE_MULTIPLIER > IEXEC_GAS_PRICE_CAP`. | Integer | `22000000000` | `22000000000` | +| `IEXEC_IS_SIDECHAIN` | Define if iExec on-chain protocol is built on top of token (`false`) or native currency (`true`). | Boolean | `false` | `false` | +| `IEXEC_SMS_DISPLAY_DEBUG_SESSION` | Whether to display TEE enclaves sessions configuration in SMS logs. | Boolean | `false` | `false` | +| `IEXEC_SECRET_PROVISIONER_WEB_HOSTNAME` | Secret provisioner server host for session management. Used to post sessions of secrets. | String | `localhost` | `localhost` | +| `IEXEC_SECRET_PROVISIONER_WEB_PORT` | Secret provisioner server port for session management. | Positive integer | `8081` | `8080` | +| `IEXEC_SECRET_PROVISIONER_ENCLAVE_HOSTNAME` | Secret provisioner server host for retrieving secrets from attested enclaves. Typically used by workers to execute TEE tasks. | Positive integer | `localhost` | `localhost` | +| `IEXEC_SECRET_PROVISIONER_ENCLAVE_PORT`| Secret provisioner server port for retrieving secrets from attested enclaves. | Positive integer | `18765` | `4433` | +| `IEXEC_TEE_WORKER_PRE_COMPUTE_IMAGE` | TEE enabled OCI image name for worker pre-compute stage of TEE tasks. | String | | | +| `IEXEC_TEE_WORKER_PRE_COMPUTE_FINGERPRINT` | Fingerprint (aka mrenclave) of the TEE enabled worker pre-compute image. | String | | | +| `IEXEC_TEE_WORKER_PRE_COMPUTE_HEAP_SIZE_GB` | Required heap size for a worker pre-compute enclave (in Giga Bytes). | Positive integer | `3` | `3` | +| `IEXEC_TEE_WORKER_PRE_COMPUTE_ENTRYPOINT` | Command executed when starting a container from the TEE enabled worker pre-compute image. | String | `java -jar /app/app.jar` | `/bin/bash /apploader.sh` | +| `IEXEC_TEE_WORKER_POST_COMPUTE_IMAGE` | TEE enabled OCI image name for worker post-compute stage of TEE tasks. | String | | | +| `IEXEC_TEE_WORKER_POST_COMPUTE_FINGERPRINT` | Fingerprint (aka mrenclave) of the TEE enabled worker post-compute image. | String | | | +| `IEXEC_TEE_WORKER_POST_COMPUTE_HEAP_SIZE_GB` | Required heap size for a worker post-compute enclave (in Giga Bytes). | Positive integer | `3` | `3` | +| `IEXEC_TEE_WORKER_POST_COMPUTE_ENTRYPOINT` | Command executed when starting a container from the TEE enabled worker post-compute image. | String | `java -jar /app/app.jar` | `/bin/bash /apploader.sh` | + +### Scone specific environment variables +| Environment variable | Description | Type | Default Scone value | | --- | --- | --- | --- | -| IEXEC_SMS_SSL_KEYSTORE | Path to the key store that holds the SSL certificate. | String | `src/main/resources/ssl-keystore-dev.p12` | -| IEXEC_SMS_SSL_KEYSTORE_PASSWORD | Password used to access the key store. | String | `whatever` | -| IEXEC_SMS_SSL_KEYSTORE_TYPE | Type of the key store. | Positive integer | `PKCS12` | -| IEXEC_SMS_SSL_KEYSTORE_ALIAS | Alias that identifies the key in the key store. | String | `iexec-core` | -| IEXEC_SCONE_TOLERATED_INSECURE_OPTIONS | List of hardware or software Scone vulnerabilities to ignore. | String | | -| IEXEC_IGNORED_SGX_ADVISORIES | List of hardware or software Intel vulnerabilities to ignore. | String | | -| IEXEC_SMS_IMAGE_LAS_IMAGE | Scontain LAS OCI image to be used by workers to execute TEE tasks. LAS performs local attestation which creates a quote that CAS can verify. | String | | +| `IEXEC_SMS_SSL_KEYSTORE` | Path to the key store that holds the SSL certificate. | String | `src/main/resources/ssl-keystore-dev.p12` | +| `IEXEC_SMS_SSL_KEYSTORE_PASSWORD` | Password used to access the key store. | String | `whatever` | +| `IEXEC_SMS_SSL_KEYSTORE_TYPE` | Type of the key store. | Positive integer | `PKCS12` | +| `IEXEC_SMS_SSL_KEYSTORE_ALIAS` | Alias that identifies the key in the key store. | String | `iexec-core` | +| `IEXEC_SCONE_TOLERATED_INSECURE_OPTIONS` | List of hardware or software Scone vulnerabilities to ignore. | String | | +| `IEXEC_IGNORED_SGX_ADVISORIES` | List of hardware or software Intel vulnerabilities to ignore. | String | | +| `IEXEC_SMS_IMAGE_LAS_IMAGE` | Scontain LAS OCI image to be used by workers to execute TEE tasks. LAS performs local attestation which creates a quote that CAS can verify. | String | | ## Health checks From 1ff013985e1681feb5f092e6d3ffd5003719ac65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20James=20Toussaint?= <33313130+jeremyjams@users.noreply.github.com> Date: Mon, 23 Jan 2023 16:14:40 +0100 Subject: [PATCH 263/293] Reword default value in tables --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 1fd49c99..39a7cd45 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ To support: ### Environment variables (Scone or Gramine TEE framework) -| Environment variable | Description | Type | Default Scone value | Default Gramine value | +| Environment variable | Description | Type | Default Scone-configuration value | Default Gramine-configuration value | | --- | --- | --- | --- | --- | | `IEXEC_SMS_TEE_RUNTIME_FRAMEWORK` | Define which TEE framework this _iExec SMS_ supports. | `scone` or `gramine` | | | | `IEXEC_SMS_PORT` | Server HTTP port. | Positive integer | `13300` | `13300` | @@ -74,7 +74,8 @@ To support: | `IEXEC_TEE_WORKER_POST_COMPUTE_ENTRYPOINT` | Command executed when starting a container from the TEE enabled worker post-compute image. | String | `java -jar /app/app.jar` | `/bin/bash /apploader.sh` | ### Scone specific environment variables -| Environment variable | Description | Type | Default Scone value | + +| Environment variable | Description | Type | Default Scone-configuration value | | --- | --- | --- | --- | | `IEXEC_SMS_SSL_KEYSTORE` | Path to the key store that holds the SSL certificate. | String | `src/main/resources/ssl-keystore-dev.p12` | | `IEXEC_SMS_SSL_KEYSTORE_PASSWORD` | Password used to access the key store. | String | `whatever` | @@ -84,9 +85,8 @@ To support: | `IEXEC_IGNORED_SGX_ADVISORIES` | List of hardware or software Intel vulnerabilities to ignore. | String | | | `IEXEC_SMS_IMAGE_LAS_IMAGE` | Scontain LAS OCI image to be used by workers to execute TEE tasks. LAS performs local attestation which creates a quote that CAS can verify. | String | | - ## Health checks -A health endpoint (`/actuator/health`) is enabled by default and can be accessed on the **IEXEC_SMS_HTTP_PORT**. +A health endpoint (`/actuator/health`) is enabled by default and can be accessed on the `IEXEC_SMS_HTTP_PORT`. This endpoint allows to define health checks in an orchestrator or a [compose file](https://github.com/compose-spec/compose-spec/blob/master/spec.md#healthcheck). No default strategy has been implemented in the [Dockerfile](Dockerfile) at the moment. From 445570bb91a1423a6e8aeecfee014c5af0fb173a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20James=20Toussaint?= <33313130+jeremyjams@users.noreply.github.com> Date: Mon, 23 Jan 2023 17:17:46 +0100 Subject: [PATCH 264/293] Move shared env vars at the top of scone yml --- src/main/resources/application-scone.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/resources/application-scone.yml b/src/main/resources/application-scone.yml index 2226a3cf..eec7fc96 100644 --- a/src/main/resources/application-scone.yml +++ b/src/main/resources/application-scone.yml @@ -7,13 +7,6 @@ tee: hostname: ${IEXEC_SECRET_PROVISIONER_ENCLAVE_HOSTNAME:localhost} port: ${IEXEC_SECRET_PROVISIONER_ENCLAVE_PORT:18765} - ssl: - key-store: ${IEXEC_SMS_SSL_KEYSTORE:/app/ssl-keystore-dev.p12} #iexec-core dev certificate for dev - key-store-password: ${IEXEC_SMS_SSL_KEYSTORE_PASSWORD:whatever} - key-store-type: ${IEXEC_SMS_SSL_KEYSTORE_TYPE:PKCS12} - key-alias: ${IEXEC_SMS_SSL_KEYSTORE_ALIAS:iexec-core} - client-auth: need - worker: pre-compute: image: ${IEXEC_TEE_WORKER_PRE_COMPUTE_IMAGE:} # e.g.: docker.io/iexechub/tee-worker-pre-compute:x.y.z-production @@ -26,6 +19,13 @@ tee: heap-size-gb: ${IEXEC_TEE_WORKER_POST_COMPUTE_HEAP_SIZE_GB:3} entrypoint: ${IEXEC_TEE_WORKER_POST_COMPUTE_ENTRYPOINT:java -jar /app/app.jar} + ssl: + key-store: ${IEXEC_SMS_SSL_KEYSTORE:/app/ssl-keystore-dev.p12} #iexec-core dev certificate for dev + key-store-password: ${IEXEC_SMS_SSL_KEYSTORE_PASSWORD:whatever} + key-store-type: ${IEXEC_SMS_SSL_KEYSTORE_TYPE:PKCS12} + key-alias: ${IEXEC_SMS_SSL_KEYSTORE_ALIAS:iexec-core} + client-auth: need + scone: las-image: ${IEXEC_SMS_IMAGE_LAS_IMAGE:} # e.g.: registry.scontain.com:5050/scone-production/iexec-las:x.y.z attestation: From d448e79ff9a82b9aaeaebe37760fc74d3aee028f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20James=20Toussaint?= <33313130+jeremyjams@users.noreply.github.com> Date: Tue, 24 Jan 2023 11:33:43 +0100 Subject: [PATCH 265/293] Update README.md single wording Co-authored-by: Maxence Cornaton <87655102+mcornaton@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 39a7cd45..de2bb0c8 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ Two TEE frameworks for TEE tasks can be supported on the iExec platform: The _iExec Secret Management Service_ is available as an OCI image on [Docker Hub](https://hub.docker.com/r/iexechub/iexec-sms/tags). -One _iExec Secret Management Service_ instance supports only one TEE framework kind of iExec TEE tasks. +A single _iExec Secret Management Service_ instance supports a single TEE framework. To support both Scone and Gramine TEE tasks, two instances of _iExec SMS_ must be configured. To run properly, the _iExec Secret Management Service_ requires: From 257ff3666fcfb52b6d589baac3407a99d800544e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20James=20Toussaint?= <33313130+jeremyjams@users.noreply.github.com> Date: Tue, 24 Jan 2023 12:07:30 +0100 Subject: [PATCH 266/293] Init structure in changelog for next version --- CHANGELOG.md | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8984042e..fc5664af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,19 +4,23 @@ All notable changes to this project will be documented in this file. ## [[8.0.0]](https://github.com/iExecBlockchainComputing/iexec-sms/releases/tag/v8.0.0) 2023 -* Add iExec banner at startup. +### New Features * Support SMS in enclave for Scone TEE tasks. -* Upgrade to Spring Boot 2.6.14. -* Refactor secret model. -* Upgrade to Gradle 7.6. +* Support Gramine framework for TEE tasks. +* Add `GET /up` client method in iexec-sms-library. +* Return a same `SmsClient` from the `SmsClientProvider` of iexec-sms-library when calling a same SMS URL. +* Add iExec banner at startup. +### Bug Fixes * Update web3 secret challenge. * Remove TLS context on server. * Remove `GET /secrets` endpoints. -* Support Gramine framework for TEE tasks. -* Add `GET /up` client method in iexec-sms-library. * Remove non-TEE workflow. -* Return a same `SmsClient` from the `SmsClientProvider` of iexec-sms-library when calling a same SMS URL. +### Quality +* Refactor secret model. * Improve code quality. +### Dependency Upgrades +* Upgrade to Spring Boot 2.6.14. +* Upgrade to Gradle 7.6. ## [[7.3.0]](https://github.com/iExecBlockchainComputing/iexec-sms/releases/tag/v7.3.0) 2023-01-18 From 118dec27cbc74c0cb4efa0cc762fc6b5ca0c9b50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20James=20Toussaint?= <33313130+jeremyjams@users.noreply.github.com> Date: Tue, 24 Jan 2023 15:47:41 +0100 Subject: [PATCH 267/293] Update README.md IEXEC_SMS_PORT Co-authored-by: Jeremy Bernard --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index de2bb0c8..20ebee73 100644 --- a/README.md +++ b/README.md @@ -87,6 +87,6 @@ To support: ## Health checks -A health endpoint (`/actuator/health`) is enabled by default and can be accessed on the `IEXEC_SMS_HTTP_PORT`. +A health endpoint (`/actuator/health`) is enabled by default and can be accessed on the `IEXEC_SMS_PORT`. This endpoint allows to define health checks in an orchestrator or a [compose file](https://github.com/compose-spec/compose-spec/blob/master/spec.md#healthcheck). No default strategy has been implemented in the [Dockerfile](Dockerfile) at the moment. From c96fd1d6b70055a3dc1e098d08a11eb79b746cca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20James=20Toussaint?= <33313130+jeremyjams@users.noreply.github.com> Date: Tue, 24 Jan 2023 15:48:19 +0100 Subject: [PATCH 268/293] Update README.md wording Co-authored-by: Jeremy Bernard --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 20ebee73..84f43da5 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ The _iExec Secret Management Service_ (SMS) stores user secrets and provisions them to authorized Trusted Execution Environment (TEE) applications running on the iExec network. -Two TEE frameworks for TEE tasks can be supported on the iExec platform: +Two TEE frameworks for TEE tasks are supported on the iExec platform: * Scone * Gramine From a53cf39815a8c98a3e13191d7b191971db12c312 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20James=20Toussaint?= <33313130+jeremyjams@users.noreply.github.com> Date: Tue, 24 Jan 2023 15:48:34 +0100 Subject: [PATCH 269/293] Update README.md format on CAS Co-authored-by: Jeremy Bernard --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 84f43da5..ca0afef8 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ To run properly, the _iExec Secret Management Service_ requires: * A Secret Provisioner instance, in charge of provisioning secrets to remote enclaves. Each TEE framework requires its own type of Secret Provisioner. * for Scone TEE tasks: * a Scontain _Configuration and Attestation Service_ (CAS). - * a valid OCI image configuration of a Scontain Local Attestation Service (LAS). + * a valid OCI image configuration of a Scontain _Local Attestation Service_ (LAS). This service will be deployed by an iExec Worker to compute TEE tasks. * for Gramine TEE tasks: * an _iExec SPS_ instance. From 5695d3a7f666769e16ad41be7c9e109e333f6d47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20James=20Toussaint?= <33313130+jeremyjams@users.noreply.github.com> Date: Tue, 24 Jan 2023 15:52:04 +0100 Subject: [PATCH 270/293] Update readme LAS description format --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index ca0afef8..d314562e 100644 --- a/README.md +++ b/README.md @@ -32,8 +32,7 @@ To run properly, the _iExec Secret Management Service_ requires: * A Secret Provisioner instance, in charge of provisioning secrets to remote enclaves. Each TEE framework requires its own type of Secret Provisioner. * for Scone TEE tasks: * a Scontain _Configuration and Attestation Service_ (CAS). - * a valid OCI image configuration of a Scontain _Local Attestation Service_ (LAS). - This service will be deployed by an iExec Worker to compute TEE tasks. + * a valid OCI image configuration of a Scontain _Local Attestation Service_ (LAS). This service will be deployed by an iExec Worker to compute TEE tasks. * for Gramine TEE tasks: * an _iExec SPS_ instance. From 7742d36215b80c08b70506ee13c2f8589aaba848 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20James=20Toussaint?= <33313130+jeremyjams@users.noreply.github.com> Date: Wed, 25 Jan 2023 10:59:50 +0100 Subject: [PATCH 271/293] Add OkHttp upgrade in changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fc5664af..fbeb1a1a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ All notable changes to this project will be documented in this file. ### Dependency Upgrades * Upgrade to Spring Boot 2.6.14. * Upgrade to Gradle 7.6. +* Upgrade OkHttp to 4.9.0. ## [[7.3.0]](https://github.com/iExecBlockchainComputing/iexec-sms/releases/tag/v7.3.0) 2023-01-18 From 31db9d00a74c9bd5eb1a82d8bf4a19b54aceac11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20James=20Toussaint?= <33313130+jeremyjams@users.noreply.github.com> Date: Wed, 25 Jan 2023 15:50:22 +0100 Subject: [PATCH 272/293] Update readme with full iExec SPS wording --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d314562e..772fcba5 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ To run properly, the _iExec Secret Management Service_ requires: * a Scontain _Configuration and Attestation Service_ (CAS). * a valid OCI image configuration of a Scontain _Local Attestation Service_ (LAS). This service will be deployed by an iExec Worker to compute TEE tasks. * for Gramine TEE tasks: - * an _iExec SPS_ instance. + * an _iExec Secret Provisioner Service_ (_iExec SPS_) instance. The _iExec Secret Management Service_ can be started locally for development purpose. It is not advised to use an instance with such configuration in production. From 1cccacaffa3a144ead7537ef233f19efb4eb62cb Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Tue, 7 Feb 2023 18:10:02 +0100 Subject: [PATCH 273/293] Remove getChallengeForGetWeb2Secret and getChallengeForGetWeb3Secret --- .../authorization/AuthorizationService.java | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/src/main/java/com/iexec/sms/authorization/AuthorizationService.java b/src/main/java/com/iexec/sms/authorization/AuthorizationService.java index 17687382..b3e96c17 100644 --- a/src/main/java/com/iexec/sms/authorization/AuthorizationService.java +++ b/src/main/java/com/iexec/sms/authorization/AuthorizationService.java @@ -112,26 +112,6 @@ public boolean isSignedByOwner(String message, String signature, String address) return !owner.isEmpty() && isSignedByHimself(message, signature, owner); } - //TODO: Remove getChallengeForGetSecret methods - public String getChallengeForGetWeb3Secret(String secretAddress) { - return HashUtils.concatenateAndHash( - Hash.sha3(DOMAIN), - secretAddress); - } - - /* - * Note - These are equals: - * BytesUtils.bytesToString(Hash.sha3(DOMAIN.getBytes()) - * Hash.sha3String(DOMAIN) - * */ - public String getChallengeForGetWeb2Secret(String ownerAddress, - String secretKey) { - return HashUtils.concatenateAndHash( - Hash.sha3String(DOMAIN), - ownerAddress, - Hash.sha3String(secretKey)); - } - public String getChallengeForSetWeb3Secret(String secretAddress, String secretValue) { return HashUtils.concatenateAndHash( From 4634b0ae7731a7a02168d331cde28764df598529 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20James=20Toussaint?= Date: Mon, 20 Feb 2023 14:58:24 +0100 Subject: [PATCH 274/293] Do not use command for Gramine --- .../sms/tee/session/gramine/GramineSessionMakerService.java | 5 +++-- .../tee/session/gramine/GramineSessionMakerServiceTests.java | 1 - src/test/resources/gramine-tee-session.json | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerService.java b/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerService.java index e4d8ec87..9a3f745a 100644 --- a/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerService.java +++ b/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerService.java @@ -58,10 +58,11 @@ public GramineSession generateSession(TeeSessionRequest request) throws TeeSessi GramineSessionBuilder gramineSession = GramineSession.builder() .session(request.getSessionId()); GramineEnclave gramineAppEnclave = toGramineEnclave(baseSession.getAppCompute()); - gramineAppEnclave.setCommand(request.getTaskDescription().getAppCommand()); GramineEnclave graminePostEnclave = toGramineEnclave(baseSession.getPostCompute()); - graminePostEnclave.setCommand(teeServicesConfig.getPostComputeProperties().getEntrypoint()); + //TODO: Validate command-line arguments from the host (https://github.com/gramineproject/gsc/issues/13) + gramineAppEnclave.setCommand(""); + graminePostEnclave.setCommand(""); // TODO: Remove useless volumes when SPS is ready gramineAppEnclave.setVolumes(List.of()); graminePostEnclave.setVolumes(List.of()); diff --git a/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerServiceTests.java b/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerServiceTests.java index a035c2e1..9fedc989 100644 --- a/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerServiceTests.java +++ b/src/test/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerServiceTests.java @@ -47,7 +47,6 @@ void beforeEach() { void shouldGetSessionJson() throws Exception { TeeEnclaveConfiguration enclaveConfig = TeeEnclaveConfiguration.builder() .fingerprint(APP_FINGERPRINT) - .entrypoint("/apploader.sh") .build(); TeeSessionRequest request = createSessionRequest(createTaskDescription(enclaveConfig)); diff --git a/src/test/resources/gramine-tee-session.json b/src/test/resources/gramine-tee-session.json index 6c48f62a..2e89e314 100644 --- a/src/test/resources/gramine-tee-session.json +++ b/src/test/resources/gramine-tee-session.json @@ -4,7 +4,7 @@ { "name": "app", "mrenclave": "01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b", - "command": "/apploader.sh args", + "command": "", "environment": { "IEXEC_TASK_ID": "taskId", "IEXEC_IN": "/iexec_in", @@ -27,7 +27,7 @@ { "name": "post-compute", "mrenclave": "mrEnclave3", - "command": "entrypoint3", + "command": "", "environment": { "RESULT_TASK_ID": "taskId", "RESULT_ENCRYPTION": "yes", From bb5f097a281535d81a1189c030a78e3410321113 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20James=20Toussaint?= Date: Mon, 20 Feb 2023 14:58:47 +0100 Subject: [PATCH 275/293] Use named version property for common --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index f4261e28..7cc1f39e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ version=7.3.0 -iexecCommonVersion=6.2.1-NEXT-SNAPSHOT +iexecCommonVersion=6.2.1-rm-useless-gramine-validation-NEXT-SNAPSHOT nexusUser nexusPassword From b44dee9e662b1c2da5d35d04325e42b952aa7de3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20James=20Toussaint?= Date: Mon, 20 Feb 2023 16:21:21 +0100 Subject: [PATCH 276/293] Remove unused member --- .../tee/session/gramine/GramineSessionMakerService.java | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerService.java b/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerService.java index 9a3f745a..86de236e 100644 --- a/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerService.java +++ b/src/main/java/com/iexec/sms/tee/session/gramine/GramineSessionMakerService.java @@ -17,7 +17,6 @@ package com.iexec.sms.tee.session.gramine; import com.iexec.common.tee.TeeFramework; -import com.iexec.sms.api.config.TeeServicesProperties; import com.iexec.sms.tee.ConditionalOnTeeFramework; import com.iexec.sms.tee.session.base.SecretEnclaveBase; import com.iexec.sms.tee.session.base.SecretSessionBase; @@ -37,12 +36,9 @@ public class GramineSessionMakerService { private final SecretSessionBaseService secretSessionBaseService; - private final TeeServicesProperties teeServicesConfig; - public GramineSessionMakerService(SecretSessionBaseService secretSessionBaseService, - TeeServicesProperties teeServicesConfig) { + public GramineSessionMakerService(SecretSessionBaseService secretSessionBaseService) { this.secretSessionBaseService = secretSessionBaseService; - this.teeServicesConfig = teeServicesConfig; } /** @@ -60,7 +56,8 @@ public GramineSession generateSession(TeeSessionRequest request) throws TeeSessi GramineEnclave gramineAppEnclave = toGramineEnclave(baseSession.getAppCompute()); GramineEnclave graminePostEnclave = toGramineEnclave(baseSession.getPostCompute()); - //TODO: Validate command-line arguments from the host (https://github.com/gramineproject/gsc/issues/13) + // TODO: Validate command-line arguments from the host + // (https://github.com/gramineproject/gsc/issues/13) gramineAppEnclave.setCommand(""); graminePostEnclave.setCommand(""); // TODO: Remove useless volumes when SPS is ready From 3356a7978cba1977a9d536831cbf0e630e6c5fec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20James=20Toussaint?= Date: Tue, 21 Feb 2023 10:14:11 +0100 Subject: [PATCH 277/293] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fbeb1a1a..f83327e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ All notable changes to this project will be documented in this file. * Remove TLS context on server. * Remove `GET /secrets` endpoints. * Remove non-TEE workflow. +* Remove enclave entrypoints from Gramine sessions since already present in manifests of applications. ### Quality * Refactor secret model. * Improve code quality. From 7c24cd6420e4e30d987b281901f6119440ee9ac8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20James=20Toussaint?= <33313130+jeremyjams@users.noreply.github.com> Date: Wed, 22 Feb 2023 10:18:38 +0100 Subject: [PATCH 278/293] Update gradle.properties --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 7cc1f39e..f4261e28 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ version=7.3.0 -iexecCommonVersion=6.2.1-rm-useless-gramine-validation-NEXT-SNAPSHOT +iexecCommonVersion=6.2.1-NEXT-SNAPSHOT nexusUser nexusPassword From ad77272af4f38d4cac86b9da43cc427f0399a202 Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Thu, 23 Feb 2023 14:25:33 +0100 Subject: [PATCH 279/293] Show application version on banner --- build.gradle | 9 ++++++++- src/main/resources/banner.txt | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 10ad7a44..da654a1f 100644 --- a/build.gradle +++ b/build.gradle @@ -117,6 +117,13 @@ springBoot { buildInfo() } +tasks.named("bootJar") { + manifest { + attributes("Implementation-Title": "iExec Secret Management Service", + "Implementation-Version": project.version) + } +} + test { useJUnitPlatform() } @@ -145,7 +152,7 @@ tasks.sonarqube.dependsOn tasks.jacocoTestReport publishing { publications { maven(MavenPublication) { - artifact bootJar + artifact tasks.named("bootJar") from components.java } } diff --git a/src/main/resources/banner.txt b/src/main/resources/banner.txt index 9dd0c73d..a9242aa6 100644 --- a/src/main/resources/banner.txt +++ b/src/main/resources/banner.txt @@ -4,4 +4,4 @@ ${Ansi.YELLOW} \ / | | _| \ \/ / _ \/ __| \ \ \ \ ${Ansi.YELLOW} /_ _\ | | |___ > < __/ (__ / / / / ${Ansi.YELLOW} \/ |_|_____/_/\_\___|\___| /_/_/_/ ${Ansi.YELLOW} ========= -${Ansi.YELLOW} :: Spring Boot${spring-boot.formatted-version} :: ${Ansi.DEFAULT} \ No newline at end of file +${Ansi.YELLOW} :: ${application.title}${application.formatted-version} build with Spring Boot${spring-boot.formatted-version} :: ${Ansi.DEFAULT} \ No newline at end of file From ad101aa743688c94211f231dfad1cf8380c874a5 Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Fri, 24 Feb 2023 16:48:43 +0100 Subject: [PATCH 280/293] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f83327e0..f268088b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ All notable changes to this project will be documented in this file. * Add `GET /up` client method in iexec-sms-library. * Return a same `SmsClient` from the `SmsClientProvider` of iexec-sms-library when calling a same SMS URL. * Add iExec banner at startup. +* Show application version on banner. ### Bug Fixes * Update web3 secret challenge. * Remove TLS context on server. From 336e752bd9933aef669978901ee026454b59ac0f Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Mon, 27 Feb 2023 09:37:21 +0100 Subject: [PATCH 281/293] Fix error in banner.txt --- src/main/resources/banner.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/banner.txt b/src/main/resources/banner.txt index a9242aa6..2bb249c3 100644 --- a/src/main/resources/banner.txt +++ b/src/main/resources/banner.txt @@ -4,4 +4,4 @@ ${Ansi.YELLOW} \ / | | _| \ \/ / _ \/ __| \ \ \ \ ${Ansi.YELLOW} /_ _\ | | |___ > < __/ (__ / / / / ${Ansi.YELLOW} \/ |_|_____/_/\_\___|\___| /_/_/_/ ${Ansi.YELLOW} ========= -${Ansi.YELLOW} :: ${application.title}${application.formatted-version} build with Spring Boot${spring-boot.formatted-version} :: ${Ansi.DEFAULT} \ No newline at end of file +${Ansi.YELLOW} :: ${application.title}${application.formatted-version} built with Spring Boot${spring-boot.formatted-version} :: ${Ansi.DEFAULT} \ No newline at end of file From 09b49176bdb052a518c04a1bdd2c6c9c0ed02d3f Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Mon, 27 Feb 2023 16:04:42 +0100 Subject: [PATCH 282/293] Use `openjdk:11.0.16-jre-slim` as base image --- Dockerfile | 2 +- docker/sconify.args | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index ce7edc57..f9326f87 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM openjdk:11.0.15-jre-slim +FROM openjdk:11.0.65-jre-slim ARG jar diff --git a/docker/sconify.args b/docker/sconify.args index a4a436f2..f978d033 100644 --- a/docker/sconify.args +++ b/docker/sconify.args @@ -1,6 +1,6 @@ --verbose \ --name=iexec-sms \ ---base=openjdk:11.0.15-jre-slim \ +--base=openjdk:11.0.16-jre-slim \ --from=${IMG_FROM} \ --to=${IMG_TO} \ --binary=/usr/local/openjdk-11/bin/java \ From 3f5f61ec4ce6dbeb62460df158ac78484a93f0f0 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Mon, 27 Feb 2023 16:08:22 +0100 Subject: [PATCH 283/293] Fix typo on base image name --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index f9326f87..ce868e59 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM openjdk:11.0.65-jre-slim +FROM openjdk:11.0.16-jre-slim ARG jar From 410d1d51f28bb04ef0cf487b64e5f5fba5d74fa0 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Tue, 28 Feb 2023 10:05:15 +0100 Subject: [PATCH 284/293] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f268088b..ca1d0456 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ All notable changes to this project will be documented in this file. * Upgrade to Spring Boot 2.6.14. * Upgrade to Gradle 7.6. * Upgrade OkHttp to 4.9.0. +* Upgrade to Java 11.0.16 patch. ## [[7.3.0]](https://github.com/iExecBlockchainComputing/iexec-sms/releases/tag/v7.3.0) 2023-01-18 From c8f370a6568ecdbd1ecfddb9796a36345d8ff164 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20James=20Toussaint?= <33313130+jeremyjams@users.noreply.github.com> Date: Thu, 2 Mar 2023 15:56:25 +0100 Subject: [PATCH 285/293] Upgrade to iexec-common@7.0.0 --- CHANGELOG.md | 1 + gradle.properties | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ca1d0456..435419de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ All notable changes to this project will be documented in this file. * Upgrade to Gradle 7.6. * Upgrade OkHttp to 4.9.0. * Upgrade to Java 11.0.16 patch. +* Upgrade to `iexec-common` 7.0.0. ## [[7.3.0]](https://github.com/iExecBlockchainComputing/iexec-sms/releases/tag/v7.3.0) 2023-01-18 diff --git a/gradle.properties b/gradle.properties index f4261e28..983cd484 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ version=7.3.0 -iexecCommonVersion=6.2.1-NEXT-SNAPSHOT +iexecCommonVersion=7.0.0 nexusUser nexusPassword From 45b55d2ff51610588ac7315ae6639f3a92ad400d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20James=20Toussaint?= <33313130+jeremyjams@users.noreply.github.com> Date: Fri, 3 Mar 2023 11:06:05 +0100 Subject: [PATCH 286/293] Upgrade to jenkins-library 2.4.0 --- CHANGELOG.md | 1 + Jenkinsfile | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 435419de..842a7bb8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ All notable changes to this project will be documented in this file. * Upgrade OkHttp to 4.9.0. * Upgrade to Java 11.0.16 patch. * Upgrade to `iexec-common` 7.0.0. +* Upgrade to `jenkins-library` 2.4.0. ## [[7.3.0]](https://github.com/iExecBlockchainComputing/iexec-sms/releases/tag/v7.3.0) 2023-01-18 diff --git a/Jenkinsfile b/Jenkinsfile index b4d2f93e..9c5216ad 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,4 +1,4 @@ -@Library('global-jenkins-library@2.2.3') _ +@Library('global-jenkins-library@2.4.0') _ String repositoryName = 'iexec-sms' From 8ec3d0de734ef1a521c5a7321b8ff7f85b687fcb Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Fri, 3 Mar 2023 12:45:22 +0100 Subject: [PATCH 287/293] Enable health checks on SMS in enclave --- CHANGELOG.md | 1 + docker/sconify.args | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 435419de..c18a88b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ All notable changes to this project will be documented in this file. * Remove `GET /secrets` endpoints. * Remove non-TEE workflow. * Remove enclave entrypoints from Gramine sessions since already present in manifests of applications. +* Update Scone transformation parameters to enable health checks in SMS in enclave. ### Quality * Refactor secret model. * Improve code quality. diff --git a/docker/sconify.args b/docker/sconify.args index f978d033..a5e40f5d 100644 --- a/docker/sconify.args +++ b/docker/sconify.args @@ -1,6 +1,6 @@ --verbose \ --name=iexec-sms \ ---base=openjdk:11.0.16-jre-slim \ +--base=${IMG_FROM} \ --from=${IMG_FROM} \ --to=${IMG_TO} \ --binary=/usr/local/openjdk-11/bin/java \ From 86c43856a81875d0950259928ccc25f381d21615 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20James=20Toussaint?= <33313130+jeremyjams@users.noreply.github.com> Date: Fri, 3 Mar 2023 15:35:32 +0100 Subject: [PATCH 288/293] Bump version to 8.0.0 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 983cd484..e15dd102 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -version=7.3.0 +version=8.0.0 iexecCommonVersion=7.0.0 nexusUser From 5be7f64d69055c84d7867dff380d521ca6384913 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20James=20Toussaint?= <33313130+jeremyjams@users.noreply.github.com> Date: Fri, 3 Mar 2023 15:35:57 +0100 Subject: [PATCH 289/293] Update changelog --- CHANGELOG.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cdc427f8..f93aa55d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ All notable changes to this project will be documented in this file. -## [[8.0.0]](https://github.com/iExecBlockchainComputing/iexec-sms/releases/tag/v8.0.0) 2023 +## [[8.0.0]](https://github.com/iExecBlockchainComputing/iexec-sms/releases/tag/v8.0.0) 2023-03-03 ### New Features * Support SMS in enclave for Scone TEE tasks. @@ -12,7 +12,6 @@ All notable changes to this project will be documented in this file. * Add iExec banner at startup. * Show application version on banner. ### Bug Fixes -* Update web3 secret challenge. * Remove TLS context on server. * Remove `GET /secrets` endpoints. * Remove non-TEE workflow. From b997d099f48a54759f874588d74a6d8548fb2cb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20James=20Toussaint?= <33313130+jeremyjams@users.noreply.github.com> Date: Fri, 3 Mar 2023 17:12:41 +0100 Subject: [PATCH 290/293] Add rc0 to version --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index e15dd102..3d8631d4 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -version=8.0.0 +version=8.0.0-rc0 iexecCommonVersion=7.0.0 nexusUser From 8f594ed308027067dd9a6d1c244d5ca3d540f916 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20James=20Toussaint?= <33313130+jeremyjams@users.noreply.github.com> Date: Fri, 3 Mar 2023 17:35:33 +0100 Subject: [PATCH 291/293] Bump version to rc1 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 3d8631d4..0af48340 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -version=8.0.0-rc0 +version=8.0.0-rc1 iexecCommonVersion=7.0.0 nexusUser From 084347c7c71443f8bf7c73bae8c88bca86f4b1a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20James=20Toussaint?= <33313130+jeremyjams@users.noreply.github.com> Date: Fri, 3 Mar 2023 18:07:14 +0100 Subject: [PATCH 292/293] Bump version to rc2 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 0af48340..8358a457 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -version=8.0.0-rc1 +version=8.0.0-rc2 iexecCommonVersion=7.0.0 nexusUser From dd90eb98627ed08d13143524cd1f273081dd63c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20James=20Toussaint?= <33313130+jeremyjams@users.noreply.github.com> Date: Mon, 6 Mar 2023 11:37:46 +0100 Subject: [PATCH 293/293] Set version to 8.0.0 --- CHANGELOG.md | 2 +- gradle.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f93aa55d..5ae8b638 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ All notable changes to this project will be documented in this file. -## [[8.0.0]](https://github.com/iExecBlockchainComputing/iexec-sms/releases/tag/v8.0.0) 2023-03-03 +## [[8.0.0]](https://github.com/iExecBlockchainComputing/iexec-sms/releases/tag/v8.0.0) 2023-03-06 ### New Features * Support SMS in enclave for Scone TEE tasks. diff --git a/gradle.properties b/gradle.properties index 8358a457..e15dd102 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -version=8.0.0-rc2 +version=8.0.0 iexecCommonVersion=7.0.0 nexusUser