Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ public class Example {
.platformEndpoint("https://your.cluster/")
.build();

// Fetch the platform base key (if configured)
sdk.getBaseKey().ifPresent(baseKey -> {
System.out.println(baseKey.getKasUri());
System.out.println(baseKey.getPublicKey().getKid());
});

// Encrypt a file
try (InputStream in = new FileInputStream("input.plaintext")) {
Config.TDFConfig c = Config.newTDFConfig(Config.withDataAttributes("attr1", "attr2"));
Expand Down
15 changes: 15 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
<protobuf.version>4.29.2</protobuf.version>
<bouncycastle.version>1.82</bouncycastle.version>
<ayza.version>10.0.0</ayza.version>
<bytebuddy.version>1.14.12</bytebuddy.version>
<!-- JaCoCo Properties -->
<jacoco.version>0.8.13</jacoco.version>
<sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
Expand Down Expand Up @@ -156,6 +157,20 @@
<artifactId>bcprov-jdk18on</artifactId>
<version>${bouncycastle.version}</version>
</dependency>
<!--
Pin Byte Buddy for test-time Mockito instrumentation on newer JVMs (e.g. Java 21).
This does NOT add a runtime dependency; it only manages the version used by modules.
-->
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>
<version>${bytebuddy.version}</version>
</dependency>
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy-agent</artifactId>
<version>${bytebuddy.version}</version>
</dependency>
</dependencies>
</dependencyManagement>

Expand Down
2 changes: 1 addition & 1 deletion sdk/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -592,4 +592,4 @@
</build>
</profile>
</profiles>
</project>
</project>
10 changes: 10 additions & 0 deletions sdk/src/main/java/io/opentdf/platform/sdk/SDK.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import com.connectrpc.impl.ProtocolClient;
import io.opentdf.platform.authorization.AuthorizationServiceClientInterface;
import io.opentdf.platform.policy.SimpleKasKey;
import io.opentdf.platform.policy.attributes.AttributesServiceClientInterface;
import io.opentdf.platform.policy.kasregistry.KeyAccessServerRegistryServiceClientInterface;
import io.opentdf.platform.policy.namespaces.NamespaceServiceClientInterface;
Expand Down Expand Up @@ -98,6 +99,15 @@ public Services getServices() {
return this.services;
}

/**
* Fetch the platform "base key" from the well-known configuration, if present.
* <p>
* This is read from the {@code base_key} field returned by {@code GetWellKnownConfiguration}.
*/
public Optional<SimpleKasKey> getBaseKey() {
return Planner.fetchBaseKey(services.wellknown());
}

public TDF.Reader loadTDF(SeekableByteChannel channel, Config.TDFReaderConfig config) throws SDKException, IOException {
var tdf = new TDF(services);
return tdf.loadTDF(channel, config, platformUrl);
Expand Down
35 changes: 34 additions & 1 deletion sdk/src/test/java/io/opentdf/platform/sdk/SDKTest.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
package io.opentdf.platform.sdk;

import com.connectrpc.impl.ProtocolClient;
import com.google.protobuf.Struct;
import com.google.protobuf.Value;
import io.opentdf.platform.policy.Algorithm;
import io.opentdf.platform.wellknownconfiguration.GetWellKnownConfigurationResponse;
import io.opentdf.platform.wellknownconfiguration.WellKnownServiceClientInterface;
import org.apache.commons.compress.utils.SeekableInMemoryByteChannel;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;

import java.io.IOException;
import java.nio.ByteBuffer;
Expand Down Expand Up @@ -30,6 +36,33 @@ void testReadingProtocolClient() {
assertThat(sdk.getPlatformServicesClient()).isSameAs(platformServicesClient);
}

@Test
void testGettingBaseKey() {
var platformServicesClient = mock(ProtocolClient.class);
var wellknownService = Mockito.mock(WellKnownServiceClientInterface.class);
var baseKeyJson = "{\"kas_url\":\"https://example.com/base_key\",\"public_key\":{\"algorithm\":\"ALGORITHM_RSA_2048\",\"kid\":\"thekid\",\"pem\": \"thepem\"}}";
var val = Value.newBuilder().setStringValue(baseKeyJson).build();
var config = Struct.newBuilder().putFields("base_key", val).build();
var response = GetWellKnownConfigurationResponse
.newBuilder()
.setConfiguration(config)
.build();

Mockito.when(wellknownService.getWellKnownConfigurationBlocking(Mockito.any(), Mockito.anyMap()))
.thenReturn(TestUtil.successfulUnaryCall(response));

var services = new FakeServicesBuilder().setWellknownService(wellknownService).build();
var sdk = new SDK(services, null, null, platformServicesClient, null);

var baseKey = sdk.getBaseKey();
assertThat(baseKey).isPresent();
var simpleKasKey = baseKey.get();
assertThat(simpleKasKey.getKasUri()).isEqualTo("https://example.com/base_key");
assertThat(simpleKasKey.getPublicKey().getAlgorithm()).isEqualTo(Algorithm.ALGORITHM_RSA_2048);
assertThat(simpleKasKey.getPublicKey().getKid()).isEqualTo("thekid");
assertThat(simpleKasKey.getPublicKey().getPem()).isEqualTo("thepem");
}

@Test
void testAuthorizationServiceClientV2() {
var platformServicesClient = mock(ProtocolClient.class);
Expand Down Expand Up @@ -108,4 +141,4 @@ void testReadingRandomBytes() {

assertThat(SDK.isTDF(new SeekableInMemoryByteChannel(tdf))).isFalse();
}
}
}
Loading