Policy XACML - Custom Application Tutorial

This tutorial shows how to build a XACML application for a Policy Type. Please be sure to clone the policy repositories before going through the tutorial. See Policy Platform Development Tools for details.

Design a Policy Type

Follow TOSCA Policy Primer for more information. For the tutorial, we will use this example Policy Type in which an ONAP PEP client would like to enforce an action authorize for a user to execute a permission on an entity.

Example Tutorial Policy Type
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
tosca_definitions_version: tosca_simple_yaml_1_1_0
policy_types:
    onap.policies.Authorization:
        derived_from: tosca.policies.Root
        version: 1.0.0
        description: Example tutorial policy type for doing user authorization
        properties:
            user:
                type: string
                required: true
                description: The unique user name
            permissions:
                type: list
                required: true
                description: A list of resource permissions
                entry_schema:
                    type: onap.datatypes.Tutorial
data_types:
    onap.datatypes.Tutorial:
        derived_from: tosca.datatypes.Root
        version: 1.0.0
        properties:
            entity:
                type: string
                required: true
                description: The resource
            permission:
                type: string
                required: true
                description: The permission level
                constraints:
                    - valid_values: [read, write, delete]

We would expect then to be able to create the following policies to allow the demo user to Read/Write an entity called foo, while the audit user can only read the entity called foo. Neither user has Delete permission.

Example Policies Derived From Tutorial Policy Type
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
tosca_definitions_version: tosca_simple_yaml_1_1_0
topology_template:
    policies:
        -
            onap.policy.tutorial.demo:
                type: onap.policies.Authorization
                type_version: 1.0.0
                version: 1.0.0
                metadata:
                    policy-id: onap.policy.tutorial.demo
                    policy-version: 1
                properties:
                    user: demo
                    permissions:
                        -
                            entity: foo
                            permission: read
                        -
                            entity: foo
                            permission: write
        -
            onap.policy.tutorial.audit:
                type: onap.policies.Authorization
                version: 1.0.0
                type_version: 1.0.0
                metadata:
                    policy-id: onap.policy.tutorial.bar
                    policy-version: 1
                properties:
                    user: audit
                    permissions:
                        -
                            entity: foo
                            permission: read

Design Decision Request and expected Decision Response

For the PEP (Policy Enforcement Point) client applications that call the Decision API, you need to design how the Decision API Request resource fields will be sent via the PEP.

Example Decision Request
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
{
  "ONAPName": "TutorialPEP",
  "ONAPComponent": "TutorialPEPComponent",
  "ONAPInstance": "TutorialPEPInstance",
  "requestId": "unique-request-id-tutorial",
  "action": "authorize",
  "resource": {
    "user": "demo",
    "entity": "foo",
    "permission" : "write"
  }
}

For simplicity, this tutorial expects only a Permit or Deny in the Decision Response. However, one could customize the Decision Response object and send back whatever information is desired.

Example Decision Response
1
2
3
{
    "status":"Permit"
}

Create A Maven Project

This part of the tutorial assumes you understand how to use Eclipse to create a Maven project. Please follow any examples for the Eclipse installation you have to create an empty application. For the tutorial, use groupId org.onap.policy.tutorial and artifactId tutorial. If you wish to go directly to the source code, please see the Download Tutorial Application Example below to download it.

../_images/eclipse-create-maven.png ../_images/eclipse-maven-project.png

Be sure to import the policy/xacml-pdp project into Eclipse.

../_images/eclipse-import.png

Add Dependencies Into Application pom.xml

Here we import the XACML PDP Application common dependency which has the interfaces we need to implement. In addition, we are importing a testing dependency that has common code for producing a JUnit test.

pom.xml dependencies
  <dependency>
    <groupId>org.onap.policy.xacml-pdp.applications</groupId>
    <artifactId>common</artifactId>
    <version>2.2.2</version>
  </dependency>
  <dependency>
    <groupId>org.onap.policy.xacml-pdp</groupId>
    <artifactId>xacml-test</artifactId>
    <version>2.2.2</version>
    <scope>test</scope>
  </dependency>

Create META-INF to expose Java Service

The ONAP XACML PDP Engine will not be able to find the tutorial application unless it has a property file located in src/main/resources/META-INF/services that contains a property file declaring the class that implements the service.

The name of the file must match org.onap.policy.pdp.xacml.application.common.XacmlApplicationServiceProvider and the contents of the file is one line org.onap.policy.tutorial.tutorial.TutorialApplication.

../_images/eclipse-meta-inf.png

Create A Java Class That Extends StdXacmlApplicationServiceProvider

You could implement XacmlApplicationServiceProvider if you wish, but for simplicity if you just extend StdXacmlApplicationServiceProvider you will get a lot of implementation done for your application up front. All that needs to be implemented is providing a custom translator.

../_images/eclipse-inherit-app.png
Custom Tutorial Application Service Provider
package org.onap.policy.tutorial.tutorial;

import org.onap.policy.pdp.xacml.application.common.ToscaPolicyTranslator;
import org.onap.policy.pdp.xacml.application.common.std.StdXacmlApplicationServiceProvider;

public class TutorialApplication extends StdXacmlApplicationServiceProvider {

      @Override
      protected ToscaPolicyTranslator getTranslator(String type) {
              // TODO Auto-generated method stub
              return null;
      }

}

Override Methods for Tutorial

Override these methods to differentiate Tutorial from other applications so that the XACML PDP Engine can determine how to route policy types and policies to the application.

Custom Tutorial Application Service Provider
package org.onap.policy.tutorial.tutorial;

import java.util.Arrays;
import java.util.List;

import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyTypeIdentifier;
import org.onap.policy.pdp.xacml.application.common.ToscaPolicyTranslator;
import org.onap.policy.pdp.xacml.application.common.std.StdXacmlApplicationServiceProvider;

public class TutorialApplication extends StdXacmlApplicationServiceProvider {

  private final ToscaPolicyTypeIdentifier supportedPolicyType = new ToscaPolicyTypeIdentifier();

  @Override
  public String applicationName() {
      return "tutorial";
  }

  @Override
  public List<String> actionDecisionsSupported() {
      return Arrays.asList("authorize");
  }

  @Override
  public synchronized List<ToscaPolicyTypeIdentifier> supportedPolicyTypes() {
      return Arrays.asList(supportedPolicyType);
  }

  @Override
  public boolean canSupportPolicyType(ToscaPolicyTypeIdentifier policyTypeId) {
      return supportedPolicyType.equals(policyTypeId);
  }

  @Override
      protected ToscaPolicyTranslator getTranslator(String type) {
      // TODO Auto-generated method stub
      return null;
  }

}

Create A Translation Class that extends the ToscaPolicyTranslator Class

Please be sure to review the existing translators in the policy/xacml-pdp repo to see if they could be re-used for your policy type. For the tutorial, we will create our own translator.

The custom translator is not only responsible for translating Policies derived from the Tutorial Policy Type, but also for translating Decision API Requests/Responses to/from the appropriate XACML requests/response objects the XACML engine understands.

Custom Tutorial Translator Class
package org.onap.policy.tutorial.tutorial;

import org.onap.policy.models.decisions.concepts.DecisionRequest;
import org.onap.policy.models.decisions.concepts.DecisionResponse;
import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
import org.onap.policy.pdp.xacml.application.common.ToscaPolicyConversionException;
import org.onap.policy.pdp.xacml.application.common.ToscaPolicyTranslator;

import com.att.research.xacml.api.Request;
import com.att.research.xacml.api.Response;

import oasis.names.tc.xacml._3_0.core.schema.wd_17.PolicyType;

public class TutorialTranslator implements ToscaPolicyTranslator {

  public PolicyType convertPolicy(ToscaPolicy toscaPolicy) throws ToscaPolicyConversionException {
      // TODO Auto-generated method stub
      return null;
  }

  public Request convertRequest(DecisionRequest request) {
      // TODO Auto-generated method stub
      return null;
  }

  public DecisionResponse convertResponse(Response xacmlResponse) {
      // TODO Auto-generated method stub
      return null;
  }

}

Implement the TutorialTranslator Methods

This is the part where knowledge of the XACML OASIS 3.0 specification is required. Please refer to that specification on the many ways to design a XACML Policy.

For the tutorial, we will build code that translates the TOSCA Policy into one XACML Policy that matches on the user and action. It will then have one or more rules for each entity and permission combination. The default combining algorithm for the XACML Rules are to “Deny Unless Permit”.

Note

There are many ways to build the policy based on the attributes. How to do so is a matter of experience and fine tuning using the many options for combining algorithms, target and/or condition matching and the rich set of functions available.

Here is one implementation example:

Example Translator Implementation
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
/*-
 * ============LICENSE_START=======================================================
 * Copyright (C) 2020 AT&T Intellectual Property. All rights reserved.
 * ================================================================================
 * 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.
 * ============LICENSE_END=========================================================
 */

package org.onap.policy.tutorial.tutorial;

import java.util.List;
import java.util.Map;
import org.onap.policy.models.decisions.concepts.DecisionRequest;
import org.onap.policy.models.decisions.concepts.DecisionResponse;
import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
import org.onap.policy.pdp.xacml.application.common.ToscaDictionary;
import org.onap.policy.pdp.xacml.application.common.ToscaPolicyConversionException;
import org.onap.policy.pdp.xacml.application.common.ToscaPolicyTranslator;
import org.onap.policy.pdp.xacml.application.common.ToscaPolicyTranslatorUtils;
import com.att.research.xacml.api.DataTypeException;
import com.att.research.xacml.api.Decision;
import com.att.research.xacml.api.Identifier;
import com.att.research.xacml.api.Request;
import com.att.research.xacml.api.Response;
import com.att.research.xacml.api.Result;
import com.att.research.xacml.api.XACML3;
import com.att.research.xacml.std.IdentifierImpl;
import com.att.research.xacml.std.annotations.RequestParser;
import oasis.names.tc.xacml._3_0.core.schema.wd_17.AnyOfType;
import oasis.names.tc.xacml._3_0.core.schema.wd_17.EffectType;
import oasis.names.tc.xacml._3_0.core.schema.wd_17.MatchType;
import oasis.names.tc.xacml._3_0.core.schema.wd_17.PolicyType;
import oasis.names.tc.xacml._3_0.core.schema.wd_17.RuleType;
import oasis.names.tc.xacml._3_0.core.schema.wd_17.TargetType;

public class TutorialTranslator implements ToscaPolicyTranslator {

    private static final Identifier ID_TUTORIAL_USER = new IdentifierImpl(ToscaDictionary.ID_URN_ONAP, "tutorial-user");
    private static final Identifier ID_TUTORIAL_ENTITY =
            new IdentifierImpl(ToscaDictionary.ID_URN_ONAP, "tutorial-entity");
    private static final Identifier ID_TUTORIAL_PERM = new IdentifierImpl(ToscaDictionary.ID_URN_ONAP, "tutorial-permission");

    @SuppressWarnings("unchecked")
    public PolicyType convertPolicy(ToscaPolicy toscaPolicy) throws ToscaPolicyConversionException {
        //
        // Here is our policy with a version and default combining algo
        //
        PolicyType newPolicyType = new PolicyType();
        newPolicyType.setPolicyId(toscaPolicy.getMetadata().get("policy-id"));
        newPolicyType.setVersion(toscaPolicy.getMetadata().get("policy-version"));
        //
        // When choosing the rule combining algorithm, be sure to be mindful of the
        // setting xacml.att.policyFinderFactory.combineRootPolicies in the
        // xacml.properties file. As that choice for ALL the policies together may have
        // an impact on the decision rendered from each individual policy.
        //
        // In this case, we will only produce XACML rules for permissions. If no permission
        // combo exists, then the default is to deny.
        //
        newPolicyType.setRuleCombiningAlgId(XACML3.ID_RULE_DENY_UNLESS_PERMIT.stringValue());
        //
        // Create the target for the Policy.
        //
        // For simplicity, let's just match on the action "authorize" and the user
        //
        MatchType matchAction = ToscaPolicyTranslatorUtils.buildMatchTypeDesignator(XACML3.ID_FUNCTION_STRING_EQUAL,
                "authorize", XACML3.ID_DATATYPE_STRING, XACML3.ID_ACTION_ACTION_ID, XACML3.ID_ATTRIBUTE_CATEGORY_ACTION);
        Map<String, Object> props = toscaPolicy.getProperties();
        String user = props.get("user").toString();
        MatchType matchUser = ToscaPolicyTranslatorUtils.buildMatchTypeDesignator(XACML3.ID_FUNCTION_STRING_EQUAL, user,
                XACML3.ID_DATATYPE_STRING, ID_TUTORIAL_USER, XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE);
        AnyOfType anyOf = new AnyOfType();
        //
        // Create AllOf (AND) of just Policy Id
        //
        anyOf.getAllOf().add(ToscaPolicyTranslatorUtils.buildAllOf(matchAction, matchUser));
        TargetType target = new TargetType();
        target.getAnyOf().add(anyOf);
        newPolicyType.setTarget(target);
        //
        // Now add the rule for each permission
        //
        int ruleNumber = 0;
        List<Object> permissions = (List<Object>) props.get("permissions");
        for (Object permission : permissions) {

            MatchType matchEntity = ToscaPolicyTranslatorUtils.buildMatchTypeDesignator(XACML3.ID_FUNCTION_STRING_EQUAL,
                    ((Map<String, String>) permission).get("entity"), XACML3.ID_DATATYPE_STRING, ID_TUTORIAL_ENTITY,
                    XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE);

            MatchType matchPermission = ToscaPolicyTranslatorUtils.buildMatchTypeDesignator(
                    XACML3.ID_FUNCTION_STRING_EQUAL, ((Map<String, String>) permission).get("permission"),
                    XACML3.ID_DATATYPE_STRING, ID_TUTORIAL_PERM, XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE);
            anyOf = new AnyOfType();
            anyOf.getAllOf().add(ToscaPolicyTranslatorUtils.buildAllOf(matchEntity, matchPermission));
            target = new TargetType();
            target.getAnyOf().add(anyOf);

            RuleType rule = new RuleType();
            rule.setDescription("Default is to PERMIT if the policy matches.");
            rule.setRuleId(newPolicyType.getPolicyId() + ":rule" + ruleNumber);

            rule.setEffect(EffectType.PERMIT);
            rule.setTarget(target);

            newPolicyType.getCombinerParametersOrRuleCombinerParametersOrVariableDefinition().add(rule);

            ruleNumber++;
        }
        return newPolicyType;
    }

    public Request convertRequest(DecisionRequest request) {
        try {
            return RequestParser.parseRequest(TutorialRequest.createRequest(request));
        } catch (IllegalArgumentException | IllegalAccessException | DataTypeException e) {
        }
        return null;
    }

    public DecisionResponse convertResponse(Response xacmlResponse) {
        DecisionResponse decisionResponse = new DecisionResponse();
        //
        // Iterate through all the results
        //
        for (Result xacmlResult : xacmlResponse.getResults()) {
            //
            // Check the result
            //
            if (xacmlResult.getDecision() == Decision.PERMIT) {
                //
                // Just simply return a Permit response
                //
                decisionResponse.setStatus(Decision.PERMIT.toString());
            } else {
                //
                // Just simply return a Deny response
                //
                decisionResponse.setStatus(Decision.DENY.toString());
            }
        }

        return decisionResponse;
    }

}

Use the TutorialTranslator in the TutorialApplication

Be sure to go back to the TutorialApplication and create an instance of the translator to return to the StdXacmlApplicationServiceProvider. The StdXacmlApplicationServiceProvider uses the translator to convert a policy when a new policy is deployed to the ONAP XACML PDP Engine.

Final TutorialApplication Class
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
package org.onap.policy.tutorial.tutorial;

import java.util.Arrays;
import java.util.List;

import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyTypeIdentifier;
import org.onap.policy.pdp.xacml.application.common.ToscaPolicyTranslator;
import org.onap.policy.pdp.xacml.application.common.std.StdXacmlApplicationServiceProvider;

public class TutorialApplication extends StdXacmlApplicationServiceProvider {

  private final ToscaPolicyTypeIdentifier supportedPolicyType = new ToscaPolicyTypeIdentifier();
  private final TutorialTranslator translator = new TutorialTranslator();

  @Override
  public String applicationName() {
      return "tutorial";
  }

  @Override
  public List<String> actionDecisionsSupported() {
      return Arrays.asList("authorize");
  }

  @Override
  public synchronized List<ToscaPolicyTypeIdentifier> supportedPolicyTypes() {
      return Arrays.asList(supportedPolicyType);
  }

  @Override
  public boolean canSupportPolicyType(ToscaPolicyTypeIdentifier policyTypeId) {
      return supportedPolicyType.equals(policyTypeId);
  }

  @Override
  protected ToscaPolicyTranslator getTranslator(String type) {
      return translator;
   }

}

Create a XACML Request from ONAP Decision Request

The easiest way to do this is to use the annotations feature from XACML PDP library to create an example XACML request. Then create an instance and simply populate it from an incoming ONAP Decision Request.

Example Decision Request to Decision Response Implementation
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
/*-
 * ============LICENSE_START=======================================================
 * Copyright (C) 2020 AT&T Intellectual Property. All rights reserved.
 * ================================================================================
 * 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.
 * ============LICENSE_END=========================================================
 */

package org.onap.policy.tutorial.tutorial;

import java.util.Map;
import java.util.Map.Entry;
import org.onap.policy.models.decisions.concepts.DecisionRequest;
import com.att.research.xacml.std.annotations.XACMLAction;
import com.att.research.xacml.std.annotations.XACMLRequest;
import com.att.research.xacml.std.annotations.XACMLResource;
import com.att.research.xacml.std.annotations.XACMLSubject;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

@Getter
@Setter
@ToString
@XACMLRequest(ReturnPolicyIdList = true)
public class TutorialRequest {
    @XACMLSubject(includeInResults = true)
    private String onapName;

    @XACMLSubject(attributeId = "urn:org:onap:onap-component", includeInResults = true)
    private String onapComponent;

    @XACMLSubject(attributeId = "urn:org:onap:onap-instance", includeInResults = true)
    private String onapInstance;

    @XACMLAction()
    private String action;

    @XACMLResource(attributeId = "urn:org:onap:tutorial-user", includeInResults = true)
    private String user;

    @XACMLResource(attributeId = "urn:org:onap:tutorial-entity", includeInResults = true)
    private String entity;

    @XACMLResource(attributeId = "urn:org:onap:tutorial-permission", includeInResults = true)
    private String permission;

    public static TutorialRequest createRequest(DecisionRequest decisionRequest) {
        //
        // Create our object
        //
        TutorialRequest request = new TutorialRequest();
        //
        // Add the subject attributes
        //
        request.onapName = decisionRequest.getOnapName();
        request.onapComponent = decisionRequest.getOnapComponent();
        request.onapInstance = decisionRequest.getOnapInstance();
        //
        // Add the action attribute
        //
        request.action = decisionRequest.getAction();
        //
        // Add the resource attributes
        //
        Map<String, Object> resources = decisionRequest.getResource();
        for (Entry<String, Object> entrySet : resources.entrySet()) {
            if ("user".equals(entrySet.getKey())) {
                request.user = entrySet.getValue().toString();
            }
            if ("entity".equals(entrySet.getKey())) {
                request.entity = entrySet.getValue().toString();
            }
            if ("permission".equals(entrySet.getKey())) {
                request.permission = entrySet.getValue().toString();
            }
        }

        return request;
    }
}

Create xacml.properties for the XACML PDP engine to use

In the applications src/test/resources directory, create a xacml.properties file that will be used by the embedded XACML PDP Engine when loading.

Example xacml.properties file
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#
# Properties that the embedded PDP engine uses to configure and load
#
# Standard API Factories
#
xacml.dataTypeFactory=com.att.research.xacml.std.StdDataTypeFactory
xacml.pdpEngineFactory=com.att.research.xacmlatt.pdp.ATTPDPEngineFactory
xacml.pepEngineFactory=com.att.research.xacml.std.pep.StdEngineFactory
xacml.pipFinderFactory=com.att.research.xacml.std.pip.StdPIPFinderFactory
xacml.traceEngineFactory=com.att.research.xacml.std.trace.LoggingTraceEngineFactory
#
# AT&T PDP Implementation Factories
#
xacml.att.evaluationContextFactory=com.att.research.xacmlatt.pdp.std.StdEvaluationContextFactory
xacml.att.combiningAlgorithmFactory=com.att.research.xacmlatt.pdp.std.StdCombiningAlgorithmFactory
xacml.att.functionDefinitionFactory=com.att.research.xacmlatt.pdp.std.StdFunctionDefinitionFactory
#
# ONAP PDP Implementation Factories
#
xacml.att.policyFinderFactory=org.onap.policy.pdp.xacml.application.common.OnapPolicyFinderFactory

#
# Use a root combining algorithm
#
xacml.att.policyFinderFactory.combineRootPolicies=urn:oasis:names:tc:xacml:3.0:policy-combining-algorithm:deny-overrides

#
# Policies to load
#
xacml.rootPolicies=
xacml.referencedPolicies=

Create a JUnit and use the TestUtils.java class in xacml-test dependency

Using Eclipse, create a JUnit and be sure to add a setup() method stub. Here you will be utilizing a TestUtils.java class from the policy/xamcl-pdp repo’s xacml-test submodule to use some utility methods for building the JUnit test.

Copy the TOSCA Policy Type link and the TOSCA Policies link into the src/test/resources directory.

We will create a temporary folder which is used by the StdXacmlApplicationServiceProvider to store working copies of policies as they are loaded into the application.

Example Translator Implementation
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
/*-
 * ============LICENSE_START=======================================================
 * Copyright (C) 2020 AT&T Intellectual Property. All rights reserved.
 * ================================================================================
 * 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.
 * ============LICENSE_END=========================================================
 */

package org.onap.policy.tutorial.tutorial;

import static org.junit.Assert.assertEquals;

import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.Properties;
import java.util.ServiceLoader;

import org.apache.commons.lang3.tuple.Pair;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.onap.policy.common.endpoints.parameters.RestServerParameters;
import org.onap.policy.common.utils.coder.CoderException;
import org.onap.policy.common.utils.coder.StandardCoder;
import org.onap.policy.common.utils.resources.TextFileUtils;
import org.onap.policy.models.decisions.concepts.DecisionRequest;
import org.onap.policy.models.decisions.concepts.DecisionResponse;
import org.onap.policy.pdp.xacml.application.common.XacmlApplicationException;
import org.onap.policy.pdp.xacml.application.common.XacmlApplicationServiceProvider;
import org.onap.policy.pdp.xacml.application.common.XacmlPolicyUtils;
import org.onap.policy.pdp.xacml.xacmltest.TestUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.att.research.xacml.api.Response;

public class TutorialApplicationTest {
	private static final Logger LOGGER = LoggerFactory.getLogger(TutorialApplicationTest.class);
    private static Properties properties = new Properties();
    private static File propertiesFile;
    private static XacmlApplicationServiceProvider service;
    private static StandardCoder gson = new StandardCoder();

    @ClassRule
    public static final TemporaryFolder policyFolder = new TemporaryFolder();

    @BeforeClass
    public static void setup() throws Exception {
        //
        // Setup our temporary folder
        //
        XacmlPolicyUtils.FileCreator myCreator = (String filename) -> policyFolder.newFile(filename);
        propertiesFile = XacmlPolicyUtils.copyXacmlPropertiesContents("src/test/resources/xacml.properties",
                properties, myCreator);
        //
        // Load XacmlApplicationServiceProvider service
        //
        ServiceLoader<XacmlApplicationServiceProvider> applicationLoader =
                ServiceLoader.load(XacmlApplicationServiceProvider.class);
        //
        // Look for our class instance and save it
        //
        Iterator<XacmlApplicationServiceProvider> iterator = applicationLoader.iterator();
        while (iterator.hasNext()) {
            XacmlApplicationServiceProvider application = iterator.next();
            //
            // Is it our service?
            //
            if (application instanceof TutorialApplication) {
            	service = application;
            }
        }
        //
        // Tell the application to initialize based on the properties file
        // we just built for it.
        //
        service.initialize(propertiesFile.toPath().getParent(), new RestServerParameters());
    }

    @Test
    public void test() throws CoderException, XacmlApplicationException, IOException {
        //
        // Now load the tutorial policies.
        //
        TestUtils.loadPolicies("src/test/resources/tutorial-policies.yaml", service);
        //
        // Load a Decision request
        //
        DecisionRequest decisionRequest = gson.decode(
                TextFileUtils
                .getTextFileAsString("src/test/resources/tutorial-decision-request.json"),
                DecisionRequest.class);
        //
        // Test a decision - should start with a permit
        //
        Pair<DecisionResponse, Response> decision = service.makeDecision(decisionRequest, null);
        LOGGER.info(decision.getLeft().toString());
        assertEquals("Permit", decision.getLeft().getStatus());
        //
        // This should be a deny
        //
        decisionRequest.getResource().put("user", "audit");
        decision = service.makeDecision(decisionRequest, null);
        LOGGER.info(decision.getLeft().toString());
        assertEquals("Deny", decision.getLeft().getStatus());
    }

}

Run the JUnit test. Its easiest to run it via a terminal command line using maven commands.

Running Maven Commands
1
> mvn clean install

Building Docker Image

Once you have created enough JUnit tests that test the TutorialTranslator.java and TutorialRequest.java classes, you are ready to now make your application build a docker image that incorporates your application with the XACML PDP Engine. The XACML PDP Engine must be able to find your Java.Service in the classpath. This is easy to do, just create a jar file for your application and copy into the same directory used to startup the XACML PDP.

Here is a Dockerfile as an example:

Dockerfile
1
2
3
4
5
6
7
FROM onap/policy-xacml-pdp:2.2.2

ADD maven/${project.build.finalName}.jar /opt/app/policy/pdpx/lib/${project.build.finalName}.jar

RUN mkdir -p /opt/app/policy/pdpx/apps/tutorial

COPY --chown=policy:policy xacml.properties /opt/app/policy/pdpx/apps/tutorial

Download Tutorial Application Example

If you don’t wish to use Eclipse, or go through the steps outlined above. The tutorial is available for download:

Download tutorial tar

After you tar xf tutorial.jar, you can import it into Eclipse or your favorite editor. Or simply use a terminal command line to build, test and run the tutorial.

In addition, there is a POSTMAN collection available for setting up and running tests against a running instance of ONAP Policy Components (api, pap, dmaap-simulator, tutorial-xacml-pdp).

Download tutorial POSTMAN Collection