Commit 6aa7d024 authored by cdanger's avatar cdanger

- Upgraded core-pdp-api version to 5.0.0 allowing to pass new parameter

for global PDP environment properties to Attribute Provider extensions
parent 7e53a04b
# Change log # Change log
All notable changes to this project are documented in this file following the [Keep a CHANGELOG](http://keepachangelog.com) conventions. All notable changes to this project are documented in this file following the [Keep a CHANGELOG](http://keepachangelog.com) conventions.
## Unreleased
## 4.0.2 ## 4.0.2
### Fixed ### Fixed
- Issues reported by Codacyi (including fixed issues in upgraded dependency core-pdp-api 4.0.2) - Issues reported by Codacyi (including fixed issues in upgraded dependency core-pdp-api 4.0.2)
......
...@@ -43,7 +43,7 @@ ...@@ -43,7 +43,7 @@
<dependency> <dependency>
<groupId>${project.groupId}</groupId> <groupId>${project.groupId}</groupId>
<artifactId>${artifactId.prefix}-core-pdp-api</artifactId> <artifactId>${artifactId.prefix}-core-pdp-api</artifactId>
<version>4.0.2</version> <version>5.0.0</version>
</dependency> </dependency>
<!-- /Authzforce dependencies --> <!-- /Authzforce dependencies -->
......
...@@ -33,77 +33,71 @@ import org.ow2.authzforce.core.pdp.api.AttributeGUID; ...@@ -33,77 +33,71 @@ import org.ow2.authzforce.core.pdp.api.AttributeGUID;
import org.ow2.authzforce.core.pdp.api.AttributeProvider; import org.ow2.authzforce.core.pdp.api.AttributeProvider;
import org.ow2.authzforce.core.pdp.api.AttributeProviderModule; import org.ow2.authzforce.core.pdp.api.AttributeProviderModule;
import org.ow2.authzforce.core.pdp.api.CloseableAttributeProviderModule; import org.ow2.authzforce.core.pdp.api.CloseableAttributeProviderModule;
import org.ow2.authzforce.core.pdp.api.EnvironmentProperties;
import org.ow2.authzforce.core.pdp.api.value.DatatypeFactoryRegistry; import org.ow2.authzforce.core.pdp.api.value.DatatypeFactoryRegistry;
import org.ow2.authzforce.xmlns.pdp.ext.AbstractAttributeProvider; import org.ow2.authzforce.xmlns.pdp.ext.AbstractAttributeProvider;
/** /**
* Closeable AttributeProvider * Closeable AttributeProvider
* <p> * <p>
* The sub-modules may very likely hold resources such as network resources to get attributes remotely, or attribute caches to speed up finding, etc. Therefore, you are required to call * The sub-modules may very likely hold resources such as network resources to
* {@link #close()} when you no longer need an instance - especially before replacing with a new instance (with different modules) - in order to make sure these resources are released properly by each * get attributes remotely, or attribute caches to speed up finding, etc.
* underlying module (e.g. close the attribute caches). * Therefore, you are required to call {@link #close()} when you no longer need
* an instance - especially before replacing with a new instance (with different
* modules) - in order to make sure these resources are released properly by
* each underlying module (e.g. close the attribute caches).
* *
* @version $Id: $ * @version $Id: $
*/ */
public final class CloseableAttributeProvider extends ModularAttributeProvider implements Closeable public final class CloseableAttributeProvider extends ModularAttributeProvider implements Closeable {
{
private static class ModuleAdapter private static class ModuleAdapter {
{
private CloseableAttributeProviderModule module; private CloseableAttributeProviderModule module;
private ModuleAdapter(CloseableAttributeProviderModule module) throws IOException private ModuleAdapter(CloseableAttributeProviderModule module) throws IOException {
{
final Set<AttributeDesignatorType> providedAttributes = module.getProvidedAttributes(); final Set<AttributeDesignatorType> providedAttributes = module.getProvidedAttributes();
if (providedAttributes == null || providedAttributes.isEmpty()) if (providedAttributes == null || providedAttributes.isEmpty()) {
{
module.close(); module.close();
throw new IllegalArgumentException("Invalid " + module + " : list of supported AttributeDesignators is null or empty"); throw new IllegalArgumentException(
"Invalid " + module + " : list of supported AttributeDesignators is null or empty");
} }
this.module = module; this.module = module;
} }
private void close() throws IOException private void close() throws IOException {
{
this.module.close(); this.module.close();
} }
private Set<AttributeDesignatorType> getProvidedAttributes() private Set<AttributeDesignatorType> getProvidedAttributes() {
{
return this.module.getProvidedAttributes(); return this.module.getProvidedAttributes();
} }
@Override @Override
public String toString() public String toString() {
{
return module.toString(); return module.toString();
} }
private AttributeProviderModule getAdaptedModule() private AttributeProviderModule getAdaptedModule() {
{
return this.module; return this.module;
} }
} }
private static void close(Set<ModuleAdapter> moduleClosers) throws IOException private static void close(Set<ModuleAdapter> moduleClosers) throws IOException {
{ // An error occuring on closing one module should not stop from closing
// An error occuring on closing one module should not stop from closing the others // the others
// But we keep the exception in memory if any, to throw it at the end as we do not want to hide that an error occurred // But we keep the exception in memory if any, to throw it at the end as
// we do not want to hide that an error occurred
IOException latestEx = null; IOException latestEx = null;
for (final ModuleAdapter mod : moduleClosers) for (final ModuleAdapter mod : moduleClosers) {
{ try {
try
{
mod.close(); mod.close();
} catch (IOException e) } catch (IOException e) {
{
latestEx = e; latestEx = e;
} }
} }
if (latestEx != null) if (latestEx != null) {
{
throw latestEx; throw latestEx;
} }
} }
...@@ -111,95 +105,118 @@ public final class CloseableAttributeProvider extends ModularAttributeProvider i ...@@ -111,95 +105,118 @@ public final class CloseableAttributeProvider extends ModularAttributeProvider i
private Set<ModuleAdapter> moduleClosers; private Set<ModuleAdapter> moduleClosers;
/** /**
* Instantiates attribute Provider that tries to find attribute values in evaluation context, then, if not there, query the {@code module} providing the requested attribute ID, if any. * Instantiates attribute Provider that tries to find attribute values in
* evaluation context, then, if not there, query the {@code module}
* providing the requested attribute ID, if any.
* *
* @param attributeFactory * @param attributeFactory
* (mandatory) attribute value factory * (mandatory) attribute value factory
* *
* @param jaxbAttributeProviderConfs * @param jaxbAttributeProviderConfs
* (optional) XML/JAXB configurations of Attribute Providers for AttributeDesignator/AttributeSelector evaluation; may be null for static expression evaluation (out of context), in * (optional) XML/JAXB configurations of Attribute Providers for
* which case AttributeSelectors/AttributeDesignators are not supported * AttributeDesignator/AttributeSelector evaluation; may be null
* for static expression evaluation (out of context), in which
* case AttributeSelectors/AttributeDesignators are not supported
* @throws IllegalArgumentException * @throws IllegalArgumentException
* If any of attribute Provider modules created from {@code jaxbAttributeProviderConfs} does not provide any attribute; or it is in conflict with another one already registered to * If any of attribute Provider modules created from
* provide the same or part of the same attributes. * {@code jaxbAttributeProviderConfs} does not provide any
* attribute; or it is in conflict with another one already
* registered to provide the same or part of the same
* attributes.
* @throws IOException * @throws IOException
* error closing the attribute Provider modules created from {@code jaxbAttributeProviderConfs}, when and before an {@link IllegalArgumentException} is raised * error closing the attribute Provider modules created from
* {@code jaxbAttributeProviderConfs}, when and before an
* {@link IllegalArgumentException} is raised
*/ */
private CloseableAttributeProvider(Map<AttributeGUID, AttributeProviderModule> modulesByAttributeId, Set<ModuleAdapter> moduleClosers) throws IOException private CloseableAttributeProvider(Map<AttributeGUID, AttributeProviderModule> modulesByAttributeId,
{ Set<ModuleAdapter> moduleClosers) throws IOException {
super(modulesByAttributeId); super(modulesByAttributeId);
this.moduleClosers = moduleClosers; this.moduleClosers = moduleClosers;
} }
/** /**
* Instantiates attribute Provider that tries to find attribute values in evaluation context, then, if not there, query the {@code module} providing the requested attribute ID, if any. * Instantiates attribute Provider that tries to find attribute values in
* evaluation context, then, if not there, query the {@code module}
* providing the requested attribute ID, if any.
* *
* @param attributeFactory * @param attributeFactory
* (mandatory) attribute value factory * (mandatory) attribute value factory
* @param jaxbAttributeProviderConfs * @param jaxbAttributeProviderConfs
* (optional) XML/JAXB configurations of Attribute Providers for AttributeDesignator/AttributeSelector evaluation; may be null for static expression evaluation (out of context), in * (optional) XML/JAXB configurations of Attribute Providers for
* which case AttributeSelectors/AttributeDesignators are not supported * AttributeDesignator/AttributeSelector evaluation; may be null
* for static expression evaluation (out of context), in which
* case AttributeSelectors/AttributeDesignators are not supported
* @param environmentProperties
* global PDP configuration environment properties
* @return instance of this class * @return instance of this class
* @throws java.lang.IllegalArgumentException * @throws java.lang.IllegalArgumentException
* If any of attribute Provider modules created from {@code jaxbAttributeProviderConfs} does not provide any attribute; or it is in conflict with another one already registered to * If any of attribute Provider modules created from
* provide the same or part of the same attributes. * {@code jaxbAttributeProviderConfs} does not provide any
* attribute; or it is in conflict with another one already
* registered to provide the same or part of the same
* attributes.
* @throws java.io.IOException * @throws java.io.IOException
* error closing the attribute Provider modules created from {@code jaxbAttributeProviderConfs}, when and before an {@link IllegalArgumentException} is raised * error closing the attribute Provider modules created from
* {@code jaxbAttributeProviderConfs}, when and before an
* {@link IllegalArgumentException} is raised
*/ */
public static CloseableAttributeProvider getInstance(List<AbstractAttributeProvider> jaxbAttributeProviderConfs, DatatypeFactoryRegistry attributeFactory) throws IOException public static CloseableAttributeProvider getInstance(List<AbstractAttributeProvider> jaxbAttributeProviderConfs,
{ DatatypeFactoryRegistry attributeFactory, EnvironmentProperties environmentProperties) throws IOException {
final Map<AttributeGUID, AttributeProviderModule> modulesByAttributeId; final Map<AttributeGUID, AttributeProviderModule> modulesByAttributeId;
final Set<ModuleAdapter> moduleCloserSet; final Set<ModuleAdapter> moduleCloserSet;
if (jaxbAttributeProviderConfs == null) if (jaxbAttributeProviderConfs == null) {
{
modulesByAttributeId = null; modulesByAttributeId = null;
moduleCloserSet = null; moduleCloserSet = null;
} else } else {
{
final int moduleCount = jaxbAttributeProviderConfs.size(); final int moduleCount = jaxbAttributeProviderConfs.size();
modulesByAttributeId = new HashMap<>(moduleCount); modulesByAttributeId = new HashMap<>(moduleCount);
moduleCloserSet = new HashSet<>(moduleCount); moduleCloserSet = new HashSet<>(moduleCount);
for (final AbstractAttributeProvider jaxbAttributeProviderConf : jaxbAttributeProviderConfs) for (final AbstractAttributeProvider jaxbAttributeProviderConf : jaxbAttributeProviderConfs) {
{ try {
try final CloseableAttributeProviderModule.FactoryBuilder<AbstractAttributeProvider> attrProviderModBuilder = PdpExtensionLoader
{ .getJaxbBoundExtension(CloseableAttributeProviderModule.FactoryBuilder.class,
final CloseableAttributeProviderModule.FactoryBuilder<AbstractAttributeProvider> attrProviderModBuilder = PdpExtensionLoader.getJaxbBoundExtension( jaxbAttributeProviderConf.getClass());
CloseableAttributeProviderModule.FactoryBuilder.class, jaxbAttributeProviderConf.getClass()); final CloseableAttributeProviderModule.DependencyAwareFactory depAwareAttrProviderModBuilder = attrProviderModBuilder
final CloseableAttributeProviderModule.DependencyAwareFactory depAwareAttrProviderModBuilder = attrProviderModBuilder.getInstance(jaxbAttributeProviderConf); .getInstance(jaxbAttributeProviderConf, environmentProperties);
final Set<AttributeDesignatorType> requiredAttrs = depAwareAttrProviderModBuilder.getDependencies(); final Set<AttributeDesignatorType> requiredAttrs = depAwareAttrProviderModBuilder.getDependencies();
/* /*
* Each AttributeProviderModule is given a read-only AttributeProvider - aka "dependency attribute Provider" - to find any attribute they require (dependency), based on the * Each AttributeProviderModule is given a read-only
* attribute Provider modules that provide these required attributes (set above); read-only so that modules use this attribute Provider only to get required attributes, nothing * AttributeProvider - aka "dependency attribute Provider" -
* else. Create this dependency attribute Provider. * to find any attribute they require (dependency), based on
* the attribute Provider modules that provide these
* required attributes (set above); read-only so that
* modules use this attribute Provider only to get required
* attributes, nothing else. Create this dependency
* attribute Provider.
*/ */
final AttributeProvider depAttrProvider; final AttributeProvider depAttrProvider;
if (requiredAttrs == null) if (requiredAttrs == null) {
{
depAttrProvider = new ModularAttributeProvider(null); depAttrProvider = new ModularAttributeProvider(null);
} else } else {
{
final Map<AttributeGUID, AttributeProviderModule> immutableCopyOfAttrProviderModsByAttrId = Collections final Map<AttributeGUID, AttributeProviderModule> immutableCopyOfAttrProviderModsByAttrId = Collections
.<AttributeGUID, AttributeProviderModule> unmodifiableMap(modulesByAttributeId); .<AttributeGUID, AttributeProviderModule> unmodifiableMap(modulesByAttributeId);
depAttrProvider = new ModularAttributeProvider(immutableCopyOfAttrProviderModsByAttrId, requiredAttrs); depAttrProvider = new ModularAttributeProvider(immutableCopyOfAttrProviderModsByAttrId,
requiredAttrs);
} }
// attrProviderMod closing isn't done in this method but handled in close() method when closing all modules // attrProviderMod closing isn't done in this method but
final ModuleAdapter moduleAdapter = new ModuleAdapter(depAwareAttrProviderModBuilder.getInstance(attributeFactory, depAttrProvider)); // handled in close() method when closing all modules
final ModuleAdapter moduleAdapter = new ModuleAdapter(
depAwareAttrProviderModBuilder.getInstance(attributeFactory, depAttrProvider));
moduleCloserSet.add(moduleAdapter); moduleCloserSet.add(moduleAdapter);
for (final AttributeDesignatorType attrDesignator : moduleAdapter.getProvidedAttributes()) for (final AttributeDesignatorType attrDesignator : moduleAdapter.getProvidedAttributes()) {
{
final AttributeGUID attrGUID = new AttributeGUID(attrDesignator); final AttributeGUID attrGUID = new AttributeGUID(attrDesignator);
if (modulesByAttributeId.containsKey(attrGUID)) if (modulesByAttributeId.containsKey(attrGUID)) {
{
moduleAdapter.close(); moduleAdapter.close();
throw new IllegalArgumentException("Conflict: " + moduleAdapter + " providing the same AttributeDesignator (" + attrGUID + ") as another already registered."); throw new IllegalArgumentException(
"Conflict: " + moduleAdapter + " providing the same AttributeDesignator ("
+ attrGUID + ") as another already registered.");
} }
modulesByAttributeId.put(attrGUID, moduleAdapter.getAdaptedModule()); modulesByAttributeId.put(attrGUID, moduleAdapter.getAdaptedModule());
} }
} catch (IllegalArgumentException e) } catch (IllegalArgumentException e) {
{
close(moduleCloserSet); close(moduleCloserSet);
throw e; throw e;
} }
...@@ -211,8 +228,7 @@ public final class CloseableAttributeProvider extends ModularAttributeProvider i ...@@ -211,8 +228,7 @@ public final class CloseableAttributeProvider extends ModularAttributeProvider i
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public void close() throws IOException public void close() throws IOException {
{
close(this.moduleClosers); close(this.moduleClosers);
} }
} }
...@@ -37,6 +37,7 @@ import oasis.names.tc.xacml._3_0.core.schema.wd_17.FunctionType; ...@@ -37,6 +37,7 @@ import oasis.names.tc.xacml._3_0.core.schema.wd_17.FunctionType;
import oasis.names.tc.xacml._3_0.core.schema.wd_17.VariableDefinition; import oasis.names.tc.xacml._3_0.core.schema.wd_17.VariableDefinition;
import oasis.names.tc.xacml._3_0.core.schema.wd_17.VariableReferenceType; import oasis.names.tc.xacml._3_0.core.schema.wd_17.VariableReferenceType;
import org.ow2.authzforce.core.pdp.api.EnvironmentProperties;
import org.ow2.authzforce.core.pdp.api.expression.BaseVariableReference; import org.ow2.authzforce.core.pdp.api.expression.BaseVariableReference;
import org.ow2.authzforce.core.pdp.api.expression.Expression; import org.ow2.authzforce.core.pdp.api.expression.Expression;
import org.ow2.authzforce.core.pdp.api.expression.ExpressionFactory; import org.ow2.authzforce.core.pdp.api.expression.ExpressionFactory;
...@@ -54,24 +55,31 @@ import org.ow2.authzforce.xmlns.pdp.ext.AbstractAttributeProvider; ...@@ -54,24 +55,31 @@ import org.ow2.authzforce.xmlns.pdp.ext.AbstractAttributeProvider;
import com.sun.xacml.UnknownIdentifierException; import com.sun.xacml.UnknownIdentifierException;
/** /**
* Implementation of ExpressionFactory that supports the Expressions defined in VariableDefinitions in order to resolve VariableReferences. In particular, it makes sure the depth of recursivity of * Implementation of ExpressionFactory that supports the Expressions defined in
* VariableDefinition does not exceed a value (to avoid inconveniences such as stackoverflow or very negative performance impact) defined by parameter to * VariableDefinitions in order to resolve VariableReferences. In particular, it
* {@link #ExpressionFactoryImpl(DatatypeFactoryRegistry, FunctionRegistry, List, int, boolean, boolean)} parameter. Note that reference loops are avoided by the fact that a VariableReference can * makes sure the depth of recursivity of VariableDefinition does not exceed a
* reference only a VariableDefinition defined previously to the VariableReference in this implementation. * value (to avoid inconveniences such as stackoverflow or very negative
* performance impact) defined by parameter to
* {@link #ExpressionFactoryImpl(DatatypeFactoryRegistry, FunctionRegistry, List, int, boolean, boolean)}
* parameter. Note that reference loops are avoided by the fact that a
* VariableReference can reference only a VariableDefinition defined previously
* to the VariableReference in this implementation.
* *
* *
* @version $Id: $ * @version $Id: $
*/ */
public class ExpressionFactoryImpl implements ExpressionFactory public class ExpressionFactoryImpl implements ExpressionFactory {
{
private static final IllegalArgumentException MISSING_ATTRIBUTE_DESIGNATOR_ISSUER_EXCEPTION = new IllegalArgumentException( private static final IllegalArgumentException MISSING_ATTRIBUTE_DESIGNATOR_ISSUER_EXCEPTION = new IllegalArgumentException(
"Missing Issuer that is required on AttributeDesignators by PDP configuration"); "Missing Issuer that is required on AttributeDesignators by PDP configuration");
private static final IllegalArgumentException UNSUPPORTED_ATTRIBUTE_SELECTOR_EXCEPTION = new IllegalArgumentException("Unsupported Expression type (optional XACML feature): AttributeSelector"); private static final IllegalArgumentException UNSUPPORTED_ATTRIBUTE_SELECTOR_EXCEPTION = new IllegalArgumentException(
"Unsupported Expression type (optional XACML feature): AttributeSelector");
private static final IllegalArgumentException NULL_FUNCTION_REGISTRY_EXCEPTION = new IllegalArgumentException("Undefined function registry"); private static final IllegalArgumentException NULL_FUNCTION_REGISTRY_EXCEPTION = new IllegalArgumentException(
"Undefined function registry");
private static final IllegalArgumentException NULL_ATTRIBUTE_DATATYPE_REGISTRY_EXCEPTION = new IllegalArgumentException("Undefined attribute datatype registry"); private static final IllegalArgumentException NULL_ATTRIBUTE_DATATYPE_REGISTRY_EXCEPTION = new IllegalArgumentException(
"Undefined attribute datatype registry");
private static final IllegalArgumentException UNSUPPORTED_ATTRIBUTE_DESIGNATOR_OR_SELECTOR_BECAUSE_OF_NULL_ATTRIBUTE_PROVIDER_EXCEPTION = new IllegalArgumentException( private static final IllegalArgumentException UNSUPPORTED_ATTRIBUTE_DESIGNATOR_OR_SELECTOR_BECAUSE_OF_NULL_ATTRIBUTE_PROVIDER_EXCEPTION = new IllegalArgumentException(
"Unsupported Expression type 'AttributeDesignator' and 'AttributeSelector' because no attribute Provider defined"); "Unsupported Expression type 'AttributeDesignator' and 'AttributeSelector' because no attribute Provider defined");
...@@ -89,10 +97,14 @@ public class ExpressionFactoryImpl implements ExpressionFactory ...@@ -89,10 +97,14 @@ public class ExpressionFactoryImpl implements ExpressionFactory
private final boolean issuerRequiredOnAttributeDesignators; private final boolean issuerRequiredOnAttributeDesignators;
/** /**
* Maximum VariableReference depth allowed for VariableDefinitions to be managed. Examples: * Maximum VariableReference depth allowed for VariableDefinitions to be
* managed. Examples:
* <ul> * <ul>
* <li>A VariableDefinition V1 that does not use any VariableReference has a reference depth of 0.</li> * <li>A VariableDefinition V1 that does not use any VariableReference has a
* <li>A VariableDefinition V1 that uses a VariableReference to VariableDefinition V2 with no further VariableReference, has a reference depth of 1</li> * reference depth of 0.</li>
* <li>A VariableDefinition V1 that uses a VariableReference to
* VariableDefinition V2 with no further VariableReference, has a reference
* depth of 1</li>
* <li>etc.</li> * <li>etc.</li>
* </ul> * </ul>
* *
...@@ -101,34 +113,52 @@ public class ExpressionFactoryImpl implements ExpressionFactory ...@@ -101,34 +113,52 @@ public class ExpressionFactoryImpl implements ExpressionFactory
* @param functionRegistry * @param functionRegistry
* function registry (not null) * function registry (not null)
* @param jaxbAttributeProviderConfs * @param jaxbAttributeProviderConfs
* XML/JAXB configurations of Attribute Providers for AttributeDesignator/AttributeSelector evaluation; may be null for static expression evaluation (out of context), in which case * XML/JAXB configurations of Attribute Providers for
* AttributeSelectors/AttributeDesignators are not supported * AttributeDesignator/AttributeSelector evaluation; may be null
* for static expression evaluation (out of context), in which
* case AttributeSelectors/AttributeDesignators are not supported
* @param maxVarRefDepth * @param maxVarRefDepth
* max depth of VariableReference chaining: VariableDefinition -> VariableDefinition ->... ('->' represents a VariableReference); strictly negative value means unlimited * max depth of VariableReference chaining: VariableDefinition ->
* VariableDefinition ->... ('->' represents a
* VariableReference); strictly negative value means unlimited
* @param allowAttributeSelectors * @param allowAttributeSelectors
* allow use of AttributeSelectors (experimental, not for production, use with caution) * allow use of AttributeSelectors (experimental, not for
* production, use with caution)
* @param issuerRequiredInAttributeDesignators * @param issuerRequiredInAttributeDesignators
* true iff it is required that all AttributeDesignator set the Issuer field, as a best practice. If the issuer is not set, remember what XACML 3.0 AttributeDesignator Evaluation says: * true iff it is required that all AttributeDesignator set the
* Issuer field, as a best practice. If the issuer is not set,
* remember what XACML 3.0 AttributeDesignator Evaluation says:
* "If the Issuer is not present in the attribute designator, then the matching of the attribute to the named attribute SHALL be governed by AttributeId and DataType attributes alone." * "If the Issuer is not present in the attribute designator, then the matching of the attribute to the named attribute SHALL be governed by AttributeId and DataType attributes alone."
* As a result, be aware that if you use AttributeDesignators without Issuer ( {@code issuerRequiredInAttributeDesignators == false}) and the requests are using matching Attributes but * As a result, be aware that if you use AttributeDesignators
* with one or more different Issuers, this PDP engine has to gather all the values from all the attributes with matching Category/AttributeId but with any Issuer or no Issuer, * without Issuer (
* {@code issuerRequiredInAttributeDesignators == false}) and the
* requests are using matching Attributes but with one or more
* different Issuers, this PDP engine has to gather all the
* values from all the attributes with matching
* Category/AttributeId but with any Issuer or no Issuer,
* resulting in lower performance. * resulting in lower performance.
* @param environmentProperties
* global PDP configuration environment properties
* @throws java.lang.IllegalArgumentException * @throws java.lang.IllegalArgumentException
* If any of attribute Provider modules created from {@code jaxbAttributeProviderConfs} does not provide any attribute; or it is in conflict with another one already registered to * If any of attribute Provider modules created from
* provide the same or part of the same attributes. * {@code jaxbAttributeProviderConfs} does not provide any
* attribute; or it is in conflict with another one already
* registered to provide the same or part of the same
* attributes.
* @throws java.io.IOException * @throws java.io.IOException
* error closing the attribute Provider modules created from {@code jaxbAttributeProviderConfs}, when and before an {@link IllegalArgumentException} is raised * error closing the attribute Provider modules created from
* {@code jaxbAttributeProviderConfs}, when and before an
* {@link IllegalArgumentException} is raised
*/ */
public ExpressionFactoryImpl(DatatypeFactoryRegistry attributeFactory, FunctionRegistry functionRegistry, List<AbstractAttributeProvider> jaxbAttributeProviderConfs, int maxVarRefDepth, public ExpressionFactoryImpl(DatatypeFactoryRegistry attributeFactory, FunctionRegistry functionRegistry,
boolean allowAttributeSelectors, boolean issuerRequiredInAttributeDesignators) throws IllegalArgumentException, IOException List<AbstractAttributeProvider> jaxbAttributeProviderConfs, int maxVarRefDepth,
{ boolean allowAttributeSelectors, boolean issuerRequiredInAttributeDesignators,
if (attributeFactory == null) EnvironmentProperties environmentProperties) throws IllegalArgumentException, IOException {
{ if (attributeFactory == null) {
throw NULL_ATTRIBUTE_DATATYPE_REGISTRY_EXCEPTION; throw NULL_ATTRIBUTE_DATATYPE_REGISTRY_EXCEPTION;
} }
if (functionRegistry == null) if (functionRegistry == null) {
{
throw NULL_FUNCTION_REGISTRY_EXCEPTION; throw NULL_FUNCTION_REGISTRY_EXCEPTION;
} }
...@@ -137,27 +167,37 @@ public class ExpressionFactoryImpl implements ExpressionFactory ...@@ -137,27 +167,37 @@ public class ExpressionFactoryImpl implements ExpressionFactory
this.maxVariableReferenceDepth = maxVarRefDepth < 0 ? UNLIMITED_MAX_VARIABLE_REF_DEPTH : maxVarRefDepth; this.maxVariableReferenceDepth = maxVarRefDepth < 0 ? UNLIMITED_MAX_VARIABLE_REF_DEPTH : maxVarRefDepth;
// finally create the global attribute Provider used to resolve // finally create the global attribute Provider used to resolve
// AttributeDesignators // AttributeDesignators
this.attributeProvider = CloseableAttributeProvider.getInstance(jaxbAttributeProviderConfs, attributeFactory); this.attributeProvider = CloseableAttributeProvider.getInstance(jaxbAttributeProviderConfs, attributeFactory,
environmentProperties);
this.allowAttributeSelectors = allowAttributeSelectors; this.allowAttributeSelectors = allowAttributeSelectors;
this.issuerRequiredOnAttributeDesignators = issuerRequiredInAttributeDesignators; this.issuerRequiredOnAttributeDesignators = issuerRequiredInAttributeDesignators;
} }
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public VariableReference<?> addVariable(VariableDefinition varDef, XPathCompiler xPathCompiler, Deque<String> inoutLongestVarRefChain) throws IllegalArgumentException public VariableReference<?> addVariable(VariableDefinition varDef, XPathCompiler xPathCompiler,
{ Deque<String> inoutLongestVarRefChain) throws IllegalArgumentException {
final String varId = varDef.getVariableId(); final String varId = varDef.getVariableId();
/* /*
* Initialize the longest variable reference chain from this VariableDefinition (varDef -> VarDef2 -> ..., where "v1 -> v2" means: v1's expression contains a VariableReference to v2) as empty * Initialize the longest variable reference chain from this
* for later update by this#getDefinition() when resolving a VariableReference within this varDef's expression (being parsed just after). The goal is to detect chains longer than * VariableDefinition (varDef -> VarDef2 -> ..., where "v1 -> v2" means:
* this.maxVariableReferenceDepth to limit abuse of VariableReferences. There may be multiple VariableReferences in a VariableDefinition's expression, such as an Apply, and each may be * v1's expression contains a VariableReference to v2) as empty for
* referencing a different VariableDefinition; but we are interested only in the one with the longest chain of references. * later update by this#getDefinition() when resolving a
* VariableReference within this varDef's expression (being parsed just
* after). The goal is to detect chains longer than
* this.maxVariableReferenceDepth to limit abuse of VariableReferences.
* There may be multiple VariableReferences in a VariableDefinition's
* expression, such as an Apply, and each may be referencing a different
* VariableDefinition; but we are interested only in the one with the
* longest chain of references.
*/ */
/* /*
* we need to check the longest variableReference chain does not have circular reference and does not exceed a specific value (need to call contains() method repeatedly and preserve the * we need to check the longest variableReference chain does not have
* order). * circular reference and does not exceed a specific value (need to call
* contains() method repeatedly and preserve the order).
*/ */
final Deque<String> longestVarRefChain = inoutLongestVarRefChain == null ? new ArrayDeque<String>() : inoutLongestVarRefChain; final Deque<String> longestVarRefChain = inoutLongestVarRefChain == null ? new ArrayDeque<String>()
: inoutLongestVarRefChain;
final Expression<?> varExpr = getInstance(varDef.getExpression().getValue(), xPathCompiler, longestVarRefChain); final Expression<?> varExpr = getInstance(varDef.getExpression().getValue(), xPathCompiler, longestVarRefChain);
final BaseVariableReference<?> var = new BaseVariableReference<>(varId, varExpr, longestVarRefChain); final BaseVariableReference<?> var = new BaseVariableReference<>(varId, varExpr, longestVarRefChain);
return idToVariableMap.put(varId, var); return idToVariableMap.put(varId, var);
...@@ -165,42 +205,56 @@ public class ExpressionFactoryImpl implements ExpressionFactory ...@@ -165,42 +205,56 @@ public class ExpressionFactoryImpl implements ExpressionFactory
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public VariableReference<?> removeVariable(String varId) public VariableReference<?> removeVariable(String varId) {
{
return idToVariableMap.remove(varId); return idToVariableMap.remove(varId);
} }
/** /**
* Resolves a VariableReference to the corresponding VariableReference(Definition) and validates the depth of VariableReference, i.e. the length of VariableReference chain. A chain of variable * Resolves a VariableReference to the corresponding
* references is a list of VariableIds, such that V1 -> V2 ->... -> Vn, where 'V1 -> V2' means: V1's Expression contains a VariableReference to V2. * VariableReference(Definition) and validates the depth of
* VariableReference, i.e. the length of VariableReference chain. A chain of
* variable references is a list of VariableIds, such that V1 -> V2 ->... ->
* Vn, where 'V1 -> V2' means: V1's Expression contains a VariableReference
* to V2.
* *
* @param jaxbVarRef * @param jaxbVarRef
* the JAXB/XACML VariableReference with merely identifying a VariableDefinition by its VariableId * the JAXB/XACML VariableReference with merely identifying a
* VariableDefinition by its VariableId
* *
* @return VariableReference containing the resolved VariableDefinition's expression referenced by <code>jaxbVarRef</code> as known by this factory, or null if unknown * @return VariableReference containing the resolved VariableDefinition's
* expression referenced by <code>jaxbVarRef</code> as known by this
* factory, or null if unknown
* @param longestVarRefChain * @param longestVarRefChain
* If we are resolving a VariableReference in a VariableDefinition's expression (may be null if not), this is the longest chain of VariableReferences starting from a one in this * If we are resolving a VariableReference in a
* VariableDefinition. If we are not resolving a VariableReference in a VariableDefinition's expression, this may be null.This is used to detect exceeding reference depth (see * VariableDefinition's expression (may be null if not), this is
* {@link #ExpressionFactoryImpl(int)} for the limit. In a Expression such as an Apply, we can have multiple VariableReferences referencing different VariableDefinitions. So we can have * the longest chain of VariableReferences starting from a one in
* different depths of VariableReference references. We compare the length of the current longest chain with the one we would get by adding the longest one in the referenced * this VariableDefinition. If we are not resolving a
* VariableDefinition and <code>jaxbVarRef</code>'s VariableId. If the latter is longer, its content becomes the content <code>longestVarRefChain</code>. * VariableReference in a VariableDefinition's expression, this
* may be null.This is used to detect exceeding reference depth
* (see {@link #ExpressionFactoryImpl(int)} for the limit. In a
* Expression such as an Apply, we can have multiple
* VariableReferences referencing different VariableDefinitions.
* So we can have different depths of VariableReference
* references. We compare the length of the current longest chain
* with the one we would get by adding the longest one in the
* referenced VariableDefinition and <code>jaxbVarRef</code>'s
* VariableId. If the latter is longer, its content becomes the
* content <code>longestVarRefChain</code>.
* @throws UnknownIdentifierException * @throws UnknownIdentifierException
* if VariableReference's VariableId is unknown by this factory * if VariableReference's VariableId is unknown by this factory
*/ */
private BaseVariableReference<?> getVariable(VariableReferenceType jaxbVarRef, Deque<String> longestVarRefChain) throws IllegalArgumentException private BaseVariableReference<?> getVariable(VariableReferenceType jaxbVarRef, Deque<String> longestVarRefChain)
{ throws IllegalArgumentException {
final String varId = jaxbVarRef.getVariableId(); final String varId = jaxbVarRef.getVariableId();
final BaseVariableReference<?> var = idToVariableMap.get(varId); final BaseVariableReference<?> var = idToVariableMap.get(varId);
if (var == null) if (var == null) {
{ throw new IllegalArgumentException("VariableReference's VariableId=" + varId
throw new IllegalArgumentException("VariableReference's VariableId=" + varId + " unknown in the current context, i.e. does not match any prior VariableDefinition's VariableId"); + " unknown in the current context, i.e. does not match any prior VariableDefinition's VariableId");
} }
if (longestVarRefChain != null) if (longestVarRefChain != null) {