hiera-file 1.0.1 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,44 +1,80 @@
1
+ require 'hiera/config'
2
+
1
3
  class Hiera
2
4
  module Backend
3
5
  class File_backend
4
6
  def initialize
5
7
  Hiera.debug("Hiera File backend starting")
8
+
9
+ if Hiera::Config.include?(:file) and Hiera::Config[:file].has_key? :interpolate
10
+ @interpolate = Hiera::Config[:file][:interpolate]
11
+ else
12
+ @interpolate = true
13
+ end
6
14
  end
7
15
 
8
16
  def lookup(key, scope, order_override, resolution_type)
9
17
  answer = nil
10
18
 
11
- Hiera.debug("Looking up #{key} in JSON backend")
19
+ Hiera.debug("Looking up #{key} in File backend")
12
20
 
13
21
  Backend.datasources(scope, order_override) do |source|
14
22
  Hiera.debug("Hiera File_backend: looking for data source '#{source}'")
15
23
 
16
24
  datadir = Backend.datafile(:file, scope, source, "d") or next
17
25
 
18
- # Expand the datadir and path, and ensure that the datadir contains
19
- # the given key. If the expanded key is outside of the datadir then
20
- # this is a directory traversal attack and should be aborted.
21
- abs_datadir = File.expand_path(datadir)
22
- abs_path = File.expand_path(File.join(abs_datadir, key))
23
- unless abs_path.index(abs_datadir) == 0
24
- raise Exception, "Hiera File backend: key lookup outside of datadir '#{key}'"
25
- end
26
+ validate_key_lookup!(datadir, key)
27
+
28
+ path = File.join(datadir, key)
29
+ next unless File.exist?(path)
26
30
 
27
- next unless File.exist?(abs_path)
28
- data = File.read(abs_path)
31
+ data = File.read(path)
29
32
 
30
33
  case resolution_type
31
34
  when :array
32
35
  answer ||= []
33
- answer << Backend.parse_answer(data, scope)
36
+ answer << parse_answer(data, scope)
34
37
  else
35
- answer = Backend.parse_answer(data, scope)
38
+ answer = parse_answer(data, scope)
36
39
  break
37
40
  end
38
41
  end
39
42
 
40
43
  answer
41
44
  end
45
+
46
+ # Ensure that looked up files are within the datadir to prevent directory traversal
47
+ #
48
+ # @param datadir [String] The directory being used for the lookup
49
+ # @param key [String] The key being looked up
50
+ #
51
+ # @todo Raise a SecurityError instead of an Exception
52
+ # @raise [Exception] If the path to the data file is outside of the datadir
53
+ def validate_key_lookup!(datadir, key)
54
+
55
+ # Expand the datadir and path, and ensure that the datadir contains
56
+ # the given key. If the expanded key is outside of the datadir then
57
+ # this is a directory traversal attack and should be aborted.
58
+ abs_datadir = File.expand_path(datadir)
59
+ abs_path = File.expand_path(File.join(abs_datadir, key))
60
+ unless abs_path.index(abs_datadir) == 0
61
+ raise Exception, "Hiera File backend: key lookup outside of datadir '#{key}'"
62
+ end
63
+ end
64
+
65
+ # Parse the answer according to the chosen interpolation mode
66
+ #
67
+ # @param data [String] The value to parse
68
+ # @param scope [Hash] The variable scope to use for interpolation
69
+ #
70
+ # @return [String] The interpolated data
71
+ def parse_answer(data, scope)
72
+ if @interpolate
73
+ Backend.parse_answer(data, scope)
74
+ else
75
+ data
76
+ end
77
+ end
42
78
  end
43
79
  end
44
80
  end
@@ -7,8 +7,9 @@ class Hiera
7
7
  before do
8
8
  Hiera.stubs(:debug)
9
9
  Hiera.stubs(:warn)
10
- end
11
10
 
11
+ Hiera::Config.load(:backends => :file)
12
+ end
12
13
 
13
14
  describe "#initialize" do
14
15
  it "should announce its creation" do # because other specs checks this
@@ -23,8 +24,6 @@ class Hiera
23
24
  Backend.stubs(:datasources).multiple_yields(["one"], ["two"])
24
25
  end
25
26
 
26
- subject { File_backend.new }
27
-
28
27
  it "should look for data in all sources" do
29
28
  Backend.expects(:datafile).with(:file, {}, "one", "d")
30
29
  Backend.expects(:datafile).with(:file, {}, "two", "d")
@@ -59,16 +58,60 @@ class Hiera
59
58
  subject.lookup("key", {}, nil, :array).should == ['value one', 'value two']
60
59
  end
61
60
 
62
- it "should parse the answer for scope variables" do
63
- scope = {'scope_val' => 'v'}
61
+ describe "With interpolation" do
62
+ after do
63
+ Hiera::Config.load({:file => {}})
64
+ end
64
65
 
65
- Backend.expects(:datafile).with(:file, scope, "one", "d").returns("/datadir/one.d")
66
- Backend.expects(:datafile).with(:file, scope, "two", "d").never
66
+ describe "explicitly enabled" do
67
+ before do
68
+ Hiera::Config.load({:file => {:interpolate => true}})
69
+ end
67
70
 
68
- File.expects(:exist?).with("/datadir/one.d/key").returns true
69
- File.expects(:read).with("/datadir/one.d/key").returns '%{scope_val}alue'
71
+ it "should parse the answer for scope variables" do
72
+ scope = {'scope_val' => 'v'}
73
+
74
+ Backend.expects(:datafile).with(:file, scope, "one", "d").returns("/datadir/one.d")
75
+ Backend.expects(:datafile).with(:file, scope, "two", "d").never
76
+
77
+ File.expects(:exist?).with("/datadir/one.d/key").returns true
78
+ File.expects(:read).with("/datadir/one.d/key").returns '%{scope_val}alue'
79
+
80
+ subject.lookup("key", scope, nil, :priority).should == 'value'
81
+ end
82
+ end
83
+
84
+ describe "set to default" do
85
+ it "should parse the answer for scope variables" do
86
+ scope = {'scope_val' => 'v'}
87
+
88
+ Backend.expects(:datafile).with(:file, scope, "one", "d").returns("/datadir/one.d")
89
+ Backend.expects(:datafile).with(:file, scope, "two", "d").never
90
+
91
+ File.expects(:exist?).with("/datadir/one.d/key").returns true
92
+ File.expects(:read).with("/datadir/one.d/key").returns '%{scope_val}alue'
93
+
94
+ subject.lookup("key", scope, nil, :priority).should == 'value'
95
+ end
96
+ end
97
+
98
+ describe "explicitly disabled" do
99
+ before do
100
+ Hiera::Config.load({:file => {:interpolate => false}})
101
+ end
102
+
103
+ it "should not parse the answer for scope variables" do
104
+ scope = {'scope_val' => 'v'}
105
+
106
+ Backend.expects(:datafile).with(:file, scope, "one", "d").returns("/datadir/one.d")
107
+ Backend.expects(:datafile).with(:file, scope, "two", "d").never
108
+
109
+ File.expects(:exist?).with("/datadir/one.d/key").returns true
110
+ File.expects(:read).with("/datadir/one.d/key").returns '%{scope_val}alue'
70
111
 
71
- subject.lookup("key", scope, nil, :priority).should == 'value'
112
+ subject.lookup("key", scope, nil, :priority).should == '%{scope_val}alue'
113
+ end
114
+ end
72
115
  end
73
116
 
74
117
  it "should prevent directory traversal attacks" do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hiera-file
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-03-11 00:00:00.000000000 Z
12
+ date: 2013-05-06 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: hiera