From 894fb6de3d98209337d82be2609be3c154c091d5 Mon Sep 17 00:00:00 2001 From: Maxence Cornaton Date: Thu, 29 Feb 2024 11:03:43 +0100 Subject: [PATCH 1/5] Backmerge 8.5.0 --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c1ab2cfe..74f5111e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ All notable changes to this project will be documented in this file. +## [[NEXT]](https://github.com/iExecBlockchainComputing/iexec-sms/releases/tag/vNEXT) 2024 + ## [[8.5.0]](https://github.com/iExecBlockchainComputing/iexec-sms/releases/tag/v8.5.0) 2024-02-29 ### New Features From fb980940858b4f1df4979392c29735cc52c04c11 Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Thu, 14 Mar 2024 17:46:25 +0100 Subject: [PATCH 2/5] Use only two SQL statements to read `TeeTaskComputeSecret` and `Web2Secret` during TEE session creation (#254) --- CHANGELOG.md | 4 + .../compute/TeeTaskComputeSecretService.java | 8 + .../sms/secret/web2/Web2SecretHeader.java | 2 +- .../sms/secret/web2/Web2SecretService.java | 8 + .../base/SecretSessionBaseService.java | 177 ++++++++++------- .../sms/tee/session/TeeSessionTestUtils.java | 39 ---- .../base/SecretSessionBaseServiceTests.java | 186 ++++++++++-------- 7 files changed, 237 insertions(+), 187 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 74f5111e..b1fad53a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. ## [[NEXT]](https://github.com/iExecBlockchainComputing/iexec-sms/releases/tag/vNEXT) 2024 +### Quality + +- Use only two SQL statements to read `TeeTaskComputeSecret` and `Web2Secret` during TEE session creation. (#254) + ## [[8.5.0]](https://github.com/iExecBlockchainComputing/iexec-sms/releases/tag/v8.5.0) 2024-02-29 ### New Features 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 cf4b4d3c..a97915da 100644 --- a/src/main/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretService.java +++ b/src/main/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretService.java @@ -26,7 +26,9 @@ import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Service; +import java.util.List; import java.util.Optional; +import java.util.stream.Collectors; @Slf4j @Service @@ -77,6 +79,12 @@ public Optional getSecret( return Optional.of(decryptedSecret); } + public List getSecretsForTeeSession(Iterable ids) { + return teeTaskComputeSecretRepository.findAllById(ids).stream() + .map(secret -> secret.withValue(encryptionService.decrypt(secret.getValue()))) + .collect(Collectors.toList()); + } + /** * Check whether a secret exists. * 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 58c52ab0..f8ae6ea7 100644 --- a/src/main/java/com/iexec/sms/secret/web2/Web2SecretHeader.java +++ b/src/main/java/com/iexec/sms/secret/web2/Web2SecretHeader.java @@ -34,7 +34,7 @@ public class Web2SecretHeader implements Serializable { private String ownerAddress; private String address; //0xdataset1, aws.amazon.com, beneficiary.key.iex.ec (Kb) - Web2SecretHeader(String ownerAddress, String address) { + public 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."); 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 db91084d..731f092b 100644 --- a/src/main/java/com/iexec/sms/secret/web2/Web2SecretService.java +++ b/src/main/java/com/iexec/sms/secret/web2/Web2SecretService.java @@ -26,8 +26,10 @@ import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Service; +import java.util.List; import java.util.Objects; import java.util.Optional; +import java.util.stream.Collectors; @Slf4j @Service @@ -68,6 +70,12 @@ public Optional getDecryptedValue(String ownerAddress, String secretAddr .map(secret -> encryptionService.decrypt(secret.getValue())); } + public List getSecretsForTeeSession(Iterable ids) { + return web2SecretRepository.findAllById(ids).stream() + .map(secret -> secret.withValue(encryptionService.decrypt(secret.getValue()))) + .collect(Collectors.toList()); + } + public boolean isSecretPresent(String ownerAddress, String secretAddress) { final Web2SecretHeader key = new Web2SecretHeader(ownerAddress, secretAddress); final Boolean found = cacheSecretService.lookSecretExistenceInCache(key); 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 229de397..5ec3fd54 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,10 +21,9 @@ import com.iexec.commons.poco.task.TaskDescription; import com.iexec.commons.poco.tee.TeeEnclaveConfiguration; import com.iexec.sms.api.config.TeeServicesProperties; -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.Web2Secret; +import com.iexec.sms.secret.web2.Web2SecretHeader; import com.iexec.sms.secret.web2.Web2SecretService; import com.iexec.sms.secret.web3.Web3SecretService; import com.iexec.sms.tee.challenge.EthereumCredentials; @@ -220,54 +219,64 @@ public SecretEnclaveBase getAppTokens(TeeSessionRequest request) 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); - if (!StringUtils.isEmpty(appDeveloperSecret)) { - tokens.put("IEXEC_APP_DEVELOPER_SECRET", appDeveloperSecret); - tokens.put(IexecEnvUtils.IEXEC_APP_DEVELOPER_SECRET_PREFIX + secretIndex, appDeveloperSecret); + final List ids = getAppComputeSecretsHeaders(taskDescription); + log.debug("TeeTaskComputeSecret looking for secrets [chainTaskId:{}, count:{}]", + taskDescription.getChainTaskId(), ids.size()); + final List secrets = teeTaskComputeSecretService.getSecretsForTeeSession(ids); + log.debug("TeeTaskComputeSecret objects fetched from database [chainTaskId:{}, count:{}]", + taskDescription.getChainTaskId(), secrets.size()); + for (TeeTaskComputeSecret secret : secrets) { + if (!StringUtils.isEmpty(secret.getHeader().getOnChainObjectAddress())) { + tokens.put("IEXEC_APP_DEVELOPER_SECRET", secret.getValue()); + tokens.put(IexecEnvUtils.IEXEC_APP_DEVELOPER_SECRET_PREFIX + "1", secret.getValue()); + } else { + final String secretKey = secret.getHeader().getKey(); + taskDescription.getSecrets().forEach((key, value) -> { + if (value.equals(secretKey)) { + tokens.put(IexecEnvUtils.IEXEC_REQUESTER_SECRET_PREFIX + key, secret.getValue()); + } + }); } } + return tokens; + } - if (taskDescription.getSecrets() == null || taskDescription.getRequester() == null) { - return tokens; + private List getAppComputeSecretsHeaders(TaskDescription taskDescription) { + final List ids = new ArrayList<>(); + final String applicationAddress = taskDescription.getAppAddress(); + if (applicationAddress != null) { + final String secretIndex = "1"; + ids.add(new TeeTaskComputeSecretHeader( + OnChainObjectType.APPLICATION, + applicationAddress.toLowerCase(), + SecretOwnerRole.APPLICATION_DEVELOPER, + "", + secretIndex)); } - 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); + if (taskDescription.getSecrets() != null && taskDescription.getRequester() != null) { + 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; } - } catch (NumberFormatException e) { - log.warn("Invalid entry found in deal parameters secrets map", e); - continue; + ids.add(new TeeTaskComputeSecretHeader( + OnChainObjectType.APPLICATION, + "", + SecretOwnerRole.REQUESTER, + taskDescription.getRequester().toLowerCase(), + secretEntry.getValue())); } - 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.putAll(requesterSecrets); - return tokens; + return ids; } /** @@ -287,12 +296,46 @@ public SecretEnclaveBase getPostComputeTokens(TeeSessionRequest request) if (taskDescription == null) { throw new TeeSessionGenerationException(NO_TASK_DESCRIPTION, "Task description must not be null"); } + + final List ids = getPostComputeSecretHeaders(taskDescription, request.getWorkerAddress()); + log.debug("Web2Secret looking for secrets [chainTaskId:{}, count:{}]", + taskDescription.getChainTaskId(), ids.size()); + final List secrets = web2SecretService.getSecretsForTeeSession(ids); + log.debug("Web2Secret objects fetched from database [chainTaskId:{}, count:{}]", + taskDescription.getChainTaskId(), secrets.size()); // encryption - Map encryptionTokens = getPostComputeEncryptionTokens(request); - tokens.putAll(encryptionTokens); + final String resultEncryptionSecret = secrets.stream() + .filter(secret -> IEXEC_RESULT_ENCRYPTION_PUBLIC_KEY.equals(secret.getHeader().getAddress())) + .findFirst() + .map(Web2Secret::getValue) + .orElse(""); + tokens.putAll(getPostComputeEncryptionTokens(request, resultEncryptionSecret)); // storage - Map storageTokens = getPostComputeStorageTokens(request); - tokens.putAll(storageTokens); + if (taskDescription.containsCallback()) { + tokens.putAll(getPostComputeStorageTokens(request, "")); + } else if (DROPBOX_RESULT_STORAGE_PROVIDER.equals(taskDescription.getResultStorageProvider())) { + final String storageToken = secrets.stream() + .filter(secret -> IEXEC_RESULT_DROPBOX_TOKEN.equals(secret.getHeader().getAddress())) + .findFirst() + .map(Web2Secret::getValue) + .orElse(""); + tokens.putAll(getPostComputeStorageTokens(request, storageToken)); + } else { + // TODO remove fallback on requester token when legacy Result Proxy endpoints have been removed + final boolean isWorkerTokenPresent = secrets.stream() + .anyMatch(secret -> IEXEC_RESULT_IEXEC_IPFS_TOKEN.equals(secret.getHeader().getAddress()) + && request.getWorkerAddress().equalsIgnoreCase(secret.getHeader().getOwnerAddress())); + final String tokenOwner = isWorkerTokenPresent ? request.getWorkerAddress() : taskDescription.getRequester(); + final String storageToken = secrets.stream() + .filter(secret -> IEXEC_RESULT_IEXEC_IPFS_TOKEN.equals(secret.getHeader().getAddress()) && + tokenOwner.equalsIgnoreCase(secret.getHeader().getOwnerAddress())) + .findFirst() + .map(Web2Secret::getValue) + .orElse(""); + log.debug("storage token [isWorkerTokenPresent:{}, tokenOwner:{}]", + isWorkerTokenPresent, tokenOwner); + tokens.putAll(getPostComputeStorageTokens(request, storageToken)); + } // enclave signature Map signTokens = getPostComputeSignTokens(request); tokens.putAll(signTokens); @@ -301,7 +344,21 @@ public SecretEnclaveBase getPostComputeTokens(TeeSessionRequest request) .build(); } - public Map getPostComputeEncryptionTokens(TeeSessionRequest request) + List getPostComputeSecretHeaders(TaskDescription taskDescription, String workerAddress) { + final List ids = new ArrayList<>(); + if (taskDescription.isResultEncryption()) { + ids.add(new Web2SecretHeader(taskDescription.getBeneficiary(), IEXEC_RESULT_ENCRYPTION_PUBLIC_KEY)); + } + if (DROPBOX_RESULT_STORAGE_PROVIDER.equals(taskDescription.getResultStorageProvider())) { + ids.add(new Web2SecretHeader(taskDescription.getRequester(), IEXEC_RESULT_DROPBOX_TOKEN)); + } else { + ids.add(new Web2SecretHeader(taskDescription.getRequester(), IEXEC_RESULT_IEXEC_IPFS_TOKEN)); + ids.add(new Web2SecretHeader(workerAddress, IEXEC_RESULT_IEXEC_IPFS_TOKEN)); + } + return ids; + } + + public Map getPostComputeEncryptionTokens(TeeSessionRequest request, String resultEncryptionKey) throws TeeSessionGenerationException { TaskDescription taskDescription = request.getTaskDescription(); String taskId = taskDescription.getChainTaskId(); @@ -313,16 +370,12 @@ public Map getPostComputeEncryptionTokens(TeeSessionRequest requ if (!shouldEncrypt) { return tokens; } - Optional beneficiaryResultEncryptionKeySecret = web2SecretService.getDecryptedValue( - taskDescription.getBeneficiary(), - IEXEC_RESULT_ENCRYPTION_PUBLIC_KEY); - if (beneficiaryResultEncryptionKeySecret.isEmpty()) { + if (StringUtils.isEmpty(resultEncryptionKey)) { throw new TeeSessionGenerationException( POST_COMPUTE_GET_ENCRYPTION_TOKENS_FAILED_EMPTY_BENEFICIARY_KEY, "Empty beneficiary encryption key - taskId: " + taskId); } - String publicKeyValue = beneficiaryResultEncryptionKeySecret.get(); - tokens.put(RESULT_ENCRYPTION_PUBLIC_KEY, publicKeyValue); // base64 encoded by client + tokens.put(RESULT_ENCRYPTION_PUBLIC_KEY, resultEncryptionKey); // base64 encoded by client return tokens; } @@ -330,7 +383,7 @@ public Map getPostComputeEncryptionTokens(TeeSessionRequest requ // to the beneficiary private storage space waiting for // that feature we only allow to push to the requester // private storage space - public Map getPostComputeStorageTokens(TeeSessionRequest request) + public Map getPostComputeStorageTokens(TeeSessionRequest request, String storageToken) throws TeeSessionGenerationException { TaskDescription taskDescription = request.getTaskDescription(); String taskId = taskDescription.getChainTaskId(); @@ -345,23 +398,13 @@ public Map getPostComputeStorageTokens(TeeSessionRequest request } String storageProvider = taskDescription.getResultStorageProvider(); String storageProxy = taskDescription.getResultStorageProxy(); - final Optional storageTokenSecret; - if (DROPBOX_RESULT_STORAGE_PROVIDER.equals(storageProvider)) { - storageTokenSecret = web2SecretService.getDecryptedValue(taskDescription.getRequester(), IEXEC_RESULT_DROPBOX_TOKEN); - } else { - // TODO remove fallback on requester token when legacy Result Proxy endpoints have been removed - final boolean isWorkerTokenPresent = web2SecretService.isSecretPresent(request.getWorkerAddress(), IEXEC_RESULT_IEXEC_IPFS_TOKEN); - final String tokenOwner = isWorkerTokenPresent ? request.getWorkerAddress() : taskDescription.getRequester(); - storageTokenSecret = web2SecretService.getDecryptedValue(tokenOwner, IEXEC_RESULT_IEXEC_IPFS_TOKEN); - } - if (storageTokenSecret.isEmpty()) { + if (StringUtils.isEmpty(storageToken)) { 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); } - final String storageToken = storageTokenSecret.get(); tokens.put(RESULT_STORAGE_PROVIDER, storageProvider); tokens.put(RESULT_STORAGE_PROXY, storageProxy); tokens.put(RESULT_STORAGE_TOKEN, storageToken); 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 7cc621e9..d38c653a 100644 --- a/src/test/java/com/iexec/sms/tee/session/TeeSessionTestUtils.java +++ b/src/test/java/com/iexec/sms/tee/session/TeeSessionTestUtils.java @@ -16,25 +16,19 @@ package com.iexec.sms.tee.session; -import com.iexec.common.precompute.PreComputeUtils; -import com.iexec.common.utils.IexecEnvUtils; import com.iexec.commons.poco.task.TaskDescription; import com.iexec.commons.poco.tee.TeeEnclaveConfiguration; 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.base.SecretSessionBaseService; import com.iexec.sms.tee.session.generic.TeeSessionRequest; 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.base.SecretSessionBaseService.*; import static org.assertj.core.api.Assertions.assertThat; @Slf4j @@ -139,39 +133,6 @@ public static TaskDescription.TaskDescriptionBuilder createTaskDescription(TeeEn .botIndex(0); } - 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, - 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)); - } - - 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 || 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 b0cee8bb..bc09bbb0 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 @@ -24,10 +24,10 @@ 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.compute.OnChainObjectType; -import com.iexec.sms.secret.compute.SecretOwnerRole; import com.iexec.sms.secret.compute.TeeTaskComputeSecret; +import com.iexec.sms.secret.compute.TeeTaskComputeSecretHeader; 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.EthereumCredentials; @@ -41,9 +41,7 @@ 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.*; import java.security.GeneralSecurityException; import java.util.HashMap; @@ -55,8 +53,6 @@ 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.*; class SecretSessionBaseServiceTests { @@ -94,6 +90,9 @@ class SecretSessionBaseServiceTests { @InjectMocks private SecretSessionBaseService teeSecretsService; + @Captor + private ArgumentCaptor> teeTaskComputeSecretIds; + @BeforeEach void beforeEach() { MockitoAnnotations.openMocks(this); @@ -112,12 +111,11 @@ void shouldGetSecretsTokens() throws Exception { when(web3SecretService.getDecryptedValue(DATASET_ADDRESS)) .thenReturn(Optional.of(DATASET_KEY)); // post - when(web2SecretService.getDecryptedValue(beneficiary, IEXEC_RESULT_ENCRYPTION_PUBLIC_KEY)) - .thenReturn(Optional.of(ENCRYPTION_PUBLIC_KEY)); - when(web2SecretService.isSecretPresent(WORKER_ADDRESS, IEXEC_RESULT_IEXEC_IPFS_TOKEN)) - .thenReturn(true); - when(web2SecretService.getDecryptedValue(WORKER_ADDRESS, IEXEC_RESULT_IEXEC_IPFS_TOKEN)) - .thenReturn(Optional.of(STORAGE_TOKEN)); + final Web2Secret resultEncryption = new Web2Secret(beneficiary, IEXEC_RESULT_ENCRYPTION_PUBLIC_KEY, ENCRYPTION_PUBLIC_KEY); + final Web2Secret requesterStorageToken = new Web2Secret(taskDescription.getRequester(), IEXEC_RESULT_IEXEC_IPFS_TOKEN, STORAGE_TOKEN); + final Web2Secret workerStorageToken = new Web2Secret(WORKER_ADDRESS, IEXEC_RESULT_IEXEC_IPFS_TOKEN, STORAGE_TOKEN); + when(web2SecretService.getSecretsForTeeSession(List.of(resultEncryption.getHeader(), requesterStorageToken.getHeader(), workerStorageToken.getHeader()))) + .thenReturn(List.of(resultEncryption, requesterStorageToken, workerStorageToken)); TeeChallenge challenge = TeeChallenge.builder() .credentials(EthereumCredentials.generate()) .build(); @@ -230,9 +228,11 @@ void shouldGetAppTokensForAdvancedTaskDescription() throws TeeSessionGenerationE 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); + final TeeTaskComputeSecret applicationSecret = getApplicationDeveloperSecret(appAddress); + final TeeTaskComputeSecret requesterSecret1 = getRequesterSecret(requesterAddress, REQUESTER_SECRET_KEY_1, REQUESTER_SECRET_VALUE_1); + final TeeTaskComputeSecret requesterSecret2 = getRequesterSecret(requesterAddress, REQUESTER_SECRET_KEY_2, REQUESTER_SECRET_VALUE_2); + when(teeTaskComputeSecretService.getSecretsForTeeSession(teeTaskComputeSecretIds.capture())) + .thenReturn(List.of(applicationSecret, requesterSecret1, requesterSecret2)); SecretEnclaveBase enclaveBase = teeSecretsService.getAppTokens(request); assertThat(enclaveBase.getName()).isEqualTo("app"); @@ -254,14 +254,11 @@ void shouldGetAppTokensForAdvancedTaskDescription() throws TeeSessionGenerationE 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); + assertThat(enclaveBase.getEnvironment()).containsExactlyInAnyOrderEntriesOf(expectedTokens); + assertThat(teeTaskComputeSecretIds.getValue()).containsExactlyInAnyOrder( + applicationSecret.getHeader(), requesterSecret1.getHeader(), requesterSecret2.getHeader()); + verify(teeTaskComputeSecretService).getSecretsForTeeSession(anyCollection()); } @Test @@ -289,13 +286,9 @@ void shouldGetTokensWithEmptyAppComputeSecretWhenSecretsDoNotExist() throws TeeS .build(); TeeSessionRequest request = createSessionRequest(taskDescription); - when(teeTaskComputeSecretService.getSecret( - OnChainObjectType.APPLICATION, - appAddress, - SecretOwnerRole.APPLICATION_DEVELOPER, - "", - APP_DEVELOPER_SECRET_INDEX)) - .thenReturn(Optional.empty()); + TeeTaskComputeSecret applicationSecret = getApplicationDeveloperSecret(appAddress); + when(teeTaskComputeSecretService.getSecretsForTeeSession(List.of(applicationSecret.getHeader()))) + .thenReturn(List.of()); SecretEnclaveBase enclaveBase = teeSecretsService.getAppTokens(request); assertThat(enclaveBase.getName()).isEqualTo("app"); @@ -313,12 +306,9 @@ void shouldGetTokensWithEmptyAppComputeSecretWhenSecretsDoNotExist() throws TeeS 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()); + assertThat(enclaveBase.getEnvironment()).containsExactlyInAnyOrderEntriesOf(expectedTokens); + verify(teeTaskComputeSecretService).getSecretsForTeeSession(anyCollection()); } @Test @@ -361,15 +351,16 @@ void shouldAddMultipleRequesterSecrets() { TeeSessionRequest request = createSessionRequest(createTaskDescription(enclaveConfig).build()); 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); + final TeeTaskComputeSecret applicationSecret = getApplicationDeveloperSecret(request.getTaskDescription().getAppAddress()); + final TeeTaskComputeSecret requesterSecret1 = getRequesterSecret(requesterAddress, REQUESTER_SECRET_KEY_1, REQUESTER_SECRET_VALUE_1); + final TeeTaskComputeSecret requesterSecret2 = getRequesterSecret(requesterAddress, REQUESTER_SECRET_KEY_2, REQUESTER_SECRET_VALUE_2); + when(teeTaskComputeSecretService.getSecretsForTeeSession(teeTaskComputeSecretIds.capture())) + .thenReturn(List.of(requesterSecret1, requesterSecret2)); 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); + + verify(teeTaskComputeSecretService).getSecretsForTeeSession(anyCollection()); + assertThat(teeTaskComputeSecretIds.getValue()).containsExactlyInAnyOrder( + applicationSecret.getHeader(), requesterSecret1.getHeader(), requesterSecret2.getHeader()); assertThat(enclaveBase.getEnvironment()).containsAllEntriesOf( Map.of( IexecEnvUtils.IEXEC_REQUESTER_SECRET_PREFIX + "1", REQUESTER_SECRET_VALUE_1, @@ -384,10 +375,12 @@ void shouldFilterRequesterSecretIndexLowerThanZero() { TeeSessionRequest request = createSessionRequest(taskDescription); String requesterAddress = request.getTaskDescription().getRequester(); - addRequesterSecret(requesterAddress, REQUESTER_SECRET_KEY_1, REQUESTER_SECRET_VALUE_1); + final TeeTaskComputeSecret applicationSecret = getApplicationDeveloperSecret(request.getTaskDescription().getAppAddress()); + final TeeTaskComputeSecret requesterSecret = getRequesterSecret(requesterAddress, REQUESTER_SECRET_KEY_1, REQUESTER_SECRET_VALUE_1); + when(teeTaskComputeSecretService.getSecretsForTeeSession(List.of(applicationSecret.getHeader(), requesterSecret.getHeader()))) + .thenReturn(List.of(requesterSecret)); SecretEnclaveBase enclaveBase = assertDoesNotThrow(() -> teeSecretsService.getAppTokens(request)); - verify(teeTaskComputeSecretService).getSecret(eq(OnChainObjectType.APPLICATION), eq(""), - eq(SecretOwnerRole.REQUESTER), any(), any()); + verify(teeTaskComputeSecretService).getSecretsForTeeSession(anyCollection()); assertThat(enclaveBase.getEnvironment()).containsAllEntriesOf( Map.of(IexecEnvUtils.IEXEC_REQUESTER_SECRET_PREFIX + "1", REQUESTER_SECRET_VALUE_1)); } @@ -396,15 +389,15 @@ void shouldFilterRequesterSecretIndexLowerThanZero() { // region getPostComputeTokens @Test void shouldGetPostComputeTokens() throws Exception { - TeeSessionRequest request = createSessionRequest(createTaskDescription(enclaveConfig).build()); + final TaskDescription taskDescription = createTaskDescription(enclaveConfig).build(); + final TeeSessionRequest request = createSessionRequest(taskDescription); final String beneficiary = request.getTaskDescription().getBeneficiary(); - when(web2SecretService.getDecryptedValue(beneficiary, IEXEC_RESULT_ENCRYPTION_PUBLIC_KEY)) - .thenReturn(Optional.of(ENCRYPTION_PUBLIC_KEY)); - when(web2SecretService.isSecretPresent(WORKER_ADDRESS, IEXEC_RESULT_IEXEC_IPFS_TOKEN)) - .thenReturn(true); - when(web2SecretService.getDecryptedValue(WORKER_ADDRESS, IEXEC_RESULT_IEXEC_IPFS_TOKEN)) - .thenReturn(Optional.of(STORAGE_TOKEN)); + final Web2Secret resultEncryption = new Web2Secret(beneficiary, IEXEC_RESULT_ENCRYPTION_PUBLIC_KEY, ENCRYPTION_PUBLIC_KEY); + final Web2Secret requesterStorageToken = new Web2Secret(taskDescription.getRequester(), IEXEC_RESULT_IEXEC_IPFS_TOKEN, STORAGE_TOKEN); + final Web2Secret workerStorageToken = new Web2Secret(WORKER_ADDRESS, IEXEC_RESULT_IEXEC_IPFS_TOKEN, STORAGE_TOKEN); + when(web2SecretService.getSecretsForTeeSession(List.of(resultEncryption.getHeader(), requesterStorageToken.getHeader(), workerStorageToken.getHeader()))) + .thenReturn(List.of(resultEncryption, requesterStorageToken, workerStorageToken)); TeeChallenge challenge = TeeChallenge.builder() .credentials(EthereumCredentials.generate()) @@ -432,6 +425,53 @@ void shouldGetPostComputeTokens() throws Exception { assertThat(enclaveBase.getEnvironment()).containsExactlyEntriesOf(expectedTokens); } + @Test + void shouldGetPostComputeTokensForDropbox() throws TeeSessionGenerationException, GeneralSecurityException { + final TaskDescription taskDescription = createTaskDescription(enclaveConfig) + .resultStorageProvider(DealParams.DROPBOX_RESULT_STORAGE_PROVIDER) + .build(); + final TeeSessionRequest request = createSessionRequest(taskDescription); + + final String beneficiary = request.getTaskDescription().getBeneficiary(); + final Web2Secret resultEncryption = new Web2Secret(beneficiary, IEXEC_RESULT_ENCRYPTION_PUBLIC_KEY, ENCRYPTION_PUBLIC_KEY); + final Web2Secret dropboxToken = new Web2Secret(taskDescription.getRequester(), IEXEC_RESULT_DROPBOX_TOKEN, "Secret value"); + when(web2SecretService.getSecretsForTeeSession(List.of(resultEncryption.getHeader(), dropboxToken.getHeader()))) + .thenReturn(List.of(resultEncryption, dropboxToken)); + 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); + } + + @Test + void shouldGetPostComputeTokensWithCallback() throws TeeSessionGenerationException, GeneralSecurityException { + final TaskDescription taskDescription = createTaskDescription(enclaveConfig) + .callback("callback") + .build(); + final TeeSessionRequest request = createSessionRequest(taskDescription); + + final String beneficiary = request.getTaskDescription().getBeneficiary(); + final Web2Secret resultEncryption = new Web2Secret(beneficiary, IEXEC_RESULT_ENCRYPTION_PUBLIC_KEY, ENCRYPTION_PUBLIC_KEY); + final Web2Secret requesterStorageToken = new Web2Secret(taskDescription.getRequester(), IEXEC_RESULT_IEXEC_IPFS_TOKEN, STORAGE_TOKEN); + final Web2Secret workerStorageToken = new Web2Secret(WORKER_ADDRESS, IEXEC_RESULT_IEXEC_IPFS_TOKEN, STORAGE_TOKEN); + when(web2SecretService.getSecretsForTeeSession(List.of(resultEncryption.getHeader(), requesterStorageToken.getHeader(), workerStorageToken.getHeader()))) + .thenReturn(List.of(resultEncryption, workerStorageToken)); + 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); + } + @Test void shouldNotGetPostComputeTokensSinceTaskDescriptionMissing() { TeeSessionRequest request = TeeSessionRequest.builder().build(); @@ -444,7 +484,7 @@ void shouldNotGetPostComputeTokensSinceTaskDescriptionMissing() { } // endregion - // region getPostComputeEncryptionTokens + // region getPostComputeStorageTokens @Test void shouldGetPostComputeStorageTokensWithCallback() { final TaskDescription taskDescription = createTaskDescription(enclaveConfig) @@ -453,7 +493,7 @@ void shouldGetPostComputeStorageTokensWithCallback() { final TeeSessionRequest sessionRequest = createSessionRequest(taskDescription); final Map tokens = assertDoesNotThrow( - () -> teeSecretsService.getPostComputeStorageTokens(sessionRequest)); + () -> teeSecretsService.getPostComputeStorageTokens(sessionRequest, "")); assertThat(tokens) .containsExactlyInAnyOrderEntriesOf( @@ -476,7 +516,7 @@ void shouldGetPostComputeStorageTokensOnIpfsWithRequesterToken() { .thenReturn(Optional.of(secretValue)); final Map tokens = assertDoesNotThrow( - () -> teeSecretsService.getPostComputeStorageTokens(sessionRequest)); + () -> teeSecretsService.getPostComputeStorageTokens(sessionRequest, secretValue)); assertThat(tokens) .containsExactlyInAnyOrderEntriesOf( @@ -498,7 +538,7 @@ void shouldGetPostComputeStorageTokensOnIpfsWithWorkerToken() { .thenReturn(Optional.of(secretValue)); final Map tokens = assertDoesNotThrow( - () -> teeSecretsService.getPostComputeStorageTokens(sessionRequest)); + () -> teeSecretsService.getPostComputeStorageTokens(sessionRequest, secretValue)); assertThat(tokens) .containsExactlyInAnyOrderEntriesOf( @@ -521,7 +561,7 @@ void shouldGetPostComputeStorageTokensOnDropbox() { .thenReturn(Optional.of(secretValue)); final Map tokens = assertDoesNotThrow( - () -> teeSecretsService.getPostComputeStorageTokens(sessionRequest)); + () -> teeSecretsService.getPostComputeStorageTokens(sessionRequest, secretValue)); assertThat(tokens) .containsExactlyInAnyOrderEntriesOf( @@ -544,13 +584,14 @@ void shouldNotGetPostComputeStorageTokensSinceNoSecret() { final TeeSessionGenerationException exception = assertThrows( TeeSessionGenerationException.class, - () -> teeSecretsService.getPostComputeStorageTokens(sessionRequest)); + () -> 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()); } + // region getPostComputeSignTokens @Test void shouldGetPostComputeSignTokens() throws GeneralSecurityException { final TaskDescription taskDescription = createTaskDescription(enclaveConfig).build(); @@ -659,7 +700,9 @@ void shouldNotGetPostComputeSignTokensSinceNoEnclaveCredentialsPrivateKey() { .isEqualTo(TeeSessionGenerationError.POST_COMPUTE_GET_SIGNATURE_TOKENS_FAILED_EMPTY_TEE_CREDENTIALS); assertThat(exception.getMessage()).isEqualTo("Empty TEE challenge credentials - taskId: " + taskId); } + // endregion + // region getPostcomputeEncryptionTokens @Test void shouldGetPostComputeEncryptionTokensWithEncryption() { TeeSessionRequest request = createSessionRequest(createTaskDescription(enclaveConfig).build()); @@ -669,7 +712,7 @@ void shouldGetPostComputeEncryptionTokensWithEncryption() { .thenReturn(Optional.of(ENCRYPTION_PUBLIC_KEY)); final Map encryptionTokens = assertDoesNotThrow( - () -> teeSecretsService.getPostComputeEncryptionTokens(request)); + () -> teeSecretsService.getPostComputeEncryptionTokens(request, ENCRYPTION_PUBLIC_KEY)); assertThat(encryptionTokens) .containsExactlyInAnyOrderEntriesOf( Map.of( @@ -685,7 +728,7 @@ void shouldGetPostComputeEncryptionTokensWithoutEncryption() { TeeSessionRequest request = createSessionRequest(taskDescription); final Map encryptionTokens = assertDoesNotThrow( - () -> teeSecretsService.getPostComputeEncryptionTokens(request)); + () -> teeSecretsService.getPostComputeEncryptionTokens(request, "")); assertThat(encryptionTokens) .containsExactlyInAnyOrderEntriesOf( Map.of( @@ -703,28 +746,11 @@ void shouldNotGetPostComputeEncryptionTokensSinceEmptyBeneficiaryKey() { final TeeSessionGenerationException exception = assertThrows( TeeSessionGenerationException.class, - () -> teeSecretsService.getPostComputeEncryptionTokens(request)); + () -> 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 +} From 7563cd54d6bd9e23b01aaf27841379b1086541ec Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Wed, 27 Mar 2024 11:55:14 +0100 Subject: [PATCH 3/5] Add `Authorization` header on `/tee/challenges/{chainTaskId}` endpoint (#255) --- CHANGELOG.md | 4 ++++ .../java/com/iexec/sms/api/SmsClient.java | 9 ++++++++ .../java/com/iexec/sms/tee/TeeController.java | 23 +++++++++++++------ 3 files changed, 29 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b1fad53a..98cfb893 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. ## [[NEXT]](https://github.com/iExecBlockchainComputing/iexec-sms/releases/tag/vNEXT) 2024 +### New Features + +- Add `Authorization` header on `/tee/challenges/{chainTaskId}` endpoint. (#255) + ### Quality - Use only two SQL statements to read `TeeTaskComputeSecret` and `Web2Secret` during TEE session creation. (#254) 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 8b840181..3775b9e3 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,9 +118,18 @@ String setWeb3Secret( // endregion // region TEE + + /** + * @deprecated use {@link SmsClient#generateTeeChallenge(String, String)} + */ + @Deprecated(forRemoval = true) @RequestLine("POST /tee/challenges/{chainTaskId}") String generateTeeChallenge(@Param("chainTaskId") String chainTaskId); + @Headers("Authorization: {authorization}") + @RequestLine("POST /tee/challenges/{chainTaskId}") + String generateTeeChallenge(@Param("authorization") String authorization, @Param("chainTaskId") String chainTaskId); + @RequestLine("POST /tee/sessions") @Headers("Authorization: {authorization}") ApiResponseBody generateTeeSession( diff --git a/src/main/java/com/iexec/sms/tee/TeeController.java b/src/main/java/com/iexec/sms/tee/TeeController.java index eb0be72f..e9ee4f20 100644 --- a/src/main/java/com/iexec/sms/tee/TeeController.java +++ b/src/main/java/com/iexec/sms/tee/TeeController.java @@ -73,6 +73,7 @@ public TeeController( /** * Return which TEE framework this SMS is configured to use. + * * @return TEE framework this SMS is configured to use. */ @GetMapping("/framework") @@ -100,10 +101,16 @@ public ResponseEntity getTeeServicesProperties( } /** - * Called by the core, not the worker + * Generates an enclave challenge for a PoCo task. + *

+ * This method is called by the scheduler. + * + * @param authorization Authorization to check the query legitimacy + * @param chainTaskId ID of the task the challenge will be produced for + * @return The Ethereum address enclave challenge for the provided */ @PostMapping("/challenges/{chainTaskId}") - public ResponseEntity generateTeeChallenge(@PathVariable String chainTaskId) { + public ResponseEntity generateTeeChallenge(@RequestHeader String authorization, @PathVariable String chainTaskId) { Optional executionChallenge = teeChallengeService.getOrCreate(chainTaskId, false); return executionChallenge @@ -118,10 +125,12 @@ public ResponseEntity generateTeeChallenge(@PathVariable String chainTas * to the enclave so the latter can talk to the CAS and get * the needed secrets. * - * @return - * 200 OK with the session id if success, - * 404 NOT_FOUND if the task is not found, - * 500 INTERNAL_SERVER_ERROR otherwise. + * @return result + *

    + *
  • 200 OK with the session id if success. + *
  • 404 NOT_FOUND if the task is not found. + *
  • 500 INTERNAL_SERVER_ERROR otherwise. + *
*/ @PostMapping("/sessions") public ResponseEntity> generateTeeSession( @@ -170,7 +179,7 @@ public ResponseEntitybuilder() .data(teeSessionGenerationResponse) .build()); - } catch(TeeSessionGenerationException e) { + } catch (TeeSessionGenerationException e) { log.error("Failed to generate secure session [taskId:{}, workerAddress:{}]", taskId, workerAddress, e); final ApiResponseBody body = From 940182e0f7d1c575a650a96853f30ba416691e1f Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Thu, 28 Mar 2024 09:35:48 +0100 Subject: [PATCH 4/5] Use `AuthorizationService` to validate `Authorization` header of `/tee/challenges/{chainTaskId}` endpoint (#256) --- CHANGELOG.md | 2 +- .../authorization/AuthorizationService.java | 64 +++++++------ .../java/com/iexec/sms/tee/TeeController.java | 24 +++-- .../AuthorizationServiceTests.java | 24 ++--- .../com/iexec/sms/tee/TeeControllerTests.java | 89 +++++++++++++++---- 5 files changed, 131 insertions(+), 72 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 98cfb893..c36d023f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ All notable changes to this project will be documented in this file. ### New Features -- Add `Authorization` header on `/tee/challenges/{chainTaskId}` endpoint. (#255) +- Add `Authorization` header on `/tee/challenges/{chainTaskId}` endpoint. (#255 #256) ### Quality diff --git a/src/main/java/com/iexec/sms/authorization/AuthorizationService.java b/src/main/java/com/iexec/sms/authorization/AuthorizationService.java index f6233980..9094bd5a 100644 --- a/src/main/java/com/iexec/sms/authorization/AuthorizationService.java +++ b/src/main/java/com/iexec/sms/authorization/AuthorizationService.java @@ -16,7 +16,6 @@ package com.iexec.sms.authorization; - import com.iexec.commons.poco.chain.ChainDeal; import com.iexec.commons.poco.chain.ChainTask; import com.iexec.commons.poco.chain.ChainTaskStatus; @@ -49,52 +48,49 @@ public AuthorizationService(IexecHubService iexecHubService) { /** * Checks whether this execution is authorized. - * If not authorized, return the reason. - * Otherwise, returns an empty {@link Optional}. + * + * @param workerpoolAuthorization The workerpool authorization to check + * @return {@code Optional.empty()} if all checks passed, the failure reason otherwise */ - public Optional isAuthorizedOnExecutionWithDetailedIssue(WorkerpoolAuthorization workerpoolAuthorization, boolean isTeeTask) { + public Optional isAuthorizedOnExecutionWithDetailedIssue(WorkerpoolAuthorization workerpoolAuthorization) { if (workerpoolAuthorization == null || StringUtils.isEmpty(workerpoolAuthorization.getChainTaskId())) { log.error("Not authorized with empty params"); return Optional.of(EMPTY_PARAMS_UNAUTHORIZED); } - String chainTaskId = workerpoolAuthorization.getChainTaskId(); - Optional optionalChainTask = iexecHubService.getChainTask(chainTaskId); - if (optionalChainTask.isEmpty()) { + final String chainTaskId = workerpoolAuthorization.getChainTaskId(); + final ChainTask chainTask = iexecHubService.getChainTask(chainTaskId).orElse(null); + if (chainTask == null) { log.error("Could not get chainTask [chainTaskId:{}]", chainTaskId); return Optional.of(GET_CHAIN_TASK_FAILED); } - ChainTask chainTask = optionalChainTask.get(); - ChainTaskStatus taskStatus = chainTask.getStatus(); - String chainDealId = chainTask.getDealid(); + final String chainDealId = chainTask.getDealid(); - if (taskStatus != ChainTaskStatus.ACTIVE) { - log.error("Task not active onchain [chainTaskId:{}, status:{}]", - chainTaskId, taskStatus); + if (chainTask.getStatus() != ChainTaskStatus.ACTIVE) { + log.error("Task not active on chain [chainTaskId:{}, status:{}]", + chainTaskId, chainTask.getStatus()); return Optional.of(TASK_NOT_ACTIVE); } - Optional optionalChainDeal = iexecHubService.getChainDeal(chainDealId); - if (optionalChainDeal.isEmpty()) { + final ChainDeal chainDeal = iexecHubService.getChainDeal(chainDealId).orElse(null); + if (chainDeal == null) { log.error("isAuthorizedOnExecution failed (getChainDeal failed) [chainTaskId:{}]", chainTaskId); return Optional.of(GET_CHAIN_DEAL_FAILED); } - ChainDeal chainDeal = optionalChainDeal.get(); - boolean isTeeTaskOnchain = TeeUtils.isTeeTag(chainDeal.getTag()); - if (isTeeTask != isTeeTaskOnchain) { - log.error("Could not match onchain task type [isTeeTask:{}, isTeeTaskOnchain:{}, chainTaskId:{}, walletAddress:{}]", - isTeeTask, isTeeTaskOnchain, chainTaskId, workerpoolAuthorization.getWorkerWallet()); + final boolean isTeeTaskOnchain = TeeUtils.isTeeTag(chainDeal.getTag()); + if (!isTeeTaskOnchain) { + log.error("Could not match onchain task type [isTeeTaskOnchain:{}, chainTaskId:{}]", + isTeeTaskOnchain, chainTaskId); return Optional.of(NO_MATCH_ONCHAIN_TYPE); } - String workerpoolAddress = chainDeal.getPoolOwner(); - boolean isSignerByWorkerpool = isSignedByHimself(workerpoolAuthorization.getHash(), - workerpoolAuthorization.getSignature().getValue(), workerpoolAddress); + final boolean isSignedByWorkerpool = isSignedByHimself(workerpoolAuthorization.getHash(), + workerpoolAuthorization.getSignature().getValue(), chainDeal.getPoolOwner()); - if (!isSignerByWorkerpool) { - log.error("isAuthorizedOnExecution failed (invalid signature) [chainTaskId:{}, isWorkerpoolSignatureValid:{}]", - chainTaskId, isSignerByWorkerpool); + if (!isSignedByWorkerpool) { + log.error("isAuthorizedOnExecution failed (invalid signature) [chainTaskId:{}, isSignedByWorkerpool:{}]", + chainTaskId, isSignedByWorkerpool); return Optional.of(INVALID_SIGNATURE); } @@ -110,14 +106,6 @@ public boolean isSignedByOwner(String message, String signature, String address) String owner = iexecHubService.getOwner(address); return !owner.isEmpty() && isSignedByHimself(message, signature, owner); } - - public String getChallengeForSetWeb3Secret(String secretAddress, - String secretValue) { - return HashUtils.concatenateAndHash( - Hash.sha3String(DOMAIN), - secretAddress, - Hash.sha3String(secretValue)); - } // endregion // region challenges @@ -152,6 +140,14 @@ public String getChallengeForSetWeb2Secret(String ownerAddress, Hash.sha3String(secretValue)); } + public String getChallengeForSetWeb3Secret(String secretAddress, + String secretValue) { + return HashUtils.concatenateAndHash( + Hash.sha3String(DOMAIN), + secretAddress, + Hash.sha3String(secretValue)); + } + public String getChallengeForWorker(WorkerpoolAuthorization workerpoolAuthorization) { return HashUtils.concatenateAndHash( workerpoolAuthorization.getWorkerWallet(), diff --git a/src/main/java/com/iexec/sms/tee/TeeController.java b/src/main/java/com/iexec/sms/tee/TeeController.java index e9ee4f20..75c8c0e7 100644 --- a/src/main/java/com/iexec/sms/tee/TeeController.java +++ b/src/main/java/com/iexec/sms/tee/TeeController.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2023 IEXEC BLOCKCHAIN TECH + * Copyright 2020-2024 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. @@ -19,13 +19,13 @@ import com.iexec.common.web.ApiResponseBody; import com.iexec.commons.poco.chain.WorkerpoolAuthorization; +import com.iexec.commons.poco.security.Signature; import com.iexec.commons.poco.tee.TeeFramework; import com.iexec.sms.api.TeeSessionGenerationError; import com.iexec.sms.api.TeeSessionGenerationResponse; 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; import com.iexec.sms.tee.challenge.TeeChallengeService; import com.iexec.sms.tee.session.TeeSessionService; import com.iexec.sms.tee.session.generic.TeeSessionGenerationException; @@ -111,11 +111,19 @@ public ResponseEntity getTeeServicesProperties( */ @PostMapping("/challenges/{chainTaskId}") public ResponseEntity generateTeeChallenge(@RequestHeader String authorization, @PathVariable String chainTaskId) { - Optional executionChallenge = - teeChallengeService.getOrCreate(chainTaskId, false); - return executionChallenge - .map(teeChallenge -> ResponseEntity - .ok(teeChallenge.getCredentials().getAddress())) + log.debug("generateTeeChallenge [authorization:{}, chainTaskId:{}]", authorization, chainTaskId); + final Optional authorizationError = authorizationService.isAuthorizedOnExecutionWithDetailedIssue( + WorkerpoolAuthorization.builder() + .chainTaskId(chainTaskId) + .enclaveChallenge("") + .workerWallet("") + .signature(new Signature(authorization)) + .build()); + if (authorizationError.isPresent()) { + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build(); + } + return teeChallengeService.getOrCreate(chainTaskId, false) + .map(teeChallenge -> ResponseEntity.ok(teeChallenge.getCredentials().getAddress())) .orElseGet(() -> ResponseEntity.notFound().build()); } @@ -149,7 +157,7 @@ public ResponseEntity authorizationError = - authorizationService.isAuthorizedOnExecutionWithDetailedIssue(workerpoolAuthorization, true); + authorizationService.isAuthorizedOnExecutionWithDetailedIssue(workerpoolAuthorization); if (authorizationError.isPresent()) { final TeeSessionGenerationError teeSessionGenerationError = authorizationToGenerationError.get(authorizationError.get()); diff --git a/src/test/java/com/iexec/sms/authorization/AuthorizationServiceTests.java b/src/test/java/com/iexec/sms/authorization/AuthorizationServiceTests.java index ec1560ec..e134e3a0 100644 --- a/src/test/java/com/iexec/sms/authorization/AuthorizationServiceTests.java +++ b/src/test/java/com/iexec/sms/authorization/AuthorizationServiceTests.java @@ -21,6 +21,7 @@ import com.iexec.commons.poco.chain.WorkerpoolAuthorization; import com.iexec.commons.poco.security.Signature; import com.iexec.commons.poco.tee.TeeUtils; +import com.iexec.commons.poco.utils.BytesUtils; import com.iexec.commons.poco.utils.TestUtils; import com.iexec.sms.blockchain.IexecHubService; import org.junit.jupiter.api.Assertions; @@ -60,33 +61,36 @@ void shouldBeAuthorizedOnExecutionOfTeeTaskWithDetails() { when(iexecHubService.getChainTask(auth.getChainTaskId())).thenReturn(Optional.of(chainTask)); when(iexecHubService.getChainDeal(chainTask.getDealid())).thenReturn(Optional.of(chainDeal)); - Optional isAuth = authorizationService.isAuthorizedOnExecutionWithDetailedIssue(auth, true); + Optional isAuth = authorizationService.isAuthorizedOnExecutionWithDetailedIssue(auth); assertThat(isAuth).isEmpty(); } @Test void shouldNotBeAuthorizedOnExecutionOfTeeTaskWithNullAuthorizationWithDetails() { - Optional isAuth = authorizationService.isAuthorizedOnExecutionWithDetailedIssue(null, true); + Optional isAuth = authorizationService.isAuthorizedOnExecutionWithDetailedIssue(null); assertThat(isAuth).isNotEmpty() .contains(EMPTY_PARAMS_UNAUTHORIZED); } @Test void shouldNotBeAuthorizedOnExecutionOfTeeTaskWithEmptyAuthorizationWithDetails() { - Optional isAuth = authorizationService.isAuthorizedOnExecutionWithDetailedIssue(WorkerpoolAuthorization.builder().build(), true); + Optional isAuth = authorizationService.isAuthorizedOnExecutionWithDetailedIssue(WorkerpoolAuthorization.builder().build()); assertThat(isAuth).isNotEmpty() .contains(EMPTY_PARAMS_UNAUTHORIZED); } @Test - void shouldNotBeAuthorizedOnExecutionOfTeeTaskWhenTaskTypeNotMatchedOnchainWithDetails() { - ChainDeal chainDeal = getChainDeal(); + void shouldNotBeAuthorizedOnExecutionOfTeeTaskWhenTaskTypeNotTeeOnchainWithDetails() { + ChainDeal chainDeal = ChainDeal.builder() + .poolOwner("0xc911f9345717ba7c8ec862ce002af3e058df84e4") + .tag(BytesUtils.EMPTY_HEX_STRING_32) + .build(); ChainTask chainTask = TestUtils.getChainTask(ACTIVE); WorkerpoolAuthorization auth = TestUtils.getTeeWorkerpoolAuth(); when(iexecHubService.getChainTask(auth.getChainTaskId())).thenReturn(Optional.of(chainTask)); when(iexecHubService.getChainDeal(chainTask.getDealid())).thenReturn(Optional.of(chainDeal)); - Optional isAuth = authorizationService.isAuthorizedOnExecutionWithDetailedIssue(auth, false); + Optional isAuth = authorizationService.isAuthorizedOnExecutionWithDetailedIssue(auth); assertThat(isAuth).isNotEmpty() .contains(NO_MATCH_ONCHAIN_TYPE); } @@ -97,7 +101,7 @@ void shouldNotBeAuthorizedOnExecutionOfTeeTaskWhenGetTaskFailedWithDetails() { when(iexecHubService.isTeeTask(auth.getChainTaskId())).thenReturn(true); when(iexecHubService.getChainTask(auth.getChainTaskId())).thenReturn(Optional.empty()); - Optional isAuth = authorizationService.isAuthorizedOnExecutionWithDetailedIssue(auth, true); + Optional isAuth = authorizationService.isAuthorizedOnExecutionWithDetailedIssue(auth); assertThat(isAuth).isNotEmpty() .contains(GET_CHAIN_TASK_FAILED); } @@ -109,7 +113,7 @@ void shouldNotBeAuthorizedOnExecutionOfTeeTaskWhenTaskNotActiveWithDetails() { when(iexecHubService.isTeeTask(auth.getChainTaskId())).thenReturn(true); when(iexecHubService.getChainTask(auth.getChainTaskId())).thenReturn(Optional.of(chainTask)); - Optional isAuth = authorizationService.isAuthorizedOnExecutionWithDetailedIssue(auth, true); + Optional isAuth = authorizationService.isAuthorizedOnExecutionWithDetailedIssue(auth); assertThat(isAuth).isNotEmpty() .contains(TASK_NOT_ACTIVE); } @@ -124,7 +128,7 @@ void shouldNotBeAuthorizedOnExecutionOfTeeTaskWhenGetDealFailedWithDetails() { when(iexecHubService.getChainTask(auth.getChainTaskId())).thenReturn(Optional.of(chainTask)); when(iexecHubService.getChainDeal(chainTask.getDealid())).thenReturn(Optional.empty()); - Optional isAuth = authorizationService.isAuthorizedOnExecutionWithDetailedIssue(auth, true); + Optional isAuth = authorizationService.isAuthorizedOnExecutionWithDetailedIssue(auth); assertThat(isAuth).isNotEmpty() .contains(GET_CHAIN_DEAL_FAILED); } @@ -139,7 +143,7 @@ void shouldNotBeAuthorizedOnExecutionOfTeeTaskWhenPoolSignatureIsNotValidWithDet when(iexecHubService.getChainTask(auth.getChainTaskId())).thenReturn(Optional.of(chainTask)); when(iexecHubService.getChainDeal(chainTask.getDealid())).thenReturn(Optional.of(chainDeal)); - Optional isAuth = authorizationService.isAuthorizedOnExecutionWithDetailedIssue(auth, true); + Optional isAuth = authorizationService.isAuthorizedOnExecutionWithDetailedIssue(auth); assertThat(isAuth).isNotEmpty() .contains(INVALID_SIGNATURE); } diff --git a/src/test/java/com/iexec/sms/tee/TeeControllerTests.java b/src/test/java/com/iexec/sms/tee/TeeControllerTests.java index c4d6cd4c..30e018d0 100644 --- a/src/test/java/com/iexec/sms/tee/TeeControllerTests.java +++ b/src/test/java/com/iexec/sms/tee/TeeControllerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 IEXEC BLOCKCHAIN TECH + * Copyright 2022-2024 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. @@ -18,6 +18,7 @@ import com.iexec.common.web.ApiResponseBody; import com.iexec.commons.poco.chain.WorkerpoolAuthorization; +import com.iexec.commons.poco.security.Signature; import com.iexec.commons.poco.tee.TeeFramework; import com.iexec.sms.api.TeeSessionGenerationError; import com.iexec.sms.api.TeeSessionGenerationResponse; @@ -27,6 +28,7 @@ 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; import com.iexec.sms.tee.challenge.TeeChallengeService; import com.iexec.sms.tee.session.TeeSessionService; import com.iexec.sms.tee.session.generic.TeeSessionGenerationException; @@ -34,6 +36,7 @@ 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.EnumSource; import org.junit.jupiter.params.provider.MethodSource; import org.mockito.InjectMocks; import org.mockito.Mock; @@ -47,7 +50,9 @@ import static com.iexec.sms.api.TeeSessionGenerationError.*; import static com.iexec.sms.authorization.AuthorizationError.*; +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.when; class TeeControllerTests { @@ -97,10 +102,7 @@ void shouldGetSconeFramework() { final ResponseEntity response = teeController.getTeeFramework(); - assertEquals(HttpStatus.OK, response.getStatusCode()); - - final TeeFramework result = response.getBody(); - assertEquals(TeeFramework.SCONE, result); + assertThat(response).isEqualTo(ResponseEntity.ok(TeeFramework.SCONE)); } @Test @@ -117,14 +119,11 @@ void shouldGetGramineFramework() { final ResponseEntity response = teeController.getTeeFramework(); - assertEquals(HttpStatus.OK, response.getStatusCode()); - - final TeeFramework result = response.getBody(); - assertEquals(TeeFramework.GRAMINE, result); + assertThat(response).isEqualTo(ResponseEntity.ok(TeeFramework.GRAMINE)); } // endregion - // region getTeeServicesConfig + // region getTeeServicesProperties @Test void shouldGetSconeProperties() { final TeeServicesProperties properties = new SconeServicesProperties( @@ -191,7 +190,7 @@ void shouldNotGetSconePropertiesSinceGramineSms() { final ResponseEntity response = teeController.getTeeServicesProperties(TeeFramework.GRAMINE); - assertEquals(HttpStatus.CONFLICT, response.getStatusCode()); + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.CONFLICT); } @Test @@ -208,7 +207,59 @@ void shouldNotGetGraminePropertiesSinceSconeSms() { final ResponseEntity response = teeController.getTeeServicesProperties(TeeFramework.SCONE); - assertEquals(HttpStatus.CONFLICT, response.getStatusCode()); + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.CONFLICT); + } + // endregion + + // region generateTeeChallenge + @ParameterizedTest + @EnumSource(value = AuthorizationError.class) + void shouldNotGenerateTeeChallengeWhenNotAuthorized(AuthorizationError cause) { + final WorkerpoolAuthorization workerpoolAuthorization = WorkerpoolAuthorization + .builder() + .chainTaskId(TASK_ID) + .enclaveChallenge("") + .workerWallet("") + .signature(new Signature(AUTHORIZATION)) + .build(); + when(authorizationService.isAuthorizedOnExecutionWithDetailedIssue(workerpoolAuthorization)) + .thenReturn(Optional.of(cause)); + final ResponseEntity response = teeController.generateTeeChallenge(AUTHORIZATION, TASK_ID); + assertThat(response).isEqualTo(ResponseEntity.status(HttpStatus.UNAUTHORIZED).build()); + verifyNoInteractions(teeChallengeService); + } + + @Test + void shouldNotGenerateTeeChallengeWhenExceptionDuringGeneration() { + final WorkerpoolAuthorization workerpoolAuthorization = WorkerpoolAuthorization + .builder() + .chainTaskId(TASK_ID) + .enclaveChallenge("") + .workerWallet("") + .signature(new Signature(AUTHORIZATION)) + .build(); + when(authorizationService.isAuthorizedOnExecutionWithDetailedIssue(workerpoolAuthorization)) + .thenReturn(Optional.empty()); + when(teeChallengeService.getOrCreate(TASK_ID, false)).thenReturn(Optional.empty()); + final ResponseEntity response = teeController.generateTeeChallenge(AUTHORIZATION, TASK_ID); + assertThat(response).isEqualTo(ResponseEntity.notFound().build()); + } + + @Test + void shouldGenerateTeeChallenge() throws Exception { + final WorkerpoolAuthorization workerpoolAuthorization = WorkerpoolAuthorization + .builder() + .chainTaskId(TASK_ID) + .enclaveChallenge("") + .workerWallet("") + .signature(new Signature(AUTHORIZATION)) + .build(); + final TeeChallenge teeChallenge = new TeeChallenge(TASK_ID); + when(authorizationService.isAuthorizedOnExecutionWithDetailedIssue(workerpoolAuthorization)) + .thenReturn(Optional.empty()); + when(teeChallengeService.getOrCreate(TASK_ID, false)).thenReturn(Optional.of(teeChallenge)); + final ResponseEntity response = teeController.generateTeeChallenge(AUTHORIZATION, TASK_ID); + assertThat(response).isEqualTo(ResponseEntity.ok(teeChallenge.getCredentials().getAddress())); } // endregion @@ -224,7 +275,7 @@ void shouldGenerateTeeSession() throws TeeSessionGenerationException { when(authorizationService.getChallengeForWorker(workerpoolAuthorization)).thenReturn(CHALLENGE); when(authorizationService.isSignedByHimself(CHALLENGE, AUTHORIZATION, WORKER_ADDRESS)).thenReturn(true); - when(authorizationService.isAuthorizedOnExecutionWithDetailedIssue(workerpoolAuthorization, true)) + when(authorizationService.isAuthorizedOnExecutionWithDetailedIssue(workerpoolAuthorization)) .thenReturn(Optional.empty()); when(teeSessionService.generateTeeSession(TASK_ID, Keys.toChecksumAddress(WORKER_ADDRESS), ENCLAVE_CHALLENGE)) .thenReturn(new TeeSessionGenerationResponse(SESSION_ID, SECRET_PROVISIONING_URL)); @@ -273,7 +324,7 @@ private static Stream notAuthorizedParams() { @ParameterizedTest @MethodSource("notAuthorizedParams") void shouldNotGenerateTeeSessionSinceNotAuthorized(AuthorizationError cause, - TeeSessionGenerationError consequence) { + TeeSessionGenerationError consequence) { final WorkerpoolAuthorization workerpoolAuthorization = WorkerpoolAuthorization .builder() .chainTaskId(TASK_ID) @@ -283,7 +334,7 @@ void shouldNotGenerateTeeSessionSinceNotAuthorized(AuthorizationError cause, when(authorizationService.getChallengeForWorker(workerpoolAuthorization)).thenReturn(CHALLENGE); when(authorizationService.isSignedByHimself(CHALLENGE, AUTHORIZATION, WORKER_ADDRESS)).thenReturn(true); - when(authorizationService.isAuthorizedOnExecutionWithDetailedIssue(workerpoolAuthorization, true)) + when(authorizationService.isAuthorizedOnExecutionWithDetailedIssue(workerpoolAuthorization)) .thenReturn(Optional.of(cause)); final ResponseEntity> response = teeController @@ -306,15 +357,15 @@ void shouldNotGenerateTeeSessionSinceEmptyResponse() throws TeeSessionGeneration when(authorizationService.getChallengeForWorker(workerpoolAuthorization)).thenReturn(CHALLENGE); when(authorizationService.isSignedByHimself(CHALLENGE, AUTHORIZATION, WORKER_ADDRESS)).thenReturn(true); - when(authorizationService.isAuthorizedOnExecutionWithDetailedIssue(workerpoolAuthorization, true)) + when(authorizationService.isAuthorizedOnExecutionWithDetailedIssue(workerpoolAuthorization)) .thenReturn(Optional.empty()); when(teeSessionService.generateTeeSession(TASK_ID, Keys.toChecksumAddress(WORKER_ADDRESS), ENCLAVE_CHALLENGE)) .thenReturn(null); final ResponseEntity> response = teeController .generateTeeSession(AUTHORIZATION, workerpoolAuthorization); - assertEquals(HttpStatus.NOT_FOUND, response.getStatusCode()); - assertNull(response.getBody()); + + assertThat(response).isEqualTo(ResponseEntity.notFound().build()); } private static Stream exceptionOnSessionIdGeneration() { @@ -345,7 +396,7 @@ void shouldNotGenerateTeeSessionSinceSessionIdGenerationFailed(Exception excepti when(authorizationService.getChallengeForWorker(workerpoolAuthorization)).thenReturn(CHALLENGE); when(authorizationService.isSignedByHimself(CHALLENGE, AUTHORIZATION, WORKER_ADDRESS)).thenReturn(true); - when(authorizationService.isAuthorizedOnExecutionWithDetailedIssue(workerpoolAuthorization, true)) + when(authorizationService.isAuthorizedOnExecutionWithDetailedIssue(workerpoolAuthorization)) .thenReturn(Optional.empty()); when(teeSessionService.generateTeeSession(TASK_ID, Keys.toChecksumAddress(WORKER_ADDRESS), ENCLAVE_CHALLENGE)) .thenThrow(exception); From af0f6d4dd5db559b79bb570869fb4d1414ed0234 Mon Sep 17 00:00:00 2001 From: Jeremy Bernard Date: Tue, 2 Apr 2024 15:40:31 +0200 Subject: [PATCH 5/5] Release 8.5.1 --- CHANGELOG.md | 2 +- gradle.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c36d023f..821d7187 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ All notable changes to this project will be documented in this file. -## [[NEXT]](https://github.com/iExecBlockchainComputing/iexec-sms/releases/tag/vNEXT) 2024 +## [[8.5.1]](https://github.com/iExecBlockchainComputing/iexec-sms/releases/tag/v8.5.1) 2024-04-02 ### New Features diff --git a/gradle.properties b/gradle.properties index 2df23816..56b8990e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -version=8.5.0 +version=8.5.1 iexecCommonVersion=8.4.0 iexecCommonsPocoVersion=3.2.0