Commit 7d9316f3 authored by cdanger's avatar cdanger
Browse files

Merge branch 'release/15.0.0'

parents 93d52fa1 bf708d6e
...@@ -2,6 +2,27 @@ ...@@ -2,6 +2,27 @@
All notable changes to this project are documented in this file following the [Keep a CHANGELOG](http://keepachangelog.com) conventions. This project adheres to [Semantic Versioning](http://semver.org). All notable changes to this project are documented in this file following the [Keep a CHANGELOG](http://keepachangelog.com) conventions. This project adheres to [Semantic Versioning](http://semver.org).
## 15.0.0
### Added
- Classes from authzforce-ce-core-pdp-engine, which may be useful to PEP implementations (PEPs should not depend on authzforce-ce-core-pdp-engine except if using an embedded PDP):
- `StandardAttributeValueFactories` (for mapping standard Java types or XACML datatypes into AuthzForce data model)
- `ImmutableAttributeValueFactoryRegistry` (required by the previous one)
- `BasePdpExtensionRegistry` (required by the previous one).
- `AttributeValueFactoryRegistry#getCompatibleFactory(Class)` method: used in unit tests.
- `AttributeValueFactoryRegistry#newAttributeBag(Collection, AttributeSource)`: creates an AttributeBag with a custom AttributeSource
- `PrimitiveDatatype#getInstanceClass()` method: gives the Java class associated to the (XACML) datatype, in AuthzForce data model.
- `XacmlJaxbParsingUtils#parseXacmlJaxbResult(Result)` method: to convert XACML/XML Result into AuthzForce data model's DecisionResult
### Changed
- For more flexibility, genericity and code simplification (better adaptation to non-XML formats such as JSON in particular), AuthzForce data model classes (e.g. `AttributeValue`) no longer extend XACML-schema-derived (JAXB-annotated) classes (e.g. `AttributeValueType`).
- `DecisionCache.Factory#getInstance(...)`: new AttributeValueFactoryRegistry parameter for the decision cache system to be able to create/restore AttributeValues from deserialized data stored or produced by external - possibly remote - systems (e.g. cache storage database).
- `CloseableDesignatedAttributeProvider` (resp. `BaseDesignatedAttributeProvider`) class renamed to `CloseableNamedAttributeProvider` (resp. `BaseNamedAttributeProvider`) to reuse the official term "named attribute" from §7.3 of XACML 3.0 spec.
### Fixed
- IllegalArgumentException for empty XACML anyURI, i.e. `<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#anyURI" />`. XACML 3.0 spec's anyURI datatype (annex B.3) is defined by W3C XML schema specification (2004)'s anyURI datatype, itself defined by RFC 2396 and 2732 at IETF. An empty URI is valid according to RFC 2396 (section 4.2), therefore an empty AttributeValue with anyURI datatype must be parsed successfully into an empty value. (Fix to `SimpleValue` class.)
- AuthzForce `IntegerValue`s wrongly considered not equal if created from different Java integer types (for the same value), e.g. `1` (Integer) and `1L` (Long). (Fix to equals() implementations in `GenericInteger` subclasses.)
## 14.0.0 ## 14.0.0
### Changed ### Changed
- Interface method DecisionCache.Factory#getInstance(...): added EnvironmentProperties parameter to allow passing environment properties to DecisionCache implementations - Interface method DecisionCache.Factory#getInstance(...): added EnvironmentProperties parameter to allow passing environment properties to DecisionCache implementations
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
<version>7.2.0</version> <version>7.2.0</version>
</parent> </parent>
<artifactId>authzforce-ce-core-pdp-api</artifactId> <artifactId>authzforce-ce-core-pdp-api</artifactId>
<version>14.0.0</version> <version>15.0.0</version>
<name>${project.groupId}:${project.artifactId}</name> <name>${project.groupId}:${project.artifactId}</name>
<description>AuthzForce - Core PDP API</description> <description>AuthzForce - Core PDP API</description>
<url>${project.url}</url> <url>${project.url}</url>
......
...@@ -19,19 +19,21 @@ package org.ow2.authzforce.core.pdp.api; ...@@ -19,19 +19,21 @@ package org.ow2.authzforce.core.pdp.api;
import java.util.Objects; import java.util.Objects;
import com.google.common.collect.ImmutableList;
import oasis.names.tc.xacml._3_0.core.schema.wd_17.Status; import oasis.names.tc.xacml._3_0.core.schema.wd_17.Status;
/** /**
* This class provides a skeletal implementation of the {@link DecisionResult} interface to minimize the effort required to implement this interface. Note that this class only overrides/implements * This class provides a skeletal implementation of the {@link DecisionResult} interface to minimize the effort required to implement this interface. Note that this class only overrides/implements
* {@link #equals(Object)}, {@link #hashCode()} and {@link #getStatus()}. * {@link #equals(Object)}, {@link #hashCode()} and {@link #getStatus()}.
*/ */
public abstract class AbstractDecisionResult implements DecisionResult public abstract class BaseDecisionResult implements DecisionResult
{ {
private final Status status; private final Status status;
private transient volatile int hashCode = 0; private transient volatile int hashCode = 0;
protected AbstractDecisionResult(final Status status) protected BaseDecisionResult(final Status status)
{ {
this.status = status; this.status = status;
} }
...@@ -80,12 +82,9 @@ public abstract class AbstractDecisionResult implements DecisionResult ...@@ -80,12 +82,9 @@ public abstract class AbstractDecisionResult implements DecisionResult
return false; return false;
} }
final PepActions otherPepActions = other.getPepActions(); final ImmutableList<PepAction> otherPepActions = other.getPepActions();
final PepActions thisPepActions = other.getPepActions(); assert otherPepActions != null;
if (thisPepActions == null) final ImmutableList<PepAction> thisPepActions = this.getPepActions();
{
return otherPepActions == null || otherPepActions.isEmpty();
}
return thisPepActions.equals(otherPepActions); return thisPepActions.equals(otherPepActions);
} }
......
...@@ -18,9 +18,9 @@ ...@@ -18,9 +18,9 @@
package org.ow2.authzforce.core.pdp.api; package org.ow2.authzforce.core.pdp.api;
/** /**
* This is a convenience class to help implement {@link CloseableDesignatedAttributeProvider}. * This is a convenience class to help implement {@link CloseableNamedAttributeProvider}.
*/ */
public abstract class BaseDesignatedAttributeProvider implements CloseableDesignatedAttributeProvider public abstract class BaseNamedAttributeProvider implements CloseableNamedAttributeProvider
{ {
private static final IllegalArgumentException UNDEF_INSTANCE_ID = new IllegalArgumentException("Undefined Attribute Provider's instance ID"); private static final IllegalArgumentException UNDEF_INSTANCE_ID = new IllegalArgumentException("Undefined Attribute Provider's instance ID");
...@@ -39,7 +39,7 @@ public abstract class BaseDesignatedAttributeProvider implements CloseableDesign ...@@ -39,7 +39,7 @@ public abstract class BaseDesignatedAttributeProvider implements CloseableDesign
* @throws IllegalArgumentException * @throws IllegalArgumentException
* if instanceId null * if instanceId null
*/ */
protected BaseDesignatedAttributeProvider(final String instanceID) throws IllegalArgumentException protected BaseNamedAttributeProvider(final String instanceID) throws IllegalArgumentException
{ {
if (instanceID == null) if (instanceID == null)
{ {
...@@ -75,12 +75,12 @@ public abstract class BaseDesignatedAttributeProvider implements CloseableDesign ...@@ -75,12 +75,12 @@ public abstract class BaseDesignatedAttributeProvider implements CloseableDesign
return true; return true;
} }
if (!(obj instanceof BaseDesignatedAttributeProvider)) if (!(obj instanceof BaseNamedAttributeProvider))
{ {
return false; return false;
} }
final BaseDesignatedAttributeProvider other = (BaseDesignatedAttributeProvider) obj; final BaseNamedAttributeProvider other = (BaseNamedAttributeProvider) obj;
return this.instanceID.equals(other.instanceID); return this.instanceID.equals(other.instanceID);
} }
......
/**
* 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.api;
import java.util.Map;
import java.util.Set;
import com.google.common.base.Function;
import com.google.common.base.Preconditions;
import com.google.common.collect.Maps;
/**
* This is a base implementation of <code>PdpExtensionRegistry</code>. This should be used as basis to implement (in a final class) an immutable PDP extension registry of a specific type. If you need
* a generic immutable PDP extension registry, see {
*
* @param <T>
* type of extension in this registry
* @version $Id: $
*/
public abstract class BasePdpExtensionRegistry<T extends PdpExtension> implements PdpExtensionRegistry<T>
{
private final Class<? super T> extClass;
private final Map<String, T> extensionsById;
private final transient String toString;
/**
* Instantiates immutable registry from a map.
*
* @param extensionClass
* extension class
* @param extensionsById
* extensions input map; the registry actually creates and uses an immutable copy of this map internally to avoid external modifications on the internal map
*/
protected BasePdpExtensionRegistry(final Class<? super T> extensionClass, final Map<String, ? extends T> extensionsById)
{
assert extensionClass != null && extensionsById != null;
this.extClass = extensionClass;
this.extensionsById = HashCollections.newImmutableMap(extensionsById);
this.toString = this + "( extensionClass= " + extClass.getCanonicalName() + " )";
}
/** {@inheritDoc} */
@Override
public final T getExtension(final String identity)
{
return extensionsById.get(identity);
}
/** {@inheritDoc} */
@Override
public final Set<T> getExtensions()
{
return HashCollections.newImmutableSet(extensionsById.values());
}
private static final class ExtensionToIdFunction<E extends PdpExtension> implements Function<E, String>
{
@Override
public String apply(final E extension) throws NullPointerException
{
assert extension != null;
return Preconditions.checkNotNull(extension, "One of the input extensions is invalid (null)").getId();
}
}
private static final Function<? extends PdpExtension, String> EXTENSION_TO_ID_FUNCTION = new ExtensionToIdFunction<>();
@SuppressWarnings("unchecked")
private static <E extends PdpExtension> Map<String, E> newImmutableMap(final Set<E> extensions)
{
return Maps.uniqueIndex(extensions, (Function<E, String>) EXTENSION_TO_ID_FUNCTION);
}
/**
* Instantiates immutable registry from a set of extensions
*
* @param extensionClass
* extension class (required not null)
* @param extensions
* extensions (required not null)
*/
protected BasePdpExtensionRegistry(final Class<? super T> extensionClass, final Set<? extends T> extensions)
{
this(extensionClass, newImmutableMap(extensions));
}
@Override
public String toString()
{
return toString;
}
}
...@@ -20,24 +20,24 @@ package org.ow2.authzforce.core.pdp.api; ...@@ -20,24 +20,24 @@ package org.ow2.authzforce.core.pdp.api;
import java.io.Closeable; import java.io.Closeable;
import java.util.Set; import java.util.Set;
import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeDesignatorType;
import org.ow2.authzforce.core.pdp.api.value.AttributeValueFactoryRegistry; import org.ow2.authzforce.core.pdp.api.value.AttributeValueFactoryRegistry;
import org.ow2.authzforce.xmlns.pdp.ext.AbstractAttributeProvider; import org.ow2.authzforce.xmlns.pdp.ext.AbstractAttributeProvider;
import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeDesignatorType;
/** /**
* {@link DesignatedAttributeProvider} that extends {@link Closeable} because it may may use resources external to the JVM such as a cache, a disk, a connection to a remote server, etc. for retrieving * {@link NamedAttributeProvider} that extends {@link Closeable} because it may may use resources external to the JVM such as a cache, a disk, a connection to a remote server, etc. for retrieving the
* the attribute values. Therefore, these resources must be released by calling {@link #close()} when it is no longer needed. * attribute values. Therefore, these resources must be released by calling {@link #close()} when it is no longer needed.
* <p> * <p>
* PDP extensions of this type (to support new ways of providing attributes) must implement the {@link FactoryBuilder} class. * PDP extensions of this type (to support new ways of providing attributes) must implement the {@link FactoryBuilder} class.
*/ */
public interface CloseableDesignatedAttributeProvider extends DesignatedAttributeProvider, Closeable public interface CloseableNamedAttributeProvider extends NamedAttributeProvider, Closeable
{ {
/** /**
* Intermediate dependency-aware {@link CloseableDesignatedAttributeProvider} factory that can create instances of Attribute Providers from a XML/JAXB configuration, and also provides the * Intermediate dependency-aware {@link CloseableNamedAttributeProvider} factory that can create instances of Attribute Providers from a XML/JAXB configuration, and also provides the dependencies
* dependencies (required attributes) (based on this configuration), that any such instance (created by it) will need. Providing the dependencies helps to optimize the {@code depAttrProvider} * (required attributes) (based on this configuration), that any such instance (created by it) will need. Providing the dependencies helps to optimize the {@code depAttrProvider} argument to
* argument to {@link #getInstance(AttributeValueFactoryRegistry, AttributeProvider)} and therefore optimize the created provider's job of finding its own supported attribute values based on other * {@link #getInstance(AttributeValueFactoryRegistry, AttributeProvider)} and therefore optimize the created provider's job of finding its own supported attribute values based on other attributes
* attributes in the evaluation context. * in the evaluation context.
* *
*/ */
interface DependencyAwareFactory interface DependencyAwareFactory
...@@ -56,14 +56,14 @@ public interface CloseableDesignatedAttributeProvider extends DesignatedAttribut ...@@ -56,14 +56,14 @@ public interface CloseableDesignatedAttributeProvider extends DesignatedAttribut
/** /**
* Create Attribute Provider instance * Create Attribute Provider instance
* *
* @param attributeValueFactoryRegistry * @param attributeValueFactories
* registry of Attribute value factories for the Provider to be able to create attribute values * AttributeValue factories for the Provider to be able to create AttributeValues
* @param depAttrProvider * @param dependencyAttributeProvider
* Existing Attribute Provider supplying the possibly required attributes that new Providers instantiated here will depend on * Existing Attribute Provider supplying the possibly required attributes that new Providers instantiated here will depend on
* *
* @return attribute value in internal model * @return attribute value in internal model
*/ */
CloseableDesignatedAttributeProvider getInstance(AttributeValueFactoryRegistry attributeValueFactoryRegistry, AttributeProvider depAttrProvider); CloseableNamedAttributeProvider getInstance(AttributeValueFactoryRegistry attributeValueFactories, AttributeProvider dependencyAttributeProvider);
} }
/** /**
...@@ -84,13 +84,13 @@ public interface CloseableDesignatedAttributeProvider extends DesignatedAttribut ...@@ -84,13 +84,13 @@ public interface CloseableDesignatedAttributeProvider extends DesignatedAttribut
/** /**
* Creates an attribute-dependency-aware AttributeProvider factory by inferring attribute dependencies (required attributes) from {@code conf}. * Creates an attribute-dependency-aware AttributeProvider factory by inferring attribute dependencies (required attributes) from {@code conf}.
* *
* @param conf * @param configuration
* configuration, that may define what attributes are required (dependency attributes) * configuration, that may define what attributes are required (dependency attributes)
* @param environmentProperties * @param environmentProperties
* global PDP configuration environment properties * global PDP configuration environment properties
* @return a factory aware of dependencies (required attributes) possibly inferred from input {@code conf} * @return a factory aware of dependencies (required attributes) possibly inferred from input {@code conf}
*/ */
public abstract DependencyAwareFactory getInstance(CONF_T conf, EnvironmentProperties environmentProperties); public abstract DependencyAwareFactory getInstance(CONF_T configuration, EnvironmentProperties environmentProperties);
} }
} }
...@@ -21,6 +21,7 @@ import java.io.Closeable; ...@@ -21,6 +21,7 @@ import java.io.Closeable;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.ow2.authzforce.core.pdp.api.value.AttributeValueFactoryRegistry;
import org.ow2.authzforce.xmlns.pdp.ext.AbstractDecisionCache; import org.ow2.authzforce.xmlns.pdp.ext.AbstractDecisionCache;
/** /**
...@@ -48,10 +49,14 @@ public interface DecisionCache extends Closeable ...@@ -48,10 +49,14 @@ public interface DecisionCache extends Closeable
* *
* @param conf * @param conf
* extension parameters * extension parameters
* @param envProps environment properties * @param envProps
* environment properties
* @param attributeValueFactories
* AttributeValue factories for the decision cache system to be able to create/restore AttributeValues from deserialized data stored or produced by external - possibly remote -
* systems (e.g. cache storage database). Remember that such attribute values can be present in decision results, typically in AttributeAssignments of Obligations/Advice.
* @return instance of extension * @return instance of extension
*/ */
public abstract DecisionCache getInstance(CONF_T conf, EnvironmentProperties envProps); public abstract DecisionCache getInstance(CONF_T conf, AttributeValueFactoryRegistry attributeValueFactories, EnvironmentProperties envProps);
} }
/** /**
...@@ -71,7 +76,8 @@ public interface DecisionCache extends Closeable ...@@ -71,7 +76,8 @@ public interface DecisionCache extends Closeable
* @param evalCtx * @param evalCtx
* evaluation context that can be used to save context about any partial/preliminary evaluation done by this decision cache when there is no cached result for {code request} yet. In * evaluation context that can be used to save context about any partial/preliminary evaluation done by this decision cache when there is no cached result for {code request} yet. In
* this case, the PDP will call back {@link DecisionCache#put(DecisionRequest, DecisionResult, EvaluationContext)} with this same {@code evalCtx} after the PDP has computed the new * this case, the PDP will call back {@link DecisionCache#put(DecisionRequest, DecisionResult, EvaluationContext)} with this same {@code evalCtx} after the PDP has computed the new
* result. Therefore, this allows the decision cache to reuse some context during an evaluation, and also to do some evaluation itself. * result. Therefore, this allows the decision cache to reuse some context during an evaluation, and also to do some evaluation itself. This argument may be null if not required, i.e.
* {@link #isEvaluationContextRequired()} returns false.
* @return the corresponding decision result from cache; null if there is no such result in cache. * @return the corresponding decision result from cache; null if there is no such result in cache.
*/ */
DecisionResult get(DecisionRequest request, EvaluationContext evalCtx); DecisionResult get(DecisionRequest request, EvaluationContext evalCtx);
...@@ -97,7 +103,7 @@ public interface DecisionCache extends Closeable ...@@ -97,7 +103,7 @@ public interface DecisionCache extends Closeable
* the corresponding decision result * the corresponding decision result
* @param evalCtx * @param evalCtx
* evaluation context that can be used to retrieve context about any partial/preliminary evaluation done by this decision cache when {@link #get(DecisionRequest, EvaluationContext)} was * evaluation context that can be used to retrieve context about any partial/preliminary evaluation done by this decision cache when {@link #get(DecisionRequest, EvaluationContext)} was
* called in the same request context. * called in the same request context. This argument may be null if not required, i.e. {@link #isEvaluationContextRequired()} returns false.
*/ */
void put(DecisionRequest request, DecisionResult result, EvaluationContext evalCtx); void put(DecisionRequest request, DecisionResult result, EvaluationContext evalCtx);
......
...@@ -25,18 +25,18 @@ import org.ow2.authzforce.core.pdp.api.policy.PrimaryPolicyMetadata; ...@@ -25,18 +25,18 @@ import org.ow2.authzforce.core.pdp.api.policy.PrimaryPolicyMetadata;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
/** /**
* Result of evaluation of {@link Decidable} (Policy, Rule...) with Obligations/Advice elements packaged together in a {@link PepActions} field. * Result of evaluation of {@link Decidable} (Policy, Rule...) with PEP actions (Obligations/Advice).
* *
*/ */
public interface DecisionResult extends ExtendedDecision public interface DecisionResult extends ExtendedDecision
{ {
/** /**
* Get PEP actions (Obligations/Advices), may be null if the decision is neither Permit or Deny * Get PEP actions (Obligations/Advices), may be empty - but <b>not null</b> - if the decision is neither Permit or Deny
* *
* @return PEP actions * @return PEP actions
*/ */
ImmutablePepActions getPepActions(); ImmutableList<PepAction> getPepActions();
/** /**
* Get the list of the "applicable" policy elements (XACML Policy/PolicySet elements) that contributed to this decision. * Get the list of the "applicable" policy elements (XACML Policy/PolicySet elements) that contributed to this decision.
...@@ -52,7 +52,7 @@ public interface DecisionResult extends ExtendedDecision ...@@ -52,7 +52,7 @@ public interface DecisionResult extends ExtendedDecision
* More formally: {@code isApplicable(policy) iff evaluate(policy) != NotApplicable && (policy.parent == null || isApplicable(policy.parent)) } * More formally: {@code isApplicable(policy) iff evaluate(policy) != NotApplicable && (policy.parent == null || isApplicable(policy.parent)) }
* *
* @return identifiers of policies found applicable for the decision request. Must be null if and only if the decision is NotApplicable. In particular, if the decision is different from * @return identifiers of policies found applicable for the decision request. Must be null if and only if the decision is NotApplicable. In particular, if the decision is different from
* NotApplicable but no applicable policy is returned (e.g. it was not requested to return such a list in the request), the returned list must be an empty list, not null. * NotApplicable but no applicable policy is returned (e.g. it was not requested to return such a list in the request), the returned list must be an empty list, <b>not null</b>.
*/ */
ImmutableList<PrimaryPolicyMetadata> getApplicablePolicies(); ImmutableList<PrimaryPolicyMetadata> getApplicablePolicies();
......
...@@ -19,21 +19,21 @@ package org.ow2.authzforce.core.pdp.api; ...@@ -19,21 +19,21 @@ package org.ow2.authzforce.core.pdp.api;
import java.util.Optional; import java.util.Optional;
import oasis.names.tc.xacml._3_0.core.schema.wd_17.DecisionType;
import oasis.names.tc.xacml._3_0.core.schema.wd_17.Status;
import org.ow2.authzforce.core.pdp.api.policy.PrimaryPolicyMetadata; import org.ow2.authzforce.core.pdp.api.policy.PrimaryPolicyMetadata;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import oasis.names.tc.xacml._3_0.core.schema.wd_17.DecisionType;
import oasis.names.tc.xacml._3_0.core.schema.wd_17.Status;
/** /**
* Factory for creating immutable {@link DecisionResult}s * Factory for creating immutable {@link DecisionResult}s
* *
*/ */
public final class DecisionResults public final class DecisionResults
{ {
private static final class ImmutableNotApplicableResult extends AbstractDecisionResult private static final class ImmutableNotApplicableResult extends BaseDecisionResult
{ {
private transient volatile String toString = null; private transient volatile String toString = null;
...@@ -49,21 +49,21 @@ public final class DecisionResults ...@@ -49,21 +49,21 @@ public final class DecisionResults
{ {
if (toString == null) if (toString == null)
{ {
toString = "Result( decision= NotApplicable, status=" + getStatus() + " )"; toString = "Result[ decision= NotApplicable, status=" + getStatus() + " ]";
} }
return toString; return toString;
} }
@Override @Override
public ImmutablePepActions getPepActions() public ImmutableList<PepAction> getPepActions()
{ {
return null; return ImmutableList.of();
} }
@Override @Override
public ImmutableList<PrimaryPolicyMetadata> getApplicablePolicies() public ImmutableList<PrimaryPolicyMetadata> getApplicablePolicies()
{ {
return null; return ImmutableList.of();
} }
@Override @Override
...@@ -85,7 +85,7 @@ public final class DecisionResults ...@@ -85,7 +85,7 @@ public final class DecisionResults
} }
} }
private static abstract class ApplicableResult extends AbstractDecisionResult private static abstract class ApplicableResult extends BaseDecisionResult
{ {