summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStan Lagun <slagun@mirantis.com>2017-11-01 18:44:44 -0700
committerzhurong <aaronzhu1121@gmail.com>2017-11-16 11:43:30 +0000
commit8b1f6fbe6beb44f33de88957c295f57649f5c3fc (patch)
tree2e1ae07b201e4b8d321b4a34dcb29dcfcd61ec42
parent9171bd3fbc6fc36b35c4008753f58e09aa10d384 (diff)
Use secure path joinstable/ocata
Notes
Notes (review): Code-Review+2: zhurong <aaronzhu1121@gmail.com> Code-Review+2: Felipe Monteiro <felipe.monteiro@att.com> Workflow+1: Felipe Monteiro <felipe.monteiro@att.com> Verified+2: Zuul Submitted-by: Zuul Submitted-at: Mon, 20 Nov 2017 15:56:14 +0000 Reviewed-on: https://review.openstack.org/517151 Project: openstack/murano Branch: refs/heads/stable/ocata
-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 178e7e4..71bfa0b 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,11 +10,10 @@
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 six 13import six
16import yaml 14import yaml
17 15
16from murano.common.helpers import path
18from murano.packages import exceptions 17from murano.packages import exceptions
19from murano.packages import package_base 18from murano.packages import package_base
20 19
@@ -137,9 +136,9 @@ class CloudifyToscaPackage(package_base.PackageBase):
137 } 136 }
138 137
139 def _get_inputs_outputs(self): 138 def _get_inputs_outputs(self):
140 path = os.path.join( 139 entry_point_path = path.secure_join(
141 self.source_directory, RESOURCES_DIR_NAME, self._entry_point) 140 self.source_directory, RESOURCES_DIR_NAME, self._entry_point)
142 with open(path) as blueprint: 141 with open(entry_point_path) as blueprint:
143 data = yaml.safe_load(blueprint) 142 data = yaml.safe_load(blueprint)
144 return data.get('inputs') or {}, data.get('outputs') or {} 143 return data.get('inputs') or {}, data.get('outputs') or {}
145 144
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 66b1931..1d8c5ad 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 4c993a3..21543ab 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