Skip to content

Commit 4c7de65

Browse files
authored
Merge pull request #257 from iExecBlockchainComputing/release/8.5.1
Release/8.5.1
2 parents ec9f8cc + af0f6d4 commit 4c7de65

File tree

13 files changed

+399
-266
lines changed

13 files changed

+399
-266
lines changed

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,16 @@
22

33
All notable changes to this project will be documented in this file.
44

5+
## [[8.5.1]](https://github.com/iExecBlockchainComputing/iexec-sms/releases/tag/v8.5.1) 2024-04-02
6+
7+
### New Features
8+
9+
- Add `Authorization` header on `/tee/challenges/{chainTaskId}` endpoint. (#255 #256)
10+
11+
### Quality
12+
13+
- Use only two SQL statements to read `TeeTaskComputeSecret` and `Web2Secret` during TEE session creation. (#254)
14+
515
## [[8.5.0]](https://github.com/iExecBlockchainComputing/iexec-sms/releases/tag/v8.5.0) 2024-02-29
616

717
### New Features

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
version=8.5.0
1+
version=8.5.1
22
iexecCommonVersion=8.4.0
33
iexecCommonsPocoVersion=3.2.0
44

iexec-sms-library/src/main/java/com/iexec/sms/api/SmsClient.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,9 +118,18 @@ String setWeb3Secret(
118118
// endregion
119119

120120
// region TEE
121+
122+
/**
123+
* @deprecated use {@link SmsClient#generateTeeChallenge(String, String)}
124+
*/
125+
@Deprecated(forRemoval = true)
121126
@RequestLine("POST /tee/challenges/{chainTaskId}")
122127
String generateTeeChallenge(@Param("chainTaskId") String chainTaskId);
123128

129+
@Headers("Authorization: {authorization}")
130+
@RequestLine("POST /tee/challenges/{chainTaskId}")
131+
String generateTeeChallenge(@Param("authorization") String authorization, @Param("chainTaskId") String chainTaskId);
132+
124133
@RequestLine("POST /tee/sessions")
125134
@Headers("Authorization: {authorization}")
126135
ApiResponseBody<TeeSessionGenerationResponse, TeeSessionGenerationError> generateTeeSession(

src/main/java/com/iexec/sms/authorization/AuthorizationService.java

Lines changed: 30 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
package com.iexec.sms.authorization;
1818

19-
2019
import com.iexec.commons.poco.chain.ChainDeal;
2120
import com.iexec.commons.poco.chain.ChainTask;
2221
import com.iexec.commons.poco.chain.ChainTaskStatus;
@@ -49,52 +48,49 @@ public AuthorizationService(IexecHubService iexecHubService) {
4948

5049
/**
5150
* Checks whether this execution is authorized.
52-
* If not authorized, return the reason.
53-
* Otherwise, returns an empty {@link Optional}.
51+
*
52+
* @param workerpoolAuthorization The workerpool authorization to check
53+
* @return {@code Optional.empty()} if all checks passed, the failure reason otherwise
5454
*/
55-
public Optional<AuthorizationError> isAuthorizedOnExecutionWithDetailedIssue(WorkerpoolAuthorization workerpoolAuthorization, boolean isTeeTask) {
55+
public Optional<AuthorizationError> isAuthorizedOnExecutionWithDetailedIssue(WorkerpoolAuthorization workerpoolAuthorization) {
5656
if (workerpoolAuthorization == null || StringUtils.isEmpty(workerpoolAuthorization.getChainTaskId())) {
5757
log.error("Not authorized with empty params");
5858
return Optional.of(EMPTY_PARAMS_UNAUTHORIZED);
5959
}
6060

61-
String chainTaskId = workerpoolAuthorization.getChainTaskId();
62-
Optional<ChainTask> optionalChainTask = iexecHubService.getChainTask(chainTaskId);
63-
if (optionalChainTask.isEmpty()) {
61+
final String chainTaskId = workerpoolAuthorization.getChainTaskId();
62+
final ChainTask chainTask = iexecHubService.getChainTask(chainTaskId).orElse(null);
63+
if (chainTask == null) {
6464
log.error("Could not get chainTask [chainTaskId:{}]", chainTaskId);
6565
return Optional.of(GET_CHAIN_TASK_FAILED);
6666
}
67-
ChainTask chainTask = optionalChainTask.get();
68-
ChainTaskStatus taskStatus = chainTask.getStatus();
69-
String chainDealId = chainTask.getDealid();
67+
final String chainDealId = chainTask.getDealid();
7068

71-
if (taskStatus != ChainTaskStatus.ACTIVE) {
72-
log.error("Task not active onchain [chainTaskId:{}, status:{}]",
73-
chainTaskId, taskStatus);
69+
if (chainTask.getStatus() != ChainTaskStatus.ACTIVE) {
70+
log.error("Task not active on chain [chainTaskId:{}, status:{}]",
71+
chainTaskId, chainTask.getStatus());
7472
return Optional.of(TASK_NOT_ACTIVE);
7573
}
7674

77-
Optional<ChainDeal> optionalChainDeal = iexecHubService.getChainDeal(chainDealId);
78-
if (optionalChainDeal.isEmpty()) {
75+
final ChainDeal chainDeal = iexecHubService.getChainDeal(chainDealId).orElse(null);
76+
if (chainDeal == null) {
7977
log.error("isAuthorizedOnExecution failed (getChainDeal failed) [chainTaskId:{}]", chainTaskId);
8078
return Optional.of(GET_CHAIN_DEAL_FAILED);
8179
}
82-
ChainDeal chainDeal = optionalChainDeal.get();
8380

84-
boolean isTeeTaskOnchain = TeeUtils.isTeeTag(chainDeal.getTag());
85-
if (isTeeTask != isTeeTaskOnchain) {
86-
log.error("Could not match onchain task type [isTeeTask:{}, isTeeTaskOnchain:{}, chainTaskId:{}, walletAddress:{}]",
87-
isTeeTask, isTeeTaskOnchain, chainTaskId, workerpoolAuthorization.getWorkerWallet());
81+
final boolean isTeeTaskOnchain = TeeUtils.isTeeTag(chainDeal.getTag());
82+
if (!isTeeTaskOnchain) {
83+
log.error("Could not match onchain task type [isTeeTaskOnchain:{}, chainTaskId:{}]",
84+
isTeeTaskOnchain, chainTaskId);
8885
return Optional.of(NO_MATCH_ONCHAIN_TYPE);
8986
}
9087

91-
String workerpoolAddress = chainDeal.getPoolOwner();
92-
boolean isSignerByWorkerpool = isSignedByHimself(workerpoolAuthorization.getHash(),
93-
workerpoolAuthorization.getSignature().getValue(), workerpoolAddress);
88+
final boolean isSignedByWorkerpool = isSignedByHimself(workerpoolAuthorization.getHash(),
89+
workerpoolAuthorization.getSignature().getValue(), chainDeal.getPoolOwner());
9490

95-
if (!isSignerByWorkerpool) {
96-
log.error("isAuthorizedOnExecution failed (invalid signature) [chainTaskId:{}, isWorkerpoolSignatureValid:{}]",
97-
chainTaskId, isSignerByWorkerpool);
91+
if (!isSignedByWorkerpool) {
92+
log.error("isAuthorizedOnExecution failed (invalid signature) [chainTaskId:{}, isSignedByWorkerpool:{}]",
93+
chainTaskId, isSignedByWorkerpool);
9894
return Optional.of(INVALID_SIGNATURE);
9995
}
10096

@@ -110,14 +106,6 @@ public boolean isSignedByOwner(String message, String signature, String address)
110106
String owner = iexecHubService.getOwner(address);
111107
return !owner.isEmpty() && isSignedByHimself(message, signature, owner);
112108
}
113-
114-
public String getChallengeForSetWeb3Secret(String secretAddress,
115-
String secretValue) {
116-
return HashUtils.concatenateAndHash(
117-
Hash.sha3String(DOMAIN),
118-
secretAddress,
119-
Hash.sha3String(secretValue));
120-
}
121109
// endregion
122110

123111
// region challenges
@@ -152,6 +140,14 @@ public String getChallengeForSetWeb2Secret(String ownerAddress,
152140
Hash.sha3String(secretValue));
153141
}
154142

143+
public String getChallengeForSetWeb3Secret(String secretAddress,
144+
String secretValue) {
145+
return HashUtils.concatenateAndHash(
146+
Hash.sha3String(DOMAIN),
147+
secretAddress,
148+
Hash.sha3String(secretValue));
149+
}
150+
155151
public String getChallengeForWorker(WorkerpoolAuthorization workerpoolAuthorization) {
156152
return HashUtils.concatenateAndHash(
157153
workerpoolAuthorization.getWorkerWallet(),

src/main/java/com/iexec/sms/secret/compute/TeeTaskComputeSecretService.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@
2626
import org.springframework.jdbc.core.JdbcTemplate;
2727
import org.springframework.stereotype.Service;
2828

29+
import java.util.List;
2930
import java.util.Optional;
31+
import java.util.stream.Collectors;
3032

3133
@Slf4j
3234
@Service
@@ -77,6 +79,12 @@ public Optional<TeeTaskComputeSecret> getSecret(
7779
return Optional.of(decryptedSecret);
7880
}
7981

82+
public List<TeeTaskComputeSecret> getSecretsForTeeSession(Iterable<TeeTaskComputeSecretHeader> ids) {
83+
return teeTaskComputeSecretRepository.findAllById(ids).stream()
84+
.map(secret -> secret.withValue(encryptionService.decrypt(secret.getValue())))
85+
.collect(Collectors.toList());
86+
}
87+
8088
/**
8189
* Check whether a secret exists.
8290
*

src/main/java/com/iexec/sms/secret/web2/Web2SecretHeader.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public class Web2SecretHeader implements Serializable {
3434
private String ownerAddress;
3535
private String address; //0xdataset1, aws.amazon.com, beneficiary.key.iex.ec (Kb)
3636

37-
Web2SecretHeader(String ownerAddress, String address) {
37+
public Web2SecretHeader(String ownerAddress, String address) {
3838
Objects.requireNonNull(ownerAddress, "Web2 secret owner address can't be null.");
3939
Objects.requireNonNull(address, "Web2 secret address can't be null.");
4040

src/main/java/com/iexec/sms/secret/web2/Web2SecretService.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,10 @@
2626
import org.springframework.jdbc.core.JdbcTemplate;
2727
import org.springframework.stereotype.Service;
2828

29+
import java.util.List;
2930
import java.util.Objects;
3031
import java.util.Optional;
32+
import java.util.stream.Collectors;
3133

3234
@Slf4j
3335
@Service
@@ -68,6 +70,12 @@ public Optional<String> getDecryptedValue(String ownerAddress, String secretAddr
6870
.map(secret -> encryptionService.decrypt(secret.getValue()));
6971
}
7072

73+
public List<Web2Secret> getSecretsForTeeSession(Iterable<Web2SecretHeader> ids) {
74+
return web2SecretRepository.findAllById(ids).stream()
75+
.map(secret -> secret.withValue(encryptionService.decrypt(secret.getValue())))
76+
.collect(Collectors.toList());
77+
}
78+
7179
public boolean isSecretPresent(String ownerAddress, String secretAddress) {
7280
final Web2SecretHeader key = new Web2SecretHeader(ownerAddress, secretAddress);
7381
final Boolean found = cacheSecretService.lookSecretExistenceInCache(key);

src/main/java/com/iexec/sms/tee/TeeController.java

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2020-2023 IEXEC BLOCKCHAIN TECH
2+
* Copyright 2020-2024 IEXEC BLOCKCHAIN TECH
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -19,13 +19,13 @@
1919

2020
import com.iexec.common.web.ApiResponseBody;
2121
import com.iexec.commons.poco.chain.WorkerpoolAuthorization;
22+
import com.iexec.commons.poco.security.Signature;
2223
import com.iexec.commons.poco.tee.TeeFramework;
2324
import com.iexec.sms.api.TeeSessionGenerationError;
2425
import com.iexec.sms.api.TeeSessionGenerationResponse;
2526
import com.iexec.sms.api.config.TeeServicesProperties;
2627
import com.iexec.sms.authorization.AuthorizationError;
2728
import com.iexec.sms.authorization.AuthorizationService;
28-
import com.iexec.sms.tee.challenge.TeeChallenge;
2929
import com.iexec.sms.tee.challenge.TeeChallengeService;
3030
import com.iexec.sms.tee.session.TeeSessionService;
3131
import com.iexec.sms.tee.session.generic.TeeSessionGenerationException;
@@ -73,6 +73,7 @@ public TeeController(
7373

7474
/**
7575
* Return which TEE framework this SMS is configured to use.
76+
*
7677
* @return TEE framework this SMS is configured to use.
7778
*/
7879
@GetMapping("/framework")
@@ -100,15 +101,29 @@ public ResponseEntity<TeeServicesProperties> getTeeServicesProperties(
100101
}
101102

102103
/**
103-
* Called by the core, not the worker
104+
* Generates an enclave challenge for a PoCo task.
105+
* <p>
106+
* This method is called by the scheduler.
107+
*
108+
* @param authorization Authorization to check the query legitimacy
109+
* @param chainTaskId ID of the task the challenge will be produced for
110+
* @return The Ethereum address enclave challenge for the provided
104111
*/
105112
@PostMapping("/challenges/{chainTaskId}")
106-
public ResponseEntity<String> generateTeeChallenge(@PathVariable String chainTaskId) {
107-
Optional<TeeChallenge> executionChallenge =
108-
teeChallengeService.getOrCreate(chainTaskId, false);
109-
return executionChallenge
110-
.map(teeChallenge -> ResponseEntity
111-
.ok(teeChallenge.getCredentials().getAddress()))
113+
public ResponseEntity<String> generateTeeChallenge(@RequestHeader String authorization, @PathVariable String chainTaskId) {
114+
log.debug("generateTeeChallenge [authorization:{}, chainTaskId:{}]", authorization, chainTaskId);
115+
final Optional<AuthorizationError> authorizationError = authorizationService.isAuthorizedOnExecutionWithDetailedIssue(
116+
WorkerpoolAuthorization.builder()
117+
.chainTaskId(chainTaskId)
118+
.enclaveChallenge("")
119+
.workerWallet("")
120+
.signature(new Signature(authorization))
121+
.build());
122+
if (authorizationError.isPresent()) {
123+
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
124+
}
125+
return teeChallengeService.getOrCreate(chainTaskId, false)
126+
.map(teeChallenge -> ResponseEntity.ok(teeChallenge.getCredentials().getAddress()))
112127
.orElseGet(() -> ResponseEntity.notFound().build());
113128
}
114129

@@ -118,10 +133,12 @@ public ResponseEntity<String> generateTeeChallenge(@PathVariable String chainTas
118133
* to the enclave so the latter can talk to the CAS and get
119134
* the needed secrets.
120135
*
121-
* @return
122-
* 200 OK with the session id if success,
123-
* 404 NOT_FOUND if the task is not found,
124-
* 500 INTERNAL_SERVER_ERROR otherwise.
136+
* @return result
137+
* <ul>
138+
* <li>200 OK with the session id if success.
139+
* <li>404 NOT_FOUND if the task is not found.
140+
* <li>500 INTERNAL_SERVER_ERROR otherwise.
141+
* </ul>
125142
*/
126143
@PostMapping("/sessions")
127144
public ResponseEntity<ApiResponseBody<TeeSessionGenerationResponse, TeeSessionGenerationError>> generateTeeSession(
@@ -140,7 +157,7 @@ public ResponseEntity<ApiResponseBody<TeeSessionGenerationResponse, TeeSessionGe
140157
.body(body);
141158
}
142159
final Optional<AuthorizationError> authorizationError =
143-
authorizationService.isAuthorizedOnExecutionWithDetailedIssue(workerpoolAuthorization, true);
160+
authorizationService.isAuthorizedOnExecutionWithDetailedIssue(workerpoolAuthorization);
144161
if (authorizationError.isPresent()) {
145162
final TeeSessionGenerationError teeSessionGenerationError =
146163
authorizationToGenerationError.get(authorizationError.get());
@@ -170,7 +187,7 @@ public ResponseEntity<ApiResponseBody<TeeSessionGenerationResponse, TeeSessionGe
170187
return ResponseEntity.ok(ApiResponseBody.<TeeSessionGenerationResponse, TeeSessionGenerationError>builder()
171188
.data(teeSessionGenerationResponse)
172189
.build());
173-
} catch(TeeSessionGenerationException e) {
190+
} catch (TeeSessionGenerationException e) {
174191
log.error("Failed to generate secure session [taskId:{}, workerAddress:{}]",
175192
taskId, workerAddress, e);
176193
final ApiResponseBody<TeeSessionGenerationResponse, TeeSessionGenerationError> body =

0 commit comments

Comments
 (0)