diff --git a/pdp-engine/src/main/java/org/ow2/authzforce/core/pdp/impl/BasePdpEngine.java b/pdp-engine/src/main/java/org/ow2/authzforce/core/pdp/impl/BasePdpEngine.java index 925f432d..2c15a128 100644 --- a/pdp-engine/src/main/java/org/ow2/authzforce/core/pdp/impl/BasePdpEngine.java +++ b/pdp-engine/src/main/java/org/ow2/authzforce/core/pdp/impl/BasePdpEngine.java @@ -177,14 +177,14 @@ private IssuedToNonIssuedAttributeCopyingRequestBuilder(final int expectedNumOfA } @Override - public Bag putNamedAttributeIfAbsent(final AttributeFqn AttributeFqn, final AttributeBag attributeValues) + public Bag putNamedAttributeIfAbsent(final AttributeFqn attributeFqn, final AttributeBag attributeValues) { /* * Put the non-issued version of the attribute first */ - final AttributeFqn nonAttributeFqn = AttributeFqns.newInstance(AttributeFqn.getCategory(), Optional.empty(), AttributeFqn.getId()); + final AttributeFqn nonAttributeFqn = AttributeFqns.newInstance(attributeFqn.getCategory(), Optional.empty(), attributeFqn.getId()); super.putNamedAttributeIfAbsent(nonAttributeFqn, attributeValues); - return super.putNamedAttributeIfAbsent(AttributeFqn, attributeValues); + return super.putNamedAttributeIfAbsent(attributeFqn, attributeValues); } } @@ -255,9 +255,9 @@ public IndividualDecisionRequestContext(final Map> /** {@inheritDoc} */ @Override - public AttributeBag getNamedAttributeValue(final AttributeFqn AttributeFqn, final BagDatatype attributeBagDatatype) throws IndeterminateEvaluationException + public AttributeBag getNamedAttributeValue(final AttributeFqn attributeFqn, final BagDatatype attributeBagDatatype) throws IndeterminateEvaluationException { - final AttributeBag bagResult = namedAttributes.get(AttributeFqn); + final AttributeBag bagResult = namedAttributes.get(attributeFqn); if (bagResult == null) { return null; @@ -270,7 +270,7 @@ public AttributeBag getNamedAttributeValue(final "Datatype (" + bagResult.getElementDatatype() + ") of AttributeDesignator " - + AttributeFqn + + attributeFqn + " in context is different from expected/requested (" + expectedElementDatatype + "). May be caused by refering to the same Attribute Category/Id/Issuer with different Datatypes in different policy elements and/or attribute providers, which is not allowed.", @@ -281,14 +281,14 @@ public AttributeBag getNamedAttributeValue(final * If datatype classes match, bagResult should have same type as datatypeClass. */ final AttributeBag result = (AttributeBag) bagResult; - this.listeners.forEach((lt, l) -> l.namedAttributeValueConsumed(AttributeFqn, result)); + this.listeners.forEach((lt, l) -> l.namedAttributeValueConsumed(attributeFqn, result)); return result; } @Override - public boolean putNamedAttributeValueIfAbsent(final AttributeFqn AttributeFqn, final AttributeBag result) + public boolean putNamedAttributeValueIfAbsent(final AttributeFqn attributeFqn, final AttributeBag result) { - final Bag duplicate = namedAttributes.putIfAbsent(AttributeFqn, result); + final Bag duplicate = namedAttributes.putIfAbsent(attributeFqn, result); if (duplicate != null) { /* @@ -296,11 +296,11 @@ public boolean putNamedAttributeValueIfAbsent(final AttributeFqn AttributeFqn, f * putAttributeDesignatorResultIfAbsent() in this case. In any case, we do not support setting a different result for same id (but different datatype URI/datatype class) in the same * context */ - LOGGER.warn("Attempt to override value of AttributeDesignator {} already set in evaluation context. Overriding value: {}", AttributeFqn, result); + LOGGER.warn("Attempt to override value of AttributeDesignator {} already set in evaluation context. Overriding value: {}", attributeFqn, result); return false; } - this.listeners.forEach((lt, l) -> l.namedAttributeValueProduced(AttributeFqn, result)); + this.listeners.forEach((lt, l) -> l.namedAttributeValueProduced(attributeFqn, result)); /* * Attribute value cannot change during evaluation context, so if old value already there, put it back */ diff --git a/pdp-engine/src/main/java/org/ow2/authzforce/core/pdp/impl/ModularAttributeProvider.java b/pdp-engine/src/main/java/org/ow2/authzforce/core/pdp/impl/ModularAttributeProvider.java index d293c720..6c9e27b1 100644 --- a/pdp-engine/src/main/java/org/ow2/authzforce/core/pdp/impl/ModularAttributeProvider.java +++ b/pdp-engine/src/main/java/org/ow2/authzforce/core/pdp/impl/ModularAttributeProvider.java @@ -42,7 +42,8 @@ import com.google.common.collect.ListMultimap; /** - * AttributeProvider that tries to resolve attributes in current request context first, else delegates to {@link DesignatedAttributeProvider}s. + * AttributeProvider that tries to resolve attributes in current request context + * first, else delegates to {@link DesignatedAttributeProvider}s. * * @version $Id: $ */ @@ -50,35 +51,39 @@ public class ModularAttributeProvider implements AttributeProvider { private static final IndeterminateEvaluationException INDETERMINATE_EXCEPTION_NO_VALUE_FROM_ATTRIBUTE_PROVIDERS = new IndeterminateEvaluationException( - "No value found by any attribute provider module", XacmlStatusCode.PROCESSING_ERROR.value()); + "No value found by any attribute provider module", XacmlStatusCode.PROCESSING_ERROR.value()); private interface IssuedToNonIssuedAttributeCopyMode { - void process(AttributeFqn AttributeFqn, AttributeBag result, EvaluationContext context); + void process(AttributeFqn attributeFqn, AttributeBag result, EvaluationContext context); } private static final IssuedToNonIssuedAttributeCopyMode ISSUED_TO_NON_ISSUED_ATTRIBUTE_COPY_ENABLED_MODE = new IssuedToNonIssuedAttributeCopyMode() { @Override - public void process(final AttributeFqn AttributeFqn, final AttributeBag result, final EvaluationContext context) - { - if (!AttributeFqn.getIssuer().isPresent()) + public void process(final AttributeFqn attributeFqn, final AttributeBag result, + final EvaluationContext context) { + if (!attributeFqn.getIssuer().isPresent()) { // Attribute already without Issuer -> nothing to copy return; } /* - * Attribute with Issuer -> make Issuer-less copy and put same result in context for match by Issuer-less AttributeDesignator + * Attribute with Issuer -> make Issuer-less copy and put same result in context + * for match by Issuer-less AttributeDesignator */ - final AttributeFqn issuerLessAttributeFqn = AttributeFqns.newInstance(AttributeFqn.getCategory(), Optional.empty(), AttributeFqn.getId()); + final AttributeFqn issuerLessAttributeFqn = AttributeFqns.newInstance(attributeFqn.getCategory(), + Optional.empty(), attributeFqn.getId()); /* - * Cache the attribute value(s) for the issuer-less attribute in context in case there is a matching Issuer-less AttributeDesignator to evaluate + * Cache the attribute value(s) for the issuer-less attribute in context in case + * there is a matching Issuer-less AttributeDesignator to evaluate */ context.putNamedAttributeValueIfAbsent(issuerLessAttributeFqn, result); - LOGGER.debug("strictAttributeIssuerMatch=false -> Cached values of attribute {}, type={}, derived, by removing Issuer, from attribute {} provided by AttributeProvider module: values= {}", - AttributeFqn, result.getElementDatatype(), AttributeFqn, result); + LOGGER.debug( + "strictAttributeIssuerMatch=false -> Cached values of attribute {}, type={}, derived, by removing Issuer, from attribute {} provided by AttributeProvider module: values= {}", + attributeFqn, result.getElementDatatype(), attributeFqn, result); } }; @@ -87,8 +92,8 @@ public void process(final AttributeFqn AttributeFqn, final AttributeBag resul { @Override - public void process(final AttributeFqn AttributeFqn, final AttributeBag result, final EvaluationContext context) - { + public void process(final AttributeFqn attributeFqn, final AttributeBag result, + final EvaluationContext context) { // do not copy the result to any Issuer-less attribute } @@ -97,34 +102,38 @@ public void process(final AttributeFqn AttributeFqn, final AttributeBag resul private static final Logger LOGGER = LoggerFactory.getLogger(ModularAttributeProvider.class); /* - * AttributeDesignator Provider modules by supported/provided attribute ID (global ID: category, issuer, AttributeId) + * AttributeDesignator Provider modules by supported/provided attribute ID + * (global ID: category, issuer, AttributeId) */ private final ImmutableListMultimap designatorModsByAttrId; private final IssuedToNonIssuedAttributeCopyMode issuedToNonIssuedAttributeCopyMode; - protected ModularAttributeProvider(final ImmutableListMultimap attributeProviderModulesByAttributeId, - final Set selectedAttributeSupport, final boolean strictAttributeIssuerMatch) + protected ModularAttributeProvider( + final ImmutableListMultimap attributeProviderModulesByAttributeId, + final Set selectedAttributeSupport, final boolean strictAttributeIssuerMatch) { assert attributeProviderModulesByAttributeId != null; if (selectedAttributeSupport == null) { designatorModsByAttrId = attributeProviderModulesByAttributeId; - } - else + } else { - final ListMultimap mutableModsByAttrIdMap = ArrayListMultimap.create(selectedAttributeSupport.size(), 1); + final ListMultimap mutableModsByAttrIdMap = ArrayListMultimap + .create(selectedAttributeSupport.size(), 1); for (final AttributeDesignatorType requiredAttr : selectedAttributeSupport) { final AttributeFqn requiredAttrGUID = AttributeFqns.newInstance(requiredAttr); - final ImmutableList requiredAttrProviderMods = attributeProviderModulesByAttributeId.get(requiredAttrGUID); + final ImmutableList requiredAttrProviderMods = attributeProviderModulesByAttributeId + .get(requiredAttrGUID); /* * According to doc, a non-null empty list is returned if no mappings */ assert requiredAttrProviderMods != null; /* - * Empty requiredAttrProviderMod means it should be provided by the request context (in the initial request from PEP) + * Empty requiredAttrProviderMod means it should be provided by the request + * context (in the initial request from PEP) */ if (!requiredAttrProviderMods.isEmpty()) { @@ -136,61 +145,84 @@ protected ModularAttributeProvider(final ImmutableListMultimap attributeProviderModulesByAttributeId, - final Set selectedAttributeSupport, final boolean strictAttributeIssuerMatch) - { + public static ModularAttributeProvider getInstance( + final ImmutableListMultimap attributeProviderModulesByAttributeId, + final Set selectedAttributeSupport, final boolean strictAttributeIssuerMatch) { if (attributeProviderModulesByAttributeId == null || attributeProviderModulesByAttributeId.isEmpty()) { return EVALUATION_CONTEXT_ONLY_SCOPED_ATTRIBUTE_PROVIDER; } - return new ModularAttributeProvider(attributeProviderModulesByAttributeId, selectedAttributeSupport, strictAttributeIssuerMatch); + return new ModularAttributeProvider(attributeProviderModulesByAttributeId, selectedAttributeSupport, + strictAttributeIssuerMatch); } /** {@inheritDoc} */ @Override - public final AttributeBag get(final AttributeFqn AttributeFqn, final BagDatatype returnDatatype, final EvaluationContext context) - throws IndeterminateEvaluationException - { + public final AttributeBag get(final AttributeFqn attributeFqn, + final BagDatatype returnDatatype, final EvaluationContext context) + throws IndeterminateEvaluationException { try { - final AttributeBag contextBag = context.getNamedAttributeValue(AttributeFqn, returnDatatype); + final AttributeBag contextBag = context.getNamedAttributeValue(attributeFqn, returnDatatype); if (contextBag != null) { - LOGGER.debug("Values of attribute {}, type={} found in evaluation context: {}", AttributeFqn, returnDatatype, contextBag); + LOGGER.debug("Values of attribute {}, type={} found in evaluation context: {}", attributeFqn, + returnDatatype, contextBag); return contextBag; } // else attribute not found in context, ask the Provider modules, if any - LOGGER.debug("Requesting attribute {} from Provider modules (by provided attribute ID): {}", AttributeFqn, designatorModsByAttrId); - final ImmutableList attrProviders = designatorModsByAttrId.get(AttributeFqn); + LOGGER.debug("Requesting attribute {} from Provider modules (by provided attribute ID): {}", attributeFqn, + designatorModsByAttrId); + final ImmutableList attrProviders = designatorModsByAttrId.get(attributeFqn); /* * According to doc, a non-null empty list is returned if no mappings */ assert attrProviders != null; if (attrProviders.isEmpty()) { - LOGGER.debug("No value found for required attribute {}, type={} in evaluation context and not supported by any Attribute Provider module", AttributeFqn, returnDatatype); - throw new IndeterminateEvaluationException("Not in context and no Attribute Provider module supporting requested attribute: " + AttributeFqn, XacmlStatusCode.MISSING_ATTRIBUTE.value()); + LOGGER.debug( + "No value found for required attribute {}, type={} in evaluation context and not supported by any Attribute Provider module", + attributeFqn, returnDatatype); + throw new IndeterminateEvaluationException( + "Not in context and no Attribute Provider module supporting requested attribute: " + + attributeFqn, + XacmlStatusCode.MISSING_ATTRIBUTE.value()); } AttributeBag result = null; @@ -199,7 +231,7 @@ public final AttributeBag get(final AttributeFqn */ for (final DesignatedAttributeProvider attrProvider : attrProviders) { - result = attrProvider.get(AttributeFqn, returnDatatype, context); + result = attrProvider.get(attributeFqn, returnDatatype, context); if (result != null && !result.isEmpty()) { break; @@ -208,36 +240,50 @@ public final AttributeBag get(final AttributeFqn if (result == null) { - result = Bags.emptyAttributeBag(returnDatatype.getElementType(), INDETERMINATE_EXCEPTION_NO_VALUE_FROM_ATTRIBUTE_PROVIDERS); + result = Bags.emptyAttributeBag(returnDatatype.getElementType(), + INDETERMINATE_EXCEPTION_NO_VALUE_FROM_ATTRIBUTE_PROVIDERS); } /* - * Cache the attribute value(s) in context to avoid waste of time querying the module twice for same attribute + * Cache the attribute value(s) in context to avoid waste of time querying the + * module twice for same attribute */ - context.putNamedAttributeValueIfAbsent(AttributeFqn, result); - LOGGER.debug("Values of attribute {}, type={} returned by attribute Provider module #{} (cached in context): {}", AttributeFqn, returnDatatype, attrProviders, result); - issuedToNonIssuedAttributeCopyMode.process(AttributeFqn, result, context); + context.putNamedAttributeValueIfAbsent(attributeFqn, result); + LOGGER.debug( + "Values of attribute {}, type={} returned by attribute Provider module #{} (cached in context): {}", + attributeFqn, returnDatatype, attrProviders, result); + issuedToNonIssuedAttributeCopyMode.process(attributeFqn, result, context); return result; - } - catch (final IndeterminateEvaluationException e) + } catch (final IndeterminateEvaluationException e) { /* - * This error does not necessarily matter, it depends on whether the attribute is required, i.e. MustBePresent=true for AttributeDesignator/Selector So we let - * AttributeDesignator/Select#evaluate() method log the errors if MustBePresent=true. Here debug level is enough + * This error does not necessarily matter, it depends on whether the attribute + * is required, i.e. MustBePresent=true for AttributeDesignator/Selector So we + * let AttributeDesignator/Select#evaluate() method log the errors if + * MustBePresent=true. Here debug level is enough */ - LOGGER.debug("Error finding attribute {}, type={}", AttributeFqn, returnDatatype, e); + LOGGER.debug("Error finding attribute {}, type={}", attributeFqn, returnDatatype, e); /** - * If error occurred, we put the empty value to prevent retry in the same context, which may succeed at another time in the same context, resulting in different value of the same attribute - * at different times during evaluation within the same context, therefore inconsistencies. The value(s) must remain constant during the evaluation context, as explained in section 7.3.5 + * If error occurred, we put the empty value to prevent retry in the same + * context, which may succeed at another time in the same context, resulting in + * different value of the same attribute at different times during evaluation + * within the same context, therefore inconsistencies. The value(s) must remain + * constant during the evaluation context, as explained in section 7.3.5 * Attribute Retrieval of XACML core spec: *

- * Regardless of any dynamic modifications of the request context during policy evaluation, the PDP SHALL behave as if each bag of attribute values is fully populated in the context before - * it is first tested, and is thereafter immutable during evaluation. (That is, every subsequent test of that attribute shall use 3313 the same bag of values that was initially tested.) + * Regardless of any dynamic modifications of the request context during policy + * evaluation, the PDP SHALL behave as if each bag of attribute values is fully + * populated in the context before it is first tested, and is thereafter + * immutable during evaluation. (That is, every subsequent test of that + * attribute shall use 3313 the same bag of values that was initially tested.) *

- * Therefore, if no value found, we keep it that way until evaluation is done for the current request context. + * Therefore, if no value found, we keep it that way until evaluation is done + * for the current request context. *

- * We could put the null value to indicate the evaluation error, instead of an empty Bag, but it would make the result of the code used at the start of this method ambiguous/confusing: + * We could put the null value to indicate the evaluation error, instead of an + * empty Bag, but it would make the result of the code used at the start of this + * method ambiguous/confusing: *

* * final Bag contextBag = context.getAttributeDesignatorResult(AttributeFqn,...) @@ -246,26 +292,46 @@ public final AttributeBag get(final AttributeFqn *

* Indeed, contextBag could be null for one of these two reasons: *

    - *
  1. The attribute ('AttributeFqn') has never been requested in this context; - *
  2. It has been requested before in this context but could not be found: error occurred (IndeterminateEvaluationException)
  3. + *
  4. The attribute ('attributeFqn') has never been requested in this context; + *
  5. It has been requested before in this context but could not be found: + * error occurred (IndeterminateEvaluationException)
  6. *
- * To avoid this confusion, we put an empty Bag (with some error info saying why this is empty). + * To avoid this confusion, we put an empty Bag (with some error info saying why + * this is empty). *

*/ final AttributeBag result = Bags.emptyAttributeBag(returnDatatype.getElementType(), e); /* - * NOTE: It might happen - e.g. in conformance test IIB033 (Request's resource-id attribute datatype is different from datatype used in Policy) - that - * context.getAttributeDesignatorResult(AttributeFqn, bagDatatype) threw IndeterminateEvaluationException although a value for 'AttributeFqn' exists in context, because the existing - * datatype is different from requested 'bagDatatype'. In this case, the call below will return false (the value should not be overridden). We don't care about the result; what matters is + * NOTE: It might happen - e.g. in conformance test IIB033 (Request's + * resource-id attribute datatype is different from datatype used in Policy) - + * that context.getAttributeDesignatorResult(AttributeFqn, bagDatatype) threw + * IndeterminateEvaluationException although a value for 'attributeFqn' exists + * in context, because the existing datatype is different from requested + * 'bagDatatype'. In this case, the call below will return false (the value + * should not be overridden). We don't care about the result; what matters is * that the value is set to an empty bag if there was no value. */ - context.putNamedAttributeValueIfAbsent(AttributeFqn, result); + context.putNamedAttributeValueIfAbsent(attributeFqn, result); return result; + } catch (UnsupportedOperationException e) + { + /* + * Should not happen, this is highly unexpected and should be considered a fatal + * error (it means the AttributeProvider does not respect its contract) + */ + throw new RuntimeException( + "Inconsistent AttributeProvider: throwing UnsupportedOperationException for an attribute (name=" + + attributeFqn + ", type=" + returnDatatype + + ") that should be supported according to the provider's contract (getProvidedAttributes() result) ", + e); } } /** - * Attribute Provider based only on the evaluation context, i.e. it does not used any extra attribute provider module to get attribute values if not found in the context + * Attribute Provider based only on the evaluation context, i.e. it does not + * used any extra attribute provider module to get attribute values if not found + * in the context */ - public static final ModularAttributeProvider EVALUATION_CONTEXT_ONLY_SCOPED_ATTRIBUTE_PROVIDER = new ModularAttributeProvider(ImmutableListMultimap.of(), null, true); + public static final ModularAttributeProvider EVALUATION_CONTEXT_ONLY_SCOPED_ATTRIBUTE_PROVIDER = new ModularAttributeProvider( + ImmutableListMultimap.of(), null, true); } diff --git a/pdp-engine/src/main/java/org/ow2/authzforce/core/pdp/impl/StandardEnvironmentAttribute.java b/pdp-engine/src/main/java/org/ow2/authzforce/core/pdp/impl/StandardEnvironmentAttribute.java index 7aad7c00..af8abc2c 100644 --- a/pdp-engine/src/main/java/org/ow2/authzforce/core/pdp/impl/StandardEnvironmentAttribute.java +++ b/pdp-engine/src/main/java/org/ow2/authzforce/core/pdp/impl/StandardEnvironmentAttribute.java @@ -51,11 +51,11 @@ public enum StandardEnvironmentAttribute */ CURRENT_DATETIME(AttributeFqns.newInstance(XacmlAttributeCategory.XACML_3_0_ENVIRONMENT.value(), Optional.empty(), XacmlAttributeId.XACML_1_0_ENVIRONMENT_CURRENT_DATETIME.value())); - private final AttributeFqn AttributeFqn; + private final AttributeFqn attributeFqn; - private StandardEnvironmentAttribute(final AttributeFqn AttributeFqn) + private StandardEnvironmentAttribute(final AttributeFqn attributeFqn) { - this.AttributeFqn = AttributeFqn; + this.attributeFqn = attributeFqn; } /** @@ -65,7 +65,7 @@ private StandardEnvironmentAttribute(final AttributeFqn AttributeFqn) */ public AttributeFqn getFQN() { - return this.AttributeFqn; + return this.attributeFqn; } private static final Map ID_TO_STD_ATTR_MAP = Maps.uniqueIndex(Arrays.asList(StandardEnvironmentAttribute.values()), @@ -84,12 +84,12 @@ public AttributeFqn apply(final StandardEnvironmentAttribute input) /** * Get the standard environment attribute corresponding to the given ID * - * @param AttributeFqn + * @param attributeFqn * standard attribute ID * @return StandardEnvironmentAttribute corresponding to given ID, or null if there is no standard environment attribute with such ID */ - public static StandardEnvironmentAttribute getInstance(final AttributeFqn AttributeFqn) + public static StandardEnvironmentAttribute getInstance(final AttributeFqn attributeFqn) { - return ID_TO_STD_ATTR_MAP.get(AttributeFqn); + return ID_TO_STD_ATTR_MAP.get(attributeFqn); } } diff --git a/pdp-testutils/pom.xml b/pdp-testutils/pom.xml index 3a7bdc27..f7669672 100644 --- a/pdp-testutils/pom.xml +++ b/pdp-testutils/pom.xml @@ -31,6 +31,18 @@ 2.14.2 + + + + com.fasterxml.jackson.core + jackson-databind + 2.9.4 + + org.jongo jongo diff --git a/pdp-testutils/src/main/java/org/ow2/authzforce/core/pdp/testutil/ext/TestAttributeProvider.java b/pdp-testutils/src/main/java/org/ow2/authzforce/core/pdp/testutil/ext/TestAttributeProvider.java index 8e41c120..7999a9f5 100644 --- a/pdp-testutils/src/main/java/org/ow2/authzforce/core/pdp/testutil/ext/TestAttributeProvider.java +++ b/pdp-testutils/src/main/java/org/ow2/authzforce/core/pdp/testutil/ext/TestAttributeProvider.java @@ -60,7 +60,7 @@ public class TestAttributeProvider extends BaseDesignatedAttributeProvider { /** - * module factory + * Module factory * */ public static class Factory extends CloseableDesignatedAttributeProvider.FactoryBuilder