Skip to content

Commit 78031d8

Browse files
committed
one more test
1 parent e900df3 commit 78031d8

3 files changed

Lines changed: 118 additions & 16 deletions

File tree

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

Lines changed: 48 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import java.util.ArrayList;
2525
import java.util.Arrays;
2626
import java.util.Collections;
27+
import java.util.Comparator;
2728
import java.util.HashMap;
2829
import java.util.HashSet;
2930
import java.util.List;
@@ -294,7 +295,6 @@ boolean addAllGrants(AttributeValueFQN fqn, List<KeyAccessServer> granted, List<
294295
mappedKeys.computeIfAbsent(fqn.key, k -> new ArrayList<>()).add(Config.KASInfo.fromSimpleKasKey(mappedKey));
295296
grants.computeIfAbsent(fqn.key, k -> new KeyAccessGrant(attr, new ArrayList<>())).kases.add(mappedKey.getKasUri());
296297
}
297-
storeKeysToCache(granted, mapped, keyCache);
298298

299299
if (foundMappedKey) {
300300
hasMappedKeys = true;
@@ -582,7 +582,7 @@ public String toString() {
582582

583583
}
584584

585-
static class PublicKeyInfo {
585+
static class PublicKeyInfo implements Comparable<PublicKeyInfo> {
586586
final String kas;
587587
final String kid;
588588

@@ -598,6 +598,44 @@ static class PublicKeyInfo {
598598
String getKas() {
599599
return kas;
600600
}
601+
602+
@Override
603+
public boolean equals(Object o) {
604+
if (o == null || getClass() != o.getClass()) return false;
605+
PublicKeyInfo that = (PublicKeyInfo) o;
606+
return Objects.equals(kas, that.kas) && Objects.equals(kid, that.kid);
607+
}
608+
609+
@Override
610+
public int hashCode() {
611+
return Objects.hash(kas, kid);
612+
}
613+
614+
@Override
615+
public String toString() {
616+
return "PublicKeyInfo{" +
617+
"kas='" + kas + '\'' +
618+
", kid='" + kid + '\'' +
619+
'}';
620+
}
621+
622+
@Override
623+
public int compareTo(PublicKeyInfo o) {
624+
if (this.kas.equals(o.kas)) {
625+
if (this.kid == null && o.kid == null) {
626+
return 0;
627+
}
628+
if (this.kid == null) {
629+
return -1;
630+
}
631+
if (o.kid == null) {
632+
return 1;
633+
}
634+
return this.kid.compareTo(o.kid);
635+
} else {
636+
return this.kas.compareTo(o.kas);
637+
}
638+
}
601639
}
602640

603641
static class KeyClause {
@@ -678,7 +716,7 @@ public BooleanKeyExpression reduce() {
678716
continue;
679717
}
680718
Disjunction terms = new Disjunction();
681-
terms.add(k.getKas());
719+
terms.add(k);
682720
if (!within(conjunction, terms)) {
683721
conjunction.add(terms);
684722
}
@@ -690,25 +728,22 @@ public BooleanKeyExpression reduce() {
690728
}
691729

692730
List<KeyClause> newValues = new ArrayList<>();
693-
for (List<String> d : conjunction) {
731+
for (List<PublicKeyInfo> d : conjunction) {
694732
List<PublicKeyInfo> pki = new ArrayList<>();
695-
for (String k : d) {
696-
pki.add(new PublicKeyInfo(k));
697-
}
733+
pki.addAll(d);
698734
newValues.add(new KeyClause(RuleType.ANY_OF, pki));
699735
}
700736
return new BooleanKeyExpression(newValues);
701737
}
702738

703739
public Disjunction sortedNoDupes(List<PublicKeyInfo> l) {
704-
Set<String> set = new HashSet<>();
740+
Set<PublicKeyInfo> set = new HashSet<>();
705741
Disjunction list = new Disjunction();
706742

707743
for (PublicKeyInfo e : l) {
708-
String kas = e.getKas();
709-
if (!kas.equals(RuleType.EMPTY_TERM) && !set.contains(kas)) {
710-
set.add(kas);
711-
list.add(kas);
744+
if (!Objects.equals(e.getKas(), RuleType.EMPTY_TERM) && !set.contains(e)) {
745+
set.add(e);
746+
list.add(e);
712747
}
713748
}
714749

@@ -718,7 +753,7 @@ public Disjunction sortedNoDupes(List<PublicKeyInfo> l) {
718753

719754
}
720755

721-
static class Disjunction extends ArrayList<String> {
756+
static class Disjunction extends ArrayList<PublicKeyInfo> {
722757

723758
public boolean less(Disjunction r) {
724759
int m = Math.min(this.size(), r.size());

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ Map<String, List<Config.KASInfo>> getSplits(Config.TDFConfig tdfConfig) {
5252
splitPlan = tdfConfig.splitPlan;
5353
}
5454

55-
if (tdfConfig.kasInfoList.isEmpty() && tdfConfig.splitPlan.isEmpty()) {
55+
if (tdfConfig.kasInfoList.isEmpty() && splitPlan.isEmpty()) {
5656
throw new SDK.KasInfoMissing("kas information is missing, no key access template specified or inferred");
5757
}
5858
return fillInKeys(tdfConfig, splitPlan);
@@ -112,12 +112,14 @@ Optional<SimpleKasKey> fetchBaseKey() {
112112
}
113113

114114
if (baseKey == null || baseKey.kasUrl == null || baseKey.publicKey == null || baseKey.publicKey.kid == null || baseKey.publicKey.pem == null || baseKey.publicKey.algorithm == null) {
115-
throw new SDKException("base key in well known configuration is missing required fields [" + baseKeyJson + "]");
115+
logger.error("base key in well known configuration is missing required fields [{}]. base key will not be used", baseKeyJson);
116+
return Optional.empty();
116117
}
117118

118119
return Optional.of(SimpleKasKey.newBuilder()
119120
.setKasUri(baseKey.kasUrl)
120-
.setPublicKey(SimpleKasPublicKey.newBuilder()
121+
.setPublicKey(
122+
SimpleKasPublicKey.newBuilder()
121123
.setKid(baseKey.publicKey.kid)
122124
.setAlgorithm(baseKey.publicKey.algorithm)
123125
.setPem(baseKey.publicKey.pem)

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

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
import com.connectrpc.ResponseMessage;
1515
import com.connectrpc.UnaryBlockingCall;
16+
import io.opentdf.platform.policy.Algorithm;
1617
import io.opentdf.platform.policy.Attribute;
1718
import io.opentdf.platform.policy.AttributeRuleTypeEnum;
1819
import io.opentdf.platform.policy.KasPublicKey;
@@ -21,6 +22,8 @@
2122
import io.opentdf.platform.policy.KeyAccessServer;
2223
import io.opentdf.platform.policy.Namespace;
2324
import io.opentdf.platform.policy.PublicKey;
25+
import io.opentdf.platform.policy.SimpleKasKey;
26+
import io.opentdf.platform.policy.SimpleKasPublicKey;
2427
import io.opentdf.platform.policy.Value;
2528
import io.opentdf.platform.policy.attributes.AttributesServiceClient;
2629
import io.opentdf.platform.policy.attributes.GetAttributeValuesByFqnsRequest;
@@ -31,6 +34,7 @@
3134
import io.opentdf.platform.sdk.Autoconfigure.KeySplitStep;
3235
import io.opentdf.platform.sdk.Autoconfigure.Granter;
3336

37+
import org.assertj.core.api.AtomicIntegerArrayAssert;
3438
import org.junit.jupiter.api.BeforeAll;
3539
import org.junit.jupiter.api.Test;
3640
import org.mockito.Mockito;
@@ -39,8 +43,10 @@
3943
import java.util.Collections;
4044
import java.util.HashSet;
4145
import java.util.List;
46+
import java.util.Objects;
4247
import java.util.Optional;
4348
import java.util.Set;
49+
import java.util.concurrent.atomic.AtomicInteger;
4450
import java.util.stream.Collectors;
4551
import java.util.regex.Matcher;
4652
import java.util.regex.Pattern;
@@ -57,6 +63,16 @@ public class AutoconfigureTest {
5763
public static final String SPECIFIED_KAS = "https://attr.kas.com/";
5864
public static final String EVEN_MORE_SPECIFIC_KAS = "https://value.kas.com/";
5965
private static final String NAMESPACE_KAS = "https://namespace.kas.com/";
66+
private static final SimpleKasKey NAMESPACE_KAS_KEY = SimpleKasKey.newBuilder().setKasUri("https://mapped.example.com").setKasId("mapped").setPublicKey(
67+
SimpleKasPublicKey.newBuilder().setAlgorithm(Algorithm.ALGORITHM_EC_P521).setPem("namespacekey").setKid("namespacekeykid").build()
68+
).build();
69+
private static final SimpleKasKey ATTRIBUTE_KEY = SimpleKasKey.newBuilder().setKasUri("https://mapped.example.com").setKasId("mapped").setPublicKey(
70+
SimpleKasPublicKey.newBuilder().setAlgorithm(Algorithm.ALGORITHM_EC_P521).setPem("attrpem").setKid("attrkeykid").build()
71+
).build();
72+
private static final SimpleKasKey VALUE_KEY = SimpleKasKey.newBuilder().setKasUri("https://mapped.example.com").setKasId("mapped").setPublicKey(
73+
SimpleKasPublicKey.newBuilder().setAlgorithm(Algorithm.ALGORITHM_EC_P521).setPem("valuepem").setKid("valuekeykid").build()
74+
).build();
75+
private static Autoconfigure.AttributeNameFQN UNMAPPED;
6076
private static Autoconfigure.AttributeNameFQN SPKSPECKED;
6177
private static Autoconfigure.AttributeNameFQN SPKUNSPECKED;
6278

@@ -65,6 +81,8 @@ public class AutoconfigureTest {
6581
private static Autoconfigure.AttributeNameFQN REL;
6682
private static Autoconfigure.AttributeNameFQN UNSPECKED;
6783
private static Autoconfigure.AttributeNameFQN SPECKED;
84+
private static Autoconfigure.AttributeNameFQN MAPPED;
85+
private static Autoconfigure.AttributeNameFQN SPKMAPPED;
6886

6987
private static Autoconfigure.AttributeValueFQN clsA;
7088
private static Autoconfigure.AttributeValueFQN clsS;
@@ -85,6 +103,9 @@ public class AutoconfigureTest {
85103
private static Autoconfigure.AttributeValueFQN spk2spk2uns;
86104
private static Autoconfigure.AttributeValueFQN spk2spk2spk;
87105

106+
private static Autoconfigure.AttributeValueFQN mp2uns2uns;
107+
private static Autoconfigure.AttributeValueFQN mp2uns2mp;
108+
88109
@BeforeAll
89110
public static void setup() throws AutoConfigureException {
90111
// Initialize the FQNs (Fully Qualified Names)
@@ -93,8 +114,11 @@ public static void setup() throws AutoConfigureException {
93114
REL = new Autoconfigure.AttributeNameFQN("https://virtru.com/attr/Releasable%20To");
94115
UNSPECKED = new Autoconfigure.AttributeNameFQN("https://other.com/attr/unspecified");
95116
SPECKED = new Autoconfigure.AttributeNameFQN("https://other.com/attr/specified");
117+
MAPPED = new Autoconfigure.AttributeNameFQN("https://other.com/attr/mapped");
118+
UNMAPPED = new Autoconfigure.AttributeNameFQN("https://mapped.com/attr/unspecified");
96119
SPKUNSPECKED = new Autoconfigure.AttributeNameFQN("https://hasgrants.com/attr/unspecified");
97120
SPKSPECKED = new Autoconfigure.AttributeNameFQN("https://hasgrants.com/attr/specified");
121+
SPKMAPPED = new Autoconfigure.AttributeNameFQN("https://hasgrants.com/attr/mapped");
98122

99123
clsA = new Autoconfigure.AttributeValueFQN("https://virtru.com/attr/Classification/value/Allowed");
100124
clsS = new Autoconfigure.AttributeValueFQN("https://virtru.com/attr/Classification/value/Secret");
@@ -118,6 +142,9 @@ public static void setup() throws AutoConfigureException {
118142
spk2uns2spk = new Autoconfigure.AttributeValueFQN("https://hasgrants.com/attr/unspecified/value/specked");
119143
spk2spk2uns = new Autoconfigure.AttributeValueFQN("https://hasgrants.com/attr/specified/value/unspecked");
120144
spk2spk2spk = new Autoconfigure.AttributeValueFQN("https://hasgrants.com/attr/specified/value/specked");
145+
146+
mp2uns2uns = new Autoconfigure.AttributeValueFQN("https://mapped.com/attr/unspecified/value/unspecked");
147+
mp2uns2mp = new Autoconfigure.AttributeValueFQN("https://mapped.com/attr/unspecified/value/mapped");
121148
}
122149

123150
private static String spongeCase(String s) {
@@ -182,6 +209,7 @@ private Attribute mockAttributeFor(Autoconfigure.AttributeNameFQN fqn) {
182209
Namespace ns1 = Namespace.newBuilder().setId("v").setName("virtru.com").setFqn("https://virtru.com").build();
183210
Namespace ns2 = Namespace.newBuilder().setId("o").setName("other.com").setFqn("https://other.com").build();
184211
Namespace ns3 = Namespace.newBuilder().setId("h").setName("hasgrants.com").addGrants(KeyAccessServer.newBuilder().setUri(NAMESPACE_KAS).build()).setFqn("https://hasgrants.com").build();
212+
Namespace ns4 = Namespace.newBuilder().setId("m").setName("mapped.com").addKasKeys(NAMESPACE_KAS_KEY).build();
185213

186214
String key = fqn.getKey();
187215
if (key.equals(CLS.getKey())) {
@@ -217,6 +245,17 @@ private Attribute mockAttributeFor(Autoconfigure.AttributeNameFQN fqn) {
217245
.setName("unspecified").setRule(AttributeRuleTypeEnum.ATTRIBUTE_RULE_TYPE_ENUM_ANY_OF)
218246
.setName(fqn.toString())
219247
.build();
248+
} else if (key.equals(MAPPED.getKey())) {
249+
return Attribute.newBuilder().setId(MAPPED.getKey()).setNamespace(ns4)
250+
.setName("mapped attribute").setRule(AttributeRuleTypeEnum.ATTRIBUTE_RULE_TYPE_ENUM_ANY_OF)
251+
.setKasKeys(0, ATTRIBUTE_KEY)
252+
.setName(fqn.toString())
253+
.build();
254+
} else if (key.equals(UNMAPPED.getKey())) {
255+
return Attribute.newBuilder().setId(UNMAPPED.getKey()).setNamespace(ns4)
256+
.setName("unmapped attribute").setRule(AttributeRuleTypeEnum.ATTRIBUTE_RULE_TYPE_ENUM_ANY_OF)
257+
.setName(fqn.toString())
258+
.build();
220259
}
221260

222261
throw new IllegalArgumentException("Key not recognized: " + key);
@@ -288,7 +327,13 @@ private Value mockValueFor(Autoconfigure.AttributeValueFQN fqn) throws AutoConfi
288327
p = p.toBuilder().addGrants(KeyAccessServer.newBuilder().setUri(EVEN_MORE_SPECIFIC_KAS).build())
289328
.build();
290329
}
330+
} else if (Objects.equals(UNMAPPED.getKey(), an.getKey())) {
331+
if (fqn.value().equalsIgnoreCase("mapped")) {
332+
p = p.toBuilder().addKasKeys(VALUE_KEY)
333+
.build();
334+
}
291335
}
336+
292337
return p;
293338
}
294339

@@ -475,6 +520,26 @@ public void testReasonerConstructAttributeBoolean() {
475520
}
476521
}
477522

523+
@Test
524+
void testUsingAttributeMappedAtNamespace() {
525+
Granter granter = Autoconfigure.newGranterFromAttributes(new KASKeyCache(), mockValueFor(mp2uns2uns));
526+
var counter = new AtomicInteger(0);
527+
var splitPlan = granter.getSplits(Collections.emptyList(), () -> Integer.toString(counter.getAndIncrement()), () -> Optional.empty());
528+
assertThat(splitPlan).isEqualTo(List.of(new KeySplitStep("https://mapped.example.com", "", NAMESPACE_KAS_KEY.getPublicKey().getKid())));
529+
}
530+
531+
@Test
532+
void testUsingAttributeMappedAtMultiplePlaces() {
533+
var attributes = new Value[] { mockValueFor(mp2uns2uns), mockValueFor(mp2uns2mp) };
534+
Granter granter = Autoconfigure.newGranterFromAttributes(new KASKeyCache(), attributes);
535+
var counter = new AtomicInteger(0);
536+
var splitPlan = granter.getSplits(Collections.emptyList(), () -> Integer.toString(counter.getAndIncrement()), () -> Optional.empty());
537+
assertThat(splitPlan).isEqualTo(List.of(
538+
new KeySplitStep(NAMESPACE_KAS_KEY.getKasUri(), "0", NAMESPACE_KAS_KEY.getPublicKey().getKid()),
539+
new KeySplitStep(VALUE_KEY.getKasUri(), "0", VALUE_KEY.getPublicKey().getKid())
540+
));
541+
}
542+
478543
GetAttributeValuesByFqnsResponse getResponse(GetAttributeValuesByFqnsRequest req) {
479544
GetAttributeValuesByFqnsResponse.Builder builder = GetAttributeValuesByFqnsResponse.newBuilder();
480545

0 commit comments

Comments
 (0)