aboutsummaryrefslogtreecommitdiffstats
path: root/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdBaseTranslator.java
blob: 61d28f5899f15172f4d768d8b22eb92959a97d59 (plain)
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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
/*-
 * ============LICENSE_START=======================================================
 * ONAP
 * ================================================================================
 * Copyright (C) 2019-2021 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.
 *
 * SPDX-License-Identifier: Apache-2.0
 * ============LICENSE_END=========================================================
 */

package org.onap.policy.pdp.xacml.application.common.std;

import com.att.research.xacml.api.Advice;
import com.att.research.xacml.api.Decision;
import com.att.research.xacml.api.Obligation;
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 java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import oasis.names.tc.xacml._3_0.core.schema.wd_17.AnyOfType;
import oasis.names.tc.xacml._3_0.core.schema.wd_17.ApplyType;
import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeDesignatorType;
import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeValueType;
import oasis.names.tc.xacml._3_0.core.schema.wd_17.ConditionType;
import oasis.names.tc.xacml._3_0.core.schema.wd_17.ObjectFactory;
import oasis.names.tc.xacml._3_0.core.schema.wd_17.ObligationExpressionType;
import oasis.names.tc.xacml._3_0.core.schema.wd_17.ObligationExpressionsType;
import oasis.names.tc.xacml._3_0.core.schema.wd_17.PolicySetType;
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 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.OnapObligation;
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 org.onap.policy.pdp.xacml.application.common.XacmlPolicyUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public abstract class StdBaseTranslator implements ToscaPolicyTranslator {
    private static final Logger LOGGER = LoggerFactory.getLogger(StdBaseTranslator.class);
    private static final ObjectFactory factory = new ObjectFactory();

    public static final String POLICY_ID = "policy-id";
    public static final String POLICY_VERSION = "policy-version";

    @Override
    public Object convertPolicy(ToscaPolicy toscaPolicy) throws ToscaPolicyConversionException {
        throw new ToscaPolicyConversionException("Please override convertPolicy");
    }

    @Override
    public Request convertRequest(DecisionRequest request) throws ToscaPolicyConversionException {
        return null;
    }

    @Override
    public DecisionResponse convertResponse(Response xacmlResponse) {
        LOGGER.info("Converting Response {}", xacmlResponse);
        var decisionResponse = new DecisionResponse();
        //
        // Setup policies
        //
        decisionResponse.setPolicies(new HashMap<>());
        //
        // Iterate through all the results
        //
        for (Result xacmlResult : xacmlResponse.getResults()) {
            //
            // Check the result
            //
            if (xacmlResult.getDecision() == Decision.PERMIT) {
                //
                // Go through obligations
                //
                scanObligations(xacmlResult.getObligations(), decisionResponse);
                //
                // Go through advice
                //
                scanAdvice(xacmlResult.getAssociatedAdvice(), decisionResponse);
            } else {
                //
                // Return error information back
                //
                decisionResponse.setStatus("error");
                decisionResponse.setMessage(xacmlResult.getStatus().getStatusMessage());
            }
        }

        return decisionResponse;
    }

    /**
     * scanObligations - scans the list of obligations and make appropriate method calls to process
     * obligations. This method must be overridden and be implemented for the specific application as
     * obligations may have different expected attributes per application.
     *
     * @param obligations Collection of obligation objects
     * @param decisionResponse DecisionResponse object used to store any results from obligations.
     */
    protected abstract void scanObligations(Collection<Obligation> obligations, DecisionResponse decisionResponse);

    /**
     * scanAdvice - scans the list of advice and make appropriate call to process the advice. This method
     * can be overridden for each specific application as advice may have different expected attributes per
     * application.
     *
     * @param advice Collection of Advice objects
     * @param decisionResponse DecisionResponse object used to store any results from advice.
     */
    protected abstract void scanAdvice(Collection<Advice> advice, DecisionResponse decisionResponse);

    /**
     * From the TOSCA metadata section, pull in values that are needed into the XACML policy.
     *
     * @param policy Policy Object to store the metadata
     * @param map The Metadata TOSCA Map
     * @return Same Policy Object
     * @throws ToscaPolicyConversionException If there is something missing from the metadata
     */
    protected PolicyType fillMetadataSection(PolicyType policy,
            Map<String, String> map) throws ToscaPolicyConversionException {
        //
        // Ensure the policy-id exists - we don't use it here. It
        // is saved in the TOSCA Policy Name field.
        //
        if (! map.containsKey(POLICY_ID)) {
            throw new ToscaPolicyConversionException(policy.getPolicyId() + " missing metadata " + POLICY_ID);
        }
        //
        // Ensure the policy-version exists
        //
        if (! map.containsKey(POLICY_VERSION)) {
            throw new ToscaPolicyConversionException(policy.getPolicyId() + " missing metadata "
                    + POLICY_VERSION);
        }
        //
        // Add in the Policy Version
        //
        policy.setVersion(map.get(POLICY_VERSION));
        return policy;
    }

    /**
     * addObligation - general code to add a json policy as an obligation. Probably could just
     * return the obligation only instead of adding it directly to a rule/policy/policyset.
     * But this is fine for now.
     *
     * @param <T> RuleType, PolicyType, PolicySetType object
     * @Param policyId The policy-id
     * @param ruleOrPolicy Incoming RuleType, PolicyType, PolicySetType object
     * @param jsonPolicy JSON String representation of policy.
     * @param weight Weighting for the policy (optional)
     * @return Return the Incoming RuleType, PolicyType, PolicySetType object for convenience.
     */
    protected <T> T addObligation(T ruleOrPolicy, String policyId, String jsonPolicy, Integer weight,
            String policyType) {
        //
        // Creating obligation for returning policy
        //
        LOGGER.info("Obligation Policy id: {} type: {} weight: {} policy:{}{}", policyId, policyType, weight,
                XacmlPolicyUtils.LINE_SEPARATOR, jsonPolicy);
        //
        // Create our OnapObligation
        //
        var onapObligation = new OnapObligation(policyId, jsonPolicy, policyType, weight);
        //
        // Generate the obligation
        //
        ObligationExpressionType obligation = onapObligation.generateObligation();
        //
        // Now we can add it into the rule/policy/policyset
        //
        var obligations = new ObligationExpressionsType();
        obligations.getObligationExpression().add(obligation);
        if (ruleOrPolicy instanceof RuleType) {
            ((RuleType) ruleOrPolicy).setObligationExpressions(obligations);
        } else if (ruleOrPolicy instanceof PolicyType) {
            ((PolicyType) ruleOrPolicy).setObligationExpressions(obligations);
        } else if (ruleOrPolicy instanceof PolicySetType) {
            ((PolicySetType) ruleOrPolicy).setObligationExpressions(obligations);
        } else {
            LOGGER.error("Unsupported class for adding obligation {}", ruleOrPolicy.getClass());
        }
        //
        // Return as a convenience
        //
        return ruleOrPolicy;
    }

    /**
     * generateAnyOfForPolicyType - Creates a specific AnyOfType that includes the check
     * to match on a specific TOSCA Policy Type.
     *
     * @param type String represenatation of TOSCA Policy Type (eg. "onap.policies.Foo")
     * @return AnyOfType object
     */
    protected AnyOfType generateAnyOfForPolicyType(String type) {
        //
        // Create the match for the policy type
        //
        var match = ToscaPolicyTranslatorUtils.buildMatchTypeDesignator(
                XACML3.ID_FUNCTION_STRING_EQUAL,
                type,
                XACML3.ID_DATATYPE_STRING,
                ToscaDictionary.ID_RESOURCE_POLICY_TYPE,
                XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE);
        //
        // Add it to an AnyOfType object
        //
        var anyOf = new AnyOfType();
        anyOf.getAllOf().add(ToscaPolicyTranslatorUtils.buildAllOf(match));
        //
        // Return new AnyOfType
        //
        return anyOf;
    }

    /**
     * generateConditionForPolicyType - create a ConditionType XACML object
     * that is able to determine if a request specifies a specific policy type
     * that the policy is created from, only then is the rule applied. If the
     * request doesn't even care about the policy type (eg it is missing) then
     * return the rule should not apply.
     *
     * @param type PolicyType (eg. onap.policies.Foo
     * @return ConditionType object
     */
    protected ConditionType generateConditionForPolicyType(String type) {
        //
        // Create an ApplyType that checks if the request contains the
        // policy-type attribute
        //
        var designator = new AttributeDesignatorType();
        designator.setAttributeId(ToscaDictionary.ID_RESOURCE_POLICY_TYPE.stringValue());
        designator.setCategory(XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE.stringValue());
        designator.setDataType(XACML3.ID_DATATYPE_STRING.stringValue());

        var applyBagSize = new ApplyType();
        applyBagSize.setDescription("Get the size of policy-type attributes");
        applyBagSize.setFunctionId(XACML3.ID_FUNCTION_STRING_BAG_SIZE.stringValue());

        var valueZero = new AttributeValueType();
        valueZero.setDataType(XACML3.ID_DATATYPE_INTEGER.stringValue());
        valueZero.getContent().add("0");    // Yes really - represent as a string

        applyBagSize.getExpression().add(factory.createAttributeDesignator(designator));

        var applyGreaterThan = new ApplyType();
        applyGreaterThan.setDescription("Does the policy-type attribute exist?");
        applyGreaterThan.setFunctionId(XACML3.ID_FUNCTION_INTEGER_EQUAL.stringValue());

        applyGreaterThan.getExpression().add(factory.createApply(applyBagSize));
        applyGreaterThan.getExpression().add(factory.createAttributeValue(valueZero));

        //
        // Create an apply type that checks the actual value
        //
        var value = new AttributeValueType();
        value.setDataType(XACML3.ID_DATATYPE_STRING.stringValue());
        value.getContent().add(type);

        //
        // Create string-is-in apply - which determines if the policy-type
        // is in the request bag of resources for policy-type
        //
        var applyIsIn = new ApplyType();
        applyIsIn.setDescription("Is this policy-type in the list?");
        applyIsIn.setFunctionId(XACML3.ID_FUNCTION_STRING_IS_IN.stringValue());
        applyIsIn.getExpression().add(factory.createAttributeValue(value));
        applyIsIn.getExpression().add(factory.createAttributeDesignator(designator));

        //
        // Create our outer apply
        //
        var applyOr = new ApplyType();
        applyOr.setDescription("IF exists and is equal");
        applyOr.setFunctionId(XACML3.ID_FUNCTION_OR.stringValue());

        applyOr.getExpression().add(factory.createApply(applyGreaterThan));
        applyOr.getExpression().add(factory.createApply(applyIsIn));

        //
        // Finally create the condition
        //
        var condition = new ConditionType();

        condition.setExpression(factory.createApply(applyOr));

        return condition;
    }

}