Peer certificate check when adding

This commit is contained in:
2025-04-25 10:48:55 +02:00
parent f43c6db4f0
commit bed55162d7
21 changed files with 160 additions and 111 deletions

View File

@@ -67,14 +67,14 @@ public class DhfsFuseIT {
var c1curl = container1.execInContainer("/bin/sh", "-c",
"curl --header \"Content-Type: application/json\" " +
" --request PUT " +
" --data '{\"uuid\":\"" + c2uuid + "\"}' " +
" http://localhost:8080/peers-manage/known-peers");
" --data '{}' " +
" http://localhost:8080/peers-manage/known-peers/" + c2uuid);
var c2curl = container2.execInContainer("/bin/sh", "-c",
"curl --header \"Content-Type: application/json\" " +
" --request PUT " +
" --data '{\"uuid\":\"" + c1uuid + "\"}' " +
" http://localhost:8080/peers-manage/known-peers");
" --data '{}' " +
" http://localhost:8080/peers-manage/known-peers/" + c1uuid);
waitingConsumer2.waitUntil(frame -> frame.getUtf8String().contains("Connected"), 60, TimeUnit.SECONDS);
waitingConsumer1.waitUntil(frame -> frame.getUtf8String().contains("Connected"), 60, TimeUnit.SECONDS);

View File

@@ -93,26 +93,26 @@ public class DhfsFusex3IT {
var c1curl = container1.execInContainer("/bin/sh", "-c",
"curl --header \"Content-Type: application/json\" " +
" --request PUT " +
" --data '{\"uuid\":\"" + c2uuid + "\"}' " +
" http://localhost:8080/peers-manage/known-peers");
" --data '{}' " +
" http://localhost:8080/peers-manage/known-peers/" + c2uuid);
var c2curl1 = container2.execInContainer("/bin/sh", "-c",
"curl --header \"Content-Type: application/json\" " +
" --request PUT " +
" --data '{\"uuid\":\"" + c1uuid + "\"}' " +
" http://localhost:8080/peers-manage/known-peers");
" --data '{}' " +
" http://localhost:8080/peers-manage/known-peers/" + c1uuid);
var c2curl3 = container2.execInContainer("/bin/sh", "-c",
"curl --header \"Content-Type: application/json\" " +
" --request PUT " +
" --data '{\"uuid\":\"" + c3uuid + "\"}' " +
" http://localhost:8080/peers-manage/known-peers");
" --data '{}' " +
" http://localhost:8080/peers-manage/known-peers/" + c3uuid);
var c3curl = container3.execInContainer("/bin/sh", "-c",
"curl --header \"Content-Type: application/json\" " +
" --request PUT " +
" --data '{\"uuid\":\"" + c2uuid + "\"}' " +
" http://localhost:8080/peers-manage/known-peers");
" --data '{}' " +
" http://localhost:8080/peers-manage/known-peers/" + c2uuid);
waitingConsumer3.waitUntil(frame -> frame.getUtf8String().contains("Connected"), 60, TimeUnit.SECONDS, 2);
waitingConsumer2.waitUntil(frame -> frame.getUtf8String().contains("Connected"), 60, TimeUnit.SECONDS, 2);

View File

@@ -78,6 +78,7 @@ public class DhfsImage implements Future<String> {
"-Ddhfs.objects.sync.timeout=30",
"-Ddhfs.objects.sync.ping.timeout=5",
"-Ddhfs.objects.reconnect_interval=1s",
"-Ddhfs.sync.cert-check=false",
"-Dquarkus.log.category.\"com.usatiuk\".level=TRACE",
"-Dquarkus.log.category.\"com.usatiuk.dhfs\".level=TRACE",
"-Dquarkus.log.category.\"com.usatiuk.objects.transaction\".level=INFO",

View File

@@ -81,14 +81,14 @@ public class KillIT {
var c1curl = container1.execInContainer("/bin/sh", "-c",
"curl --header \"Content-Type: application/json\" " +
" --request PUT " +
" --data '{\"uuid\":\"" + c2uuid + "\"}' " +
" http://localhost:8080/peers-manage/known-peers");
" --data '{}' " +
" http://localhost:8080/peers-manage/known-peers/" + c2uuid);
var c2curl = container2.execInContainer("/bin/sh", "-c",
"curl --header \"Content-Type: application/json\" " +
" --request PUT " +
" --data '{\"uuid\":\"" + c1uuid + "\"}' " +
" http://localhost:8080/peers-manage/known-peers");
" --data '{}' " +
" http://localhost:8080/peers-manage/known-peers/" + c1uuid);
waitingConsumer2.waitUntil(frame -> frame.getUtf8String().contains("Connected"), 60, TimeUnit.SECONDS);
waitingConsumer1.waitUntil(frame -> frame.getUtf8String().contains("Connected"), 60, TimeUnit.SECONDS);

View File

@@ -93,14 +93,14 @@ public class LazyFsIT {
var c1curl = container1.execInContainer("/bin/sh", "-c",
"curl --header \"Content-Type: application/json\" " +
" --request PUT " +
" --data '{\"uuid\":\"" + c2uuid + "\"}' " +
" http://localhost:8080/peers-manage/known-peers");
" --data '{}' " +
" http://localhost:8080/peers-manage/known-peers/"+c2uuid);
var c2curl = container2.execInContainer("/bin/sh", "-c",
"curl --header \"Content-Type: application/json\" " +
" --request PUT " +
" --data '{\"uuid\":\"" + c1uuid + "\"}' " +
" http://localhost:8080/peers-manage/known-peers");
" --data '{}' " +
" http://localhost:8080/peers-manage/known-peers/"+c1uuid);
waitingConsumer2.waitUntil(frame -> frame.getUtf8String().contains("Connected"), 60, TimeUnit.SECONDS);
waitingConsumer1.waitUntil(frame -> frame.getUtf8String().contains("Connected"), 60, TimeUnit.SECONDS);

View File

@@ -75,14 +75,14 @@ public class ResyncIT {
var c1curl = container1.execInContainer("/bin/sh", "-c",
"curl --header \"Content-Type: application/json\" " +
" --request PUT " +
" --data '{\"uuid\":\"" + c2uuid + "\"}' " +
" http://localhost:8080/peers-manage/known-peers");
" --data '{}' " +
" http://localhost:8080/peers-manage/known-peers/" + c2uuid);
var c2curl = container2.execInContainer("/bin/sh", "-c",
"curl --header \"Content-Type: application/json\" " +
" --request PUT " +
" --data '{\"uuid\":\"" + c1uuid + "\"}' " +
" http://localhost:8080/peers-manage/known-peers");
" --data '{}' " +
" http://localhost:8080/peers-manage/known-peers/" + c1uuid);
waitingConsumer2.waitUntil(frame -> frame.getUtf8String().contains("Connected"), 60, TimeUnit.SECONDS);
waitingConsumer1.waitUntil(frame -> frame.getUtf8String().contains("Connected"), 60, TimeUnit.SECONDS);
@@ -115,14 +115,14 @@ public class ResyncIT {
var c1curl = container1.execInContainer("/bin/sh", "-c",
"curl --header \"Content-Type: application/json\" " +
" --request PUT " +
" --data '{\"uuid\":\"" + c2uuid + "\"}' " +
" http://localhost:8080/peers-manage/known-peers");
" --data '{}' " +
" http://localhost:8080/peers-manage/known-peers/" + c2uuid);
var c2curl = container2.execInContainer("/bin/sh", "-c",
"curl --header \"Content-Type: application/json\" " +
" --request PUT " +
" --data '{\"uuid\":\"" + c1uuid + "\"}' " +
" http://localhost:8080/peers-manage/known-peers");
" --data '{}' " +
" http://localhost:8080/peers-manage/known-peers/" + c1uuid);
waitingConsumer2.waitUntil(frame -> frame.getUtf8String().contains("Connected"), 60, TimeUnit.SECONDS);
waitingConsumer1.waitUntil(frame -> frame.getUtf8String().contains("Connected"), 60, TimeUnit.SECONDS);

View File

@@ -2,6 +2,7 @@ package com.usatiuk.dhfs.peersync;
import com.usatiuk.dhfs.peerdiscovery.PeerAddress;
import com.usatiuk.dhfs.peerdiscovery.PeerDiscoveryDirectory;
import com.usatiuk.dhfs.peersync.api.ApiPeerInfo;
import com.usatiuk.dhfs.peersync.api.PeerSyncApiClientDynamic;
import com.usatiuk.dhfs.peertrust.PeerTrustManager;
import com.usatiuk.dhfs.remoteobj.SyncHandler;
@@ -13,11 +14,13 @@ import io.quarkus.logging.Log;
import io.quarkus.runtime.StartupEvent;
import io.quarkus.scheduler.Scheduled;
import io.smallrye.common.annotation.Blocking;
import jakarta.annotation.Nullable;
import jakarta.annotation.Priority;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.event.Observes;
import jakarta.enterprise.inject.Instance;
import jakarta.inject.Inject;
import org.apache.commons.lang3.tuple.Pair;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import java.io.IOException;
@@ -47,6 +50,8 @@ public class PeerManager {
PeerTrustManager peerTrustManager;
@ConfigProperty(name = "dhfs.objects.sync.ping.timeout")
long pingTimeout;
@ConfigProperty(name = "dhfs.sync.cert-check", defaultValue = "true")
boolean certCheck;
@Inject
PeerDiscoveryDirectory peerDiscoveryDirectory;
@Inject
@@ -185,24 +190,39 @@ public class PeerManager {
return peerDiscoveryDirectory.getForPeer(host).stream().min(Comparator.comparing(PeerAddress::type));
}
public void addRemoteHost(PeerId host) {
transactionManager.run(() -> {
private ApiPeerInfo getInfo(PeerId host) {
return transactionManager.run(() -> {
if (peerInfoService.getPeerInfo(host).isPresent())
throw new IllegalStateException("Host " + host + " is already added");
var addr = selectBestAddress(host).orElseThrow(() -> new IllegalStateException("Host " + host + " is unreachable"));
var info = peerSyncApiClient.getSelfInfo(addr);
var cert = Base64.getDecoder().decode(info.cert());
peerInfoService.putPeer(host, cert);
return info;
});
}
public void addRemoteHost(PeerId host, @Nullable String cert) {
transactionManager.run(() -> {
var info = getInfo(host);
var certGot = Base64.getDecoder().decode(info.cert());
if (certCheck) {
var certApi = Base64.getDecoder().decode(cert);
if (!Arrays.equals(certGot, certApi))
throw new IllegalStateException("Host " + host + " has different cert");
}
peerInfoService.putPeer(host, certGot);
});
peerTrustManager.reloadTrustManagerHosts(transactionManager.run(() -> peerInfoService.getPeers().stream().toList())); //FIXME:
}
public Collection<PeerId> getSeenButNotAddedHosts() {
public Collection<Pair<PeerId, ApiPeerInfo>> getSeenButNotAddedHosts() {
return transactionManager.run(() -> {
return peerDiscoveryDirectory.getReachablePeers().stream().filter(p -> !peerInfoService.getPeerInfo(p).isPresent()).toList();
return peerDiscoveryDirectory.getReachablePeers().stream().filter(p -> !peerInfoService.getPeerInfo(p).isPresent())
.map(p -> Pair.of(p, getInfo(p))).toList();
});
}

View File

@@ -1,4 +0,0 @@
package com.usatiuk.dhfs.webapi;
public record KnownPeerDelete(String uuid) {
}

View File

@@ -1,6 +0,0 @@
package com.usatiuk.dhfs.webapi;
import jakarta.annotation.Nullable;
public record KnownPeerInfo(String uuid, @Nullable String knownAddress) {
}

View File

@@ -1,4 +1,6 @@
package com.usatiuk.dhfs.webapi;
public record KnownPeerPut(String uuid) {
import jakarta.annotation.Nullable;
public record KnownPeerPut(@Nullable String cert) {
}

View File

@@ -1,6 +0,0 @@
package com.usatiuk.dhfs.webapi;
import java.util.List;
public record KnownPeers(List<KnownPeerInfo> peers, String selfUuid) {
}

View File

@@ -1,4 +1,6 @@
package com.usatiuk.dhfs.webapi;
public record PeerInfo(String uuid, String address) {
import jakarta.annotation.Nullable;
public record PeerInfo(String uuid, String cert, @Nullable String knownAddress) {
}

View File

@@ -5,14 +5,9 @@ import com.usatiuk.dhfs.peersync.PeerInfoService;
import com.usatiuk.dhfs.peersync.PeerManager;
import com.usatiuk.dhfs.peersync.PersistentPeerDataService;
import jakarta.inject.Inject;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.*;
import java.util.Collection;
import java.util.Objects;
import java.util.Optional;
import java.util.*;
@Path("/peers-manage")
public class PeerManagementApi {
@@ -25,43 +20,30 @@ public class PeerManagementApi {
@Path("known-peers")
@GET
public KnownPeers knownPeers() {
return new KnownPeers(peerInfoService.getPeers().stream().map(peerInfo -> new KnownPeerInfo(peerInfo.id().toString(),
Optional.ofNullable(peerManager.getAddress(peerInfo.id())).map(Objects::toString).orElse(null))).toList(),
persistentPeerDataService.getSelfUuid().toString());
public List<PeerInfo> knownPeers() {
return peerInfoService.getPeers().stream().map(
peerInfo -> new PeerInfo(peerInfo.id().toString(), Base64.getEncoder().encodeToString(peerInfo.cert().toByteArray()),
Optional.ofNullable(peerManager.getAddress(peerInfo.id())).map(Objects::toString).orElse(null))).toList();
}
@Path("known-peers")
@Path("known-peers/{peerId}")
@PUT
public void addPeer(KnownPeerPut knownPeerPut) {
peerManager.addRemoteHost(PeerId.of(knownPeerPut.uuid()));
public void addPeer(@PathParam("peerId") String peerId, KnownPeerPut knownPeerPut) {
peerManager.addRemoteHost(PeerId.of(peerId), knownPeerPut.cert());
}
@Path("known-peers")
@Path("known-peers/{peerId}")
@DELETE
public void deletePeer(KnownPeerDelete knownPeerDelete) {
peerManager.removeRemoteHost(PeerId.of(knownPeerDelete.uuid()));
public void deletePeer(@PathParam("peerId") String peerId) {
peerManager.removeRemoteHost(PeerId.of(peerId));
}
@Path("available-peers")
@GET
public Collection<KnownPeerInfo> availablePeers() {
public Collection<PeerInfo> availablePeers() {
return peerManager.getSeenButNotAddedHosts().stream()
.map(p -> new KnownPeerInfo(p.toString(),
peerManager.selectBestAddress(p).map(Objects::toString).orElse(null)))
.map(p -> new PeerInfo(p.getLeft().toString(), p.getRight().cert(),
peerManager.selectBestAddress(p.getLeft()).map(Objects::toString).orElse(null)))
.toList();
}
@Path("peer-state")
@GET
public Collection<PeerInfo> peerInfos(Collection<String> peerIdStrings) {
return peerIdStrings.stream().map(PeerId::of).map(
peerId -> {
return new PeerInfo(
peerId.toString(),
peerManager.getAddress(peerId).toString()
);
}
).toList();
}
}

View File

@@ -0,0 +1,4 @@
package com.usatiuk.dhfs.webapi;
public record SelfInfo(String uuid, String cert) {
}