Skip to content

Commit 95232ad

Browse files
committed
add more tests
1 parent 1ba4cd5 commit 95232ad

5 files changed

Lines changed: 201 additions & 41 deletions

File tree

sdk/src/main/java/io/opentdf/platform/sdk/Autoconfigure.java

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -824,7 +824,7 @@ public static String ruleToOperator(AttributeRuleTypeEnum e) {
824824
// Given a policy (list of data attributes or tags),
825825
// get a set of grants from attribute values to KASes.
826826
// Unlike `NewGranterFromService`, this works offline.
827-
public static Granter newGranterFromAttributes(KASKeyCache keyCache, Value... attrValues) throws AutoConfigureException {
827+
static Granter newGranterFromAttributes(KASKeyCache keyCache, Value... attrValues) throws AutoConfigureException {
828828
var attrsAndValues = Arrays.stream(attrValues).map(v -> {
829829
if (!v.hasAttribute()) {
830830
throw new AutoConfigureException("tried to use an attribute that is not initialized");
@@ -839,7 +839,7 @@ public static Granter newGranterFromAttributes(KASKeyCache keyCache, Value... at
839839
}
840840

841841
// Gets a list of directory of KAS grants for a list of attribute FQNs
842-
public static Granter newGranterFromService(AttributesServiceClientInterface as, KASKeyCache keyCache, AttributeValueFQN... fqns) throws AutoConfigureException {
842+
static Granter newGranterFromService(AttributesServiceClientInterface as, KASKeyCache keyCache, AttributeValueFQN... fqns) throws AutoConfigureException {
843843
GetAttributeValuesByFqnsRequest request = GetAttributeValuesByFqnsRequest.newBuilder()
844844
.addAllFqns(Arrays.stream(fqns).map(AttributeValueFQN::toString).collect(Collectors.toList()))
845845
.setWithValue(AttributeValueSelector.newBuilder().setWithKeyAccessGrants(true).build())
@@ -852,6 +852,18 @@ public static Granter newGranterFromService(AttributesServiceClientInterface as,
852852
return getGranter(keyCache, new ArrayList<>(av.getFqnAttributeValuesMap().values()));
853853
}
854854

855+
856+
static Autoconfigure.Granter createGranter(SDK.Services services, Config.TDFConfig tdfConfig) {
857+
Autoconfigure.Granter granter = new Autoconfigure.Granter(new ArrayList<>());
858+
if (tdfConfig.attributeValues != null && !tdfConfig.attributeValues.isEmpty()) {
859+
granter = Autoconfigure.newGranterFromAttributes(services.kas().getKeyCache(), tdfConfig.attributeValues.toArray(new Value[0]));
860+
} else if (tdfConfig.attributes != null && !tdfConfig.attributes.isEmpty()) {
861+
granter = Autoconfigure.newGranterFromService(services.attributes(), services.kas().getKeyCache(),
862+
tdfConfig.attributes.toArray(new Autoconfigure.AttributeValueFQN[0]));
863+
}
864+
return granter;
865+
}
866+
855867
private static Granter getGranter(KASKeyCache keyCache, List<GetAttributeValuesByFqnsResponse.AttributeAndValue> values) {
856868
Granter grants = new Granter(values.stream().map(GetAttributeValuesByFqnsResponse.AttributeAndValue::getValue).map(Value::getFqn).map(AttributeValueFQN::new).collect(Collectors.toList()));
857869
for (var attributeAndValue: values) {
@@ -862,7 +874,6 @@ private static Granter getGranter(KASKeyCache keyCache, List<GetAttributeValuesB
862874
var attribute = attributeAndValue.getAttribute();
863875
var namespace = attribute.getNamespace();
864876

865-
866877
if (grants.addAllGrants(fqn, value.getGrantsList(), value.getKasKeysList(), attribute, keyCache)) {
867878
storeKeysToCache(value.getGrantsList(), value.getKasKeysList(), keyCache);
868879
continue;

sdk/src/main/java/io/opentdf/platform/sdk/Planner.java

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77
import io.opentdf.platform.policy.Algorithm;
88
import io.opentdf.platform.policy.SimpleKasKey;
99
import io.opentdf.platform.policy.SimpleKasPublicKey;
10-
import io.opentdf.platform.policy.Value;
1110
import io.opentdf.platform.wellknownconfiguration.GetWellKnownConfigurationRequest;
1211
import io.opentdf.platform.wellknownconfiguration.GetWellKnownConfigurationResponse;
12+
import io.opentdf.platform.wellknownconfiguration.WellKnownServiceClientInterface;
1313
import org.slf4j.Logger;
1414
import org.slf4j.LoggerFactory;
1515

@@ -21,6 +21,8 @@
2121
import java.util.Objects;
2222
import java.util.Optional;
2323
import java.util.UUID;
24+
import java.util.function.BiFunction;
25+
2426

2527
public class Planner {
2628
private static final String BASE_KEY = "base_key";
@@ -30,7 +32,7 @@ public class Planner {
3032

3133
private static final Logger logger = LoggerFactory.getLogger(Planner.class);
3234

33-
public Planner(Config.TDFConfig config, SDK.Services services) {
35+
public Planner(Config.TDFConfig config, SDK.Services services, BiFunction<SDK.Services, Config.TDFConfig, Autoconfigure.Granter> granterFactory) {
3436
this.tdfConfig = Objects.requireNonNull(config);
3537
this.services = Objects.requireNonNull(services);
3638
}
@@ -45,7 +47,7 @@ Map<String, List<Config.KASInfo>> getSplits(Config.TDFConfig tdfConfig) {
4547
if (tdfConfig.splitPlan != null && !tdfConfig.splitPlan.isEmpty()) {
4648
throw new IllegalArgumentException("cannot use autoconfigure with a split plan provided in the TDFConfig");
4749
}
48-
splitPlan = getAutoconfigurePlan(tdfConfig);
50+
splitPlan = getAutoconfigurePlan(services, tdfConfig);
4951
} else if (tdfConfig.splitPlan == null || tdfConfig.splitPlan.isEmpty()) {
5052
splitPlan = generatePlanFromProvidedKases(tdfConfig.kasInfoList);
5153
} else {
@@ -58,17 +60,12 @@ Map<String, List<Config.KASInfo>> getSplits(Config.TDFConfig tdfConfig) {
5860
return resolveKeys(splitPlan);
5961
}
6062

61-
private List<Autoconfigure.KeySplitStep> getAutoconfigurePlan(Config.TDFConfig tdfConfig) {
62-
Autoconfigure.Granter granter = new Autoconfigure.Granter(new ArrayList<>());
63-
if (tdfConfig.attributeValues != null && !tdfConfig.attributeValues.isEmpty()) {
64-
granter = Autoconfigure.newGranterFromAttributes(services.kas().getKeyCache(), tdfConfig.attributeValues.toArray(new Value[0]));
65-
} else if (tdfConfig.attributes != null && !tdfConfig.attributes.isEmpty()) {
66-
granter = Autoconfigure.newGranterFromService(services.attributes(), services.kas().getKeyCache(),
67-
tdfConfig.attributes.toArray(new Autoconfigure.AttributeValueFQN[0]));
68-
}
69-
return granter.getSplits(defaultKases(tdfConfig), Planner::getUUID, this::fetchBaseKey);
63+
private static List<Autoconfigure.KeySplitStep> getAutoconfigurePlan(SDK.Services services, Config.TDFConfig tdfConfig) {
64+
Autoconfigure.Granter granter = Autoconfigure.createGranter(services, tdfConfig);
65+
return granter.getSplits(defaultKases(tdfConfig), Planner::getUUID, () -> Planner.fetchBaseKey(services.wellknown()));
7066
}
7167

68+
7269
List<Autoconfigure.KeySplitStep> generatePlanFromProvidedKases(List<Config.KASInfo> kases) {
7370
if (kases.size() == 1) {
7471
var kasInfo = kases.get(0);
@@ -81,8 +78,8 @@ List<Autoconfigure.KeySplitStep> generatePlanFromProvidedKases(List<Config.KASIn
8178
return splitPlan;
8279
}
8380

84-
Optional<SimpleKasKey> fetchBaseKey() {
85-
var responseMessage = services.wellknown()
81+
static Optional<SimpleKasKey> fetchBaseKey(WellKnownServiceClientInterface wellknown) {
82+
var responseMessage = wellknown
8683
.getWellKnownConfigurationBlocking(GetWellKnownConfigurationRequest.getDefaultInstance(), Collections.emptyMap())
8784
.execute();
8885
GetWellKnownConfigurationResponse response;
@@ -143,7 +140,6 @@ private static class Key {
143140
}
144141
}
145142

146-
147143
Map<String, List<Config.KASInfo>> resolveKeys(List<Autoconfigure.KeySplitStep> splitPlan) {
148144
Map<String, List<Config.KASInfo>> conjunction = new HashMap<>();
149145
var latestKASInfo = new HashMap<String, Config.KASInfo>();

sdk/src/main/java/io/opentdf/platform/sdk/TDF.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,7 @@ private static byte[] calculateSignature(byte[] data, byte[] secret, Config.Inte
345345
}
346346

347347
TDFObject createTDF(InputStream payload, OutputStream outputStream, Config.TDFConfig tdfConfig) throws SDKException, IOException {
348-
Planner planner = new Planner(tdfConfig, services);
348+
Planner planner = new Planner(tdfConfig, services, Autoconfigure::createGranter);
349349
Map<String, List<KASInfo>> splits = planner.getSplits(tdfConfig);
350350

351351
TDFObject tdfObject = new TDFObject();

sdk/src/test/java/io/opentdf/platform/sdk/AutoconfigureTest.java

Lines changed: 102 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import org.assertj.core.api.AtomicIntegerArrayAssert;
3939
import org.junit.jupiter.api.BeforeAll;
4040
import org.junit.jupiter.api.Test;
41+
import org.junit.platform.commons.JUnitException;
4142
import org.mockito.Mockito;
4243

4344
import java.util.ArrayList;
@@ -532,7 +533,7 @@ void testUsingAttributeMappedAtNamespace() {
532533

533534
@Test
534535
void testUsingAttributeMappedAtMultiplePlaces() {
535-
var attributes = new Value[] { mockValueFor(mp2uns2uns), mockValueFor(mp2uns2mp) };
536+
var attributes = new Value[]{mockValueFor(mp2uns2uns), mockValueFor(mp2uns2mp)};
536537
Granter granter = Autoconfigure.newGranterFromAttributes(new KASKeyCache(), attributes);
537538
var counter = new AtomicInteger(0);
538539
var splitPlan = granter.getSplits(Collections.emptyList(), () -> Integer.toString(counter.getAndIncrement()), () -> Optional.empty());
@@ -756,7 +757,7 @@ private static class ReasonerTestCase {
756757
private final List<KeySplitStep> plan;
757758

758759
ReasonerTestCase(String name, List<AttributeValueFQN> policy, List<String> defaults, String ats, String keyed,
759-
String reduced, List<KeySplitStep> plan) {
760+
String reduced, List<KeySplitStep> plan) {
760761
this.name = name;
761762
this.policy = policy;
762763
this.defaults = defaults;
@@ -809,8 +810,8 @@ public List<KeySplitStep> getPlan() {
809810
void testStoreKeysToCache_NoKeys() {
810811
KASKeyCache keyCache = Mockito.mock(KASKeyCache.class);
811812
KeyAccessServer kas1 = KeyAccessServer.newBuilder().setPublicKey(
812-
PublicKey.newBuilder().setCached(
813-
KasPublicKeySet.newBuilder()))
813+
PublicKey.newBuilder().setCached(
814+
KasPublicKeySet.newBuilder()))
814815
.build();
815816

816817
Autoconfigure.storeKeysToCache(List.of(kas1), Collections.emptyList(), keyCache);
@@ -906,7 +907,7 @@ void testStoreKeysToCache_MultipleKasEntries() {
906907
}
907908

908909
GetAttributeValuesByFqnsResponse getResponseWithGrants(GetAttributeValuesByFqnsRequest req,
909-
List<KeyAccessServer> grants) {
910+
List<KeyAccessServer> grants) {
910911
GetAttributeValuesByFqnsResponse.Builder builder = GetAttributeValuesByFqnsResponse.newBuilder();
911912

912913
for (String v : req.getFqnsList()) {
@@ -958,13 +959,15 @@ void testKeyCacheFromGrants() {
958959

959960
AttributesServiceClient attributesServiceClient = mock(AttributesServiceClient.class);
960961
when(attributesServiceClient.getAttributeValuesByFqnsBlocking(any(), any())).thenAnswer(invocation -> {
961-
var request = (GetAttributeValuesByFqnsRequest)invocation.getArgument(0);
962-
return new UnaryBlockingCall<GetAttributeValuesByFqnsResponse>(){
962+
var request = (GetAttributeValuesByFqnsRequest) invocation.getArgument(0);
963+
return new UnaryBlockingCall<GetAttributeValuesByFqnsResponse>() {
963964
@Override
964965
public ResponseMessage<GetAttributeValuesByFqnsResponse> execute() {
965966
return new ResponseMessage.Success<>(getResponseWithGrants(request, List.of(kas1)), Collections.emptyMap(), Collections.emptyMap());
966967
}
967-
@Override public void cancel() {
968+
969+
@Override
970+
public void cancel() {
968971
// not really calling anything
969972
}
970973
};
@@ -996,17 +999,19 @@ public ResponseMessage<GetAttributeValuesByFqnsResponse> execute() {
996999
void testUsingBaseKeyWhenNoMappedKeysOrGrants() {
9971000
Autoconfigure.Granter granter = Autoconfigure.newGranterFromAttributes(null);
9981001
SimpleKasKey key = SimpleKasKey.newBuilder()
999-
.setKasUri("https://example.com/kas")
1000-
.setPublicKey(
1001-
SimpleKasPublicKey.newBuilder()
1002-
.setKid("thenewkid")
1003-
.setPem("anotherpem")
1004-
.setAlgorithm(Algorithm.ALGORITHM_EC_P521)
1005-
).build();
1002+
.setKasUri("https://example.com/kas")
1003+
.setPublicKey(
1004+
SimpleKasPublicKey.newBuilder()
1005+
.setKid("thenewkid")
1006+
.setPem("anotherpem")
1007+
.setAlgorithm(Algorithm.ALGORITHM_EC_P521)
1008+
).build();
10061009

10071010
var splits = granter.getSplits(
10081011
List.of("https://example.org/kas2"),
1009-
() -> { throw new IllegalStateException("the plan should have a single element"); },
1012+
() -> {
1013+
throw new IllegalStateException("the plan should have a single element");
1014+
},
10101015
() -> Optional.of(key));
10111016
assertThat(splits).hasSize(1);
10121017
assertThat(splits.get(0)).isEqualTo(new KeySplitStep("https://example.com/kas", "", "thenewkid"));
@@ -1029,4 +1034,85 @@ void testUsingDefaultKasesWhenNothingElseProvided() {
10291034
new KeySplitStep("https://example.org/kas2", "1", null)
10301035
);
10311036
}
1037+
1038+
@Test
1039+
void createsGranterFromAttributeValues() {
1040+
// Arrange
1041+
Config.TDFConfig config = new Config.TDFConfig();
1042+
config.attributeValues = List.of(mockValueFor(spk2spk), mockValueFor(rel2gbr));
1043+
1044+
SDK.Services services = mock(SDK.Services.class);
1045+
SDK.KAS kas = mock(SDK.KAS.class);
1046+
when(services.kas()).thenReturn(kas);
1047+
when(services.attributes()).thenThrow(new IllegalStateException("should never use the attribute service when attributes are provided"));
1048+
when(kas.getKeyCache()).thenReturn(null); // No cache needed for this test
1049+
1050+
// Act
1051+
Autoconfigure.Granter granter = Autoconfigure.createGranter(services, config);
1052+
1053+
// Assert
1054+
assertThat(granter).isNotNull();
1055+
assertThat(granter.getPolicy()).hasSize(2);
1056+
assertThat(granter.getPolicy()).containsExactlyInAnyOrder(
1057+
new AttributeValueFQN("https://other.com/attr/specified/value/specked"),
1058+
new AttributeValueFQN("https://virtru.com/attr/Releasable%20To/value/GBR")
1059+
);
1060+
}
1061+
1062+
@Test
1063+
void createsGranterFromService() {
1064+
// Arrange
1065+
SDK.Services services = mock(SDK.Services.class);
1066+
SDK.KAS kas = mock(SDK.KAS.class);
1067+
AttributesServiceClient attributesServiceClient = mock(AttributesServiceClient.class);
1068+
1069+
// Prepare a request and a mocked response
1070+
List<AttributeValueFQN> policy = List.of(
1071+
new AttributeValueFQN("https://other.com/attr/specified/value/specked"),
1072+
new AttributeValueFQN("https://virtru.com/attr/Releasable%20To/value/GBR")
1073+
);
1074+
// GetAttributeValuesByFqnsRequest request = GetAttributeValuesByFqnsRequest.newBuilder()
1075+
// .addAllFqns(policy.stream().map(AttributeValueFQN::toString).collect(Collectors.toList()))
1076+
// .build();
1077+
1078+
when(services.kas()).thenReturn(kas);
1079+
when(services.attributes()).thenReturn(attributesServiceClient);
1080+
1081+
// Mock the attribute service to return a response with the expected values
1082+
when(attributesServiceClient.getAttributeValuesByFqnsBlocking(any(), any())).thenAnswer(invocation -> {
1083+
return new UnaryBlockingCall<GetAttributeValuesByFqnsResponse>() {
1084+
@Override
1085+
public ResponseMessage<GetAttributeValuesByFqnsResponse> execute() {
1086+
GetAttributeValuesByFqnsResponse.Builder builder = GetAttributeValuesByFqnsResponse.newBuilder();
1087+
for (AttributeValueFQN fqn : policy) {
1088+
Value value = Value.newBuilder()
1089+
.setId(fqn.toString())
1090+
.setFqn(fqn.toString())
1091+
.build();
1092+
builder.putFqnAttributeValues(fqn.toString(),
1093+
GetAttributeValuesByFqnsResponse.AttributeAndValue.newBuilder()
1094+
.setValue(value)
1095+
.build());
1096+
}
1097+
return new ResponseMessage.Success<>(builder.build(), Collections.emptyMap(), Collections.emptyMap());
1098+
}
1099+
1100+
@Override
1101+
public void cancel() {
1102+
}
1103+
};
1104+
});
1105+
1106+
// Act
1107+
Autoconfigure.Granter granter = Autoconfigure.createGranter(services, new Config.TDFConfig() {{
1108+
attributeValues = null; // force use of service
1109+
attributes = policy;
1110+
}});
1111+
1112+
// Assert
1113+
assertThat(granter).isNotNull();
1114+
// The policy should be empty because attributeValues is null, but the test ensures the service is called
1115+
// If you want to check the service call, verify it:
1116+
verify(services).attributes();
1117+
}
10321118
}

0 commit comments

Comments
 (0)