summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStan Lagun <slagun@mirantis.com>2017-11-01 00:11:48 -0700
committerStan Lagun <slagun@mirantis.com>2017-11-02 01:37:52 +0000
commitde53ba8f9a97ad30c492063d9cc497ca56093e38 (patch)
tree880afb21412eee676e586e74b6404f08d5c0c175
parent52218ef398aa5ec8967eedf6d7340cabbf57d9f8 (diff)
Use secure path joinstable/pike
Notes
Notes (review): Code-Review+2: Felipe Monteiro <felipe.monteiro@att.com> Code-Review+2: zhurong <aaronzhu1121@gmail.com> Workflow+1: zhurong <aaronzhu1121@gmail.com> Verified+2: Zuul Submitted-by: Zuul Submitted-at: Wed, 08 Nov 2017 12:54:53 +0000 Reviewed-on: https://review.openstack.org/517150 Project: openstack/murano Branch: refs/heads/stable/pike
-rw-r--r--contrib/plugins/cloudify_plugin/murano_cloudify_plugin/cloudify_tosca_package.py7
-rw-r--r--murano/common/helpers/path.py33
-rw-r--r--murano/packages/hot_package.py19
-rw-r--r--murano/packages/load_utils.py5
-rw-r--r--murano/packages/mpl_package.py7
-rw-r--r--murano/packages/package.py10
-rw-r--r--murano/packages/package_base.py7
7 files changed, 64 insertions, 24 deletions
diff --git a/contrib/plugins/cloudify_plugin/murano_cloudify_plugin/cloudify_tosca_package.py b/contrib/plugins/cloudify_plugin/murano_cloudify_plugin/cloudify_tosca_package.py
index 1e6ae21..fe04e8f 100644
--- a/contrib/plugins/cloudify_plugin/murano_cloudify_plugin/cloudify_tosca_package.py
+++ b/contrib/plugins/cloudify_plugin/murano_cloudify_plugin/cloudify_tosca_package.py
@@ -10,10 +10,9 @@
10# License for the specific language governing permissions and limitations 10# License for the specific language governing permissions and limitations
11# under the License. 11# under the License.
12 12
13import os
14
15import yaml 13import yaml
16 14
15from murano.common.helpers import path
17from murano.packages import exceptions 16from murano.packages import exceptions
18from murano.packages import package_base 17from murano.packages import package_base
19 18
@@ -136,9 +135,9 @@ class CloudifyToscaPackage(package_base.PackageBase):
136 } 135 }
137 136
138 def _get_inputs_outputs(self): 137 def _get_inputs_outputs(self):
139 path = os.path.join( 138 entry_point_path = path.secure_join(
140 self.source_directory, RESOURCES_DIR_NAME, self._entry_point) 139 self.source_directory, RESOURCES_DIR_NAME, self._entry_point)
141 with open(path) as blueprint: 140 with open(entry_point_path) as blueprint:
142 data = yaml.safe_load(blueprint) 141 data = yaml.safe_load(blueprint)
143 return data.get('inputs') or {}, data.get('outputs') or {} 142 return data.get('inputs') or {}, data.get('outputs') or {}
144 143
diff --git a/murano/common/helpers/path.py b/murano/common/helpers/path.py
new file mode 100644
index 0000000..927c343
--- /dev/null
+++ b/murano/common/helpers/path.py
@@ -0,0 +1,33 @@
1# Copyright (c) 2017 Mirantis Inc.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12# implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16import os.path
17
18
19def secure_join(*parts):
20 """Secure version of os.path.join(*parts)
21
22 Joins pathname components and ensures that with each join the result
23 is a subdirectory of the previous join
24 """
25 new = prev = ""
26 for part in parts:
27 new = os.path.normpath(os.path.join(prev, part))
28 if len(new) <= len(prev) or prev != "" and not new.startswith(
29 prev + os.path.sep):
30 raise ValueError('path {0} is not allowed {1}'.format(
31 os.path.join(*parts), parts))
32 prev = new
33 return new
diff --git a/murano/packages/hot_package.py b/murano/packages/hot_package.py
index ea3ddab..de780f1 100644
--- a/murano/packages/hot_package.py
+++ b/murano/packages/hot_package.py
@@ -19,6 +19,7 @@ import sys
19import six 19import six
20import yaml 20import yaml
21 21
22from murano.common.helpers import path
22from murano.packages import exceptions 23from murano.packages import exceptions
23from murano.packages import package_base 24from murano.packages import package_base
24 25
@@ -76,7 +77,8 @@ class HotPackage(package_base.PackageBase):
76 return self._translated_class, '<generated code>' 77 return self._translated_class, '<generated code>'
77 78
78 def _translate_class(self): 79 def _translate_class(self):
79 template_file = os.path.join(self._source_directory, 'template.yaml') 80 template_file = path.secure_join(
81 self._source_directory, 'template.yaml')
80 82
81 if not os.path.isfile(template_file): 83 if not os.path.isfile(template_file):
82 raise exceptions.PackageClassLoadError( 84 raise exceptions.PackageClassLoadError(
@@ -92,9 +94,8 @@ class HotPackage(package_base.PackageBase):
92 'Extends': 'io.murano.Application' 94 'Extends': 'io.murano.Application'
93 } 95 }
94 96
95 hot_envs_path = os.path.join(self._source_directory, 97 hot_envs_path = path.secure_join(
96 RESOURCES_DIR_NAME, 98 self._source_directory, RESOURCES_DIR_NAME, HOT_ENV_DIR_NAME)
97 HOT_ENV_DIR_NAME)
98 99
99 # if using hot environments, doing parameter validation with contracts 100 # if using hot environments, doing parameter validation with contracts
100 # will overwrite the parameters in the hot environment. 101 # will overwrite the parameters in the hot environment.
@@ -190,9 +191,8 @@ class HotPackage(package_base.PackageBase):
190 191
191 @staticmethod 192 @staticmethod
192 def _translate_files(source_directory): 193 def _translate_files(source_directory):
193 hot_files_path = os.path.join(source_directory, 194 hot_files_path = path.secure_join(
194 RESOURCES_DIR_NAME, 195 source_directory, RESOURCES_DIR_NAME, HOT_FILES_DIR_NAME)
195 HOT_FILES_DIR_NAME)
196 196
197 return HotPackage._build_hot_resources(hot_files_path) 197 return HotPackage._build_hot_resources(hot_files_path)
198 198
@@ -202,7 +202,7 @@ class HotPackage(package_base.PackageBase):
202 if os.path.isdir(basedir): 202 if os.path.isdir(basedir):
203 for root, _, files in os.walk(os.path.abspath(basedir)): 203 for root, _, files in os.walk(os.path.abspath(basedir)):
204 for f in files: 204 for f in files:
205 full_path = os.path.join(root, f) 205 full_path = path.secure_join(root, f)
206 relative_path = os.path.relpath(full_path, basedir) 206 relative_path = os.path.relpath(full_path, basedir)
207 result.append(relative_path) 207 result.append(relative_path)
208 return result 208 return result
@@ -517,7 +517,8 @@ class HotPackage(package_base.PackageBase):
517 return app 517 return app
518 518
519 def _translate_ui(self): 519 def _translate_ui(self):
520 template_file = os.path.join(self._source_directory, 'template.yaml') 520 template_file = path.secure_join(
521 self._source_directory, 'template.yaml')
521 522
522 if not os.path.isfile(template_file): 523 if not os.path.isfile(template_file):
523 raise exceptions.PackageClassLoadError( 524 raise exceptions.PackageClassLoadError(
diff --git a/murano/packages/load_utils.py b/murano/packages/load_utils.py
index 6b37412..68357a6 100644
--- a/murano/packages/load_utils.py
+++ b/murano/packages/load_utils.py
@@ -22,6 +22,7 @@ import zipfile
22import six 22import six
23import yaml 23import yaml
24 24
25from murano.common.helpers import path
25from murano.common.plugins import package_types_loader 26from murano.common.plugins import package_types_loader
26import murano.packages.exceptions as e 27import murano.packages.exceptions as e
27import murano.packages.hot_package 28import murano.packages.hot_package
@@ -76,14 +77,14 @@ def load_from_file(archive_path, target_dir=None, drop_dir=False):
76 shutil.rmtree(target_dir) 77 shutil.rmtree(target_dir)
77 else: 78 else:
78 for f in os.listdir(target_dir): 79 for f in os.listdir(target_dir):
79 os.unlink(os.path.join(target_dir, f)) 80 os.unlink(path.secure_join(target_dir, f))
80 81
81 82
82def load_from_dir(source_directory, filename='manifest.yaml'): 83def load_from_dir(source_directory, filename='manifest.yaml'):
83 if not os.path.isdir(source_directory) or not os.path.exists( 84 if not os.path.isdir(source_directory) or not os.path.exists(
84 source_directory): 85 source_directory):
85 raise e.PackageLoadError('Invalid package directory') 86 raise e.PackageLoadError('Invalid package directory')
86 full_path = os.path.join(source_directory, filename) 87 full_path = path.secure_join(source_directory, filename)
87 if not os.path.isfile(full_path): 88 if not os.path.isfile(full_path):
88 raise e.PackageLoadError('Unable to find package manifest') 89 raise e.PackageLoadError('Unable to find package manifest')
89 90
diff --git a/murano/packages/mpl_package.py b/murano/packages/mpl_package.py
index 1c173e7..09f1d82 100644
--- a/murano/packages/mpl_package.py
+++ b/murano/packages/mpl_package.py
@@ -14,6 +14,7 @@
14 14
15import os 15import os
16 16
17from murano.common.helpers import path
17from murano.packages import exceptions 18from murano.packages import exceptions
18from murano.packages import package_base 19from murano.packages import package_base
19 20
@@ -34,7 +35,8 @@ class MuranoPlPackage(package_base.PackageBase):
34 35
35 @property 36 @property
36 def ui(self): 37 def ui(self):
37 full_path = os.path.join(self._source_directory, 'UI', self._ui_file) 38 full_path = path.secure_join(
39 self._source_directory, 'UI', self._ui_file)
38 if not os.path.isfile(full_path): 40 if not os.path.isfile(full_path):
39 return None 41 return None
40 with open(full_path, 'rb') as stream: 42 with open(full_path, 'rb') as stream:
@@ -49,7 +51,8 @@ class MuranoPlPackage(package_base.PackageBase):
49 raise exceptions.PackageClassLoadError( 51 raise exceptions.PackageClassLoadError(
50 name, 'Class not defined in package ' + self.full_name) 52 name, 'Class not defined in package ' + self.full_name)
51 def_file = self._classes[name] 53 def_file = self._classes[name]
52 full_path = os.path.join(self._source_directory, 'Classes', def_file) 54 full_path = path.secure_join(
55 self._source_directory, 'Classes', def_file)
53 if not os.path.isfile(full_path): 56 if not os.path.isfile(full_path):
54 raise exceptions.PackageClassLoadError( 57 raise exceptions.PackageClassLoadError(
55 name, 'File with class definition not found') 58 name, 'File with class definition not found')
diff --git a/murano/packages/package.py b/murano/packages/package.py
index 057a3f3..40fb350 100644
--- a/murano/packages/package.py
+++ b/murano/packages/package.py
@@ -20,6 +20,8 @@ import zipfile
20 20
21import six 21import six
22 22
23from murano.common.helpers import path
24
23 25
24class PackageType(object): 26class PackageType(object):
25 Library = 'Library' 27 Library = 'Library'
@@ -114,11 +116,11 @@ class Package(object):
114 raise NotImplementedError() 116 raise NotImplementedError()
115 117
116 118
117def _zip_dir(path, zip_file): 119def _zip_dir(base, zip_file):
118 for root, _, files in os.walk(path): 120 for root, _, files in os.walk(base):
119 for f in files: 121 for f in files:
120 abs_path = os.path.join(root, f) 122 abs_path = path.secure_join(root, f)
121 relative_path = os.path.relpath(abs_path, path) 123 relative_path = os.path.relpath(abs_path, base)
122 zip_file.write(abs_path, relative_path) 124 zip_file.write(abs_path, relative_path)
123 125
124 126
diff --git a/murano/packages/package_base.py b/murano/packages/package_base.py
index 475a55b..b392645 100644
--- a/murano/packages/package_base.py
+++ b/murano/packages/package_base.py
@@ -22,6 +22,7 @@ import sys
22import semantic_version 22import semantic_version
23import six 23import six
24 24
25from murano.common.helpers import path
25from murano.common.i18n import _ 26from murano.common.i18n import _
26from murano.packages import exceptions 27from murano.packages import exceptions
27from murano.packages import package 28from murano.packages import package
@@ -119,13 +120,13 @@ class PackageBase(package.Package):
119 self._supplier.get('Logo'), 'supplier_logo.png', 'supplier logo') 120 self._supplier.get('Logo'), 'supplier_logo.png', 'supplier logo')
120 121
121 def get_resource(self, name): 122 def get_resource(self, name):
122 resources_dir = os.path.join(self._source_directory, 'Resources') 123 resources_dir = path.secure_join(self._source_directory, 'Resources')
123 if not os.path.exists(resources_dir): 124 if not os.path.exists(resources_dir):
124 os.makedirs(resources_dir) 125 os.makedirs(resources_dir)
125 return os.path.join(resources_dir, name) 126 return path.secure_join(resources_dir, name)
126 127
127 def _load_image(self, file_name, default_name, what_image): 128 def _load_image(self, file_name, default_name, what_image):
128 full_path = os.path.join( 129 full_path = path.secure_join(
129 self._source_directory, file_name or default_name) 130 self._source_directory, file_name or default_name)
130 if not os.path.isfile(full_path) and not file_name: 131 if not os.path.isfile(full_path) and not file_name:
131 return 132 return