Skip to content

Commit 4368840

Browse files
feat(lib): add fallback to namespace kas (#166)
If there is no KAS specified for an attribute value, or attribute, then use the KAS specified on the namespace to mediate access to the key. Also refactor and clarify that we need attributes that have been hydrated by the service to provide a split plan. Addresses virtru-corp/data-security-platform#609 --------- Co-authored-by: Dave Mihalcik <[email protected]>
1 parent ed6e982 commit 4368840

File tree

4 files changed

+176
-106
lines changed

4 files changed

+176
-106
lines changed

cmdline/pom.xml

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,22 @@
7474
<artifactId>picocli</artifactId>
7575
<version>4.7.6</version>
7676
</dependency>
77+
<dependency>
78+
<groupId>org.apache.logging.log4j</groupId>
79+
<artifactId>log4j-slf4j2-impl</artifactId>
80+
</dependency>
81+
<dependency>
82+
<groupId>org.apache.logging.log4j</groupId>
83+
<artifactId>log4j-core</artifactId>
84+
</dependency>
85+
<dependency>
86+
<groupId>org.apache.logging.log4j</groupId>
87+
<artifactId>log4j-api</artifactId>
88+
</dependency>
7789
<dependency>
7890
<groupId>io.opentdf.platform</groupId>
7991
<artifactId>sdk</artifactId>
8092
<version>${project.version}</version>
8193
</dependency>
8294
</dependencies>
83-
</project>
95+
</project>

cmdline/src/main/resources/log4j2.xml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<configuration status="WARN">
3+
<appenders>
4+
<Console name="Console" target="SYSTEM_ERR">
5+
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
6+
</Console>
7+
</appenders>
8+
<loggers>
9+
<root level="trace">
10+
<appender-ref ref="Console"/>
11+
</root>
12+
<Logger name="io.grpc.netty" level="error" additivity="false">
13+
<AppenderRef ref="Console" />
14+
</Logger>
15+
</loggers>
16+
</configuration>

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

Lines changed: 75 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,21 @@
11
package io.opentdf.platform.sdk;
22

3+
import com.google.common.base.Supplier;
4+
import io.opentdf.platform.policy.Attribute;
5+
import io.opentdf.platform.policy.AttributeRuleTypeEnum;
6+
import io.opentdf.platform.policy.AttributeValueSelector;
7+
import io.opentdf.platform.policy.KasPublicKey;
8+
import io.opentdf.platform.policy.KasPublicKeyAlgEnum;
9+
import io.opentdf.platform.policy.KeyAccessServer;
10+
import io.opentdf.platform.policy.Value;
11+
import io.opentdf.platform.policy.attributes.AttributesServiceGrpc.AttributesServiceFutureStub;
12+
import io.opentdf.platform.policy.attributes.GetAttributeValuesByFqnsRequest;
13+
import io.opentdf.platform.policy.attributes.GetAttributeValuesByFqnsResponse;
14+
import io.opentdf.platform.policy.attributes.GetAttributeValuesByFqnsResponse.AttributeAndValue;
15+
import org.slf4j.Logger;
16+
import org.slf4j.LoggerFactory;
17+
18+
import javax.annotation.Nullable;
319
import java.io.UnsupportedEncodingException;
420
import java.net.URLDecoder;
521
import java.net.URLEncoder;
@@ -19,23 +35,6 @@
1935
import java.util.regex.Pattern;
2036
import java.util.stream.Collectors;
2137

22-
import org.slf4j.Logger;
23-
import org.slf4j.LoggerFactory;
24-
25-
import com.google.common.base.Supplier;
26-
27-
import io.opentdf.platform.policy.KeyAccessServer;
28-
import io.opentdf.platform.policy.attributes.AttributesServiceGrpc.AttributesServiceFutureStub;
29-
import io.opentdf.platform.policy.attributes.GetAttributeValuesByFqnsRequest;
30-
import io.opentdf.platform.policy.attributes.GetAttributeValuesByFqnsResponse;
31-
import io.opentdf.platform.policy.attributes.GetAttributeValuesByFqnsResponse.AttributeAndValue;
32-
import io.opentdf.platform.policy.Attribute;
33-
import io.opentdf.platform.policy.Value;
34-
import io.opentdf.platform.policy.KasPublicKey;
35-
import io.opentdf.platform.policy.AttributeValueSelector;
36-
import io.opentdf.platform.policy.AttributeRuleTypeEnum;
37-
import io.opentdf.platform.policy.KasPublicKeyAlgEnum;
38-
3938
// Attribute rule types: operators!
4039
class RuleType {
4140
public static final String HIERARCHY = "hierarchy";
@@ -349,7 +348,7 @@ BooleanKeyExpression insertKeysForAttribute(AttributeBooleanExpression e) throws
349348
}
350349

351350
String op = ruleToOperator(clause.def.getRule());
352-
if (op == RuleType.UNSPECIFIED) {
351+
if (op.equals(RuleType.UNSPECIFIED)) {
353352
logger.warn("Unknown attribute rule type: " + clause);
354353
}
355354

@@ -672,80 +671,81 @@ public static String ruleToOperator(AttributeRuleTypeEnum e) {
672671

673672
}
674673

674+
// Given a policy (list of data attributes or tags),
675+
// get a set of grants from attribute values to KASes.
676+
// Unlike `NewGranterFromService`, this works offline.
677+
public static Granter newGranterFromAttributes(Value... attrValues) throws AutoConfigureException {
678+
var attrsAndValues = Arrays.stream(attrValues).map(v -> {
679+
if (!v.hasAttribute()) {
680+
throw new AutoConfigureException("tried to use an attribute that is not initialized");
681+
}
682+
return AttributeAndValue.newBuilder()
683+
.setValue(v)
684+
.setAttribute(v.getAttribute())
685+
.build();
686+
}).collect(Collectors.toList());
687+
688+
return getGranter(null, attrsAndValues);
689+
}
690+
675691
// Gets a list of directory of KAS grants for a list of attribute FQNs
676-
public static Granter newGranterFromService(AttributesServiceFutureStub as, KASKeyCache keyCache,
677-
AttributeValueFQN... fqns) throws AutoConfigureException, InterruptedException, ExecutionException {
678-
String[] fqnsStr = new String[fqns.length];
679-
for (int i = 0; i < fqns.length; i++) {
680-
fqnsStr[i] = fqns[i].toString();
681-
}
692+
public static Granter newGranterFromService(AttributesServiceFutureStub as, KASKeyCache keyCache, AttributeValueFQN... fqns) throws AutoConfigureException, ExecutionException, InterruptedException {
682693

683694
GetAttributeValuesByFqnsRequest request = GetAttributeValuesByFqnsRequest.newBuilder()
684-
.addAllFqns(Arrays.asList(fqnsStr))
695+
.addAllFqns(Arrays.stream(fqns).map(AttributeValueFQN::toString).collect(Collectors.toList()))
685696
.setWithValue(AttributeValueSelector.newBuilder().setWithKeyAccessGrants(true).build())
686697
.build();
687698

688-
GetAttributeValuesByFqnsResponse av;
689-
av = as.getAttributeValuesByFqns(request).get();
699+
GetAttributeValuesByFqnsResponse av = as.getAttributeValuesByFqns(request).get();
690700

691-
Granter grants = new Granter(Arrays.asList(fqns));
701+
return getGranter(keyCache, new ArrayList<>(av.getFqnAttributeValuesMap().values()));
702+
}
692703

693-
for (Map.Entry<String, GetAttributeValuesByFqnsResponse.AttributeAndValue> entry : av.getFqnAttributeValuesMap()
694-
.entrySet()) {
695-
String fqnstr = entry.getKey();
696-
AttributeAndValue pair = entry.getValue();
704+
private static Granter getGranter(@Nullable KASKeyCache keyCache, List<AttributeAndValue> values) {
705+
Granter grants = new Granter(values.stream().map(AttributeAndValue::getValue).map(Value::getFqn).map(AttributeValueFQN::new).collect(Collectors.toList()));
697706

698-
AttributeValueFQN fqn;
699-
try {
700-
fqn = new AttributeValueFQN(fqnstr);
701-
} catch (Exception e) {
702-
return grants;
703-
}
707+
for (var attributeAndValue: values) {
708+
var val = attributeAndValue.getValue();
709+
var attribute = attributeAndValue.getAttribute();
710+
String fqnstr = val.getFqn();
711+
AttributeValueFQN fqn = new AttributeValueFQN(fqnstr);
704712

705-
Attribute def = pair.getAttribute();
706-
Value v = pair.getValue();
707-
if (v != null && !v.getGrantsList().isEmpty()) {
708-
grants.addAllGrants(fqn, v.getGrantsList(), def);
709-
storeKeysToCache(v.getGrantsList(), keyCache);
710-
} else {
711-
if (def != null) {
712-
grants.addAllGrants(fqn, def.getGrantsList(), def);
713-
storeKeysToCache(def.getGrantsList(), keyCache);
713+
if (!val.getGrantsList().isEmpty()) {
714+
if (logger.isDebugEnabled()) {
715+
logger.debug("adding grants from attribute value [{}]: {}", val.getFqn(), val.getGrantsList().stream().map(KeyAccessServer::getUri).collect(Collectors.toList()));
716+
}
717+
grants.addAllGrants(fqn, val.getGrantsList(), attribute);
718+
if (keyCache != null) {
719+
storeKeysToCache(val.getGrantsList(), keyCache);
720+
}
721+
} else if (!attribute.getGrantsList().isEmpty()) {
722+
var attributeGrants = attribute.getGrantsList();
723+
if (logger.isDebugEnabled()) {
724+
logger.debug("adding grants from attribute [{}]: {}", attribute.getFqn(), attributeGrants.stream().map(KeyAccessServer::getId).collect(Collectors.toList()));
725+
}
726+
grants.addAllGrants(fqn, attributeGrants, attribute);
727+
if (keyCache != null) {
728+
storeKeysToCache(attributeGrants, keyCache);
729+
}
730+
} else if (!attribute.getNamespace().getGrantsList().isEmpty()) {
731+
var nsGrants = attribute.getNamespace().getGrantsList();
732+
if (logger.isDebugEnabled()) {
733+
logger.debug("adding grants from namespace [{}]: [{}]", attribute.getNamespace().getName(), nsGrants.stream().map(KeyAccessServer::getId).collect(Collectors.toList()));
734+
}
735+
grants.addAllGrants(fqn, nsGrants, attribute);
736+
if (keyCache != null) {
737+
storeKeysToCache(nsGrants, keyCache);
714738
}
739+
} else {
740+
// this is needed to mark the fact that we have an empty
741+
grants.addAllGrants(fqn, List.of(), attribute);
742+
logger.debug("didn't find any grants on value, attribute, or namespace for attribute value [{}]", fqnstr);
715743
}
716744
}
717745

718746
return grants;
719747
}
720748

721-
// Given a policy (list of data attributes or tags),
722-
// get a set of grants from attribute values to KASes.
723-
// Unlike `NewGranterFromService`, this works offline.
724-
public static Granter newGranterFromAttributes(Value... attrs) throws AutoConfigureException {
725-
List<AttributeValueFQN> policyList = new ArrayList<>(attrs.length);
726-
727-
Granter grants = new Granter(policyList);
728-
729-
for (Value v : attrs) {
730-
AttributeValueFQN fqn;
731-
try {
732-
fqn = new AttributeValueFQN(v.getFqn());
733-
} catch (Exception e) {
734-
return grants;
735-
}
736-
737-
grants.policy.add(fqn);
738-
Attribute def = v.getAttribute();
739-
if (def == null) {
740-
throw new AutoConfigureException("No associated definition with value [" + fqn.toString() + "]");
741-
}
742-
743-
grants.addAllGrants(fqn, def.getGrantsList(), def);
744-
grants.addAllGrants(fqn, v.getGrantsList(), def);
745-
}
746-
747-
return grants;
748-
}
749749

750750
static void storeKeysToCache(List<KeyAccessServer> kases, KASKeyCache keyCache) {
751751
for (KeyAccessServer kas : kases) {

0 commit comments

Comments
 (0)