Skip to content

Commit 2811256

Browse files
authored
Generate enclave challenge with Authorization header after on-chain task has been initialized (#686)
1 parent 1d56278 commit 2811256

File tree

6 files changed

+78
-70
lines changed

6 files changed

+78
-70
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ All notable changes to this project will be documented in this file.
77
### New Features
88

99
- Add `ConsensusReachedTaskDetector` to detect missed `TaskConsensus` on-chain events. (#683 #684)
10+
- Generate enclave challenge with `Authorization` header after on-chain task has been initialized. (#686)
1011

1112
### Bug Fixes
1213

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ iexecCommonVersion=8.4.0
33
iexecCommonsPocoVersion=3.2.0
44
iexecBlockchainAdapterVersion=8.4.0
55
iexecResultVersion=8.4.0
6-
iexecSmsVersion=8.5.0
6+
iexecSmsVersion=8.5.0-NEXT-SNAPSHOT
77

88
nexusUser
99
nexusPassword

src/main/java/com/iexec/core/sms/SmsService.java

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import com.iexec.commons.poco.tee.TeeFramework;
2020
import com.iexec.commons.poco.tee.TeeUtils;
2121
import com.iexec.commons.poco.utils.BytesUtils;
22+
import com.iexec.core.chain.SignatureService;
2223
import com.iexec.core.registry.PlatformRegistryConfiguration;
2324
import com.iexec.sms.api.SmsClient;
2425
import com.iexec.sms.api.SmsClientProvider;
@@ -29,16 +30,18 @@
2930

3031
import java.util.Optional;
3132

32-
3333
@Slf4j
3434
@Service
3535
public class SmsService {
3636
private final PlatformRegistryConfiguration registryConfiguration;
37+
private final SignatureService signatureService;
3738
private final SmsClientProvider smsClientProvider;
3839

3940
public SmsService(PlatformRegistryConfiguration registryConfiguration,
41+
SignatureService signatureService,
4042
SmsClientProvider smsClientProvider) {
4143
this.registryConfiguration = registryConfiguration;
44+
this.signatureService = signatureService;
4245
this.smsClientProvider = smsClientProvider;
4346
}
4447

@@ -54,7 +57,7 @@ public SmsService(PlatformRegistryConfiguration registryConfiguration,
5457
*
5558
* @param chainTaskId ID of the on-chain task.
5659
* @param tag Tag of the deal.
57-
* @return SMS url if TEE types of tag & SMS match.
60+
* @return SMS url if TEE types of tag & SMS match.
5861
*/
5962
public Optional<String> getVerifiedSmsUrl(String chainTaskId, String tag) {
6063
final TeeFramework teeFrameworkForDeal = TeeUtils.getTeeFramework(tag);
@@ -124,11 +127,13 @@ Optional<String> generateEnclaveChallenge(String chainTaskId, String smsUrl) {
124127
final SmsClient smsClient = smsClientProvider.getSmsClient(smsUrl);
125128

126129
try {
127-
final String teeChallengePublicKey = smsClient.generateTeeChallenge(chainTaskId);
130+
final String teeChallengePublicKey = smsClient.generateTeeChallenge(
131+
signatureService.createAuthorization("", chainTaskId, "").getSignature().getValue(),
132+
chainTaskId);
128133

129134
if (StringUtils.isEmpty(teeChallengePublicKey)) {
130-
log.error("An error occurred while getting teeChallengePublicKey "
131-
+ "[chainTaskId:{}, smsUrl:{}]", chainTaskId, smsUrl);
135+
log.error("An error occurred while getting teeChallengePublicKey [chainTaskId:{}, smsUrl:{}]",
136+
chainTaskId, smsUrl);
132137
return Optional.empty();
133138
}
134139

src/main/java/com/iexec/core/task/update/TaskUpdateManager.java

Lines changed: 40 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,7 @@ void received2Initializing(Task task) {
229229
}
230230

231231
final Update update = new Update();
232+
// First check on SMS URL before submitting transaction to fail fast
232233
if (task.isTeeTask()) {
233234
final Optional<String> smsUrl = smsService.getVerifiedSmsUrl(task.getChainTaskId(), task.getTag());
234235
if (smsUrl.isEmpty()) {
@@ -239,14 +240,6 @@ void received2Initializing(Task task) {
239240
task.setSmsUrl(smsUrl.get()); //SMS URL source of truth for the task
240241
update.set("smsUrl", smsUrl.get());
241242
}
242-
final Optional<String> enclaveChallenge = smsService.getEnclaveChallenge(task.getChainTaskId(), task.getSmsUrl());
243-
if (enclaveChallenge.isEmpty()) {
244-
log.error("Can't initialize task, enclave challenge is empty [chainTaskId:{}]", task.getChainTaskId());
245-
toFailed(task, INITIALIZE_FAILED);
246-
return;
247-
}
248-
task.setEnclaveChallenge(enclaveChallenge.get());
249-
update.set("enclaveChallenge", enclaveChallenge.get());
250243
taskService.updateTask(task.getChainTaskId(), task.getCurrentStatus(), update);
251244

252245
blockchainAdapterService
@@ -272,24 +265,34 @@ void initializing2Initialized(Task task) {
272265
return;
273266
}
274267
// TODO: the block where initialization happened can be found
275-
blockchainAdapterService
276-
.isInitialized(task.getChainTaskId())
277-
.ifPresentOrElse(isSuccess -> {
278-
if (Boolean.TRUE.equals(isSuccess)) {
279-
log.info("Initialized on blockchain (tx mined) [chainTaskId:{}]",
280-
task.getChainTaskId());
281-
//Without receipt, using deal block for initialization block
282-
task.setInitializationBlockNumber(task.getDealBlockNumber());
283-
replicatesService.createEmptyReplicateList(task.getChainTaskId());
284-
updateTaskStatusAndSave(task, INITIALIZED, null);
285-
return;
286-
}
287-
log.error("Initialization failed on blockchain (tx reverted) [chainTaskId:{}]",
288-
task.getChainTaskId());
289-
toFailed(task, INITIALIZE_FAILED);
290-
}, () -> log.error("Unable to check initialization on blockchain " +
291-
"(likely too long), should use a detector [chainTaskId:{}]",
292-
task.getChainTaskId()));
268+
final Optional<Boolean> isInitialized = blockchainAdapterService.isInitialized(task.getChainTaskId());
269+
if (isInitialized.isEmpty()) {
270+
log.error("Unable to check initialization on blockchain (likely too long), should use a detector [chainTaskId:{}]",
271+
task.getChainTaskId());
272+
} else if (Boolean.TRUE.equals(isInitialized.get())) {
273+
log.info("Initialized on blockchain (tx mined) [chainTaskId:{}]", task.getChainTaskId());
274+
final Update update = new Update();
275+
// Without receipt, using deal block for initialization block
276+
task.setInitializationBlockNumber(task.getDealBlockNumber());
277+
update.set("initializationBlockNumber", task.getDealBlockNumber());
278+
279+
// Create enclave challenge after task has been initialized on-chain
280+
final Optional<String> enclaveChallenge = smsService.getEnclaveChallenge(task.getChainTaskId(), task.getSmsUrl());
281+
if (enclaveChallenge.isEmpty()) {
282+
log.error("Can't initialize task, enclave challenge is empty [chainTaskId:{}]", task.getChainTaskId());
283+
toFailed(task, INITIALIZE_FAILED);
284+
return;
285+
}
286+
task.setEnclaveChallenge(enclaveChallenge.get());
287+
update.set("enclaveChallenge", enclaveChallenge.get());
288+
taskService.updateTask(task.getChainTaskId(), task.getCurrentStatus(), update);
289+
290+
replicatesService.createEmptyReplicateList(task.getChainTaskId());
291+
updateTaskStatusAndSave(task, INITIALIZED, null);
292+
} else {
293+
log.error("Initialization failed on blockchain (tx reverted) [chainTaskId:{}]", task.getChainTaskId());
294+
toFailed(task, INITIALIZE_FAILED);
295+
}
293296
}
294297

295298
void initialized2Running(Task task, ChainTask chainTask) {
@@ -676,21 +679,17 @@ void finalizing2Finalized2Completed(Task task) {
676679
emitError(task, FINALIZING, "finalizing2Finalized2Completed");
677680
return;
678681
}
679-
blockchainAdapterService
680-
.isFinalized(task.getChainTaskId())
681-
.ifPresentOrElse(isSuccess -> {
682-
if (Boolean.TRUE.equals(isSuccess)) {
683-
log.info("Finalized on blockchain (tx mined) [chainTaskId:{}]",
684-
task.getChainTaskId());
685-
toFinalizedToCompleted(task);
686-
return;
687-
}
688-
log.error("Finalization failed on blockchain (tx reverted) [chainTaskId:{}]",
689-
task.getChainTaskId());
690-
toFailed(task, FINALIZE_FAILED);
691-
}, () -> log.error("Unable to check finalization on blockchain " +
692-
"(likely too long), should use a detector [chainTaskId:{}]",
693-
task.getChainTaskId()));
682+
final Optional<Boolean> isFinalized = blockchainAdapterService.isFinalized(task.getChainTaskId());
683+
if (isFinalized.isEmpty()) {
684+
log.error("Unable to check finalization on blockchain (likely too long), should use a detector [chainTaskId:{}]",
685+
task.getChainTaskId());
686+
} else if (Boolean.TRUE.equals(isFinalized.get())) {
687+
log.info("Finalized on blockchain (tx mined) [chainTaskId:{}]", task.getChainTaskId());
688+
toFinalizedToCompleted(task);
689+
} else {
690+
log.error("Finalization failed on blockchain (tx reverted) [chainTaskId:{}]", task.getChainTaskId());
691+
toFailed(task, FINALIZE_FAILED);
692+
}
694693
}
695694

696695
void finalizedToCompleted(Task task) {

src/test/java/com/iexec/core/sms/SmsServiceTests.java

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,12 @@
1616

1717
package com.iexec.core.sms;
1818

19+
import com.iexec.commons.poco.chain.WorkerpoolAuthorization;
20+
import com.iexec.commons.poco.security.Signature;
1921
import com.iexec.commons.poco.tee.TeeFramework;
2022
import com.iexec.commons.poco.tee.TeeUtils;
2123
import com.iexec.commons.poco.utils.BytesUtils;
24+
import com.iexec.core.chain.SignatureService;
2225
import com.iexec.core.registry.PlatformRegistryConfiguration;
2326
import com.iexec.sms.api.SmsClient;
2427
import com.iexec.sms.api.SmsClientProvider;
@@ -42,14 +45,16 @@
4245

4346
class SmsServiceTests {
4447

48+
private static final String AUTHORIZATION = "authorization";
4549
private static final String GRAMINE_SMS_URL = "http://gramine-sms";
4650
private static final String SCONE_SMS_URL = "http://scone-sms";
4751
private static final String CHAIN_TASK_ID = "chainTaskId";
4852
private static final String url = "url";
4953

54+
@Mock
55+
private SignatureService signatureService;
5056
@Mock
5157
private SmsClient smsClient;
52-
5358
@Mock
5459
private SmsClientProvider smsClientProvider;
5560
@Mock
@@ -63,6 +68,8 @@ void init() {
6368
MockitoAnnotations.openMocks(this);
6469
when(registryConfiguration.getSconeSms()).thenReturn(SCONE_SMS_URL);
6570
when(registryConfiguration.getGramineSms()).thenReturn(GRAMINE_SMS_URL);
71+
when(signatureService.createAuthorization("", CHAIN_TASK_ID, ""))
72+
.thenReturn(WorkerpoolAuthorization.builder().signature(new Signature(AUTHORIZATION)).build());
6673
}
6774

6875
// region isSmsClientReady
@@ -119,34 +126,30 @@ void shouldNotGetVerifiedSmsUrlSinceWrongTeeEnclaveProviderOnRemoteSms() {
119126
// region getEnclaveChallenge
120127
@Test
121128
void shouldGetEmptyAddressForStandardTask() {
122-
when(smsClientProvider.getSmsClient(url)).thenReturn(smsClient);
123-
when(smsClient.generateTeeChallenge(CHAIN_TASK_ID)).thenReturn("");
124-
125129
Assertions.assertThat(smsService.getEnclaveChallenge(CHAIN_TASK_ID, ""))
126-
.get()
127-
.isEqualTo(BytesUtils.EMPTY_ADDRESS);
128-
verify(smsClient, never()).generateTeeChallenge(anyString());
130+
.isEqualTo(Optional.of(BytesUtils.EMPTY_ADDRESS));
131+
132+
verifyNoInteractions(smsClientProvider, smsClient);
129133
}
130134

131135
@Test
132136
void shouldGetEnclaveChallengeForTeeTask() {
133137
String expected = "challenge";
134138
when(smsClientProvider.getSmsClient(url)).thenReturn(smsClient);
135-
when(smsClient.generateTeeChallenge(CHAIN_TASK_ID)).thenReturn(expected);
139+
when(smsClient.generateTeeChallenge(AUTHORIZATION, CHAIN_TASK_ID)).thenReturn(expected);
136140

137141
Optional<String> received = smsService.getEnclaveChallenge(CHAIN_TASK_ID, url);
138-
verify(smsClient).generateTeeChallenge(CHAIN_TASK_ID);
142+
verify(smsClient).generateTeeChallenge(AUTHORIZATION, CHAIN_TASK_ID);
139143
Assertions.assertThat(received)
140-
.get()
141-
.isEqualTo(expected);
144+
.isEqualTo(Optional.of(expected));
142145
}
143146

144147
@Test
145148
void shouldNotGetEnclaveChallengeForTeeTaskWhenEmptySmsResponse() {
146149
when(smsClientProvider.getSmsClient(url)).thenReturn(smsClient);
147-
when(smsClient.generateTeeChallenge(CHAIN_TASK_ID)).thenReturn("");
150+
when(smsClient.generateTeeChallenge(AUTHORIZATION, CHAIN_TASK_ID)).thenReturn("");
148151
Optional<String> received = smsService.getEnclaveChallenge(CHAIN_TASK_ID, url);
149-
verify(smsClient).generateTeeChallenge(CHAIN_TASK_ID);
152+
verify(smsClient).generateTeeChallenge(AUTHORIZATION, CHAIN_TASK_ID);
150153
Assertions.assertThat(received).isEmpty();
151154
}
152155
// endregion
@@ -157,7 +160,7 @@ void shouldGenerateEnclaveChallenge() {
157160
final String expected = "challenge";
158161

159162
when(smsClientProvider.getSmsClient(url)).thenReturn(smsClient);
160-
when(smsClient.generateTeeChallenge(CHAIN_TASK_ID)).thenReturn(expected);
163+
when(smsClient.generateTeeChallenge(AUTHORIZATION, CHAIN_TASK_ID)).thenReturn(expected);
161164

162165
Optional<String> received = smsService.generateEnclaveChallenge(CHAIN_TASK_ID, url);
163166
Assertions.assertThat(received)
@@ -167,7 +170,7 @@ void shouldGenerateEnclaveChallenge() {
167170
@Test
168171
void shouldNotGenerateEnclaveChallengeSinceNoPublicKeyReturned() {
169172
when(smsClientProvider.getSmsClient(url)).thenReturn(smsClient);
170-
when(smsClient.generateTeeChallenge(CHAIN_TASK_ID)).thenReturn("");
173+
when(smsClient.generateTeeChallenge(AUTHORIZATION, CHAIN_TASK_ID)).thenReturn("");
171174

172175
Optional<String> received = smsService.generateEnclaveChallenge(CHAIN_TASK_ID, url);
173176
Assertions.assertThat(received)
@@ -177,7 +180,7 @@ void shouldNotGenerateEnclaveChallengeSinceNoPublicKeyReturned() {
177180
@Test
178181
void shouldNotGenerateEnclaveChallengeSinceFeignException() {
179182
when(smsClientProvider.getSmsClient(url)).thenReturn(smsClient);
180-
when(smsClient.generateTeeChallenge(CHAIN_TASK_ID)).thenThrow(FeignException.GatewayTimeout.class);
183+
when(smsClient.generateTeeChallenge(AUTHORIZATION, CHAIN_TASK_ID)).thenThrow(FeignException.GatewayTimeout.class);
181184

182185
Optional<String> received = smsService.generateEnclaveChallenge(CHAIN_TASK_ID, url);
183186
Assertions.assertThat(received)
@@ -187,7 +190,7 @@ void shouldNotGenerateEnclaveChallengeSinceFeignException() {
187190
@Test
188191
void shouldNotGenerateEnclaveChallengeSinceRuntimeException() {
189192
when(smsClientProvider.getSmsClient(url)).thenReturn(smsClient);
190-
when(smsClient.generateTeeChallenge(CHAIN_TASK_ID)).thenThrow(RuntimeException.class);
193+
when(smsClient.generateTeeChallenge(AUTHORIZATION, CHAIN_TASK_ID)).thenThrow(RuntimeException.class);
191194

192195
Optional<String> received = smsService.generateEnclaveChallenge(CHAIN_TASK_ID, url);
193196
Assertions.assertThat(received)

src/test/java/com/iexec/core/task/update/TaskUpdateManagerTest.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,6 @@ static void registerProperties(DynamicPropertyRegistry registry) {
111111
@Mock
112112
private SmsService smsService;
113113

114-
private TaskService taskService;
115114
private TaskUpdateManager taskUpdateManager;
116115

117116
@Captor
@@ -126,10 +125,10 @@ static void initRegistry() {
126125
void init() {
127126
MockitoAnnotations.openMocks(this);
128127
taskRepository.deleteAll();
129-
taskService = new TaskService(mongoTemplate, taskRepository, iexecHubService, applicationEventPublisher);
128+
final TaskService taskService = new TaskService(mongoTemplate, taskRepository, iexecHubService, applicationEventPublisher);
130129
taskUpdateManager = new TaskUpdateManager(taskService, iexecHubService, replicatesService, applicationEventPublisher,
131130
workerService, blockchainAdapterService, smsService);
132-
ChainTask chainTask = ChainTask.builder().chainTaskId(CHAIN_TASK_ID).status(ChainTaskStatus.ACTIVE).build();
131+
final ChainTask chainTask = ChainTask.builder().chainTaskId(CHAIN_TASK_ID).status(ChainTaskStatus.ACTIVE).build();
133132
when(iexecHubService.getChainTask(CHAIN_TASK_ID)).thenReturn(Optional.of(chainTask));
134133
}
135134

@@ -329,15 +328,15 @@ void shouldNotUpdateReceived2InitializingSinceAfterContributionDeadline() {
329328
@Test
330329
void shouldNotUpdateReceived2InitializingSinceNoSmsClient() {
331330
final Task task = getStubTask();
331+
task.setTag(TeeUtils.TEE_SCONE_ONLY_TAG);
332332
taskRepository.save(task);
333333

334334
when(iexecHubService.hasEnoughGas()).thenReturn(true);
335335
when(iexecHubService.isTaskInUnsetStatusOnChain(CHAIN_DEAL_ID, 0)).thenReturn(true);
336336
when(iexecHubService.isBeforeContributionDeadline(task.getChainDealId()))
337337
.thenReturn(true);
338338
when(blockchainAdapterService.requestInitialize(CHAIN_DEAL_ID, 0)).thenReturn(Optional.of(CHAIN_TASK_ID));
339-
when(smsService.getVerifiedSmsUrl(CHAIN_TASK_ID, task.getTag()))
340-
.thenReturn(Optional.of(smsUrl));
339+
when(smsService.getVerifiedSmsUrl(CHAIN_TASK_ID, task.getTag())).thenReturn(Optional.empty());
341340

342341
taskUpdateManager.updateTask(CHAIN_TASK_ID);
343342
final Task resultTask = taskRepository.findByChainTaskId(task.getChainTaskId()).orElseThrow();
@@ -380,7 +379,7 @@ void shouldUpdateInitializing2InitializeFailedSinceEnclaveChallengeIsEmpty() {
380379
taskUpdateManager.updateTask(task.getChainTaskId());
381380

382381
final Task resultTask = taskRepository.findByChainTaskId(task.getChainTaskId()).orElseThrow();
383-
assertThatTaskContainsStatuses(resultTask, FAILED, List.of(RECEIVED, INITIALIZE_FAILED, FAILED));
382+
assertThatTaskContainsStatuses(resultTask, FAILED, List.of(RECEIVED, INITIALIZING, INITIALIZE_FAILED, FAILED));
384383
}
385384

386385
@Test
@@ -481,6 +480,7 @@ void shouldUpdateInitializing2Initialized() {
481480
taskRepository.save(task);
482481

483482
when(blockchainAdapterService.isInitialized(CHAIN_TASK_ID)).thenReturn(Optional.of(true));
483+
when(smsService.getEnclaveChallenge(CHAIN_TASK_ID, null)).thenReturn(Optional.of(BytesUtils.EMPTY_ADDRESS));
484484

485485
taskUpdateManager.updateTask(CHAIN_TASK_ID);
486486
final Task resultTask = taskRepository.findByChainTaskId(task.getChainTaskId()).orElseThrow();

0 commit comments

Comments
 (0)