|
1 | 1 | package io.opentdf.platform.sdk;
|
2 | 2 |
|
| 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; |
3 | 19 | import java.io.UnsupportedEncodingException;
|
4 | 20 | import java.net.URLDecoder;
|
5 | 21 | import java.net.URLEncoder;
|
|
19 | 35 | import java.util.regex.Pattern;
|
20 | 36 | import java.util.stream.Collectors;
|
21 | 37 |
|
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 |
| - |
39 | 38 | // Attribute rule types: operators!
|
40 | 39 | class RuleType {
|
41 | 40 | public static final String HIERARCHY = "hierarchy";
|
@@ -349,7 +348,7 @@ BooleanKeyExpression insertKeysForAttribute(AttributeBooleanExpression e) throws
|
349 | 348 | }
|
350 | 349 |
|
351 | 350 | String op = ruleToOperator(clause.def.getRule());
|
352 |
| - if (op == RuleType.UNSPECIFIED) { |
| 351 | + if (op.equals(RuleType.UNSPECIFIED)) { |
353 | 352 | logger.warn("Unknown attribute rule type: " + clause);
|
354 | 353 | }
|
355 | 354 |
|
@@ -672,80 +671,81 @@ public static String ruleToOperator(AttributeRuleTypeEnum e) {
|
672 | 671 |
|
673 | 672 | }
|
674 | 673 |
|
| 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 | + |
675 | 691 | // 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 { |
682 | 693 |
|
683 | 694 | GetAttributeValuesByFqnsRequest request = GetAttributeValuesByFqnsRequest.newBuilder()
|
684 |
| - .addAllFqns(Arrays.asList(fqnsStr)) |
| 695 | + .addAllFqns(Arrays.stream(fqns).map(AttributeValueFQN::toString).collect(Collectors.toList())) |
685 | 696 | .setWithValue(AttributeValueSelector.newBuilder().setWithKeyAccessGrants(true).build())
|
686 | 697 | .build();
|
687 | 698 |
|
688 |
| - GetAttributeValuesByFqnsResponse av; |
689 |
| - av = as.getAttributeValuesByFqns(request).get(); |
| 699 | + GetAttributeValuesByFqnsResponse av = as.getAttributeValuesByFqns(request).get(); |
690 | 700 |
|
691 |
| - Granter grants = new Granter(Arrays.asList(fqns)); |
| 701 | + return getGranter(keyCache, new ArrayList<>(av.getFqnAttributeValuesMap().values())); |
| 702 | + } |
692 | 703 |
|
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())); |
697 | 706 |
|
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); |
704 | 712 |
|
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); |
714 | 738 | }
|
| 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); |
715 | 743 | }
|
716 | 744 | }
|
717 | 745 |
|
718 | 746 | return grants;
|
719 | 747 | }
|
720 | 748 |
|
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 |
| - } |
749 | 749 |
|
750 | 750 | static void storeKeysToCache(List<KeyAccessServer> kases, KASKeyCache keyCache) {
|
751 | 751 | for (KeyAccessServer kas : kases) {
|
|
0 commit comments