httpd_configmap_generator 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/.rspec +1 -0
  4. data/.travis.yml +14 -0
  5. data/Dockerfile +16 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE +201 -0
  8. data/README-active-directory.md +38 -0
  9. data/README-ipa.md +41 -0
  10. data/README-saml.md +70 -0
  11. data/README.md +386 -0
  12. data/Rakefile +8 -0
  13. data/bin/httpd_configmap_generator +101 -0
  14. data/httpd_configmap_generator.gemspec +34 -0
  15. data/lib/httpd_configmap_generator.rb +29 -0
  16. data/lib/httpd_configmap_generator/active_directory.rb +114 -0
  17. data/lib/httpd_configmap_generator/base.rb +83 -0
  18. data/lib/httpd_configmap_generator/base/command.rb +29 -0
  19. data/lib/httpd_configmap_generator/base/config.rb +13 -0
  20. data/lib/httpd_configmap_generator/base/config_map.rb +183 -0
  21. data/lib/httpd_configmap_generator/base/file.rb +66 -0
  22. data/lib/httpd_configmap_generator/base/kerberos.rb +13 -0
  23. data/lib/httpd_configmap_generator/base/network.rb +37 -0
  24. data/lib/httpd_configmap_generator/base/pam.rb +9 -0
  25. data/lib/httpd_configmap_generator/base/principal.rb +33 -0
  26. data/lib/httpd_configmap_generator/base/sssd.rb +51 -0
  27. data/lib/httpd_configmap_generator/export.rb +31 -0
  28. data/lib/httpd_configmap_generator/ipa.rb +122 -0
  29. data/lib/httpd_configmap_generator/options.rb +13 -0
  30. data/lib/httpd_configmap_generator/saml.rb +104 -0
  31. data/lib/httpd_configmap_generator/update.rb +39 -0
  32. data/lib/httpd_configmap_generator/version.rb +3 -0
  33. data/templates/etc/pam.d/httpd-auth +2 -0
  34. data/templates/httpd-configmap-generator-template.yaml +113 -0
  35. metadata +203 -0
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :test => :spec
7
+ task :default => :spec
8
+
@@ -0,0 +1,101 @@
1
+ #! /usr/bin/env ruby
2
+ #
3
+ # Script for configuring container with external authentication
4
+ #
5
+ # Stdout: standard processing messages ...
6
+ # Stderr: any errors during configuration ...
7
+ # -o filename: for the generated auth-config map.
8
+ #
9
+
10
+ require "bundler/setup"
11
+ require "trollop"
12
+ require "httpd_configmap_generator"
13
+
14
+ CMD = File.basename($PROGRAM_NAME)
15
+
16
+ def error_msg(msg)
17
+ $stderr.puts msg
18
+ exit 1
19
+ end
20
+
21
+ module HttpdConfigmapGenerator
22
+ class Cli
23
+ def parse_arguments(auth_config)
24
+ opts = Trollop.options do
25
+ version("#{CMD} #{HttpdConfigmapGenerator::VERSION} - External Authentication Configuration script")
26
+ banner <<-EOS
27
+ #{version}
28
+
29
+ Usage: #{CMD} auth_type | update | export [--help | options]
30
+
31
+ #{CMD} options are:
32
+ EOS
33
+ opt :version, "Version of the #{CMD} command",
34
+ :default => false, :short => "-V"
35
+ auth_config.required_options.each do |key, key_options|
36
+ opt key, key_options[:description], HttpdConfigmapGenerator::Cli.options_for(key_options, true)
37
+ end
38
+ auth_config.optional_options.each do |key, key_options|
39
+ opt key, key_options[:description], HttpdConfigmapGenerator::Cli.options_for(key_options)
40
+ end
41
+ end
42
+ opts
43
+ end
44
+
45
+ def run_configure(auth_type)
46
+ begin
47
+ auth_config = HttpdConfigmapGenerator.new_config(auth_type)
48
+ rescue => err
49
+ error_msg(err.to_s)
50
+ end
51
+
52
+ auth_config.run_configure(parse_arguments(auth_config))
53
+ end
54
+
55
+ def run_update
56
+ begin
57
+ auth_config = HttpdConfigmapGenerator::Update.new
58
+ rescue => err
59
+ error_msg(err.to_s)
60
+ end
61
+
62
+ auth_config.update(parse_arguments(auth_config))
63
+ end
64
+
65
+ def run_export
66
+ begin
67
+ auth_config = HttpdConfigmapGenerator::Export.new
68
+ rescue => err
69
+ error_msg(err.to_s)
70
+ end
71
+
72
+ auth_config.export(parse_arguments(auth_config))
73
+ end
74
+
75
+ def self.options_for(key_options, required = false)
76
+ options = {}
77
+ options[:default] = key_options.key?(:default) ? key_options[:default] : ""
78
+ options[:required] = true if required
79
+ options[:short] = key_options[:short] if key_options[:short]
80
+ options[:multi] = key_options[:multi] if key_options[:multi]
81
+ options
82
+ end
83
+ end
84
+ end
85
+
86
+ if ARGV.empty?
87
+ error_msg("
88
+ Usage: #{CMD} auth_type | update | export [--help | options]
89
+ Supported auth_type: #{HttpdConfigmapGenerator.supported_auth_types.join(', ')}
90
+ ")
91
+ else
92
+ auth_type = ARGV.shift
93
+ case auth_type
94
+ when "update"
95
+ HttpdConfigmapGenerator::Cli.new.run_update
96
+ when "export"
97
+ HttpdConfigmapGenerator::Cli.new.run_export
98
+ else
99
+ HttpdConfigmapGenerator::Cli.new.run_configure(auth_type)
100
+ end
101
+ end
@@ -0,0 +1,34 @@
1
+ lib = File.expand_path("../lib", __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+
4
+ # Declare Gem's Version
5
+ require "httpd_configmap_generator/version"
6
+
7
+ # Declare Dependencies
8
+ Gem::Specification.new do |s|
9
+ s.name = "httpd_configmap_generator"
10
+ s.version = HttpdConfigmapGenerator::VERSION
11
+ s.authors = ["Httpd Auth Config Developers"]
12
+ s.homepage = "https://github.com/ManageIQ/httpd_configmap_generator"
13
+ s.summary = "The Httpd Configmap Generator"
14
+ s.description = "The Httpd Configmap Generator"
15
+ s.licenses = ["Apache-2.0"]
16
+
17
+ s.files = `git ls-files -z`.split("\x0").reject do |f|
18
+ f.match(%r{^(test|spec|features)/})
19
+ end
20
+ s.bindir = "bin"
21
+ s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
22
+ s.require_paths = ["lib"]
23
+
24
+ s.add_development_dependency "codeclimate-test-reporter", "~> 1.0.0"
25
+ s.add_development_dependency "rspec", "~> 3.0"
26
+ s.add_development_dependency "rake"
27
+ s.add_development_dependency "simplecov"
28
+
29
+ s.add_dependency "activesupport", ">=5.0"
30
+ s.add_dependency "awesome_spawn", "~> 1.4"
31
+ s.add_dependency "iniparse", "~> 1.4"
32
+ s.add_dependency "more_core_extensions", "~> 3.4"
33
+ s.add_dependency "trollop", "~> 2.1"
34
+ end
@@ -0,0 +1,29 @@
1
+ require "httpd_configmap_generator/version"
2
+ require "httpd_configmap_generator/base"
3
+ require "httpd_configmap_generator/active_directory"
4
+ require "httpd_configmap_generator/ipa"
5
+ require "httpd_configmap_generator/saml"
6
+ require "httpd_configmap_generator/update"
7
+ require "httpd_configmap_generator/export"
8
+ require "more_core_extensions/core_ext/hash"
9
+
10
+ module HttpdConfigmapGenerator
11
+ def self.new_config(auth_type)
12
+ auth_class(auth_type).new
13
+ end
14
+
15
+ def self.supported_auth_types
16
+ constants.collect do |c|
17
+ k = const_get(c)
18
+ k::AUTH[:subtype] if k.kind_of?(Class) && k.constants.include?(:AUTH)
19
+ end.compact
20
+ end
21
+
22
+ def self.auth_class(auth_type)
23
+ require "active_support/core_ext/string" # for camelize
24
+
25
+ auth_type = auth_type.tr('-', '_').camelize
26
+ raise "Invalid Authentication Type #{auth_type} specified" unless const_defined?(auth_type, false)
27
+ const_get(auth_type, false)
28
+ end
29
+ end
@@ -0,0 +1,114 @@
1
+ module HttpdConfigmapGenerator
2
+ class ActiveDirectory < Base
3
+ REALM_COMMAND = "/usr/sbin/realm".freeze
4
+ KERBEROS_KEYTAB_FILE = "/etc/krb5.keytab".freeze
5
+ AUTH = {
6
+ :type => "active-directory",
7
+ :subtype => "active-directory"
8
+ }.freeze
9
+
10
+ def required_options
11
+ super.merge(
12
+ :ad_domain => { :description => "Active Directory Domain" },
13
+ :ad_user => { :description => "Active Directory User" },
14
+ :ad_password => { :description => "Active Directory Password" }
15
+ )
16
+ end
17
+
18
+ def optional_options
19
+ super.merge(
20
+ :ad_realm => { :description => "Active Directory Realm" },
21
+ :ad_server => { :description => "Active Directory Server" }
22
+ )
23
+ end
24
+
25
+ def persistent_files
26
+ %w(
27
+ /etc/krb5.keytab
28
+ /etc/krb5.conf
29
+ /etc/nsswitch.conf
30
+ /etc/openldap/ldap.conf
31
+ /etc/pam.d/fingerprint-auth-ac
32
+ /etc/pam.d/httpd-auth
33
+ /etc/pam.d/password-auth-ac
34
+ /etc/pam.d/postlogin-ac
35
+ /etc/pam.d/smartcard-auth-ac
36
+ /etc/pam.d/system-auth-ac
37
+ /etc/resolv.conf
38
+ /etc/sssd/sssd.conf
39
+ /etc/sysconfig/authconfig
40
+ /etc/sysconfig/network
41
+ )
42
+ end
43
+
44
+ def configure(opts)
45
+ update_hostname(opts[:host])
46
+ join_ad_realm
47
+ realm_permit_all
48
+ configure_pam
49
+ configure_sssd
50
+ update_kerberos_keytab_permissions
51
+ enable_kerberos_dns_lookups
52
+ config_map = ConfigMap.new(opts)
53
+ config_map.generate(AUTH[:type], realm, persistent_files)
54
+ config_map.save(opts[:output])
55
+ rescue => err
56
+ log_command_error(err)
57
+ raise err
58
+ end
59
+
60
+ def configured?
61
+ File.exist?(SSSD_CONFIG)
62
+ end
63
+
64
+ def unconfigure
65
+ return unless configured?
66
+ end
67
+
68
+ def realm
69
+ @realm ||= opts[:ad_realm] if opts[:ad_realm].present?
70
+ @realm ||= domain
71
+ @realm ||= super
72
+ @realm = @realm.upcase
73
+ end
74
+
75
+ def domain
76
+ @domain ||= opts[:ad_domain] if opts[:ad_domain].present?
77
+ @domain ||= super
78
+ @domain
79
+ end
80
+
81
+ private
82
+
83
+ def configure_sssd
84
+ info_msg("Configuring SSSD Service")
85
+ sssd = Sssd.new(opts)
86
+ sssd.load(SSSD_CONFIG)
87
+ sssd.configure_domain(domain)
88
+ sssd.section("domain/#{domain}")["ad_server"] = opts[:ad_server] if opts[:ad_server].present?
89
+ sssd.section("sssd")["domains"] = domain
90
+ sssd.section("sssd")["default_domain_suffix"] = domain
91
+ sssd.add_service("pam")
92
+ sssd.configure_ifp
93
+ debug_msg("- Creating #{SSSD_CONFIG}")
94
+ sssd.save(SSSD_CONFIG)
95
+ end
96
+
97
+ def join_ad_realm
98
+ info_msg("Joining the AD Realm ...")
99
+ debug_msg(" - realm join #{realm} ...")
100
+ command_run!(REALM_COMMAND, :params => ["join", domain, "-U", opts[:ad_user]], :stdin_data => opts[:ad_password])
101
+ end
102
+
103
+ def realm_permit_all
104
+ info_msg("Allowing AD Users to Login ...")
105
+ command_run!(REALM_COMMAND, :params => ["permit", "--all"])
106
+ end
107
+
108
+ def update_kerberos_keytab_permissions
109
+ info_msg("Updating Kerberos keytab permissions ...")
110
+ FileUtils.chown("apache", "root", KERBEROS_KEYTAB_FILE)
111
+ FileUtils.chmod(0o640, KERBEROS_KEYTAB_FILE)
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,83 @@
1
+ require "pathname"
2
+ require "httpd_configmap_generator/base/command"
3
+ require "httpd_configmap_generator/base/config"
4
+ require "httpd_configmap_generator/base/config_map"
5
+ require "httpd_configmap_generator/base/file"
6
+ require "httpd_configmap_generator/base/kerberos"
7
+ require "httpd_configmap_generator/base/network"
8
+ require "httpd_configmap_generator/base/pam"
9
+ require "httpd_configmap_generator/base/principal"
10
+ require "httpd_configmap_generator/base/sssd"
11
+
12
+ module HttpdConfigmapGenerator
13
+ class Base
14
+ APACHE_USER = "apache".freeze
15
+ HTTP_KEYTAB = "/etc/http.keytab".freeze
16
+ IPA_COMMAND = "/usr/bin/ipa".freeze
17
+ KERBEROS_CONFIG_FILE = "/etc/krb5.conf".freeze
18
+ LDAP_ATTRS = {
19
+ "mail" => "REMOTE_USER_EMAIL",
20
+ "givenname" => "REMOTE_USER_FIRSTNAME",
21
+ "sn" => "REMOTE_USER_LASTNAME",
22
+ "displayname" => "REMOTE_USER_FULLNAME",
23
+ "domainname" => "REMOTE_USER_DOMAIN"
24
+ }.freeze
25
+ PAM_CONFIG = "/etc/pam.d/httpd-auth".freeze
26
+ SSSD_CONFIG = "/etc/sssd/sssd.conf".freeze
27
+ TIMESTAMP_FORMAT = "%Y%m%d_%H%M%S".freeze
28
+
29
+ attr_accessor :opts
30
+
31
+ def initialize(opts = {})
32
+ @opts = opts
33
+ @realm = @domain = nil
34
+ end
35
+
36
+ def err_msg(msg)
37
+ STDERR.puts(msg)
38
+ end
39
+
40
+ def info_msg(msg)
41
+ STDOUT.puts(msg)
42
+ end
43
+
44
+ def debug_msg(msg)
45
+ STDOUT.puts(msg) if opts[:debug]
46
+ end
47
+
48
+ def required_options
49
+ {
50
+ :host => { :description => "Application Domain",
51
+ :short => "-h" },
52
+ :output => { :description => "Configuration map file to create",
53
+ :short => "-o" }
54
+ }
55
+ end
56
+
57
+ def optional_options
58
+ {
59
+ :force => { :description => "Force configuration if configured already",
60
+ :short => "-f",
61
+ :default => false },
62
+ :debug => { :description => "Enable debugging",
63
+ :short => "-d",
64
+ :default => false }
65
+ }
66
+ end
67
+
68
+ def run_configure(opts)
69
+ validate_options(opts)
70
+ @opts = opts
71
+ unconfigure if configured? && opts[:force]
72
+ raise "#{self.class.name} Already Configured" if configured?
73
+ unless ENV["HTTPD_AUTH_TYPE"]
74
+ raise "Not running in httpd_configmap_generator container - Skipping #{self.class.name} configuration"
75
+ end
76
+ configure(opts)
77
+ end
78
+
79
+ def validate_options(_options)
80
+ nil
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,29 @@
1
+ require "awesome_spawn"
2
+
3
+ module HttpdConfigmapGenerator
4
+ class Base
5
+ def command_run(executable, options = {})
6
+ if opts && opts[:debug]
7
+ debug_msg("Running Command: #{AwesomeSpawn.build_command_line(executable, options)}")
8
+ end
9
+ AwesomeSpawn.run(executable, options)
10
+ end
11
+
12
+ def command_run!(executable, options = {})
13
+ if opts && opts[:debug]
14
+ debug_msg("Running Command: #{AwesomeSpawn.build_command_line(executable, options)}")
15
+ end
16
+ AwesomeSpawn.run!(executable, options)
17
+ end
18
+
19
+ def log_command_error(err)
20
+ err_msg("Command Error: #{err}")
21
+ if err.kind_of?(AwesomeSpawn::CommandResultError)
22
+ err_msg("stdout: #{err.result.output}")
23
+ err_msg("stderr: #{err.result.error}")
24
+ else
25
+ err_msg(err.backtrace)
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,13 @@
1
+ require "active_support"
2
+ require "active_support/core_ext" # for Time.current
3
+
4
+ module HttpdConfigmapGenerator
5
+ class Base
6
+ def config_file_backup(path)
7
+ if File.exist?(path)
8
+ timestamp = Time.current.strftime(TIMESTAMP_FORMAT)
9
+ FileUtils.copy(path, "#{path}.#{timestamp}")
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,183 @@
1
+ require "base64"
2
+ require "yaml"
3
+ require "uri"
4
+ require "etc"
5
+
6
+ module HttpdConfigmapGenerator
7
+ class ConfigMap < Base
8
+ DATA_SECTION = "data".freeze
9
+ AUTH_CONFIGURATION = "auth-configuration.conf".freeze
10
+
11
+ attr_accessor :config_map
12
+ attr_accessor :opts
13
+
14
+ def initialize(opts = {})
15
+ @opts = opts
16
+ @config_map = template
17
+ end
18
+
19
+ def generate(auth_type, realm, file_list)
20
+ info_msg("Generating Auth Config-Map for #{auth_type}")
21
+ @config_map = template(auth_type, realm)
22
+ file_specs = gen_filespecs(file_list)
23
+ define_configuration(file_specs)
24
+ include_files(file_specs)
25
+ end
26
+
27
+ def load(file_path)
28
+ @config_map = File.exist?(file_path) ? YAML.load_file(file_path) : {}
29
+ end
30
+
31
+ def save(file_path)
32
+ delete_target_file(file_path)
33
+ info_msg("Saving Auth Config-Map to #{file_path}")
34
+ File.open(file_path, "w") { |f| f.write(config_map.to_yaml) }
35
+ end
36
+
37
+ def add_files(file_list)
38
+ return unless file_list
39
+ file_specs = gen_filespecs_for_files_to_add(file_list)
40
+ update_configuration(file_specs)
41
+ include_files(file_specs)
42
+ end
43
+
44
+ def export_file(file_entry, output_file)
45
+ basename, _target_file, _mode = search_file_entry(file_entry)
46
+ raise "File #{file_entry} does not exist in the configuration map" unless basename
47
+ delete_target_file(output_file)
48
+ create_target_directory(output_file)
49
+ debug_msg("Exporting #{file_entry} to #{output_file} ...")
50
+ content = config_map.fetch_path(DATA_SECTION, basename)
51
+ content = Base64.decode64(content) if basename =~ /^.*\.base64$/
52
+ File.write(output_file, content)
53
+ end
54
+
55
+ private
56
+
57
+ def template(auth_type = "internal", kerberos_realms = "undefined")
58
+ {
59
+ DATA_SECTION => {
60
+ "auth-type" => auth_type,
61
+ "auth-kerberos-realms" => kerberos_realms
62
+ },
63
+ "kind" => "ConfigMap",
64
+ "metadata" => {
65
+ "name" => "httpd-auth-configs"
66
+ }
67
+ }
68
+ end
69
+
70
+ def gen_filespecs(file_list)
71
+ file_specs = []
72
+ file_list.each do |file|
73
+ file_specs << file_entry_spec(file.strip)
74
+ end
75
+ file_specs.sort_by { |file_spec| file_spec[:basename] }
76
+ end
77
+
78
+ # Supporting the following signatures:
79
+ # /path/of/real/file
80
+ # /path/of/source/file,/path/of/real/file
81
+ # /path/of/source/file,/path/of/real/file,mode
82
+ # http://url_source,/path/of/real/file,mode
83
+ def gen_filespecs_for_files_to_add(file_list)
84
+ file_specs = []
85
+ file_list.each do |file_to_add|
86
+ file_spec = file_to_add.split(",").map(&:strip)
87
+ case file_spec.length
88
+ when 1
89
+ file = file_spec.first
90
+ file_entry = file_entry_spec(file)
91
+ when 2
92
+ source_file, target_file = file_spec
93
+ raise "Must specify a mode for URL file sources" if source_file =~ URI.regexp(%w(http https))
94
+ file_entry = file_entry_spec(source_file, target_file)
95
+ when 3
96
+ source_file, target_file, mode = file_spec
97
+ if source_file =~ URI.regexp(%w(http https))
98
+ fetch_network_file(source_file, target_file)
99
+ file_entry = file_entry_spec(target_file, target_file, mode)
100
+ else
101
+ file_entry = file_entry_spec(source_file, target_file, mode)
102
+ end
103
+ else
104
+ raise "Invalid file specification #{file_to_add}"
105
+ end
106
+ file_specs << file_entry
107
+ end
108
+ file_specs.sort_by { |file_spec| file_spec[:basename] }
109
+ end
110
+
111
+ def file_entry_spec(source_file, target_file = nil, mode = nil)
112
+ target_file = source_file.dup unless target_file
113
+ unless mode
114
+ stat = File.stat(source_file)
115
+ file_owner = Etc.getpwuid(stat.uid).name
116
+ file_group = Etc.getgrgid(stat.gid).name
117
+ end
118
+ {
119
+ :basename => File.basename(target_file).dup,
120
+ :binary => file_binary?(source_file),
121
+ :target => target_file,
122
+ :mode => mode ? mode : "%4o:%s:%s" % [stat.mode & 0o7777, file_owner, file_group]
123
+ }
124
+ end
125
+
126
+ def update_configuration(file_specs)
127
+ auth_configuration = fetch_auth_configuration
128
+ return define_configuration(file_specs) unless auth_configuration
129
+ # first, remove any file_specs references in the file list, we don't want duplication here.
130
+ auth_configuration = auth_configuration.split("\n")
131
+ file_specs.each do |file_spec|
132
+ entry = auth_configuration.select { |line| line =~ file_entry_regex(file_spec[:target]) }
133
+ auth_configuration -= entry if entry
134
+ end
135
+ auth_configuration = auth_configuration.join("\n") + "\n"
136
+ # now, append any of the new file_specs at the end of the list.
137
+ append_configuration(auth_configuration, file_specs)
138
+ end
139
+
140
+ def search_file_entry(target_file)
141
+ auth_configuration = fetch_auth_configuration
142
+ return nil unless auth_configuration
143
+ auth_configuration = auth_configuration.split("\n")
144
+ entry = auth_configuration.select { |line| line =~ file_entry_regex(target_file) }
145
+ entry ? entry.first.split('=')[1].strip.split(' ') : nil
146
+ end
147
+
148
+ def define_configuration(file_specs)
149
+ auth_configuration = "# External Authentication Configuration File\n#\n"
150
+ append_configuration(auth_configuration, file_specs)
151
+ end
152
+
153
+ def include_files(file_specs)
154
+ file_specs.each do |file_spec|
155
+ content = File.read(file_spec[:target])
156
+ content = Base64.encode64(content) if file_spec[:binary]
157
+ # encode(:universal_newline => true) will convert \r\n to \n, necessary for to_yaml to render properly.
158
+ config_map[DATA_SECTION].merge!(file_basename(file_spec) => content.encode(:universal_newline => true))
159
+ end
160
+ end
161
+
162
+ def file_basename(file_spec)
163
+ file_spec[:binary] ? "#{file_spec[:basename]}.base64" : file_spec[:basename]
164
+ end
165
+
166
+ def append_configuration(auth_configuration, file_specs)
167
+ file_specs.each do |file_spec|
168
+ debug_msg("Adding file #{file_spec[:target]} ...")
169
+ auth_configuration += "file = #{file_basename(file_spec)} #{file_spec[:target]} #{file_spec[:mode]}\n"
170
+ end
171
+ config_map[DATA_SECTION] ||= {}
172
+ config_map[DATA_SECTION].merge!(AUTH_CONFIGURATION => auth_configuration)
173
+ end
174
+
175
+ def fetch_auth_configuration
176
+ config_map.fetch_path(DATA_SECTION, AUTH_CONFIGURATION)
177
+ end
178
+
179
+ def file_entry_regex(target_file)
180
+ /^file = .* #{target_file} .*$/
181
+ end
182
+ end
183
+ end