b30dd9434c4f5f2274e1993db4aa477ff8a791f7
[policy/xacml-pdp.git] / tutorials / tutorial-xacml-application / src / main / java / org / onap / policy / tutorial / tutorial / TutorialTranslator.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * Copyright (C) 2020-2021 AT&T Intellectual Property. All rights reserved.
4  * ================================================================================
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  * ============LICENSE_END=========================================================
17  */
18
19 package org.onap.policy.tutorial.tutorial;
20
21 import com.att.research.xacml.api.Advice;
22 import com.att.research.xacml.api.DataTypeException;
23 import com.att.research.xacml.api.Decision;
24 import com.att.research.xacml.api.Identifier;
25 import com.att.research.xacml.api.Obligation;
26 import com.att.research.xacml.api.Request;
27 import com.att.research.xacml.api.Response;
28 import com.att.research.xacml.api.Result;
29 import com.att.research.xacml.api.XACML3;
30 import com.att.research.xacml.std.IdentifierImpl;
31 import java.util.ArrayList;
32 import java.util.Collection;
33 import java.util.HashMap;
34 import java.util.List;
35 import java.util.Map;
36 import oasis.names.tc.xacml._3_0.core.schema.wd_17.AnyOfType;
37 import oasis.names.tc.xacml._3_0.core.schema.wd_17.EffectType;
38 import oasis.names.tc.xacml._3_0.core.schema.wd_17.PolicyType;
39 import oasis.names.tc.xacml._3_0.core.schema.wd_17.RuleType;
40 import oasis.names.tc.xacml._3_0.core.schema.wd_17.TargetType;
41 import org.onap.policy.models.decisions.concepts.DecisionRequest;
42 import org.onap.policy.models.decisions.concepts.DecisionResponse;
43 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
44 import org.onap.policy.pdp.xacml.application.common.ToscaDictionary;
45 import org.onap.policy.pdp.xacml.application.common.ToscaPolicyConversionException;
46 import org.onap.policy.pdp.xacml.application.common.ToscaPolicyTranslatorUtils;
47 import org.onap.policy.pdp.xacml.application.common.std.StdBaseTranslator;
48
49 public class TutorialTranslator extends StdBaseTranslator {
50
51     private static final Identifier ID_TUTORIAL_USER = new IdentifierImpl(ToscaDictionary.ID_URN_ONAP, "tutorial-user");
52     private static final Identifier ID_TUTORIAL_ENTITY =
53             new IdentifierImpl(ToscaDictionary.ID_URN_ONAP, "tutorial-entity");
54     private static final Identifier ID_TUTORIAL_PERM =
55             new IdentifierImpl(ToscaDictionary.ID_URN_ONAP, "tutorial-permission");
56
57     /**
58      * Constructor will setup some defaults.
59      */
60     public TutorialTranslator() {
61         //
62         // For demonstration purposes, this tutorial will have
63         // the original attributes returned in the request.
64         //
65         this.booleanReturnAttributes = true;
66         this.booleanReturnSingleValueAttributesAsCollection = false;
67     }
68
69     /**
70      * Convert Policy from TOSCA to XACML.
71      */
72     @SuppressWarnings("unchecked")
73     @Override
74     public PolicyType convertPolicy(ToscaPolicy toscaPolicy) throws ToscaPolicyConversionException {
75         //
76         // Here is our policy with a version and default combining algo
77         //
78         var newPolicyType = new PolicyType();
79         newPolicyType.setPolicyId(String.valueOf(toscaPolicy.getMetadata().get("policy-id")));
80         newPolicyType.setVersion(String.valueOf(toscaPolicy.getMetadata().get("policy-version")));
81         //
82         // When choosing the rule combining algorithm, be sure to be mindful of the
83         // setting xacml.att.policyFinderFactory.combineRootPolicies in the
84         // xacml.properties file. As that choice for ALL the policies together may have
85         // an impact on the decision rendered from each individual policy.
86         //
87         // In this case, we will only produce XACML rules for permissions. If no permission
88         // combo exists, then the default is to deny.
89         //
90         newPolicyType.setRuleCombiningAlgId(XACML3.ID_RULE_DENY_UNLESS_PERMIT.stringValue());
91         //
92         // Create the target for the Policy.
93         //
94         // For simplicity, let's just match on the action "authorize" and the user
95         //
96         var matchAction =
97                 ToscaPolicyTranslatorUtils.buildMatchTypeDesignator(XACML3.ID_FUNCTION_STRING_EQUAL, "authorize",
98                         XACML3.ID_DATATYPE_STRING, XACML3.ID_ACTION_ACTION_ID, XACML3.ID_ATTRIBUTE_CATEGORY_ACTION);
99         Map<String, Object> props = toscaPolicy.getProperties();
100         var user = props.get("user").toString();
101         var matchUser = ToscaPolicyTranslatorUtils.buildMatchTypeDesignator(XACML3.ID_FUNCTION_STRING_EQUAL, user,
102                 XACML3.ID_DATATYPE_STRING, ID_TUTORIAL_USER, XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE);
103         var anyOf = new AnyOfType();
104         //
105         // Create AllOf (AND) of just Policy Id
106         //
107         anyOf.getAllOf().add(ToscaPolicyTranslatorUtils.buildAllOf(matchAction, matchUser));
108         var target = new TargetType();
109         target.getAnyOf().add(anyOf);
110         newPolicyType.setTarget(target);
111         //
112         // Now add the rule for each permission
113         //
114         var ruleNumber = 0;
115         List<Object> permissions = (List<Object>) props.get("permissions");
116         for (Object permission : permissions) {
117
118             var matchEntity = ToscaPolicyTranslatorUtils.buildMatchTypeDesignator(XACML3.ID_FUNCTION_STRING_EQUAL,
119                     ((Map<String, String>) permission).get("entity"), XACML3.ID_DATATYPE_STRING, ID_TUTORIAL_ENTITY,
120                     XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE);
121
122             var matchPermission = ToscaPolicyTranslatorUtils.buildMatchTypeDesignator(XACML3.ID_FUNCTION_STRING_EQUAL,
123                     ((Map<String, String>) permission).get("permission"), XACML3.ID_DATATYPE_STRING, ID_TUTORIAL_PERM,
124                     XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE);
125             anyOf = new AnyOfType();
126             anyOf.getAllOf().add(ToscaPolicyTranslatorUtils.buildAllOf(matchEntity, matchPermission));
127             target = new TargetType();
128             target.getAnyOf().add(anyOf);
129
130             var rule = new RuleType();
131             rule.setDescription("Default is to PERMIT if the policy matches.");
132             rule.setRuleId(newPolicyType.getPolicyId() + ":rule" + ruleNumber);
133
134             rule.setEffect(EffectType.PERMIT);
135             rule.setTarget(target);
136
137             newPolicyType.getCombinerParametersOrRuleCombinerParametersOrVariableDefinition().add(rule);
138
139             ruleNumber++;
140         }
141         return newPolicyType;
142     }
143
144     /**
145      * Convert ONAP DecisionRequest to XACML Request.
146      */
147     @Override
148     public Request convertRequest(DecisionRequest request) {
149         try {
150             return TutorialRequest.createRequest(request);
151         } catch (IllegalArgumentException | IllegalAccessException | DataTypeException e) {
152             // Empty
153         }
154         return null;
155     }
156
157     @Override
158     public DecisionResponse convertResponse(Response xacmlResponse) {
159         //
160         // Single or Multi?
161         //
162         if (xacmlResponse.getResults().size() > 1) {
163             return convertMultiResponse(xacmlResponse);
164         } else {
165             return convertSingleResponse(xacmlResponse.getResults().iterator().next());
166         }
167     }
168
169     protected DecisionResponse convertSingleResponse(Result xacmlResult) {
170         var decisionResponse = new DecisionResponse();
171         //
172         // Setup policies
173         //
174         decisionResponse.setPolicies(new HashMap<>());
175         //
176         // Check the result
177         //
178         if (xacmlResult.getDecision() == Decision.PERMIT) {
179             //
180             // This tutorial will simply set the status to Permit
181             //
182             decisionResponse.setStatus(Decision.PERMIT.toString());
183         } else {
184             //
185             // This tutorial will simply set the status to Deny
186             //
187             decisionResponse.setStatus(Decision.DENY.toString());
188         }
189         //
190         // Add attributes use the default scanAttributes. Note that one
191         // could override that method and return the structure as desired.
192         // The attributes returned by default method are in the format
193         // of XACML syntax. It may be more desirable to map them back to
194         // the original request name-value.
195         //
196         if (booleanReturnAttributes) {
197             scanAttributes(xacmlResult.getAttributes(), decisionResponse);
198         }
199         return decisionResponse;
200     }
201
202     protected DecisionResponse convertMultiResponse(Response xacmlResponse) {
203         TutorialResponse decisionResponse = new TutorialResponse();
204         //
205         // Setup policies
206         //
207         decisionResponse.setPolicies(new HashMap<>());
208         decisionResponse.setStatus("multi");
209         List<TutorialResponsePermission> permissions = new ArrayList<>();
210         for (Result xacmlResult : xacmlResponse.getResults()) {
211             TutorialResponsePermission permission = new TutorialResponsePermission();
212             //
213             // Check the result
214             //
215             if (xacmlResult.getDecision() == Decision.PERMIT) {
216                 //
217                 // This tutorial will simply set the status to Permit
218                 //
219                 permission.setStatus(Decision.PERMIT.toString());
220             } else {
221                 //
222                 // This tutorial will simply set the status to Deny
223                 //
224                 permission.setStatus(Decision.DENY.toString());
225             }
226             //
227             // Add attributes use the default scanAttributes. Note that one
228             // could override that method and return the structure as desired.
229             // The attributes returned by default method are in the format
230             // of XACML syntax. It may be more desirable to map them back to
231             // the original request name-value.
232             //
233             if (booleanReturnAttributes) {
234                 //
235                 // Call existing method
236                 //
237                 scanAttributes(xacmlResult.getAttributes(), decisionResponse);
238                 //
239                 // Move from overall response to the individual permission
240                 //
241                 permission.setAttributes(decisionResponse.getAttributes());
242                 decisionResponse.setAttributes(null);
243             }
244             //
245             // Add it
246             //
247             permissions.add(permission);
248         }
249         decisionResponse.setPermissions(permissions);
250         return decisionResponse;
251     }
252
253     @Override
254     protected void scanObligations(Collection<Obligation> obligations, DecisionResponse decisionResponse) {
255         //
256         // No obligations in this tutorial yet.
257         //
258     }
259
260     @Override
261     protected void scanAdvice(Collection<Advice> advice, DecisionResponse decisionResponse) {
262         //
263         // No advice in this tutorial yet.
264         //
265     }
266
267 }