aboutsummaryrefslogtreecommitdiffstats
path: root/plugins/reception-plugins/src/main/java/org/onap/policy/distribution/reception/decoding/policy/file/PolicyDecoderFileInCsarToPolicy.java
blob: fe7f2dcc971e9d7ccf0433094f67202a26e405f8 (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
/*-
 * ============LICENSE_START=======================================================
 *  Copyright (C) 2018 Ericsson. All rights reserved.
 *  Copyright (C) 2019 Nordix Foundation.
 *  Modifications Copyright (C) 2020-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.distribution.reception.decoding.policy.file;

import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import org.onap.policy.common.parameters.ParameterService;
import org.onap.policy.common.utils.coder.CoderException;
import org.onap.policy.common.utils.coder.StandardCoder;
import org.onap.policy.distribution.model.Csar;
import org.onap.policy.distribution.model.PolicyInput;
import org.onap.policy.distribution.reception.decoding.PolicyDecoder;
import org.onap.policy.distribution.reception.decoding.PolicyDecodingException;
import org.onap.policy.models.tosca.authorative.concepts.ToscaEntity;
import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate;

/**
 * This class extracts policy files from a CSAR file.
 *
 * @author Ram Krishna Verma (ram.krishna.verma@ericsson.com)
 */
public class PolicyDecoderFileInCsarToPolicy implements PolicyDecoder<Csar, ToscaEntity> {

    private PolicyDecoderFileInCsarToPolicyParameterGroup decoderParameters;
    private StandardCoder coder;
    private static final long MAX_FILE_SIZE = 512L * 1024;

    /**
     * {@inheritDoc}.
     */
    @Override
    public void configure(final String parameterGroupName) {
        decoderParameters = ParameterService.get(parameterGroupName);
        coder = new StandardCoder();
    }

    /**
     * {@inheritDoc}.
     */
    @Override
    public boolean canHandle(final PolicyInput policyInput) {
        return policyInput.getClass().isAssignableFrom(Csar.class);
    }

    /**
     * {@inheritDoc}.
     */
    @Override
    public Collection<ToscaEntity> decode(final Csar csar) throws PolicyDecodingException {
        final Collection<ToscaEntity> policyList = new ArrayList<>();

        try (var zipFile = new ZipFile(csar.getCsarPath())) {
            final Enumeration<? extends ZipEntry> entries = zipFile.entries();
            while (entries.hasMoreElements()) {
                //
                // Sonar will flag this as a Security Hotspot
                // "Expanding archive files is security-sensitive"
                // isZipEntryValid ensures the file being read exists in the archive
                //
                final ZipEntry entry = entries.nextElement(); // NOSONAR
                if (isZipEntryValid(entry.getName(), csar.getCsarPath(), entry.getSize())) {
                    final ToscaServiceTemplate policy =
                            coder.decode(zipFile.getInputStream(entry), ToscaServiceTemplate.class);
                    policyList.add(policy);
                }
            }
        } catch (final IOException | CoderException exp) {
            throw new PolicyDecodingException("Failed decoding the policy", exp);
        }

        return policyList;
    }

    /**
     * Method to filter out Policy type and Policy files. In addition,
     * ensures validation of entries in the Zipfile. Attempts to solve path
     * injection java security issues.
     *
     * @param entryName name of the ZipEntry to check
     * @param csarPath Absolute path to the csar the ZipEntry is in
     * @param entrySize size of the ZipEntry
     * @return true if no injection detected, and it is a policy type  or policy file.
     * @throws PolicyDecodingException if the file size is too large
     */
    private boolean isZipEntryValid(String entryName, String csarPath, long entrySize) throws PolicyDecodingException {
        //
        // We only care about policy types and policies
        //
        if (entryName.contains(decoderParameters.getPolicyTypeFileName())
                || entryName.contains(decoderParameters.getPolicyFileName())) {
            //
            // Check file size
            //
            if (entrySize > MAX_FILE_SIZE) {
                throw new PolicyDecodingException("Zip entry for " + entryName + " is too large " + entrySize);
            }
            //
            // Now ensure that there is no path injection
            //
            var path = Path.of(csarPath, entryName).normalize();
            //
            // Throw an exception if path is outside the csar
            //
            if (! path.startsWith(csarPath)) {
                throw new PolicyDecodingException("Potential path injection for zip entry " + entryName);
            }
            return true;
        }

        return false;
    }
}