Skip to content

Attribute Providers

Rik Theunis edited this page Feb 25, 2020 · 21 revisions

These are PDP extensions that enable the PDP to get attributes from other sources than PEPs' requests. Such sources may be remote services, databases, etc.

If you wish to make your own attribute provider, read on the section Making an Attribute Provider. The AuthzForce project also provides a separate Attribute Provider example, but only for testing and documentation purposes.

If you wish to understand in details how the PDP loads and uses Attribute Providers during initialization and policy evaluation for each request, see the section How the PDP uses Attribute Providers.

Making an Attribute Provider

The steps to make your own PDP Attribute Provider extension for AuthzForce go as follows:

  1. Create a Maven project with jar packaging type.

  2. Create an XML schema file with .xsd extension in the src/main/resources folder of your Maven project. Make sure this filename is potentially unique on a Java classpath, like your usual Java class names. One way to make sure is to use a filename prefix following the same conventions as the Java package naming conventions. In this schema file, define an XML type for your attribute provider configuration format. This type must extend AbstractAttributeProvider from namespace http://authzforce.github.io/xmlns/pdp/ext/3. You may use the schema of AuthzForce TestAttributeProvider (used for AuthzForce unit tests only) as an example. In this example, the XSD filename is org.ow2.authzforce.core.pdp.testutil.ext.xsd and the defined XML type extending AbstractAttributeProvider is TestAttributeProviderDescriptor.

  3. Copy the files bindings.xjb and catalog.xml from AuthzForce source code into the src/main/jaxb folder (you have to create this folder first) of your Maven project.

  4. Add the following Maven dependency and build plugin configuration to your Maven POM:

       ...
       <dependencies>
        <dependency>
         <groupId>org.ow2.authzforce</groupId>
         <artifactId>authzforce-ce-core-pdp-api</artifactId>
         <version>15.0.0</version>
         <scope>provided</scope>
        </dependency>
        ...
       </dependencies> 
       ...
    
       <build>
        ...
        <plugins>
         <plugin>
          <groupId>org.jvnet.jaxb2.maven2</groupId>
          <artifactId>maven-jaxb2-plugin</artifactId>
          <version>0.14.0</version>
          <configuration>
           <debug>false</debug>
           <strict>false</strict>
           <verbose>true</verbose>
           <removeOldOutput>true</removeOldOutput>
           <extension>true</extension>
           <useDependenciesAsEpisodes>true</useDependenciesAsEpisodes>
           <catalog>src/main/jaxb/catalog.xml</catalog>
           <bindingDirectory>src/main/jaxb</bindingDirectory>
           <schemaDirectory>src/main/resources</schemaDirectory>
          </configuration>
          <executions>
           <execution>
            <id>jaxb-generate-compile-sources</id>
            <phase>generate-sources</phase>
            <goals>
             <goal>generate</goal>
            </goals>
           </execution>
          </executions>
         </plugin>
         ...
        </plugins>
       </build>
       ...
  5. Run Maven generate-sources. This will generate the JAXB-annotated class(es) from the XML schema into the folder target/generated-sources/xjc, one of which corresponds to your attribute provider XML type defined in the second step, therefore has the same name and also extends org.ow2.authzforce.xmlns.pdp.ext.AbstractAttributeProvider class corresponding to AbstractAttributeProvider type in the XML schema. For example, in the case of the AuthzForce Test AttributeProvider aforementioned, the corresponding generated class is org.ow2.authzforce.core.pdp.testutil.ext.xmlns.TestAttributeProviderDescriptor. In your case and in general, we will refer to it as your Attribute Provider Model class.

  6. Create your Attribute Provider factory and concrete implementation class (as in the Factory design pattern). The factory class must be public, and extend CloseableNamedAttributeProvider.FactoryBuilder<APM>, where APM stands for your Attribute Provider Model Class; and the factory class must have a public no-argument constructor or no constructor. You may use the AuthzForce TestAttributeProvider implementation class (used for AuthzForce unit tests only) as an example. In this example, the static nested class Factory is the one extending CloseableNamedAttributeProvider.FactoryBuilder<TestAttributeProviderDescriptor>. Such a class has a factory method getInstance(APM config, ...) (getInstance(TestAttributeProviderDescriptor conf, ...) in the example) that, from an instance of your APM representing the XML input (TestAttributeProviderDescriptor in the example), creates an instance of your Attribute Provider implementation class (TestAttributeProvider in the example). Indeed, your Attribute Provider implementation class must implement the interface CloseableNamedAttributeProvider. To facilitate the implementation process, instead of implementing this interface directly, you should extend BaseNamedAttributeProvider in your implementation class, whenever possible. This class already implements the required interface. There are cases where it is not possible; for instance, since BaseNamedAttributeProvider is an abstract class, if your implementation needs to extend another abstract class, you have no choice but to implement the interface directly, because a Java class cannot extend multiple abstract classes. In any case, as mandated by the interface, your implementation class must implement the method get(attributeFQN, datatype, context) in charge of actually retrieving the extra attributes (TestAttributeProvider#get(...) in the example). The attributeFQN identifies an XACML attribute's fully qualified name, i.e. category, ID and optional Issuer that the PDP is requesting from your attribute provider; the datatype is the expected attribute datatype; and context is the request context, including the content from the current XACML Request and possibly extra attributes retrieved so far by other Attribute Providers.

  7. When your Attribute Provider implementation class is ready, you create a configuration file to enable AuthzForce extension manager to discover this new extension dynamically at runtime. AuthzForce extension mechanism is based on Java native extension mechanism. In this regard, the PdpExtension interface is the SPI, and your AttributeProvider implementation must be registered as one of the Service Provider for this SPI. In short, all you have to do is create a configuration file org.ow2.authzforce.core.pdp.api.PdpExtension in folder src/main/resources/META-INF/services (you may have to create the folder first) and put the fully qualified name of your implementation class on the first line of this file (or a new line if there are others already there), like in the example from AuthzForce source code. More info.

  8. Run Maven package to produce a JAR from the Maven project.

Now you have an Attribute Provider extension ready for use by AuthzForce PDP engine, as explained in the next section.

Enabling Attribute Providers on the PDP

This section assumes you have an Attribute Provider extension in form of a JAR, typically produced by the process in the previous section. You may use AuthzForce PDP Core Tests JAR if you only wish to test the examples in this documentation. This JAR is available on Maven Central. Use the same version as authzforce-ce-core-pdp-engine.

The steps to enable the PDP to use the Attribute Provider go as follows:

  1. Make sure the JAR containing your Attribute Provider implementation with schema file, and its own dependencies, if any, are on the classpath.

  2. Import your attribute provider XML schema into the PDP extensions (XML) schema file that will be used as extensionXsdLocation argument to method PdpEngineConfiguration#getInstance(String,String,String), say pdp-ext.xsd, using namespace only (no schemaLocation), like in the example from AuthzForce code with this schema import for AuthzForce TestAttributeProvider:

       <xs:import namespace="http://authzforce.github.io/core/xmlns/test/3" />
  3. Add a uri element to the XML catalog file catalog.xml that will be used as catalogLocation argument to method PdpEngineConfiguration#getInstance(String,String,String), with your attribute provider XML namespace as name attribute value, and, the location of your XML schema file within the JAR, as uri attribute value, prefixed by classpath:. For example, in the sample XML catalog from AuthzForce source code, we add the following line for AuthzForce TestAttributeProvider:

       <uri name="http://authzforce.github.io/core/xmlns/test/3" uri="classpath:org.ow2.authzforce.core.pdp.testutil.ext.xsd" />
  4. In PDP configuration file that will be used as confLocation argument to method PdpEngineConfiguration#getInstance(String,String,String), e.g. pdp.xml, add an attributeProvider element with the Attribute Provider's XML type as defined in its XML schema. How to add the element exactly is defined by PDP configuration schema. If you don't have a PDP configuration file, here is an example for the TestAttributeProvider:

    <?xml version="1.0" encoding="UTF-8"?>
    <pdp xmlns="http://authzforce.github.io/core/xmlns/pdp/6.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"     version="6.0.0">
    ...
    <attributeProvider 
       id="test" 
       xmlns:test="http://authzforce.github.io/core/xmlns/test/3" 
       xsi:type="test:TestAttributeProviderDescriptor"
       xmlns:xacml="urn:oasis:names:tc:xacml:3.0:core:schema:wd-17" >
     <xacml:Attributes Category="urn:oasis:names:tc:xacml:1.0:subject-category:access-subject">
     	<xacml:Attribute AttributeId="urn:oasis:names:tc:xacml:1.0:example:attribute:role" IncludeInResult="false">
     		<xacml:AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">Physician</xacml:AttributeValue>
     	</xacml:Attribute>
     </xacml:Attributes>   
    </attributeProvider>
    ...
    <rootPolicyProvider id="rootPolicyProvider" xsi:type="StaticRefBasedRootPolicyProvider">
       <policyRef>root-rbac-policyset</policyRef>
    </rootPolicyProvider>
    
    </pdp>
  5. Finally, in your code, in order to instantiate a PDP engine, use method PdpEngineConfiguration#getInstance(confLocation, catalogLocation, extensionXsdLocation) with aforementioned pdp.xml, catalog.xml and pdp-ext.xsd as confLocation, catalogLocation, and extensionXsdLocation arguments respectively. Then refer to the Java API section of the README for more information.

How the PDP uses Attribute Providers

Initialization

The PDP is initialized with attribute providers based on the attributeProvider elements in the PDP (XML) configuration, if there is any. (You can also do it programmatically if you really need to, but it is rather for more advanced users.) As the XML schema says, there may be zero, one or many of these. Indeed, using Attribute Providers is not mandatory. They are unnecessary if you expect all attributes to be provided in the requests (from PEP), or computed directly by the PDP like the current date/time as I mention in the next paragraph.

There is a special case for the standard current date/time attributes (§10.2.5 of XACML spec):

  • If and only if the PDP configuration has the standardEnvAttributeSource set to PDP_ONLY, the PDP will always provide the current date/time attributes on its own (internally) for each request.
  • If set to REQUEST_ELSE_PDP, same thing but only if the attribute is not present in the request.
  • Else the PDP never provides it on its own.

Attribute providers implement Java interface CloseableNamedAttributeProvider; and during initialization, the PDP constructor calls method getProvidedAttributes() (defined by superinterface NamedAttributeProvider) on each one, in order to know which attributes it supports / can provide. Therefore, at the end of initialization, the PDP knows which attribute provider to call depending on the attribute it needs. (This avoids looping over all of them every time until it finds the good one.)

Request evaluation

After the PDP is initialized, it is ready to handle XACML requests. For each request, the PDP initializes a request context (represented by Java class EvaluationContext) and puts in it all request attributes, and the current date/time attributes if necessary, depending on the standardEnvAttributeSource configuration parameter mentioned previously, and whether these attributes are in the request already. Then begins the evaluation of the request against the policy (XACML Policy or PolicySet). During the evaluation, the PDP will query Attribute Providers - calling their method get (...) in the following cases:

  1. The PDP comes upon an AttributeDesignator and cannot find a matching attribute in the current request context.
  2. The PDP comes upon an AttributeSelector with a ContextSelectorId and cannot find a matching attribute in the current request context.
  3. An attribute provider is being called but requires/depends on another attribute X to proceed, and X cannot be found in the current request context. This is the edge case. For example, the PDP is calling an Attribute Provider to get the subject role attribute. But this Attribute Provider needs the subject ID attribute in order to find the subject role. However, there is no subject ID in the request context (again, this is an edge case just for example). Therefore it calls another Attribute Provider that can provide the subject ID based on the MAC address attribute (assuming there is a one-to-one relationship between the two), and this time the MAC address happens to be in the request context. All's well that ends well.

In all cases, the new attribute (category, ID...) is added to the request context with the result returned by AttributeProvider#get(...) as value, so that it can be retrieved from there directly if needed again.

Clone this wiki locally