Skip to content

Commit a2d8b83

Browse files
committed
minor refactor
1 parent 14288d5 commit a2d8b83

File tree

2 files changed

+57
-107
lines changed

2 files changed

+57
-107
lines changed

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

Lines changed: 49 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import org.slf4j.Logger;
1515
import org.slf4j.LoggerFactory;
1616

17+
import javax.annotation.Nonnull;
1718
import javax.annotation.Nullable;
1819
import java.io.UnsupportedEncodingException;
1920
import java.net.URLDecoder;
@@ -53,11 +54,11 @@ class RuleType {
5354
* This class includes functionality to create granter instances based on
5455
* attributes either from a list of attribute values or from a service.
5556
*/
56-
public class Autoconfigure {
57+
class Autoconfigure {
5758

58-
public static Logger logger = LoggerFactory.getLogger(Autoconfigure.class);
59+
private static Logger logger = LoggerFactory.getLogger(Autoconfigure.class);
5960

60-
public static class KeySplitStep {
61+
static class KeySplitStep {
6162
public String kas;
6263
public String splitID;
6364

@@ -93,7 +94,7 @@ public int hashCode() {
9394
}
9495

9596
// Utility class for an attribute name FQN.
96-
public static class AttributeNameFQN {
97+
static class AttributeNameFQN {
9798
private final String url;
9899
private final String key;
99100

@@ -156,7 +157,7 @@ public String name() throws AutoConfigureException {
156157
}
157158

158159
// Utility class for an attribute value FQN.
159-
public static class AttributeValueFQN {
160+
static class AttributeValueFQN {
160161
private final String url;
161162
private final String key;
162163

@@ -203,11 +204,11 @@ public int hashCode() {
203204
return Objects.hash(key);
204205
}
205206

206-
public String getKey() {
207+
String getKey() {
207208
return key;
208209
}
209210

210-
public String authority() {
211+
String authority() {
211212
Pattern pattern = Pattern.compile("^(https?://[\\w./-]+)/attr/\\S*/value/\\S*$");
212213
Matcher matcher = pattern.matcher(url);
213214
if (!matcher.find()) {
@@ -216,7 +217,7 @@ public String authority() {
216217
return matcher.group(1);
217218
}
218219

219-
public AttributeNameFQN prefix() throws AutoConfigureException {
220+
AttributeNameFQN prefix() throws AutoConfigureException {
220221
Pattern pattern = Pattern.compile("^(https?://[\\w./-]+/attr/\\S*)/value/\\S*$");
221222
Matcher matcher = pattern.matcher(url);
222223
if (!matcher.find()) {
@@ -225,7 +226,7 @@ public AttributeNameFQN prefix() throws AutoConfigureException {
225226
return new AttributeNameFQN(matcher.group(1));
226227
}
227228

228-
public String value() {
229+
String value() {
229230
Pattern pattern = Pattern.compile("^https?://[\\w./-]+/attr/\\S*/value/(\\S*)$");
230231
Matcher matcher = pattern.matcher(url);
231232
if (!matcher.find()) {
@@ -238,21 +239,21 @@ public String value() {
238239
}
239240
}
240241

241-
public String name() {
242+
String name() {
242243
Pattern pattern = Pattern.compile("^https?://[\\w./-]+/attr/(\\S*)/value/\\S*$");
243244
Matcher matcher = pattern.matcher(url);
244245
if (!matcher.find()) {
245246
throw new RuntimeException("invalid attributeInstance");
246247
}
247248
try {
248-
return URLDecoder.decode(matcher.group(1), StandardCharsets.UTF_8.name());
249-
} catch (UnsupportedEncodingException | IllegalArgumentException e) {
249+
return URLDecoder.decode(matcher.group(1), StandardCharsets.UTF_8);
250+
} catch (IllegalArgumentException e) {
250251
throw new RuntimeException("invalid attributeInstance", e);
251252
}
252253
}
253254
}
254255

255-
public static class KeyAccessGrant {
256+
static class KeyAccessGrant {
256257
public Attribute attr;
257258
public List<String> kases;
258259

@@ -295,11 +296,11 @@ public void addAllGrants(AttributeValueFQN fqn, List<KeyAccessServer> gs, Attrib
295296
}
296297
}
297298

298-
public KeyAccessGrant byAttribute(AttributeValueFQN fqn) {
299+
KeyAccessGrant byAttribute(AttributeValueFQN fqn) {
299300
return grants.get(fqn.key);
300301
}
301302

302-
public List<KeySplitStep> plan(List<String> defaultKas, Supplier<String> genSplitID)
303+
@Nonnull List<KeySplitStep> plan(List<String> defaultKas, Supplier<String> genSplitID)
303304
throws AutoConfigureException {
304305
AttributeBooleanExpression b = constructAttributeBoolean();
305306
BooleanKeyExpression k = insertKeysForAttribute(b);
@@ -311,17 +312,7 @@ public List<KeySplitStep> plan(List<String> defaultKas, Supplier<String> genSpli
311312
int l = k.size();
312313
if (l == 0) {
313314
// default behavior: split key across all default KAS
314-
if (defaultKas.isEmpty()) {
315-
throw new AutoConfigureException("no default KAS specified; required for grantless plans");
316-
} else if (defaultKas.size() == 1) {
317-
return Collections.singletonList(new KeySplitStep(defaultKas.get(0), ""));
318-
} else {
319-
List<KeySplitStep> result = new ArrayList<>();
320-
for (String kas : defaultKas) {
321-
result.add(new KeySplitStep(kas, genSplitID.get()));
322-
}
323-
return result;
324-
}
315+
return generatePlanFromDefaultKases(defaultKas, genSplitID);
325316
}
326317

327318
List<KeySplitStep> steps = new ArrayList<>();
@@ -334,6 +325,20 @@ public List<KeySplitStep> plan(List<String> defaultKas, Supplier<String> genSpli
334325
return steps;
335326
}
336327

328+
static List<KeySplitStep> generatePlanFromDefaultKases(List<String> defaultKas, Supplier<String> genSplitID) {
329+
if (defaultKas.isEmpty()) {
330+
throw new AutoConfigureException("no default KAS specified; required for grantless plans");
331+
} else if (defaultKas.size() == 1) {
332+
return Collections.singletonList(new KeySplitStep(defaultKas.get(0), ""));
333+
} else {
334+
List<KeySplitStep> result = new ArrayList<>();
335+
for (String kas : defaultKas) {
336+
result.add(new KeySplitStep(kas, genSplitID.get()));
337+
}
338+
return result;
339+
}
340+
}
341+
337342
BooleanKeyExpression insertKeysForAttribute(AttributeBooleanExpression e) throws AutoConfigureException {
338343
List<KeyClause> kcs = new ArrayList<>(e.must.size());
339344

@@ -348,6 +353,7 @@ BooleanKeyExpression insertKeysForAttribute(AttributeBooleanExpression e) throws
348353

349354
List<String> kases = grant.kases;
350355
if (kases.isEmpty()) {
356+
// TODO: replace this with a reference to the base key
351357
kases = List.of(RuleType.EMPTY_TERM);
352358
}
353359

@@ -368,6 +374,13 @@ BooleanKeyExpression insertKeysForAttribute(AttributeBooleanExpression e) throws
368374
return new BooleanKeyExpression(kcs);
369375
}
370376

377+
/**
378+
* Constructs an AttributeBooleanExpression from the policy, splitting each attribute
379+
* into its own clause. Each clause contains the attribute definition and a list of
380+
* values.
381+
* @return
382+
* @throws AutoConfigureException
383+
*/
371384
AttributeBooleanExpression constructAttributeBoolean() throws AutoConfigureException {
372385
Map<String, SingleAttributeClause> prefixes = new HashMap<>();
373386
List<String> sortedPrefixes = new ArrayList<>();
@@ -378,7 +391,7 @@ AttributeBooleanExpression constructAttributeBoolean() throws AutoConfigureExcep
378391
clause.values.add(aP);
379392
} else if (byAttribute(aP) != null) {
380393
var x = new SingleAttributeClause(byAttribute(aP).attr,
381-
new ArrayList<AttributeValueFQN>(Arrays.asList(aP)));
394+
new ArrayList<>(Arrays.asList(aP)));
382395
prefixes.put(a.getKey(), x);
383396
sortedPrefixes.add(a.getKey());
384397
}
@@ -391,39 +404,6 @@ AttributeBooleanExpression constructAttributeBoolean() throws AutoConfigureExcep
391404
return new AttributeBooleanExpression(must);
392405
}
393406

394-
static class AttributeMapping {
395-
396-
private Map<AttributeNameFQN, Attribute> dict;
397-
398-
public AttributeMapping() {
399-
this.dict = new HashMap<>();
400-
}
401-
402-
public void put(Attribute ad) throws AutoConfigureException {
403-
if (this.dict == null) {
404-
this.dict = new HashMap<>();
405-
}
406-
407-
AttributeNameFQN prefix = new AttributeNameFQN(ad.getFqn());
408-
409-
if (this.dict.containsKey(prefix)) {
410-
throw new AutoConfigureException("Attribute prefix already found: [" + prefix.toString() + "]");
411-
}
412-
413-
this.dict.put(prefix, ad);
414-
}
415-
416-
public Attribute get(AttributeNameFQN prefix) throws AutoConfigureException {
417-
Attribute ad = this.dict.get(prefix);
418-
if (ad == null) {
419-
throw new AutoConfigureException("Unknown attribute type: [" + prefix.toString() + "], not in ["
420-
+ this.dict.keySet().toString() + "]");
421-
}
422-
return ad;
423-
}
424-
425-
}
426-
427407
static class SingleAttributeClause {
428408

429409
private Attribute def;
@@ -435,9 +415,9 @@ public SingleAttributeClause(Attribute def, List<AttributeValueFQN> values) {
435415
}
436416
}
437417

438-
class AttributeBooleanExpression {
418+
static class AttributeBooleanExpression {
439419

440-
private List<SingleAttributeClause> must;
420+
private final List<SingleAttributeClause> must;
441421

442422
public AttributeBooleanExpression(List<SingleAttributeClause> must) {
443423
this.must = must;
@@ -478,7 +458,7 @@ public String toString() {
478458

479459
}
480460

481-
public class PublicKeyInfo {
461+
public static class PublicKeyInfo {
482462
private String kas;
483463

484464
public PublicKeyInfo(String kas) {
@@ -494,9 +474,9 @@ public void setKas(String kas) {
494474
}
495475
}
496476

497-
public class KeyClause {
498-
private String operator;
499-
private List<PublicKeyInfo> values;
477+
public static class KeyClause {
478+
private final String operator;
479+
private final List<PublicKeyInfo> values;
500480

501481
public KeyClause(String operator, List<PublicKeyInfo> values) {
502482
this.operator = operator;
@@ -531,8 +511,8 @@ public String toString() {
531511
}
532512
}
533513

534-
public class BooleanKeyExpression {
535-
private List<KeyClause> values;
514+
public static class BooleanKeyExpression {
515+
private final List<KeyClause> values;
536516

537517
public BooleanKeyExpression(List<KeyClause> values) {
538518
this.values = values;
@@ -612,7 +592,7 @@ public Disjunction sortedNoDupes(List<PublicKeyInfo> l) {
612592

613593
}
614594

615-
class Disjunction extends ArrayList<String> {
595+
static class Disjunction extends ArrayList<String> {
616596

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

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

Lines changed: 8 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import java.security.*;
2929
import java.text.ParseException;
3030
import java.util.*;
31+
import java.util.stream.Collectors;
3132

3233
/**
3334
* The TDF class is responsible for handling operations related to
@@ -151,22 +152,6 @@ private void prepareManifest(Config.TDFConfig tdfConfig, SDK.KAS kas) {
151152
String base64PolicyObject = encoder
152153
.encodeToString(gson.toJson(policyObject).getBytes(StandardCharsets.UTF_8));
153154
Map<String, Config.KASInfo> latestKASInfo = new HashMap<>();
154-
if (tdfConfig.splitPlan == null || tdfConfig.splitPlan.isEmpty()) {
155-
// Default split plan: Split keys across all KASes
156-
List<Autoconfigure.KeySplitStep> splitPlan = new ArrayList<>(tdfConfig.kasInfoList.size());
157-
int i = 0;
158-
for (Config.KASInfo kasInfo : tdfConfig.kasInfoList) {
159-
Autoconfigure.KeySplitStep step = new Autoconfigure.KeySplitStep(kasInfo.URL, "");
160-
if (tdfConfig.kasInfoList.size() > 1) {
161-
step.splitID = String.format("s-%d", i++);
162-
}
163-
splitPlan.add(step);
164-
if (kasInfo.PublicKey != null && !kasInfo.PublicKey.isEmpty()) {
165-
latestKASInfo.put(kasInfo.URL, kasInfo);
166-
}
167-
}
168-
tdfConfig.splitPlan = splitPlan;
169-
}
170155

171156
// Seed anything passed in manually
172157
for (Config.KASInfo kasInfo : tdfConfig.kasInfoList) {
@@ -177,7 +162,6 @@ private void prepareManifest(Config.TDFConfig tdfConfig, SDK.KAS kas) {
177162

178163
// split plan: restructure by conjunctions
179164
Map<String, List<Config.KASInfo>> conjunction = new HashMap<>();
180-
List<String> splitIDs = new ArrayList<>();
181165

182166
for (Autoconfigure.KeySplitStep splitInfo : tdfConfig.splitPlan) {
183167
// Public key was passed in with kasInfoList
@@ -192,18 +176,11 @@ private void prepareManifest(Config.TDFConfig tdfConfig, SDK.KAS kas) {
192176
latestKASInfo.put(splitInfo.kas, getKI);
193177
ki = getKI;
194178
}
195-
if (conjunction.containsKey(splitInfo.splitID)) {
196-
conjunction.get(splitInfo.splitID).add(ki);
197-
} else {
198-
List<Config.KASInfo> newList = new ArrayList<>();
199-
newList.add(ki);
200-
conjunction.put(splitInfo.splitID, newList);
201-
splitIDs.add(splitInfo.splitID);
202-
}
179+
conjunction.computeIfAbsent(splitInfo.splitID, s -> new ArrayList<>()).add(ki);
203180
}
204181

205-
List<byte[]> symKeys = new ArrayList<>(splitIDs.size());
206-
for (String splitID : splitIDs) {
182+
List<byte[]> symKeys = new ArrayList<>(conjunction.size());
183+
for (String splitID : conjunction.keySet()) {
207184
// Symmetric key
208185
byte[] symKey = new byte[GCM_KEY_SIZE];
209186
sRandom.nextBytes(symKey);
@@ -401,6 +378,7 @@ private static byte[] calculateSignature(byte[] data, byte[] secret, Config.Inte
401378

402379
TDFObject createTDF(InputStream payload, OutputStream outputStream, Config.TDFConfig tdfConfig) throws SDKException, IOException {
403380

381+
List<String> dk = defaultKases(tdfConfig);
404382
if (tdfConfig.autoconfigure) {
405383
Autoconfigure.Granter granter = new Autoconfigure.Granter(new ArrayList<>());
406384
if (tdfConfig.attributeValues != null && !tdfConfig.attributeValues.isEmpty()) {
@@ -413,14 +391,9 @@ TDFObject createTDF(InputStream payload, OutputStream outputStream, Config.TDFCo
413391
if (granter == null) {
414392
throw new AutoConfigureException("Failed to create Granter"); // Replace with appropriate error handling
415393
}
416-
417-
List<String> dk = defaultKases(tdfConfig);
418394
tdfConfig.splitPlan = granter.plan(dk, () -> UUID.randomUUID().toString());
419-
420-
if (tdfConfig.splitPlan == null) {
421-
throw new AutoConfigureException("Failed to generate Split Plan"); // Replace with appropriate error
422-
// handling
423-
}
395+
} else {
396+
tdfConfig.splitPlan = Autoconfigure.Granter.generatePlanFromDefaultKases(dk, () -> UUID.randomUUID().toString());
424397
}
425398

426399
if (tdfConfig.kasInfoList.isEmpty() && (tdfConfig.splitPlan == null || tdfConfig.splitPlan.isEmpty())) {
@@ -572,10 +545,7 @@ static List<String> defaultKases(TDFConfig config) {
572545
allk.add(kasInfo.URL);
573546
}
574547
}
575-
if (defk.isEmpty()) {
576-
return allk;
577-
}
578-
return defk;
548+
return defk.isEmpty() ? allk : defk;
579549
}
580550

581551
Reader loadTDF(SeekableByteChannel tdf, String platformUrl) throws SDKException, IOException {

0 commit comments

Comments
 (0)