Commit a2c1872d authored by cdanger's avatar cdanger

- Fixed typos in README

- Upgraded authzforce-ce-core-pdp-api dependency: 12.1.0 -> 13.0.0
- Implementation of feature requested in Github issue 10 (with unit
tests): creation of (XACML) AttributeValues from standard Java types
parent a2da6b4b
...@@ -88,14 +88,14 @@ Copy the content of [that folder](pdp-cli/src/test/resources/conformance/xacml-3 ...@@ -88,14 +88,14 @@ Copy the content of [that folder](pdp-cli/src/test/resources/conformance/xacml-3
$ ./authzforce-ce-core-pdp-cli-10.0.0.jar pdp.xml IIA001/Request.xml $ ./authzforce-ce-core-pdp-cli-10.0.0.jar pdp.xml IIA001/Request.xml
``` ```
* `pdp.xml`: PDP configuration file, that defines the location(s) of XACML policy(ies), among other PDP engine parameters; this content of this file is a XML document compliant with the PDP configuration [XML schema](pdp-engine/src/main/resources/pdp.xsd), so you can read the documentation of every configuration parameter in that schema file; * `pdp.xml`: PDP configuration file, that defines the location(s) of XACML policy(ies), among other PDP engine parameters; the content of this file is a XML document compliant with the PDP configuration [XML schema](pdp-engine/src/main/resources/pdp.xsd), so you can read the documentation of every configuration parameter in that schema file;
* `request.xml`: XACML request in XACML 3.0/XML (core specification) format. * `Request.xml`: XACML request in XACML 3.0/XML (core specification) format.
If you want to test the JSON Profile of XACML 3.0, run it with extra option `-t XACML_JSON`: If you want to test the JSON Profile of XACML 3.0, run it with extra option `-t XACML_JSON`:
``` ```
$ ./authzforce-ce-core-pdp-cli-10.0.0.jar -t XACML_JSON pdp.xml IIA001/Request.json $ ./authzforce-ce-core-pdp-cli-10.0.0.jar -t XACML_JSON pdp.xml IIA001/Request.json
``` ```
* `request.json`: XACML request in XACML 3.0/JSON (Profile) format. * `Request.json`: XACML request in XACML 3.0/JSON (Profile) format.
For more info, run it without parameters and you'll get detailed information on usage. For more info, run it without parameters and you'll get detailed information on usage.
...@@ -233,7 +233,7 @@ If you are experiencing any issue with this project, please report it on the [OW ...@@ -233,7 +233,7 @@ If you are experiencing any issue with this project, please report it on the [OW
Please include as much information as possible; the more we know, the better the chance of a quicker resolution: Please include as much information as possible; the more we know, the better the chance of a quicker resolution:
* Software version * Software version
* Platform (OS and JDK) * Platform (OS and JRE)
* Stack traces generally really help! If in doubt include the whole thing; often exceptions get wrapped in other exceptions and the exception right near the bottom explains the actual error, not the first few lines at the top. It's very easy for us to skim-read past unnecessary parts of a stack trace. * Stack traces generally really help! If in doubt include the whole thing; often exceptions get wrapped in other exceptions and the exception right near the bottom explains the actual error, not the first few lines at the top. It's very easy for us to skim-read past unnecessary parts of a stack trace.
* Log output can be useful too; sometimes enabling DEBUG logging can help; * Log output can be useful too; sometimes enabling DEBUG logging can help;
* Your code & configuration files are often useful. * Your code & configuration files are often useful.
......
...@@ -42,7 +42,6 @@ ...@@ -42,7 +42,6 @@
<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>12.1.0</version>
</dependency> </dependency>
<!-- /Authzforce dependencies --> <!-- /Authzforce dependencies -->
......
...@@ -18,22 +18,34 @@ ...@@ -18,22 +18,34 @@
package org.ow2.authzforce.core.pdp.impl.value; package org.ow2.authzforce.core.pdp.impl.value;
import java.io.Serializable; import java.io.Serializable;
import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors;
import javax.xml.namespace.QName; import javax.xml.namespace.QName;
import net.sf.saxon.s9api.XPathCompiler; import net.sf.saxon.s9api.XPathCompiler;
import org.ow2.authzforce.core.pdp.api.AttributeSources;
import org.ow2.authzforce.core.pdp.api.HashCollections;
import org.ow2.authzforce.core.pdp.api.expression.ConstantExpression; import org.ow2.authzforce.core.pdp.api.expression.ConstantExpression;
import org.ow2.authzforce.core.pdp.api.expression.ConstantPrimitiveAttributeValueExpression; import org.ow2.authzforce.core.pdp.api.expression.ConstantPrimitiveAttributeValueExpression;
import org.ow2.authzforce.core.pdp.api.value.AttributeBag;
import org.ow2.authzforce.core.pdp.api.value.AttributeValue; import org.ow2.authzforce.core.pdp.api.value.AttributeValue;
import org.ow2.authzforce.core.pdp.api.value.AttributeValueFactory; import org.ow2.authzforce.core.pdp.api.value.AttributeValueFactory;
import org.ow2.authzforce.core.pdp.api.value.AttributeValueFactoryRegistry; import org.ow2.authzforce.core.pdp.api.value.AttributeValueFactoryRegistry;
import org.ow2.authzforce.core.pdp.api.value.Bags;
import org.ow2.authzforce.core.pdp.api.value.Datatype;
import org.ow2.authzforce.core.pdp.api.value.SimpleValue.StringParseableValueFactory;
import org.ow2.authzforce.core.pdp.impl.BasePdpExtensionRegistry; import org.ow2.authzforce.core.pdp.impl.BasePdpExtensionRegistry;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableSet;
/** /**
* Immutable <code>DatatypeFactoryRegistry</code>. * Immutable <code>DatatypeFactoryRegistry</code>.
...@@ -45,19 +57,6 @@ public final class ImmutableAttributeValueFactoryRegistry extends BasePdpExtensi ...@@ -45,19 +57,6 @@ public final class ImmutableAttributeValueFactoryRegistry extends BasePdpExtensi
{ {
private static final IllegalArgumentException ILLEGAL_DATATYPE_ID_ARGUMENT_EXCEPTION = new IllegalArgumentException("Undefined datatype ID"); private static final IllegalArgumentException ILLEGAL_DATATYPE_ID_ARGUMENT_EXCEPTION = new IllegalArgumentException("Undefined datatype ID");
/**
* <p>
* Constructor for BaseDatatypeFactoryRegistry.
* </p>
*
* @param attributeValueFactories
* attribute value factories
*/
public ImmutableAttributeValueFactoryRegistry(final Set<? extends AttributeValueFactory<?>> attributeValueFactories)
{
super(AttributeValueFactory.class, Preconditions.checkNotNull(attributeValueFactories, "Input attribute datatype factories undefined (attributeValueFactories == null)"));
}
/** /**
* <p> * <p>
* createValue * createValue
...@@ -75,7 +74,7 @@ public final class ImmutableAttributeValueFactoryRegistry extends BasePdpExtensi ...@@ -75,7 +74,7 @@ public final class ImmutableAttributeValueFactoryRegistry extends BasePdpExtensi
* @throws java.lang.IllegalArgumentException * @throws java.lang.IllegalArgumentException
* if any. * if any.
*/ */
private static <V extends AttributeValue> V newValue(final AttributeValueFactory<V> attValFactory, final List<Serializable> content, final Map<QName, String> otherAttributes, private static <V extends AttributeValue> V newAttributeValue(final AttributeValueFactory<V> attValFactory, final List<Serializable> content, final Map<QName, String> otherAttributes,
final XPathCompiler xPathCompiler) throws IllegalArgumentException final XPathCompiler xPathCompiler) throws IllegalArgumentException
{ {
assert attValFactory != null; assert attValFactory != null;
...@@ -96,10 +95,75 @@ public final class ImmutableAttributeValueFactoryRegistry extends BasePdpExtensi ...@@ -96,10 +95,75 @@ public final class ImmutableAttributeValueFactoryRegistry extends BasePdpExtensi
final Map<QName, String> otherAttributes, final XPathCompiler xPathCompiler) throws IllegalArgumentException final Map<QName, String> otherAttributes, final XPathCompiler xPathCompiler) throws IllegalArgumentException
{ {
assert attValFactory != null; assert attValFactory != null;
final V rawValue = newValue(attValFactory, content, otherAttributes, xPathCompiler); final V rawValue = newAttributeValue(attValFactory, content, otherAttributes, xPathCompiler);
return new ConstantPrimitiveAttributeValueExpression<>(attValFactory.getDatatype(), rawValue); return new ConstantPrimitiveAttributeValueExpression<>(attValFactory.getDatatype(), rawValue);
} }
/**
* Creates instance of immutable attribute bag from raw values, with {@link AttributeSources#REQUEST} as attribute source.
*
* @param attributeValueFactory
* factory in charge of create attribute values in the bag
*
* @param rawValues
* raw values to be parsed by {@code attributeValueFactory} to create {@link AttributeValue}s
*
* @return attribute bag
* @throws IllegalArgumentException
* if {@code attributeValueFactory == null } or {@code rawValues} has at least one element which is null:
* {@code rawValues != null && !rawValues.isEmpty() && rawValues.iterator().next() == null}
*/
private static <AV extends AttributeValue> AttributeBag<AV> newAttributeBag(final StringParseableValueFactory<AV> attributeValueFactory, final Collection<? extends Serializable> rawValues)
throws IllegalArgumentException
{
assert attributeValueFactory != null;
final Datatype<AV> elementDatatype = attributeValueFactory.getDatatype();
if (rawValues == null || rawValues.isEmpty())
{
return Bags.emptyAttributeBag(elementDatatype, null);
}
return Bags.newAttributeBag(elementDatatype, rawValues.stream().map(rawValue -> attributeValueFactory.getInstance(rawValue)).collect(Collectors.toList()));
}
private final Map<Class<? extends Serializable>, StringParseableValueFactory<?>> inputClassToAttValFactory;
private final Set<Entry<Class<? extends Serializable>, StringParseableValueFactory<?>>> nonFinalInputClassToAttValFactory;
/**
* <p>
* Constructor for BaseDatatypeFactoryRegistry.
* </p>
*
* @param attributeValueFactories
* attribute value factories
*/
public ImmutableAttributeValueFactoryRegistry(final Collection<? extends AttributeValueFactory<?>> attributeValueFactories)
{
super(AttributeValueFactory.class, HashCollections.newImmutableSet(Preconditions.checkNotNull(attributeValueFactories,
"Input attribute datatype factories undefined (attributeValueFactories == null)")));
final Map<Class<? extends Serializable>, StringParseableValueFactory<?>> mutableJavaClassToAttValFactory = HashCollections.newUpdatableMap();
attributeValueFactories.forEach(factory -> {
if (factory instanceof StringParseableValueFactory)
{
final StringParseableValueFactory<?> simpleValueFactory = (StringParseableValueFactory<?>) factory;
simpleValueFactory.getSupportedInputTypes().forEach(inputType -> mutableJavaClassToAttValFactory.putIfAbsent(inputType, simpleValueFactory));
}
});
inputClassToAttValFactory = HashCollections.newImmutableMap(mutableJavaClassToAttValFactory);
/*
* Using inputClassToAttValFactory.get(instanceClass) to get the corresponding factory is faster that doing many instanceOf checks but only works for equal match. For non-final classes, we
* still have to do the instanceOf check because the instance class might not be equal (i.e same class) but a subclass. So we gather the non-final classes for which instanceOf check is
* necessary iff no equal match.
*/
final Set<Entry<Class<? extends Serializable>, StringParseableValueFactory<?>>> mutableSet = inputClassToAttValFactory.entrySet().stream()
.filter(e -> !Modifier.isFinal(e.getKey().getModifiers())).collect(Collectors.toSet());// HashCollections.newUpdatableSet(JAVA_TYPE_TO_ATT_VALUE_FACTORY.size());
nonFinalInputClassToAttValFactory = ImmutableSet.copyOf(mutableSet);
}
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public ConstantExpression<? extends AttributeValue> newExpression(final String datatypeId, final List<Serializable> content, final Map<QName, String> otherAttributes, public ConstantExpression<? extends AttributeValue> newExpression(final String datatypeId, final List<Serializable> content, final Map<QName, String> otherAttributes,
...@@ -119,4 +183,55 @@ public final class ImmutableAttributeValueFactoryRegistry extends BasePdpExtensi ...@@ -119,4 +183,55 @@ public final class ImmutableAttributeValueFactoryRegistry extends BasePdpExtensi
return newExpression(datatypeFactory, content, otherAttributes, xPathCompiler); return newExpression(datatypeFactory, content, otherAttributes, xPathCompiler);
} }
private final StringParseableValueFactory<?> getCompatibleFactory(final Class<? extends Serializable> rawValueClass)
{
final StringParseableValueFactory<?> attValFactoryFromMap = inputClassToAttValFactory.get(rawValueClass);
if (attValFactoryFromMap == null)
{
/*
* This may look like the collection is fully filtered before findfirst() is called but it is not the case. "All intermediate operations e.g. filter(), map() etc are lazy and they are only
* executed when a terminal operation like findFirst() or forEach() is called.
*
* This also means, a lot of opportunity for optimization depending upon the size of the original list." (Quote from:
* http://javarevisited.blogspot.fr/2016/03/how-to-find-first-element-of-stream-in.html)
*/
final Optional<Entry<Class<? extends Serializable>, StringParseableValueFactory<?>>> optionalResult = nonFinalInputClassToAttValFactory.stream()
.filter(e -> e.getKey().isAssignableFrom(rawValueClass)).findFirst();
if (optionalResult.isPresent())
{
return optionalResult.get().getValue();
}
throw new UnsupportedOperationException("Unsupported input value type: '" + rawValueClass + "' (no suitable XACML datatype factory found)");
}
return attValFactoryFromMap;
}
@Override
public AttributeValue newAttributeValue(final Serializable rawValue) throws IllegalArgumentException, UnsupportedOperationException
{
Preconditions.checkArgument(rawValue != null, "Null arg");
final StringParseableValueFactory<?> factory = getCompatibleFactory(rawValue.getClass());
if (factory == null)
{
throw new UnsupportedOperationException("Unsupported input value type: '" + rawValue.getClass() + "' (no suitable XACML datatype factory found)");
}
return factory.getInstance(rawValue);
}
@Override
public AttributeBag<?> newAttributeBag(final Collection<? extends Serializable> rawVals) throws UnsupportedOperationException, IllegalArgumentException
{
Preconditions.checkArgument(rawVals != null && !rawVals.isEmpty(), "Null/empty arg");
final Serializable rawVal0 = rawVals.iterator().next();
final StringParseableValueFactory<?> factory = getCompatibleFactory(rawVal0.getClass());
if (factory == null)
{
throw new UnsupportedOperationException("Unsupported input value type: '" + rawVal0.getClass() + "' (no suitable XACML datatype factory found)");
}
return newAttributeBag(factory, rawVals);
}
} }
...@@ -393,7 +393,7 @@ ...@@ -393,7 +393,7 @@
</attribute> </attribute>
<attribute name="maxIntegerValue" type="positiveInteger" use="optional" default="2147483647"> <attribute name="maxIntegerValue" type="positiveInteger" use="optional" default="2147483647">
<annotation> <annotation>
<documentation> Maximum integer value. This is the expected maximum value for XACML attributes of standard type 'http://www.w3.org/2001/XMLSchema#integer' (requires useStandardDatatypes <documentation> Maximum absolute integer value. This is the expected maximum absolute value for XACML attributes of standard type 'http://www.w3.org/2001/XMLSchema#integer' (requires useStandardDatatypes
= true). Decreasing this value as much = true). Decreasing this value as much
as as
possible helps the PDP engine optimize the processing of integer possible helps the PDP engine optimize the processing of integer
......
...@@ -37,6 +37,7 @@ import org.ow2.authzforce.core.pdp.impl.test.func.SpecialMatchFunctionsTest; ...@@ -37,6 +37,7 @@ import org.ow2.authzforce.core.pdp.impl.test.func.SpecialMatchFunctionsTest;
import org.ow2.authzforce.core.pdp.impl.test.func.StringConversionFunctionsTest; import org.ow2.authzforce.core.pdp.impl.test.func.StringConversionFunctionsTest;
import org.ow2.authzforce.core.pdp.impl.test.func.StringFunctionsTest; import org.ow2.authzforce.core.pdp.impl.test.func.StringFunctionsTest;
import org.ow2.authzforce.core.pdp.impl.test.value.AnyURIAttributeTest; import org.ow2.authzforce.core.pdp.impl.test.value.AnyURIAttributeTest;
import org.ow2.authzforce.core.pdp.impl.test.value.StandardJavaTypeToXacmlAttributeDatatypeConversionTest;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
...@@ -52,7 +53,7 @@ import org.slf4j.LoggerFactory; ...@@ -52,7 +53,7 @@ import org.slf4j.LoggerFactory;
@RunWith(Suite.class) @RunWith(Suite.class)
@SuiteClasses(value = { EqualityFunctionsTest.class, NumericArithmeticFunctionsTest.class, StringConversionFunctionsTest.class, NumericConversionFunctionsTest.class, LogicalFunctionsTest.class, @SuiteClasses(value = { EqualityFunctionsTest.class, NumericArithmeticFunctionsTest.class, StringConversionFunctionsTest.class, NumericConversionFunctionsTest.class, LogicalFunctionsTest.class,
NumericComparisonFunctionsTest.class, DateTimeArithmeticFunctionsTest.class, NonNumericComparisonFunctionsTest.class, StringFunctionsTest.class, BagFunctionsTest.class, NumericComparisonFunctionsTest.class, DateTimeArithmeticFunctionsTest.class, NonNumericComparisonFunctionsTest.class, StringFunctionsTest.class, BagFunctionsTest.class,
SetFunctionsTest.class, HigherOrderFunctionsTest.class, RegExpBasedFunctionsTest.class, SpecialMatchFunctionsTest.class }) SetFunctionsTest.class, HigherOrderFunctionsTest.class, RegExpBasedFunctionsTest.class, SpecialMatchFunctionsTest.class, StandardJavaTypeToXacmlAttributeDatatypeConversionTest.class })
public class MainTest public class MainTest
{ {
/** /**
......
/**
* Copyright 2012-2018 Thales Services SAS.
*
* This file is part of AuthzForce CE.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.ow2.authzforce.core.pdp.impl.test.value;
import java.io.Serializable;
import java.time.LocalDate;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import org.ow2.authzforce.core.pdp.api.value.AttributeValue;
import org.ow2.authzforce.core.pdp.api.value.StandardDatatypes;
import org.ow2.authzforce.core.pdp.impl.value.StandardAttributeValueFactories;
/**
*
* Tests conversion from raw Java types to XACML datatype (attribute value)
*/
@RunWith(value = Parameterized.class)
public class PojoToAttributeBagConversionTest
{
@Parameters()
public static Collection<Object[]> data()
{
final Object[][] data = new Object[][] {
/* empty collection */
{ Collections.emptyList(), StandardDatatypes.STRING.getId() },
/* string type */
{ Arrays.asList("string"), StandardDatatypes.STRING.getId() },
/*
* date
*/
/*
* matching type (LocalDate)
*/
{ Arrays.asList(LocalDate.now()), StandardDatatypes.DATE.getId() },
/* subtype (of Date) */
{ Arrays.asList(java.sql.Date.valueOf(LocalDate.now())), StandardDatatypes.DATE.getId() },
/*
* TODO: others
*/
/* invalid mix of datatypes */
{ Arrays.asList(new Integer(0), LocalDate.now()), StandardDatatypes.DATE.getId() } };
return Arrays.asList(data);
}
private final Collection<? extends Serializable> rawValues;
private final String expectedAttributeDatatypeId;
public PojoToAttributeBagConversionTest(final Collection<? extends Serializable> rawValues,
final String expectedAttributeDatatypeId)
{
this.rawValues = rawValues;
this.expectedAttributeDatatypeId = expectedAttributeDatatypeId;
}
@Test
public void test()
{
if (rawValues.isEmpty())
{
}
final AttributeValue attVal = StandardAttributeValueFactories.newAttributeValue(rawValue);
Assert.assertEquals(attVal.getDataType(), expectedAttributeDatatypeId,
"Unexpected datatype for created attribute value");
}
}
...@@ -26,7 +26,6 @@ ...@@ -26,7 +26,6 @@
<dependency> <dependency>
<groupId>org.ow2.authzforce</groupId> <groupId>org.ow2.authzforce</groupId>
<artifactId>authzforce-ce-core-pdp-api</artifactId> <artifactId>authzforce-ce-core-pdp-api</artifactId>
<version>12.1.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.testng</groupId> <groupId>org.testng</groupId>
......
...@@ -19,16 +19,23 @@ ...@@ -19,16 +19,23 @@
<!-- Publicly browsable repository URL. For example, via Gitlab web UI. --> <!-- Publicly browsable repository URL. For example, via Gitlab web UI. -->
<url>${git.url.base}/core</url> <url>${git.url.base}/core</url>
</scm> </scm>
<repositories> <repositories>
<repository> <repository>
<!-- Required by owasp dependency-check plugin for find info (POM) about dependency org.everit.json.schema in child modules --> <!-- Required by owasp dependency-check plugin for find info (POM) about dependency org.everit.json.schema in child modules -->
<id>jitpack.io</id> <id>jitpack.io</id>
<url>https://jitpack.io</url> <url>https://jitpack.io</url>
</repository> </repository>
</repositories> </repositories>
<!-- distributionManagement defined in parent POM already --> <!-- distributionManagement defined in parent POM already -->
<dependencyManagement> <dependencyManagement>
<dependencies> <dependencies>
<!-- AuthzForce dependencies -->
<dependency>
<groupId>org.ow2.authzforce</groupId>
<artifactId>authzforce-ce-core-pdp-api</artifactId>
<version>13.0.0</version>
</dependency>
<!-- /AuthzForce dependencies -->
<!-- Test dependencies --> <!-- Test dependencies -->
<dependency> <dependency>
<groupId>junit</groupId> <groupId>junit</groupId>
...@@ -39,14 +46,14 @@ ...@@ -39,14 +46,14 @@
</dependencies> </dependencies>
</dependencyManagement> </dependencyManagement>
<build> <build>
<pluginManagement> <pluginManagement>
<plugins> <plugins>
<plugin> <plugin>
<artifactId>maven-resources-plugin</artifactId> <artifactId>maven-resources-plugin</artifactId>
<version>3.0.1</version> <version>3.0.1</version>
</plugin> </plugin>
</plugins> </plugins>
</pluginManagement> </pluginManagement>
</build> </build>
<modules> <modules>
<module>pdp-engine</module> <module>pdp-engine</module>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment