httpd_configmap_generator 0.1.1 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitignore +1 -0
- data/.travis.yml +3 -2
- data/.yamllint +11 -0
- data/Dockerfile +3 -2
- data/Gemfile +4 -0
- data/README-active-directory.md +11 -15
- data/README-ipa.md +7 -12
- data/README-ldap.md +62 -0
- data/README-oidc.md +39 -0
- data/README-saml.md +9 -14
- data/README.md +37 -49
- data/bin/httpd_configmap_generator +36 -50
- data/httpd_configmap_generator.gemspec +5 -3
- data/lib/httpd_configmap_generator.rb +2 -0
- data/lib/httpd_configmap_generator/active_directory.rb +2 -2
- data/lib/httpd_configmap_generator/base.rb +10 -6
- data/lib/httpd_configmap_generator/base/command.rb +19 -17
- data/lib/httpd_configmap_generator/base/config_helper.rb +15 -0
- data/lib/httpd_configmap_generator/base/config_map.rb +43 -26
- data/lib/httpd_configmap_generator/base/file_helper.rb +67 -0
- data/lib/httpd_configmap_generator/base/kerberos.rb +10 -8
- data/lib/httpd_configmap_generator/base/network.rb +27 -25
- data/lib/httpd_configmap_generator/base/pam.rb +6 -4
- data/lib/httpd_configmap_generator/base/sssd.rb +1 -1
- data/lib/httpd_configmap_generator/ipa.rb +12 -1
- data/lib/httpd_configmap_generator/ldap.rb +186 -0
- data/lib/httpd_configmap_generator/oidc.rb +48 -0
- data/lib/httpd_configmap_generator/saml.rb +16 -14
- data/lib/httpd_configmap_generator/version.rb +1 -1
- data/templates/httpd-scc-sysadmin.yaml +38 -0
- metadata +18 -14
- data/lib/httpd_configmap_generator/base/config.rb +0 -13
- data/lib/httpd_configmap_generator/base/file.rb +0 -65
- data/lib/httpd_configmap_generator/options.rb +0 -13
@@ -7,8 +7,8 @@
|
|
7
7
|
# -o filename: for the generated auth-config map.
|
8
8
|
#
|
9
9
|
|
10
|
-
require "bundler/setup"
|
11
|
-
require "
|
10
|
+
Dir.chdir(__dir__) { require "bundler/setup" }
|
11
|
+
require "optimist"
|
12
12
|
require "httpd_configmap_generator"
|
13
13
|
|
14
14
|
CMD = File.basename($PROGRAM_NAME)
|
@@ -20,62 +20,63 @@ end
|
|
20
20
|
|
21
21
|
module HttpdConfigmapGenerator
|
22
22
|
class Cli
|
23
|
-
|
24
|
-
|
23
|
+
SUB_COMMANDS = [HttpdConfigmapGenerator.supported_auth_types] | %w(update export)
|
24
|
+
|
25
|
+
def run
|
26
|
+
Optimist.options do
|
25
27
|
version("#{CMD} #{HttpdConfigmapGenerator::VERSION} - External Authentication Configuration script")
|
26
28
|
banner <<-EOS
|
27
29
|
#{version}
|
28
30
|
|
29
31
|
Usage: #{CMD} auth_type | update | export [--help | options]
|
30
32
|
|
33
|
+
supported auth_type: #{HttpdConfigmapGenerator.supported_auth_types.sort.join(', ')}
|
34
|
+
|
31
35
|
#{CMD} options are:
|
32
36
|
EOS
|
33
37
|
opt :version, "Version of the #{CMD} command",
|
34
38
|
:default => false, :short => "-V"
|
35
|
-
|
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)
|
39
|
+
stop_on(SUB_COMMANDS)
|
50
40
|
end
|
51
41
|
|
52
|
-
|
53
|
-
|
42
|
+
auth_type = ARGV.shift
|
43
|
+
Optimist.die "Must specify an authentication type" if auth_type.nil?
|
54
44
|
|
55
|
-
def run_update
|
56
45
|
begin
|
57
|
-
auth_config =
|
46
|
+
auth_config =
|
47
|
+
case auth_type
|
48
|
+
when "update" then HttpdConfigmapGenerator::Update.new
|
49
|
+
when "export" then HttpdConfigmapGenerator::Export.new
|
50
|
+
else HttpdConfigmapGenerator.new_config(auth_type)
|
51
|
+
end
|
58
52
|
rescue => err
|
59
53
|
error_msg(err.to_s)
|
60
54
|
end
|
61
55
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
error_msg(err.to_s)
|
56
|
+
params = Optimist.options do
|
57
|
+
auth_config.required_options.each do |key, key_options|
|
58
|
+
opt key, key_options[:description], HttpdConfigmapGenerator::Cli.options_for(key_options, true)
|
59
|
+
end
|
60
|
+
auth_config.optional_options.each do |key, key_options|
|
61
|
+
opt key, key_options[:description], HttpdConfigmapGenerator::Cli.options_for(key_options)
|
62
|
+
end
|
70
63
|
end
|
71
64
|
|
72
|
-
|
65
|
+
case auth_type
|
66
|
+
when "update" then auth_config.update(params)
|
67
|
+
when "export" then auth_config.export(params)
|
68
|
+
else auth_config.run_configure(params)
|
69
|
+
end
|
73
70
|
end
|
74
71
|
|
75
72
|
def self.options_for(key_options, required = false)
|
76
73
|
options = {}
|
77
|
-
|
78
|
-
|
74
|
+
if key_options[:default].nil?
|
75
|
+
options[:type] = key_options[:type] || :string
|
76
|
+
else
|
77
|
+
options[:default] = key_options[:default]
|
78
|
+
end
|
79
|
+
options[:required] = required
|
79
80
|
options[:short] = key_options[:short] if key_options[:short]
|
80
81
|
options[:multi] = key_options[:multi] if key_options[:multi]
|
81
82
|
options
|
@@ -83,19 +84,4 @@ Usage: #{CMD} auth_type | update | export [--help | options]
|
|
83
84
|
end
|
84
85
|
end
|
85
86
|
|
86
|
-
|
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
|
87
|
+
HttpdConfigmapGenerator::Cli.new.run
|
@@ -14,8 +14,10 @@ Gem::Specification.new do |s|
|
|
14
14
|
s.description = "The Httpd Configmap Generator"
|
15
15
|
s.licenses = ["Apache-2.0"]
|
16
16
|
|
17
|
-
|
18
|
-
|
17
|
+
if Dir.exist?(File.join(__dir__, ".git"))
|
18
|
+
s.files = `git ls-files -z`.split("\x0").reject do |f|
|
19
|
+
f.match(%r{^(test|spec|features)/})
|
20
|
+
end
|
19
21
|
end
|
20
22
|
s.bindir = "bin"
|
21
23
|
s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) } - %w(console setup)
|
@@ -30,5 +32,5 @@ Gem::Specification.new do |s|
|
|
30
32
|
s.add_dependency "awesome_spawn", "~> 1.4"
|
31
33
|
s.add_dependency "iniparse", "~> 1.4"
|
32
34
|
s.add_dependency "more_core_extensions", "~> 3.4"
|
33
|
-
s.add_dependency "
|
35
|
+
s.add_dependency "optimist", "~> 3.0"
|
34
36
|
end
|
@@ -2,7 +2,9 @@ require "httpd_configmap_generator/version"
|
|
2
2
|
require "httpd_configmap_generator/base"
|
3
3
|
require "httpd_configmap_generator/active_directory"
|
4
4
|
require "httpd_configmap_generator/ipa"
|
5
|
+
require "httpd_configmap_generator/ldap"
|
5
6
|
require "httpd_configmap_generator/saml"
|
7
|
+
require "httpd_configmap_generator/oidc"
|
6
8
|
require "httpd_configmap_generator/update"
|
7
9
|
require "httpd_configmap_generator/export"
|
8
10
|
require "more_core_extensions/core_ext/hash"
|
@@ -9,6 +9,8 @@ module HttpdConfigmapGenerator
|
|
9
9
|
|
10
10
|
def required_options
|
11
11
|
super.merge(
|
12
|
+
:host => { :description => "Application Domain",
|
13
|
+
:short => "-h" },
|
12
14
|
:ad_domain => { :description => "Active Directory Domain" },
|
13
15
|
:ad_user => { :description => "Active Directory User" },
|
14
16
|
:ad_password => { :description => "Active Directory Password" }
|
@@ -34,10 +36,8 @@ module HttpdConfigmapGenerator
|
|
34
36
|
/etc/pam.d/postlogin-ac
|
35
37
|
/etc/pam.d/smartcard-auth-ac
|
36
38
|
/etc/pam.d/system-auth-ac
|
37
|
-
/etc/resolv.conf
|
38
39
|
/etc/sssd/sssd.conf
|
39
40
|
/etc/sysconfig/authconfig
|
40
|
-
/etc/sysconfig/network
|
41
41
|
)
|
42
42
|
end
|
43
43
|
|
@@ -1,8 +1,8 @@
|
|
1
1
|
require "pathname"
|
2
2
|
require "httpd_configmap_generator/base/command"
|
3
|
-
require "httpd_configmap_generator/base/
|
3
|
+
require "httpd_configmap_generator/base/config_helper"
|
4
4
|
require "httpd_configmap_generator/base/config_map"
|
5
|
-
require "httpd_configmap_generator/base/
|
5
|
+
require "httpd_configmap_generator/base/file_helper"
|
6
6
|
require "httpd_configmap_generator/base/kerberos"
|
7
7
|
require "httpd_configmap_generator/base/network"
|
8
8
|
require "httpd_configmap_generator/base/pam"
|
@@ -11,6 +11,13 @@ require "httpd_configmap_generator/base/sssd"
|
|
11
11
|
|
12
12
|
module HttpdConfigmapGenerator
|
13
13
|
class Base
|
14
|
+
include Command
|
15
|
+
include ConfigHelper
|
16
|
+
include FileHelper
|
17
|
+
include Kerberos
|
18
|
+
include Network
|
19
|
+
include Pam
|
20
|
+
|
14
21
|
APACHE_USER = "apache".freeze
|
15
22
|
HTTP_KEYTAB = "/etc/http.keytab".freeze
|
16
23
|
IPA_COMMAND = "/usr/bin/ipa".freeze
|
@@ -47,10 +54,7 @@ module HttpdConfigmapGenerator
|
|
47
54
|
|
48
55
|
def required_options
|
49
56
|
{
|
50
|
-
:
|
51
|
-
:short => "-h" },
|
52
|
-
:output => { :description => "Configuration map file to create",
|
53
|
-
:short => "-o" }
|
57
|
+
:output => { :description => "Configuration map file to create", :short => "-o" }
|
54
58
|
}
|
55
59
|
end
|
56
60
|
|
@@ -2,27 +2,29 @@ require "awesome_spawn"
|
|
2
2
|
|
3
3
|
module HttpdConfigmapGenerator
|
4
4
|
class Base
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
module Command
|
6
|
+
def command_run(executable, options = {})
|
7
|
+
if opts && opts[:debug]
|
8
|
+
debug_msg("Running Command: #{AwesomeSpawn.build_command_line(executable, options)}")
|
9
|
+
end
|
10
|
+
AwesomeSpawn.run(executable, options)
|
8
11
|
end
|
9
|
-
AwesomeSpawn.run(executable, options)
|
10
|
-
end
|
11
12
|
|
12
|
-
|
13
|
-
|
14
|
-
|
13
|
+
def command_run!(executable, options = {})
|
14
|
+
if opts && opts[:debug]
|
15
|
+
debug_msg("Running Command: #{AwesomeSpawn.build_command_line(executable, options)}")
|
16
|
+
end
|
17
|
+
AwesomeSpawn.run!(executable, options)
|
15
18
|
end
|
16
|
-
AwesomeSpawn.run!(executable, options)
|
17
|
-
end
|
18
19
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
20
|
+
def log_command_error(err)
|
21
|
+
err_msg("Command Error: #{err}")
|
22
|
+
if err.kind_of?(AwesomeSpawn::CommandResultError)
|
23
|
+
err_msg("stdout: #{err.result.output}")
|
24
|
+
err_msg("stderr: #{err.result.error}")
|
25
|
+
else
|
26
|
+
err_msg(err.backtrace)
|
27
|
+
end
|
26
28
|
end
|
27
29
|
end
|
28
30
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require "active_support"
|
2
|
+
require "active_support/core_ext" # for Time.current
|
3
|
+
|
4
|
+
module HttpdConfigmapGenerator
|
5
|
+
class Base
|
6
|
+
module ConfigHelper
|
7
|
+
def config_file_backup(path)
|
8
|
+
if File.exist?(path)
|
9
|
+
timestamp = Time.current.strftime(TIMESTAMP_FORMAT)
|
10
|
+
FileUtils.copy(path, "#{path}.#{timestamp}")
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -16,11 +16,11 @@ module HttpdConfigmapGenerator
|
|
16
16
|
@config_map = template
|
17
17
|
end
|
18
18
|
|
19
|
-
def generate(auth_type, realm, file_list)
|
19
|
+
def generate(auth_type, realm = "undefined", file_list = nil, metadata = {})
|
20
20
|
info_msg("Generating Auth Config-Map for #{auth_type}")
|
21
21
|
@config_map = template(auth_type, realm)
|
22
22
|
file_specs = gen_filespecs(file_list)
|
23
|
-
define_configuration(file_specs)
|
23
|
+
define_configuration(file_specs, metadata)
|
24
24
|
include_files(file_specs)
|
25
25
|
end
|
26
26
|
|
@@ -71,7 +71,7 @@ module HttpdConfigmapGenerator
|
|
71
71
|
file_specs = []
|
72
72
|
file_list.each do |file|
|
73
73
|
file_specs << file_entry_spec(file.strip)
|
74
|
-
end
|
74
|
+
end unless file_list.nil?
|
75
75
|
file_specs.sort_by { |file_spec| file_spec[:basename] }
|
76
76
|
end
|
77
77
|
|
@@ -84,30 +84,42 @@ module HttpdConfigmapGenerator
|
|
84
84
|
file_specs = []
|
85
85
|
file_list.each do |file_to_add|
|
86
86
|
file_spec = file_to_add.split(",").map(&:strip)
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
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)
|
87
|
+
file_entry =
|
88
|
+
case file_spec.length
|
89
|
+
when 1
|
90
|
+
file_entry_spec(file_spec.first)
|
91
|
+
when 2
|
92
|
+
source_file, target_file = file_spec
|
93
|
+
file_entry_for_source_target(source_file, target_file)
|
94
|
+
when 3
|
95
|
+
source_file, target_file, mode = file_spec
|
96
|
+
file_entry_for_source_target_mode(source_file, target_file, mode)
|
100
97
|
else
|
101
|
-
|
98
|
+
raise "Invalid file specification #{file_to_add}"
|
102
99
|
end
|
103
|
-
else
|
104
|
-
raise "Invalid file specification #{file_to_add}"
|
105
|
-
end
|
106
100
|
file_specs << file_entry
|
107
101
|
end
|
108
102
|
file_specs.sort_by { |file_spec| file_spec[:basename] }
|
109
103
|
end
|
110
104
|
|
105
|
+
def file_entry_for_source_target(source_file, target_file)
|
106
|
+
raise "Must specify a mode for URL file sources" if source_file =~ URI.regexp(%w(http https))
|
107
|
+
file_entry = file_entry_spec(source_file, target_file)
|
108
|
+
file_entry[:source_file] = source_file
|
109
|
+
file_entry
|
110
|
+
end
|
111
|
+
|
112
|
+
def file_entry_for_source_target_mode(source_file, target_file, mode)
|
113
|
+
if source_file =~ URI.regexp(%w(http https))
|
114
|
+
fetch_network_file(source_file, target_file)
|
115
|
+
file_entry = file_entry_spec(target_file, target_file, mode)
|
116
|
+
else
|
117
|
+
file_entry = file_entry_spec(source_file, target_file, mode)
|
118
|
+
file_entry[:source_file] = source_file
|
119
|
+
end
|
120
|
+
file_entry
|
121
|
+
end
|
122
|
+
|
111
123
|
def file_entry_spec(source_file, target_file = nil, mode = nil)
|
112
124
|
target_file = source_file.dup unless target_file
|
113
125
|
unless mode
|
@@ -123,7 +135,7 @@ module HttpdConfigmapGenerator
|
|
123
135
|
}
|
124
136
|
end
|
125
137
|
|
126
|
-
def update_configuration(file_specs)
|
138
|
+
def update_configuration(file_specs, metadata={})
|
127
139
|
auth_configuration = fetch_auth_configuration
|
128
140
|
return define_configuration(file_specs) unless auth_configuration
|
129
141
|
# first, remove any file_specs references in the file list, we don't want duplication here.
|
@@ -134,7 +146,7 @@ module HttpdConfigmapGenerator
|
|
134
146
|
end
|
135
147
|
auth_configuration = auth_configuration.join("\n") + "\n"
|
136
148
|
# now, append any of the new file_specs at the end of the list.
|
137
|
-
append_configuration(auth_configuration, file_specs)
|
149
|
+
append_configuration(auth_configuration, file_specs, metadata)
|
138
150
|
end
|
139
151
|
|
140
152
|
def search_file_entry(target_file)
|
@@ -145,14 +157,14 @@ module HttpdConfigmapGenerator
|
|
145
157
|
entry ? entry.first.split('=')[1].strip.split(' ') : nil
|
146
158
|
end
|
147
159
|
|
148
|
-
def define_configuration(file_specs)
|
160
|
+
def define_configuration(file_specs, metadata={})
|
149
161
|
auth_configuration = "# External Authentication Configuration File\n#\n"
|
150
|
-
append_configuration(auth_configuration, file_specs)
|
162
|
+
append_configuration(auth_configuration, file_specs, metadata)
|
151
163
|
end
|
152
164
|
|
153
165
|
def include_files(file_specs)
|
154
166
|
file_specs.each do |file_spec|
|
155
|
-
content = File.read(file_spec[:target])
|
167
|
+
content = File.read(file_spec[:source_file] || file_spec[:target])
|
156
168
|
content = Base64.encode64(content) if file_spec[:binary]
|
157
169
|
# encode(:universal_newline => true) will convert \r\n to \n, necessary for to_yaml to render properly.
|
158
170
|
config_map[DATA_SECTION].merge!(file_basename(file_spec) => content.encode(:universal_newline => true))
|
@@ -163,12 +175,17 @@ module HttpdConfigmapGenerator
|
|
163
175
|
file_spec[:binary] ? "#{file_spec[:basename]}.base64" : file_spec[:basename]
|
164
176
|
end
|
165
177
|
|
166
|
-
def append_configuration(auth_configuration, file_specs)
|
178
|
+
def append_configuration(auth_configuration, file_specs, metadata)
|
167
179
|
file_specs.each do |file_spec|
|
168
180
|
debug_msg("Adding file #{file_spec[:target]} ...")
|
169
181
|
auth_configuration += "file = #{file_basename(file_spec)} #{file_spec[:target]} #{file_spec[:mode]}\n"
|
170
182
|
end
|
171
183
|
config_map[DATA_SECTION] ||= {}
|
184
|
+
|
185
|
+
metadata.each do |key, value|
|
186
|
+
config_map[DATA_SECTION].merge!(key => value)
|
187
|
+
end
|
188
|
+
|
172
189
|
config_map[DATA_SECTION].merge!(AUTH_CONFIGURATION => auth_configuration)
|
173
190
|
end
|
174
191
|
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require "pathname"
|
2
|
+
|
3
|
+
module HttpdConfigmapGenerator
|
4
|
+
class Base
|
5
|
+
module FileHelper
|
6
|
+
def template_directory
|
7
|
+
@template_directory ||=
|
8
|
+
Pathname.new(Gem::Specification.find_by_name("httpd_configmap_generator").full_gem_path).join("templates")
|
9
|
+
end
|
10
|
+
|
11
|
+
def cp_template(file, src_dir, dest_dir = "/")
|
12
|
+
src_path = path_join(src_dir, file)
|
13
|
+
dest_path = path_join(dest_dir, file.gsub(".erb", ""))
|
14
|
+
if src_path.to_s.include?(".erb")
|
15
|
+
File.write(dest_path, ERB.new(File.read(src_path), nil, '-').result(binding))
|
16
|
+
else
|
17
|
+
FileUtils.cp(src_path, dest_path)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def delete_target_file(file_path)
|
22
|
+
if File.exist?(file_path)
|
23
|
+
if opts[:force]
|
24
|
+
info_msg("File #{file_path} exists, forcing a delete")
|
25
|
+
File.delete(file_path)
|
26
|
+
else
|
27
|
+
raise "File #{file_path} already exist"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def create_target_directory(file_path)
|
33
|
+
dirname = File.dirname(file_path)
|
34
|
+
return if File.exist?(dirname)
|
35
|
+
debug_msg("Creating directory #{dirname} ...")
|
36
|
+
FileUtils.mkdir_p(dirname)
|
37
|
+
end
|
38
|
+
|
39
|
+
def rm_file(file, dir = "/")
|
40
|
+
path = path_join(dir, file)
|
41
|
+
File.delete(path) if File.exist?(path)
|
42
|
+
end
|
43
|
+
|
44
|
+
def path_join(*args)
|
45
|
+
path = Pathname.new(args.shift)
|
46
|
+
args.each { |path_seg| path = path.join("./#{path_seg}") }
|
47
|
+
path
|
48
|
+
end
|
49
|
+
|
50
|
+
def file_binary?(file)
|
51
|
+
data = File.read(file)
|
52
|
+
ascii = control = binary = total = 0
|
53
|
+
data[0..512].each_byte do |c|
|
54
|
+
total += 1
|
55
|
+
if c < 32
|
56
|
+
control += 1
|
57
|
+
elsif c >= 32 && c <= 128
|
58
|
+
ascii += 1
|
59
|
+
else
|
60
|
+
binary += 1
|
61
|
+
end
|
62
|
+
end
|
63
|
+
control.to_f / ascii > 0.1 || binary.to_f / ascii > 0.05
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|