Skip to content

Commit

Permalink
Add logs for better traceability (#675)
Browse files Browse the repository at this point in the history
  • Loading branch information
thewhitewizard authored Mar 15, 2024
1 parent 038f984 commit 475a2e2
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 2 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ All notable changes to this project will be documented in this file.
### Quality

- Prepare migration to `java.time` package by building `Date` objects from `Instant` objects. (#671)
- Add logs for better traceability. (#675)

## [[8.4.0]](https://github.com/iExecBlockchainComputing/iexec-core/releases/tag/v8.4.0) 2024-02-29

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import com.iexec.core.chain.BlockchainConnectionHealthIndicator;
import com.iexec.core.security.JwtTokenProvider;
import com.iexec.core.worker.WorkerService;
import com.iexec.core.worker.WorkerUtils;
import feign.FeignException;
import io.vavr.control.Either;
import lombok.extern.slf4j.Slf4j;
Expand Down Expand Up @@ -62,6 +63,7 @@ public ResponseEntity<ReplicateTaskSummary> getAvailableReplicateTaskSummary(
@RequestHeader("Authorization") String bearerToken) {
String workerWalletAddress = jwtTokenProvider.getWalletAddressFromBearerToken(bearerToken);
if (workerWalletAddress.isEmpty()) {
WorkerUtils.emitWarnOnUnAuthorizedAccess("");
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
}

Expand All @@ -70,8 +72,10 @@ public ResponseEntity<ReplicateTaskSummary> getAvailableReplicateTaskSummary(
" [workerAddress: {}]", workerWalletAddress);
return ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE).build();
}
log.debug("Worker requests replicate [workerAddress:{}]", workerWalletAddress);

if (!workerService.isWorkerAllowedToAskReplicate(workerWalletAddress)) {
log.debug("Worker is not allowed to ask replicate [workerAddress:{}]", workerWalletAddress);
return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
}
workerService.updateLastReplicateDemandDate(workerWalletAddress);
Expand All @@ -89,9 +93,11 @@ public ResponseEntity<List<TaskNotification>> getMissedTaskNotifications(

String workerWalletAddress = jwtTokenProvider.getWalletAddressFromBearerToken(bearerToken);
if (workerWalletAddress.isEmpty()) {
WorkerUtils.emitWarnOnUnAuthorizedAccess("");
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
}

log.debug("Worker asks for missed tasks [workerAddress:{}]", workerWalletAddress);
List<TaskNotification> missedTaskNotifications =
replicateSupplyService.getMissedTaskNotifications(blockNumber, workerWalletAddress);

Expand Down Expand Up @@ -120,6 +126,7 @@ public ResponseEntity<TaskNotificationType> updateReplicateStatus(
String walletAddress = jwtTokenProvider.getWalletAddressFromBearerToken(bearerToken);

if (walletAddress.isEmpty()) {
WorkerUtils.emitWarnOnUnAuthorizedAccess("");
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
}

Expand All @@ -142,6 +149,8 @@ public ResponseEntity<TaskNotificationType> updateReplicateStatus(
}
}

log.debug("Worker request to update a replicate status [workerAddress:{}, chainTaskId:{}, statusUpdate:{}]", walletAddress, chainTaskId, statusUpdate);

final Either<ReplicateStatusUpdateError, TaskNotificationType> updateResult = replicatesService
.updateReplicateStatus(chainTaskId, walletAddress, statusUpdate);
if (updateResult.isRight()) {
Expand Down
15 changes: 13 additions & 2 deletions src/main/java/com/iexec/core/worker/WorkerController.java
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -58,8 +58,10 @@ public WorkerController(WorkerService workerService,
public ResponseEntity<String> ping(@RequestHeader("Authorization") String bearerToken) {
String workerWalletAddress = jwtTokenProvider.getWalletAddressFromBearerToken(bearerToken);
if (workerWalletAddress.isEmpty()) {
WorkerUtils.emitWarnOnUnAuthorizedAccess("");
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
}
log.debug("Worker keepalive ping [workerAddress:{}]", workerWalletAddress);
final String publicConfigurationHash = publicConfigurationService.getPublicConfigurationHash();
workerService.updateLastAlive(workerWalletAddress);
return ok(publicConfigurationHash);
Expand All @@ -68,28 +70,34 @@ public ResponseEntity<String> ping(@RequestHeader("Authorization") String bearer
@GetMapping(path = "/workers/challenge")
public ResponseEntity<String> getChallenge(@RequestParam(name = "walletAddress") String walletAddress) {
if (!workerService.isAllowedToJoin(walletAddress)) {
WorkerUtils.emitWarnOnUnAuthorizedAccess(walletAddress);
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
}
log.debug("Worker challenge request [workerAddress:{}]", walletAddress);
return ok(challengeService.getChallenge(walletAddress));
}

@PostMapping(path = "/workers/login")
public ResponseEntity<String> getToken(@RequestParam(name = "walletAddress") String walletAddress,
@RequestBody Signature signature) {
if (!workerService.isAllowedToJoin(walletAddress)) {
WorkerUtils.emitWarnOnUnAuthorizedAccess(walletAddress);
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
}

log.debug("Worker login attempt [workerAddress:{}]", walletAddress);
String challenge = challengeService.getChallenge(walletAddress);
byte[] hashToCheck = Hash.sha3(BytesUtils.stringToBytes(challenge));

if (SignatureUtils.doesSignatureMatchesAddress(signature.getR(), signature.getS(),
BytesUtils.bytesToString(hashToCheck), walletAddress)) {
challengeService.removeChallenge(walletAddress, challenge);
String token = jwtTokenProvider.getOrCreateToken(walletAddress);
log.debug("Worker has successfully logged on [workerAddress:{}]", walletAddress);
return ok(token);
}

log.debug("Worker has failed to log in [workerAddress:{}]", walletAddress);
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
}

Expand All @@ -98,6 +106,7 @@ public ResponseEntity<Worker> registerWorker(@RequestHeader("Authorization") Str
@RequestBody WorkerModel model) {
String workerWalletAddress = jwtTokenProvider.getWalletAddressFromBearerToken(bearerToken);
if (workerWalletAddress.isEmpty()) {
WorkerUtils.emitWarnOnUnAuthorizedAccess("");
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
}

Expand Down Expand Up @@ -125,6 +134,7 @@ public ResponseEntity<Worker> registerWorker(@RequestHeader("Authorization") Str

@GetMapping(path = "/workers/config")
public ResponseEntity<PublicConfiguration> getPublicConfiguration() {
log.debug("Ask for the public configuration");
final PublicConfiguration config = publicConfigurationService.getPublicConfiguration();
return ok(config);
}
Expand All @@ -134,9 +144,10 @@ public ResponseEntity<PublicConfiguration> getPublicConfiguration() {
public ResponseEntity<List<String>> getComputingTasks(@RequestHeader("Authorization") String bearerToken) {
String workerWalletAddress = jwtTokenProvider.getWalletAddressFromBearerToken(bearerToken);
if (workerWalletAddress.isEmpty()) {
WorkerUtils.emitWarnOnUnAuthorizedAccess("");
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
}
log.debug("Worker requests for computing tasks ids [workerAddress:{}]", workerWalletAddress);
return ok(workerService.getComputingTaskIds(workerWalletAddress));
}

}
38 changes: 38 additions & 0 deletions src/main/java/com/iexec/core/worker/WorkerUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright 2024-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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.iexec.core.worker;

import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

@NoArgsConstructor(access = AccessLevel.PRIVATE)
@Slf4j
public class WorkerUtils {

/**
* Utility function to log a message in the event of unauthorized access
* Either because the worker is not whitelisted or because the worker address was not found in the JWT token
*
* @param workerWalletAddress Address of the worker who attempted access
*/
public static void emitWarnOnUnAuthorizedAccess(String workerWalletAddress) {
final String workerAddress = StringUtils.isEmpty(workerWalletAddress) ? "NotAvailable" : workerWalletAddress;
log.warn("Worker is not allowed to join this workerpool [workerAddress:{}]", workerAddress);
}
}
46 changes: 46 additions & 0 deletions src/test/java/com/iexec/core/worker/WorkerUtilsTests.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Copyright 2024-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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.iexec.core.worker;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.NullSource;
import org.junit.jupiter.params.provider.ValueSource;
import org.springframework.boot.test.system.CapturedOutput;
import org.springframework.boot.test.system.OutputCaptureExtension;

import static org.assertj.core.api.Assertions.assertThat;

@ExtendWith(OutputCaptureExtension.class)
class WorkerUtilsTests {

@Test
void testEmitOnErrorWithWorkerAddress(CapturedOutput output) {
final String workerAddress = "0x9d693a8fd049c607a6";
WorkerUtils.emitWarnOnUnAuthorizedAccess(workerAddress);
assertThat(output.getOut()).contains("Worker is not allowed to join this workerpool [workerAddress:0x9d693a8fd049c607a6]");
}

@ParameterizedTest
@NullSource
@ValueSource(strings = {""})
void testEmitOnErrorWithEmptyWorkerAddress(String value, CapturedOutput output) {
WorkerUtils.emitWarnOnUnAuthorizedAccess(value);
assertThat(output.getOut()).contains("Worker is not allowed to join this workerpool [workerAddress:NotAvailable]");
}
}

0 comments on commit 475a2e2

Please sign in to comment.