forked from TrueCloudLab/frostfs-sdk-java
[#1] Add additional security
Signed-off-by: Ori Bruk <o.bruk@yadro.com>
This commit is contained in:
parent
bf2f19f08d
commit
1be65c63ae
62 changed files with 670 additions and 281 deletions
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package info.frostfs.sdk.services;
|
||||
package info.frostfs.sdk;
|
||||
|
||||
import frostfs.session.Types;
|
||||
import info.frostfs.sdk.dto.SessionToken;
|
||||
|
@ -15,6 +15,7 @@ import info.frostfs.sdk.jdo.ClientEnvironment;
|
|||
import info.frostfs.sdk.jdo.ClientSettings;
|
||||
import info.frostfs.sdk.jdo.NetworkSettings;
|
||||
import info.frostfs.sdk.jdo.PutObjectParameters;
|
||||
import info.frostfs.sdk.services.*;
|
||||
import info.frostfs.sdk.services.impl.*;
|
||||
import io.grpc.Channel;
|
||||
|
||||
|
@ -27,11 +28,11 @@ public class FrostFSClient implements ContainerClient, ObjectClient, NetmapClien
|
|||
private static final String ERROR_CLIENT_OPTIONS_INIT = "Options must be initialized.";
|
||||
private static final String ERROR_VERSION_SUPPORT_TEMPLATE = "FrostFS %s is not supported.";
|
||||
|
||||
private final ContainerService containerService;
|
||||
private final NetmapService netmapService;
|
||||
private final ObjectService objectService;
|
||||
private final SessionService sessionService;
|
||||
private final ObjectTools objectTools;
|
||||
private final ContainerClientImpl containerClientImpl;
|
||||
private final NetmapClientImpl netmapClientImpl;
|
||||
private final ObjectClientImpl objectClientImpl;
|
||||
private final SessionClientImpl sessionClientImpl;
|
||||
private final ObjectToolsImpl objectToolsImpl;
|
||||
|
||||
public FrostFSClient(ClientSettings clientSettings) {
|
||||
if (isNull(clientSettings)) {
|
||||
|
@ -43,18 +44,18 @@ public class FrostFSClient implements ContainerClient, ObjectClient, NetmapClien
|
|||
Channel channel = initGrpcChannel(clientSettings.getHost(), clientSettings.getCreds());
|
||||
|
||||
ClientEnvironment clientEnvironment =
|
||||
new ClientEnvironment(clientSettings.getKey(), channel, new Version(2, 13), this);
|
||||
new ClientEnvironment(clientSettings.getKey(), channel, new Version(), this);
|
||||
|
||||
this.containerService = new ContainerService(clientEnvironment);
|
||||
this.netmapService = new NetmapService(clientEnvironment);
|
||||
this.sessionService = new SessionService(clientEnvironment);
|
||||
this.objectService = new ObjectService(clientEnvironment);
|
||||
this.objectTools = new ObjectTools(clientEnvironment);
|
||||
this.containerClientImpl = new ContainerClientImpl(clientEnvironment);
|
||||
this.netmapClientImpl = new NetmapClientImpl(clientEnvironment);
|
||||
this.sessionClientImpl = new SessionClientImpl(clientEnvironment);
|
||||
this.objectClientImpl = new ObjectClientImpl(clientEnvironment);
|
||||
this.objectToolsImpl = new ObjectToolsImpl(clientEnvironment);
|
||||
checkFrostFsVersionSupport(clientEnvironment.getVersion());
|
||||
}
|
||||
|
||||
private void checkFrostFsVersionSupport(Version version) {
|
||||
var localNodeInfo = netmapService.getLocalNodeInfo();
|
||||
var localNodeInfo = netmapClientImpl.getLocalNodeInfo();
|
||||
if (!localNodeInfo.getVersion().isSupported(version)) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format(ERROR_VERSION_SUPPORT_TEMPLATE, localNodeInfo.getVersion())
|
||||
|
@ -64,75 +65,75 @@ public class FrostFSClient implements ContainerClient, ObjectClient, NetmapClien
|
|||
|
||||
@Override
|
||||
public Container getContainer(ContainerId cid) {
|
||||
return containerService.getContainer(cid);
|
||||
return containerClientImpl.getContainer(cid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ContainerId> listContainers() {
|
||||
return containerService.listContainers();
|
||||
return containerClientImpl.listContainers();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContainerId createContainer(Container container) {
|
||||
return containerService.createContainer(container);
|
||||
return containerClientImpl.createContainer(container);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteContainer(ContainerId cid) {
|
||||
containerService.deleteContainer(cid);
|
||||
containerClientImpl.deleteContainer(cid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectHeader getObjectHead(ContainerId containerId, ObjectId objectId) {
|
||||
return objectService.getObjectHead(containerId, objectId);
|
||||
return objectClientImpl.getObjectHead(containerId, objectId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectFrostFS getObject(ContainerId containerId, ObjectId objectId) {
|
||||
return objectService.getObject(containerId, objectId);
|
||||
return objectClientImpl.getObject(containerId, objectId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectId putObject(PutObjectParameters parameters) {
|
||||
return objectService.putObject(parameters);
|
||||
return objectClientImpl.putObject(parameters);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteObject(ContainerId containerId, ObjectId objectId) {
|
||||
objectService.deleteObject(containerId, objectId);
|
||||
objectClientImpl.deleteObject(containerId, objectId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<ObjectId> searchObjects(ContainerId cid, ObjectFilter... filters) {
|
||||
return objectService.searchObjects(cid, filters);
|
||||
return objectClientImpl.searchObjects(cid, filters);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NetmapSnapshot getNetmapSnapshot() {
|
||||
return netmapService.getNetmapSnapshot();
|
||||
return netmapClientImpl.getNetmapSnapshot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public NodeInfo getLocalNodeInfo() {
|
||||
return netmapService.getLocalNodeInfo();
|
||||
return netmapClientImpl.getLocalNodeInfo();
|
||||
}
|
||||
|
||||
@Override
|
||||
public NetworkSettings getNetworkSettings() {
|
||||
return netmapService.getNetworkSettings();
|
||||
return netmapClientImpl.getNetworkSettings();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SessionToken createSession(long expiration) {
|
||||
return sessionService.createSession(expiration);
|
||||
return sessionClientImpl.createSession(expiration);
|
||||
}
|
||||
|
||||
public Types.SessionToken createSessionInternal(long expiration) {
|
||||
return sessionService.createSessionInternal(expiration);
|
||||
return sessionClientImpl.createSessionInternal(expiration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectId calculateObjectId(ObjectHeader header) {
|
||||
return objectTools.calculateObjectId(header);
|
||||
return objectToolsImpl.calculateObjectId(header);
|
||||
}
|
||||
}
|
|
@ -2,4 +2,7 @@ package info.frostfs.sdk.constants;
|
|||
|
||||
public class CryptoConst {
|
||||
public static final String SIGNATURE_ALGORITHM = "NONEwithECDSAinP1363Format";
|
||||
|
||||
private CryptoConst() {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,8 +2,11 @@ package info.frostfs.sdk.jdo;
|
|||
|
||||
import info.frostfs.sdk.dto.OwnerId;
|
||||
import info.frostfs.sdk.dto.Version;
|
||||
import info.frostfs.sdk.services.FrostFSClient;
|
||||
import info.frostfs.sdk.FrostFSClient;
|
||||
import io.grpc.Channel;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import static java.util.Objects.isNull;
|
||||
|
||||
public class ClientEnvironment {
|
||||
private final OwnerId ownerId;
|
||||
|
@ -14,8 +17,12 @@ public class ClientEnvironment {
|
|||
private NetworkSettings networkSettings;
|
||||
|
||||
public ClientEnvironment(String wif, Channel channel, Version version, FrostFSClient frostFSClient) {
|
||||
if (StringUtils.isEmpty(wif) || isNull(channel) || isNull(version) || isNull(frostFSClient)) {
|
||||
throw new IllegalArgumentException("One of the input attributes is missing");
|
||||
}
|
||||
|
||||
this.key = new ECDsa(wif);
|
||||
this.ownerId = OwnerId.fromKey(key.getPublicKeyByte());
|
||||
this.ownerId = new OwnerId(key.getPublicKeyByte());
|
||||
this.version = version;
|
||||
this.channel = channel;
|
||||
this.frostFSClient = frostFSClient;
|
||||
|
|
|
@ -13,6 +13,14 @@ public class ClientSettings {
|
|||
public ClientSettings(String key, String host) {
|
||||
this.key = key;
|
||||
this.host = host;
|
||||
validate();
|
||||
}
|
||||
|
||||
public ClientSettings(String key, String host, ChannelCredentials creds) {
|
||||
this.key = key;
|
||||
this.host = host;
|
||||
this.creds = creds;
|
||||
validate();
|
||||
}
|
||||
|
||||
public ChannelCredentials getCreds() {
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package info.frostfs.sdk.jdo;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.security.PrivateKey;
|
||||
|
||||
import static info.frostfs.sdk.KeyExtension.*;
|
||||
|
@ -10,6 +12,10 @@ public class ECDsa {
|
|||
private final PrivateKey privateKey;
|
||||
|
||||
public ECDsa(String wif) {
|
||||
if (StringUtils.isEmpty(wif)) {
|
||||
throw new IllegalArgumentException("Wif is invalid");
|
||||
}
|
||||
|
||||
this.privateKeyByte = getPrivateKeyFromWIF(wif);
|
||||
this.publicKeyByte = loadPublicKey(privateKeyByte);
|
||||
this.privateKey = loadPrivateKey(privateKeyByte);
|
||||
|
|
|
@ -19,11 +19,15 @@ public class PutObjectParameters {
|
|||
this.payload = payload;
|
||||
this.clientCut = clientCut;
|
||||
this.bufferMaxSize = bufferMaxSize;
|
||||
|
||||
validate();
|
||||
}
|
||||
|
||||
public PutObjectParameters(ObjectHeader header, FileInputStream payload) {
|
||||
this.header = header;
|
||||
this.payload = payload;
|
||||
|
||||
validate();
|
||||
}
|
||||
|
||||
public ObjectHeader getHeader() {
|
||||
|
|
|
@ -11,33 +11,36 @@ import info.frostfs.sdk.mappers.container.ContainerIdMapper;
|
|||
import info.frostfs.sdk.mappers.container.ContainerMapper;
|
||||
import info.frostfs.sdk.services.ContainerClient;
|
||||
import info.frostfs.sdk.services.ContextAccessor;
|
||||
import info.frostfs.sdk.tools.Verifier;
|
||||
import info.frostfs.sdk.tools.RequestConstructor;
|
||||
import info.frostfs.sdk.tools.RequestSigner;
|
||||
import info.frostfs.sdk.tools.Verifier;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static info.frostfs.sdk.tools.RequestConstructor.addMetaHeader;
|
||||
import static info.frostfs.sdk.tools.RequestSigner.signRFC6979;
|
||||
import static java.util.Objects.isNull;
|
||||
|
||||
public class ContainerService extends ContextAccessor implements ContainerClient {
|
||||
public class ContainerClientImpl extends ContextAccessor implements ContainerClient {
|
||||
private final ContainerServiceGrpc.ContainerServiceBlockingStub serviceBlockingStub;
|
||||
|
||||
public ContainerService(ClientEnvironment clientEnvironment) {
|
||||
public ContainerClientImpl(ClientEnvironment clientEnvironment) {
|
||||
super(clientEnvironment);
|
||||
this.serviceBlockingStub = ContainerServiceGrpc.newBlockingStub(clientEnvironment.getChannel());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Container getContainer(ContainerId cid) {
|
||||
var request = Service.GetRequest.newBuilder()
|
||||
.setBody(
|
||||
Service.GetRequest.Body.newBuilder()
|
||||
.setContainerId(ContainerIdMapper.toGrpcMessage(cid))
|
||||
.build()
|
||||
);
|
||||
if (isNull(cid)) {
|
||||
throw new IllegalArgumentException("ContainerId is not present");
|
||||
}
|
||||
|
||||
RequestConstructor.addMetaHeader(request);
|
||||
var body = Service.GetRequest.Body.newBuilder()
|
||||
.setContainerId(ContainerIdMapper.toGrpcMessage(cid))
|
||||
.build();
|
||||
var request = Service.GetRequest.newBuilder()
|
||||
.setBody(body);
|
||||
|
||||
RequestConstructor.addDefaultMetaHeader(request);
|
||||
RequestSigner.sign(request, getContext().getKey());
|
||||
|
||||
var response = serviceBlockingStub.get(request.build());
|
||||
|
@ -46,15 +49,15 @@ public class ContainerService extends ContextAccessor implements ContainerClient
|
|||
return ContainerMapper.toModel(response.getBody().getContainer());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ContainerId> listContainers() {
|
||||
var body = Service.ListRequest.Body.newBuilder()
|
||||
.setOwnerId(OwnerIdMapper.toGrpcMessage(getContext().getOwnerId()))
|
||||
.build();
|
||||
var request = Service.ListRequest.newBuilder()
|
||||
.setBody(
|
||||
Service.ListRequest.Body.newBuilder()
|
||||
.setOwnerId(OwnerIdMapper.toGrpcMessage(getContext().getOwnerId()))
|
||||
.build()
|
||||
);
|
||||
.setBody(body);
|
||||
|
||||
RequestConstructor.addMetaHeader(request);
|
||||
RequestConstructor.addDefaultMetaHeader(request);
|
||||
RequestSigner.sign(request, getContext().getKey());
|
||||
|
||||
var response = serviceBlockingStub.list(request.build());
|
||||
|
@ -62,51 +65,54 @@ public class ContainerService extends ContextAccessor implements ContainerClient
|
|||
Verifier.checkResponse(response);
|
||||
|
||||
return response.getBody().getContainerIdsList().stream()
|
||||
.map(cid -> ContainerId.fromHash(cid.getValue().toByteArray()))
|
||||
.map(cid -> new ContainerId(cid.getValue().toByteArray()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContainerId createContainer(Container container) {
|
||||
var grpcContainer = ContainerMapper.toGrpcMessage(container);
|
||||
if (isNull(container)) {
|
||||
throw new IllegalArgumentException("Container is not present");
|
||||
}
|
||||
|
||||
var grpcContainer = ContainerMapper.toGrpcMessage(container);
|
||||
grpcContainer = grpcContainer.toBuilder()
|
||||
.setOwnerId(OwnerIdMapper.toGrpcMessage(getContext().getOwnerId()))
|
||||
.setVersion(VersionMapper.toGrpcMessage(getContext().getVersion()))
|
||||
.build();
|
||||
|
||||
var body = Service.PutRequest.Body.newBuilder()
|
||||
.setContainer(grpcContainer)
|
||||
.setSignature(RequestSigner.signRFC6979(getContext().getKey(), grpcContainer))
|
||||
.build();
|
||||
var request = Service.PutRequest.newBuilder()
|
||||
.setBody(
|
||||
Service.PutRequest.Body.newBuilder()
|
||||
.setContainer(grpcContainer)
|
||||
.setSignature(
|
||||
RequestSigner.signRFC6979(getContext().getKey(), grpcContainer)
|
||||
)
|
||||
.build()
|
||||
);
|
||||
.setBody(body);
|
||||
|
||||
RequestConstructor.addMetaHeader(request);
|
||||
RequestConstructor.addDefaultMetaHeader(request);
|
||||
RequestSigner.sign(request, getContext().getKey());
|
||||
|
||||
var response = serviceBlockingStub.put(request.build());
|
||||
|
||||
Verifier.checkResponse(response);
|
||||
return ContainerId.fromHash(response.getBody().getContainerId().getValue().toByteArray());
|
||||
return new ContainerId(response.getBody().getContainerId().getValue().toByteArray());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteContainer(ContainerId cid) {
|
||||
if (isNull(cid)) {
|
||||
throw new IllegalArgumentException("ContainerId is not present");
|
||||
}
|
||||
|
||||
var grpcContainerId = ContainerIdMapper.toGrpcMessage(cid);
|
||||
|
||||
var body = Service.DeleteRequest.Body.newBuilder()
|
||||
.setContainerId(grpcContainerId)
|
||||
.setSignature(RequestSigner.signRFC6979(getContext().getKey(), grpcContainerId.getValue()))
|
||||
.build();
|
||||
var request = Service.DeleteRequest.newBuilder()
|
||||
.setBody(
|
||||
Service.DeleteRequest.Body.newBuilder()
|
||||
.setContainerId(grpcContainerId)
|
||||
.setSignature(RequestSigner.signRFC6979(
|
||||
getContext().getKey(), grpcContainerId.getValue()
|
||||
))
|
||||
.build()
|
||||
);
|
||||
.setBody(body);
|
||||
|
||||
RequestConstructor.addMetaHeader(request);
|
||||
RequestConstructor.addDefaultMetaHeader(request);
|
||||
RequestSigner.sign(request, getContext().getKey());
|
||||
|
||||
var response = serviceBlockingStub.delete(request.build());
|
|
@ -11,25 +11,27 @@ import info.frostfs.sdk.mappers.netmap.NetmapSnapshotMapper;
|
|||
import info.frostfs.sdk.mappers.netmap.NodeInfoMapper;
|
||||
import info.frostfs.sdk.services.ContextAccessor;
|
||||
import info.frostfs.sdk.services.NetmapClient;
|
||||
import info.frostfs.sdk.tools.RequestConstructor;
|
||||
import info.frostfs.sdk.tools.Verifier;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import static info.frostfs.sdk.tools.RequestConstructor.addMetaHeader;
|
||||
import static info.frostfs.sdk.tools.RequestSigner.sign;
|
||||
import static java.util.Objects.nonNull;
|
||||
|
||||
public class NetmapService extends ContextAccessor implements NetmapClient {
|
||||
public class NetmapClientImpl extends ContextAccessor implements NetmapClient {
|
||||
private final NetmapServiceGrpc.NetmapServiceBlockingStub netmapServiceClient;
|
||||
|
||||
public NetmapService(ClientEnvironment clientEnvironment) {
|
||||
public NetmapClientImpl(ClientEnvironment clientEnvironment) {
|
||||
super(clientEnvironment);
|
||||
this.netmapServiceClient = NetmapServiceGrpc.newBlockingStub(getContext().getChannel());
|
||||
}
|
||||
|
||||
private static boolean getBoolValue(byte[] bytes) {
|
||||
for (var byteValue : bytes) {
|
||||
if (byteValue != 0) return true;
|
||||
if (byteValue != 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -115,7 +117,7 @@ public class NetmapService extends ContextAccessor implements NetmapClient {
|
|||
var request = Service.LocalNodeInfoRequest.newBuilder()
|
||||
.setBody(Service.LocalNodeInfoRequest.Body.newBuilder().build());
|
||||
|
||||
addMetaHeader(request);
|
||||
RequestConstructor.addDefaultMetaHeader(request);
|
||||
sign(request, getContext().getKey());
|
||||
|
||||
var response = netmapServiceClient.localNodeInfo(request.build());
|
||||
|
@ -128,7 +130,7 @@ public class NetmapService extends ContextAccessor implements NetmapClient {
|
|||
var request = Service.NetworkInfoRequest.newBuilder()
|
||||
.setBody(Service.NetworkInfoRequest.Body.newBuilder().build());
|
||||
|
||||
addMetaHeader(request);
|
||||
RequestConstructor.addDefaultMetaHeader(request);
|
||||
sign(request, getContext().getKey());
|
||||
|
||||
var response = netmapServiceClient.networkInfo(request.build());
|
||||
|
@ -143,7 +145,7 @@ public class NetmapService extends ContextAccessor implements NetmapClient {
|
|||
var request = Service.NetmapSnapshotRequest.newBuilder()
|
||||
.setBody(Service.NetmapSnapshotRequest.Body.newBuilder().build());
|
||||
|
||||
addMetaHeader(request);
|
||||
RequestConstructor.addDefaultMetaHeader(request);
|
||||
sign(request, getContext().getKey());
|
||||
|
||||
var response = netmapServiceClient.netmapSnapshot(request.build());
|
|
@ -20,6 +20,10 @@ import info.frostfs.sdk.mappers.object.ObjectHeaderMapper;
|
|||
import info.frostfs.sdk.mappers.object.ObjectIdMapper;
|
||||
import info.frostfs.sdk.services.ContextAccessor;
|
||||
import info.frostfs.sdk.services.ObjectClient;
|
||||
import info.frostfs.sdk.services.impl.rwhelper.ObjectReader;
|
||||
import info.frostfs.sdk.services.impl.rwhelper.ObjectWriter;
|
||||
import info.frostfs.sdk.services.impl.rwhelper.SearchReader;
|
||||
import info.frostfs.sdk.tools.RequestConstructor;
|
||||
import info.frostfs.sdk.tools.Verifier;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
|
||||
|
@ -30,39 +34,37 @@ import java.util.Arrays;
|
|||
import java.util.List;
|
||||
|
||||
import static info.frostfs.sdk.Helper.getSha256;
|
||||
import static info.frostfs.sdk.tools.RequestConstructor.addMetaHeader;
|
||||
import static info.frostfs.sdk.tools.RequestConstructor.addObjectSessionToken;
|
||||
import static info.frostfs.sdk.tools.RequestSigner.sign;
|
||||
import static java.util.Objects.nonNull;
|
||||
|
||||
public class ObjectService extends ContextAccessor implements ObjectClient {
|
||||
public class ObjectClientImpl extends ContextAccessor implements ObjectClient {
|
||||
private static final String ERROR_PAYLOAD = "PayloadLength must be specified";
|
||||
|
||||
private final ObjectServiceGrpc.ObjectServiceBlockingStub objectServiceBlockingClient;
|
||||
private final ObjectServiceGrpc.ObjectServiceStub objectServiceClient;
|
||||
private final ObjectTools objectTools;
|
||||
private final ObjectToolsImpl objectToolsImpl;
|
||||
|
||||
public ObjectService(ClientEnvironment clientEnvironment) {
|
||||
public ObjectClientImpl(ClientEnvironment clientEnvironment) {
|
||||
super(clientEnvironment);
|
||||
this.objectServiceBlockingClient = ObjectServiceGrpc.newBlockingStub(getContext().getChannel());
|
||||
this.objectServiceClient = ObjectServiceGrpc.newStub(getContext().getChannel());
|
||||
this.objectTools = new ObjectTools(clientEnvironment);
|
||||
this.objectToolsImpl = new ObjectToolsImpl(clientEnvironment);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectHeader getObjectHead(ContainerId cid, ObjectId oid) {
|
||||
var address = Types.Address.newBuilder()
|
||||
.setContainerId(ContainerIdMapper.toGrpcMessage(cid))
|
||||
.setObjectId(ObjectIdMapper.toGrpcMessage(oid))
|
||||
.build();
|
||||
var body = Service.HeadRequest.Body.newBuilder()
|
||||
.setAddress(address)
|
||||
.build();
|
||||
var request = Service.HeadRequest.newBuilder()
|
||||
.setBody(
|
||||
Service.HeadRequest.Body.newBuilder()
|
||||
.setAddress(
|
||||
Types.Address.newBuilder()
|
||||
.setContainerId(ContainerIdMapper.toGrpcMessage(cid))
|
||||
.setObjectId(ObjectIdMapper.toGrpcMessage(oid))
|
||||
.build()
|
||||
).build()
|
||||
);
|
||||
.setBody(body);
|
||||
|
||||
addMetaHeader(request);
|
||||
RequestConstructor.addDefaultMetaHeader(request);
|
||||
sign(request, getContext().getKey());
|
||||
|
||||
var response = objectServiceBlockingClient.head(request.build());
|
||||
|
@ -75,19 +77,17 @@ public class ObjectService extends ContextAccessor implements ObjectClient {
|
|||
public ObjectFrostFS getObject(ContainerId cid, ObjectId oid) {
|
||||
var sessionToken = getContext().getFrostFSClient().createSessionInternal(-1);
|
||||
|
||||
var address = Types.Address.newBuilder()
|
||||
.setContainerId(ContainerIdMapper.toGrpcMessage(cid))
|
||||
.setObjectId(ObjectIdMapper.toGrpcMessage(oid))
|
||||
.build();
|
||||
var body = Service.GetRequest.Body.newBuilder()
|
||||
.setAddress(address)
|
||||
.build();
|
||||
var request = Service.GetRequest.newBuilder()
|
||||
.setBody(
|
||||
Service.GetRequest.Body.newBuilder()
|
||||
.setAddress(
|
||||
Types.Address.newBuilder()
|
||||
.setContainerId(ContainerIdMapper.toGrpcMessage(cid))
|
||||
.setObjectId(ObjectIdMapper.toGrpcMessage(oid))
|
||||
.build()
|
||||
)
|
||||
.build()
|
||||
);
|
||||
.setBody(body);
|
||||
|
||||
addMetaHeader(request);
|
||||
RequestConstructor.addDefaultMetaHeader(request);
|
||||
addObjectSessionToken(
|
||||
request, sessionToken, ContainerIdMapper.toGrpcMessage(cid), ObjectIdMapper.toGrpcMessage(oid),
|
||||
frostfs.session.Types.ObjectSessionContext.Verb.GET, getContext().getKey()
|
||||
|
@ -101,18 +101,17 @@ public class ObjectService extends ContextAccessor implements ObjectClient {
|
|||
|
||||
@Override
|
||||
public void deleteObject(ContainerId cid, ObjectId oid) {
|
||||
var address = Types.Address.newBuilder()
|
||||
.setContainerId(ContainerIdMapper.toGrpcMessage(cid))
|
||||
.setObjectId(ObjectIdMapper.toGrpcMessage(oid))
|
||||
.build();
|
||||
var body = Service.DeleteRequest.Body.newBuilder()
|
||||
.setAddress(address)
|
||||
.build();
|
||||
var request = Service.DeleteRequest.newBuilder()
|
||||
.setBody(
|
||||
Service.DeleteRequest.Body.newBuilder()
|
||||
.setAddress(
|
||||
Types.Address.newBuilder()
|
||||
.setContainerId(ContainerIdMapper.toGrpcMessage(cid))
|
||||
.setObjectId(ObjectIdMapper.toGrpcMessage(oid))
|
||||
.build()
|
||||
)
|
||||
.build());
|
||||
.setBody(body);
|
||||
|
||||
addMetaHeader(request);
|
||||
RequestConstructor.addDefaultMetaHeader(request);
|
||||
sign(request, getContext().getKey());
|
||||
|
||||
var response = objectServiceBlockingClient.delete(request.build());
|
||||
|
@ -132,12 +131,12 @@ public class ObjectService extends ContextAccessor implements ObjectClient {
|
|||
var request = Service.SearchRequest.newBuilder()
|
||||
.setBody(body.build());
|
||||
|
||||
addMetaHeader(request);
|
||||
RequestConstructor.addDefaultMetaHeader(request);
|
||||
sign(request, getContext().getKey());
|
||||
|
||||
var objectsIds = searchObjects(request.build());
|
||||
|
||||
return Iterables.transform(objectsIds, input -> ObjectId.fromHash(input.getValue().toByteArray()));
|
||||
return Iterables.transform(objectsIds, input -> new ObjectId(input.getValue().toByteArray()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -150,13 +149,13 @@ public class ObjectService extends ContextAccessor implements ObjectClient {
|
|||
public ObjectId putSingleObject(ObjectFrostFS modelObject) {
|
||||
var sessionToken = getContext().getFrostFSClient().createSessionInternal(-1);
|
||||
|
||||
var grpcObject = objectTools.createObject(modelObject);
|
||||
var grpcObject = objectToolsImpl.createObject(modelObject);
|
||||
|
||||
var request = Service.PutSingleRequest.newBuilder()
|
||||
.setBody(Service.PutSingleRequest.Body.newBuilder().setObject(grpcObject).build());
|
||||
|
||||
|
||||
addMetaHeader(request);
|
||||
RequestConstructor.addDefaultMetaHeader(request);
|
||||
addObjectSessionToken(
|
||||
request, sessionToken, grpcObject.getHeader().getContainerId(), grpcObject.getObjectId(),
|
||||
frostfs.session.Types.ObjectSessionContext.Verb.PUT, getContext().getKey()
|
||||
|
@ -167,7 +166,7 @@ public class ObjectService extends ContextAccessor implements ObjectClient {
|
|||
|
||||
Verifier.checkResponse(response);
|
||||
|
||||
return ObjectId.fromHash(grpcObject.getObjectId().getValue().toByteArray());
|
||||
return new ObjectId(grpcObject.getObjectId().getValue().toByteArray());
|
||||
}
|
||||
|
||||
private frostfs.object.Types.Object getObject(Service.GetRequest request) {
|
||||
|
@ -215,7 +214,7 @@ public class ObjectService extends ContextAccessor implements ObjectClient {
|
|||
).build()
|
||||
);
|
||||
|
||||
addMetaHeader(initRequest);
|
||||
RequestConstructor.addDefaultMetaHeader(initRequest);
|
||||
addObjectSessionToken(
|
||||
initRequest, sessionToken, hdr.getContainerId(), oid,
|
||||
frostfs.session.Types.ObjectSessionContext.Verb.PUT, getContext().getKey()
|
||||
|
@ -232,8 +231,9 @@ public class ObjectService extends ContextAccessor implements ObjectClient {
|
|||
var buffer = new byte[bufferSize];
|
||||
while (true) {
|
||||
var bytesCount = readNBytes(parameters.getPayload(), buffer, bufferSize);
|
||||
if (bytesCount <= 0)
|
||||
if (bytesCount <= 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
var chunkRequest = Service.PutRequest.newBuilder(initRequest.build())
|
||||
.setBody(
|
||||
|
@ -249,7 +249,7 @@ public class ObjectService extends ContextAccessor implements ObjectClient {
|
|||
var response = writer.complete();
|
||||
Verifier.checkResponse(response);
|
||||
|
||||
return ObjectId.fromHash(response.getBody().getObjectId().getValue().toByteArray());
|
||||
return new ObjectId(response.getBody().getObjectId().getValue().toByteArray());
|
||||
}
|
||||
|
||||
private ObjectId putClientCutObject(PutObjectParameters parameters) {
|
||||
|
@ -285,8 +285,9 @@ public class ObjectService extends ContextAccessor implements ObjectClient {
|
|||
);
|
||||
currentObject.setSplit(split);
|
||||
|
||||
if (largeObject.getPayloadLength() == fullLength)
|
||||
if (largeObject.getPayloadLength() == fullLength) {
|
||||
break;
|
||||
}
|
||||
|
||||
objectId = putSingleObject(currentObject);
|
||||
|
||||
|
@ -314,7 +315,7 @@ public class ObjectService extends ContextAccessor implements ObjectClient {
|
|||
|
||||
putSingleObject(linkObject);
|
||||
|
||||
return objectTools.calculateObjectId(largeObject.getHeader());
|
||||
return objectToolsImpl.calculateObjectId(largeObject.getHeader());
|
||||
}
|
||||
|
||||
private ObjectWriter putObjectInit(Service.PutRequest initRequest) {
|
|
@ -18,8 +18,8 @@ import static info.frostfs.sdk.Helper.getSha256;
|
|||
import static info.frostfs.sdk.tools.RequestSigner.signData;
|
||||
import static java.util.Objects.nonNull;
|
||||
|
||||
public class ObjectTools extends ContextAccessor implements ToolsClient {
|
||||
public ObjectTools(ClientEnvironment context) {
|
||||
public class ObjectToolsImpl extends ContextAccessor implements ToolsClient {
|
||||
public ObjectToolsImpl(ClientEnvironment context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
|
@ -59,15 +59,13 @@ public class ObjectTools extends ContextAccessor implements ToolsClient {
|
|||
if (nonNull(split.getParentHeader())) {
|
||||
var grpcParentHeader = createHeader(split.getParentHeader(), new byte[]{});
|
||||
var parent = frostfs.refs.Types.ObjectID.newBuilder().setValue(getSha256(grpcParentHeader)).build();
|
||||
var parentSig = frostfs.refs.Types.Signature.newBuilder()
|
||||
.setKey(ByteString.copyFrom(getContext().getKey().getPublicKeyByte()))
|
||||
.setSign(ByteString.copyFrom(signData(getContext().getKey(), parent.toByteArray())));
|
||||
|
||||
splitGrpc
|
||||
.setParent(parent)
|
||||
splitGrpc.setParent(parent)
|
||||
.setParentHeader(grpcParentHeader)
|
||||
.setParentSignature(
|
||||
frostfs.refs.Types.Signature.newBuilder()
|
||||
.setKey(ByteString.copyFrom(getContext().getKey().getPublicKeyByte()))
|
||||
.setSign(ByteString.copyFrom(signData(getContext().getKey(), parent.toByteArray())))
|
||||
);
|
||||
.setParentSignature(parentSig);
|
||||
|
||||
split.setParent(ObjectIdMapper.toModel(parent));
|
||||
}
|
||||
|
@ -79,15 +77,14 @@ public class ObjectTools extends ContextAccessor implements ToolsClient {
|
|||
|
||||
var grpcHeader = grpcHeaderBuilder.build();
|
||||
var objectId = frostfs.refs.Types.ObjectID.newBuilder().setValue(getSha256(grpcHeader)).build();
|
||||
var sig = frostfs.refs.Types.Signature.newBuilder()
|
||||
.setKey(ByteString.copyFrom(getContext().getKey().getPublicKeyByte()))
|
||||
.setSign(ByteString.copyFrom(signData(getContext().getKey(), objectId.toByteArray())));
|
||||
return Types.Object.newBuilder()
|
||||
.setHeader(grpcHeader)
|
||||
.setObjectId(objectId)
|
||||
.setPayload(ByteString.copyFrom(objectFrostFs.getPayload()))
|
||||
.setSignature(
|
||||
frostfs.refs.Types.Signature.newBuilder()
|
||||
.setKey(ByteString.copyFrom(getContext().getKey().getPublicKeyByte()))
|
||||
.setSign(ByteString.copyFrom(signData(getContext().getKey(), objectId.toByteArray())))
|
||||
)
|
||||
.setSignature(sig)
|
||||
.build();
|
||||
}
|
||||
|
||||
|
@ -96,10 +93,11 @@ public class ObjectTools extends ContextAccessor implements ToolsClient {
|
|||
.setOwnerId(OwnerIdMapper.toGrpcMessage(getContext().getOwnerId()))
|
||||
.setVersion(VersionMapper.toGrpcMessage(getContext().getVersion()));
|
||||
|
||||
if (header.getPayloadCheckSum() != null)
|
||||
if (header.getPayloadCheckSum() != null) {
|
||||
grpcHeader.setPayloadHash(sha256Checksum(header.getPayloadCheckSum()));
|
||||
else if (payload != null)
|
||||
} else if (payload != null) {
|
||||
grpcHeader.setPayloadHash(sha256Checksum(payload));
|
||||
}
|
||||
|
||||
return grpcHeader.build();
|
||||
}
|
|
@ -11,13 +11,12 @@ import info.frostfs.sdk.services.ContextAccessor;
|
|||
import info.frostfs.sdk.services.SessionClient;
|
||||
import info.frostfs.sdk.tools.RequestConstructor;
|
||||
|
||||
import static info.frostfs.sdk.tools.RequestConstructor.addMetaHeader;
|
||||
import static info.frostfs.sdk.tools.RequestSigner.sign;
|
||||
|
||||
public class SessionService extends ContextAccessor implements SessionClient {
|
||||
public class SessionClientImpl extends ContextAccessor implements SessionClient {
|
||||
private final SessionServiceGrpc.SessionServiceBlockingStub serviceBlockingStub;
|
||||
|
||||
public SessionService(ClientEnvironment clientEnvironment) {
|
||||
public SessionClientImpl(ClientEnvironment clientEnvironment) {
|
||||
super(clientEnvironment);
|
||||
this.serviceBlockingStub = SessionServiceGrpc.newBlockingStub(getContext().getChannel());
|
||||
}
|
||||
|
@ -30,14 +29,14 @@ public class SessionService extends ContextAccessor implements SessionClient {
|
|||
}
|
||||
|
||||
public Types.SessionToken createSessionInternal(long expiration) {
|
||||
var body = Service.CreateRequest.Body.newBuilder()
|
||||
.setOwnerId(OwnerIdMapper.toGrpcMessage(getContext().getOwnerId()))
|
||||
.setExpiration(expiration)
|
||||
.build();
|
||||
var request = Service.CreateRequest.newBuilder()
|
||||
.setBody(
|
||||
Service.CreateRequest.Body.newBuilder()
|
||||
.setOwnerId(OwnerIdMapper.toGrpcMessage(getContext().getOwnerId()))
|
||||
.setExpiration(expiration).build()
|
||||
);
|
||||
.setBody(body);
|
||||
|
||||
RequestConstructor.addMetaHeader(request);
|
||||
RequestConstructor.addDefaultMetaHeader(request);
|
||||
sign(request, getContext().getKey());
|
||||
|
||||
return createSession(request.build());
|
|
@ -1,4 +1,4 @@
|
|||
package info.frostfs.sdk.services.impl;
|
||||
package info.frostfs.sdk.services.impl.rwhelper;
|
||||
|
||||
import frostfs.object.Service;
|
||||
import frostfs.object.Types;
|
|
@ -1,4 +1,4 @@
|
|||
package info.frostfs.sdk.services.impl;
|
||||
package info.frostfs.sdk.services.impl.rwhelper;
|
||||
|
||||
import frostfs.object.ObjectServiceGrpc;
|
||||
import frostfs.object.Service;
|
|
@ -1,4 +1,4 @@
|
|||
package info.frostfs.sdk.services.impl;
|
||||
package info.frostfs.sdk.services.impl.rwhelper;
|
||||
|
||||
import frostfs.object.Service;
|
||||
import info.frostfs.sdk.tools.Verifier;
|
|
@ -12,6 +12,9 @@ import static java.util.Objects.isNull;
|
|||
public class GrpcClient {
|
||||
private static final String ERROR_INVALID_HOST_TEMPLATE = "Host %s has invalid format. Error: %s";
|
||||
|
||||
private GrpcClient() {
|
||||
}
|
||||
|
||||
public static Channel initGrpcChannel(String host, ChannelCredentials creds) {
|
||||
try {
|
||||
URI uri = new URI(host);
|
||||
|
|
|
@ -5,6 +5,9 @@ import com.google.protobuf.MessageOrBuilder;
|
|||
|
||||
public class MessageHelper {
|
||||
|
||||
private MessageHelper() {
|
||||
}
|
||||
|
||||
public static Message getField(MessageOrBuilder messageOrBuilder, String fieldName) {
|
||||
return (Message) messageOrBuilder.getField(messageOrBuilder.getDescriptorForType().findFieldByName(fieldName));
|
||||
}
|
||||
|
|
|
@ -14,13 +14,20 @@ import static java.util.Objects.isNull;
|
|||
|
||||
public class RequestConstructor {
|
||||
|
||||
public static void addMetaHeader(Message.Builder request) {
|
||||
private RequestConstructor() {
|
||||
}
|
||||
|
||||
public static void addDefaultMetaHeader(Message.Builder request) {
|
||||
addMetaHeader(request, null);
|
||||
}
|
||||
|
||||
public static void addMetaHeader(Message.Builder request, Types.RequestMetaHeader metaHeader) {
|
||||
if (isNull(request)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isNull(metaHeader) || metaHeader.getSerializedSize() == 0) {
|
||||
metaHeader = MetaHeaderMapper.toGrpcMessage(MetaHeader.getDefault());
|
||||
metaHeader = MetaHeaderMapper.toGrpcMessage(new MetaHeader());
|
||||
setField(request, META_HEADER_FIELD_NAME, metaHeader);
|
||||
}
|
||||
}
|
||||
|
@ -31,6 +38,10 @@ public class RequestConstructor {
|
|||
frostfs.refs.Types.ObjectID oid,
|
||||
Types.ObjectSessionContext.Verb verb,
|
||||
ECDsa key) {
|
||||
if (isNull(request) || isNull(sessionToken)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var header = (Types.RequestMetaHeader) getField(request, META_HEADER_FIELD_NAME);
|
||||
if (header.getSessionToken().getSerializedSize() > 0) {
|
||||
return;
|
||||
|
|
|
@ -3,8 +3,8 @@ package info.frostfs.sdk.tools;
|
|||
import com.google.protobuf.ByteString;
|
||||
import com.google.protobuf.Message;
|
||||
import frostfs.session.Types;
|
||||
import info.frostfs.sdk.jdo.ECDsa;
|
||||
import info.frostfs.sdk.constants.CryptoConst;
|
||||
import info.frostfs.sdk.jdo.ECDsa;
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.bouncycastle.asn1.sec.SECNamedCurves;
|
||||
import org.bouncycastle.asn1.sec.SECObjectIdentifiers;
|
||||
|
@ -24,6 +24,9 @@ public class RequestSigner {
|
|||
public static final String ERROR_UNSUPPORTED_TYPE_TEMPLATE = "Unsupported message type: %s";
|
||||
public static final int RFC6979_SIGNATURE_SIZE = 64;
|
||||
|
||||
private RequestSigner() {
|
||||
}
|
||||
|
||||
public static byte[] signData(ECDsa key, byte[] data) {
|
||||
var hash = new byte[65];
|
||||
hash[0] = 0x04;
|
||||
|
|
|
@ -2,8 +2,8 @@ package info.frostfs.sdk.tools;
|
|||
|
||||
import com.google.protobuf.Message;
|
||||
import frostfs.session.Types;
|
||||
import info.frostfs.sdk.mappers.StatusMapper;
|
||||
import info.frostfs.sdk.constants.CryptoConst;
|
||||
import info.frostfs.sdk.mappers.StatusMapper;
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.bouncycastle.asn1.sec.SECNamedCurves;
|
||||
import org.bouncycastle.asn1.sec.SECObjectIdentifiers;
|
||||
|
@ -28,12 +28,17 @@ public class Verifier {
|
|||
public static final String ERROR_INVALID_RESPONSE = "Invalid response";
|
||||
public static final int RFC6979_SIG_SIZE = 64;
|
||||
|
||||
private Verifier() {
|
||||
}
|
||||
|
||||
public static boolean verifyRFC6979(frostfs.refs.Types.SignatureRFC6979 signature, Message data) {
|
||||
return verifyRFC6979(signature.getKey().toByteArray(), data.toByteArray(), signature.getSign().toByteArray());
|
||||
}
|
||||
|
||||
public static boolean verifyRFC6979(byte[] publicKey, byte[] data, byte[] sig) {
|
||||
if (isNull(publicKey) || isNull(data) || isNull(sig)) return false;
|
||||
if (isNull(publicKey) || isNull(data) || isNull(sig)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var rs = decodeSignature(sig);
|
||||
var digest = createSHA256();
|
||||
|
@ -85,9 +90,15 @@ public class Verifier {
|
|||
public static boolean verifyMatryoshkaLevel(Message data,
|
||||
frostfs.session.Types.ResponseMetaHeader meta,
|
||||
frostfs.session.Types.ResponseVerificationHeader verification) {
|
||||
if (!verifyMessagePart(verification.getMetaSignature(), meta)) return false;
|
||||
if (!verifyMessagePart(verification.getMetaSignature(), meta)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var origin = verification.getOrigin();
|
||||
if (!verifyMessagePart(verification.getOriginSignature(), origin)) return false;
|
||||
if (!verifyMessagePart(verification.getOriginSignature(), origin)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (origin.getSerializedSize() == 0) {
|
||||
return verifyMessagePart(verification.getBodySignature(), data);
|
||||
}
|
||||
|
@ -96,7 +107,9 @@ public class Verifier {
|
|||
}
|
||||
|
||||
public static boolean verifyMessagePart(frostfs.refs.Types.Signature sig, Message data) {
|
||||
if (sig.getSerializedSize() == 0 || sig.getKey().isEmpty() || sig.getSign().isEmpty()) return false;
|
||||
if (sig.getSerializedSize() == 0 || sig.getKey().isEmpty() || sig.getSign().isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var publicKey = getPublicKeyFromBytes(sig.getKey().toByteArray());
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue