manageiq-appliance_console 5.4.0 → 6.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.codeclimate.yml +24 -25
- data/.rspec_ci +2 -0
- data/.rubocop.yml +3 -3
- data/.rubocop_cc.yml +3 -4
- data/.rubocop_local.yml +1 -1
- data/.travis.yml +4 -3
- data/Gemfile +1 -3
- data/README.md +1 -2
- data/Rakefile +20 -1
- data/bin/appliance_console +30 -6
- data/lib/manageiq/appliance_console/certificate_authority.rb +1 -1
- data/lib/manageiq/appliance_console/cli.rb +66 -20
- data/lib/manageiq/appliance_console/database_configuration.rb +2 -1
- data/lib/manageiq/appliance_console/database_replication.rb +1 -1
- data/lib/manageiq/appliance_console/database_replication_standby.rb +1 -1
- data/lib/manageiq/appliance_console/internal_database_configuration.rb +1 -1
- data/lib/manageiq/appliance_console/logfile_configuration.rb +2 -2
- data/lib/manageiq/appliance_console/message_configuration.rb +199 -0
- data/lib/manageiq/appliance_console/message_configuration_client.rb +96 -0
- data/lib/manageiq/appliance_console/message_configuration_server.rb +319 -0
- data/lib/manageiq/appliance_console/oidc_authentication.rb +43 -4
- data/lib/manageiq/appliance_console/postgres_admin.rb +325 -0
- data/lib/manageiq/appliance_console/utilities.rb +45 -1
- data/lib/manageiq/appliance_console/version.rb +1 -1
- data/lib/manageiq-appliance_console.rb +2 -6
- data/locales/appliance/en.yml +1 -1
- data/locales/container/en.yml +1 -1
- data/manageiq-appliance_console.gemspec +3 -3
- metadata +39 -24
- data/lib/manageiq/appliance_console/messaging_configuration.rb +0 -92
@@ -0,0 +1,96 @@
|
|
1
|
+
require "awesome_spawn"
|
2
|
+
require "fileutils"
|
3
|
+
require "linux_admin"
|
4
|
+
require 'net/scp'
|
5
|
+
require "manageiq/appliance_console/message_configuration"
|
6
|
+
|
7
|
+
module ManageIQ
|
8
|
+
module ApplianceConsole
|
9
|
+
class MessageClientConfiguration < MessageConfiguration
|
10
|
+
attr_reader :message_server_password, :message_server_username, :installed_files,
|
11
|
+
:message_truststore_path_src, :message_ca_cert_path_src
|
12
|
+
|
13
|
+
def initialize(options = {})
|
14
|
+
super(options)
|
15
|
+
|
16
|
+
@message_server_host = options[:message_server_host]
|
17
|
+
@message_server_username = options[:message_server_usernamed] || "root"
|
18
|
+
@message_server_password = options[:message_server_password]
|
19
|
+
|
20
|
+
@message_truststore_path_src = options[:message_truststore_path_src] || truststore_path
|
21
|
+
@message_ca_cert_path_src = options[:message_ca_cert_path_src] || ca_cert_path
|
22
|
+
|
23
|
+
@installed_files = [client_properties_path, messaging_yaml_path, truststore_path]
|
24
|
+
end
|
25
|
+
|
26
|
+
def configure
|
27
|
+
begin
|
28
|
+
MessageServerConfiguration.new.unconfigure if MessageServerConfiguration.configured?
|
29
|
+
configure_messaging_yaml # Set up the local message client in case EVM is actually running on this, Message Server
|
30
|
+
create_client_properties # Create the client.properties configuration fle
|
31
|
+
fetch_truststore_from_server # Fetch the Java Keystore from the Kafka Server
|
32
|
+
configure_messaging_type("kafka") # Settings.prototype.messaging_type = 'kafka'
|
33
|
+
restart_evmserverd
|
34
|
+
rescue AwesomeSpawn::CommandResultError => e
|
35
|
+
say(e.result.output)
|
36
|
+
say(e.result.error)
|
37
|
+
say("")
|
38
|
+
say("Failed to Configure the Message Client- #{e}")
|
39
|
+
return false
|
40
|
+
rescue => e
|
41
|
+
say("Failed to Configure the Message Client- #{e}")
|
42
|
+
return false
|
43
|
+
end
|
44
|
+
true
|
45
|
+
end
|
46
|
+
|
47
|
+
def ask_for_parameters
|
48
|
+
say("\nMessage Client Parameters:\n\n")
|
49
|
+
|
50
|
+
@message_server_host = ask_for_string("Message Server Hostname or IP address")
|
51
|
+
@message_server_port = ask_for_integer("Message Server Port number", (1..65_535), 9_093).to_i
|
52
|
+
@message_server_username = ask_for_string("Message Server Username", message_server_username)
|
53
|
+
@message_server_password = ask_for_password("Message Server Password")
|
54
|
+
@message_truststore_path_src = ask_for_string("Message Server Truststore Path", truststore_path)
|
55
|
+
@message_ca_cert_path_src = ask_for_string("Message Server CA Cert Path", ca_cert_path)
|
56
|
+
@message_keystore_username = ask_for_string("Message Keystore Username", message_keystore_username) if secure?
|
57
|
+
@message_keystore_password = ask_for_password("Message Keystore Password") if secure?
|
58
|
+
end
|
59
|
+
|
60
|
+
def show_parameters
|
61
|
+
say("\nMessage Client Configuration:\n")
|
62
|
+
say("Message Client Details:\n")
|
63
|
+
say(" Message Server Hostname: #{message_server_host}\n")
|
64
|
+
say(" Message Server Username: #{message_server_username}\n")
|
65
|
+
say(" Message Keystore Username: #{message_keystore_username}\n")
|
66
|
+
end
|
67
|
+
|
68
|
+
def fetch_truststore_from_server
|
69
|
+
say(__method__.to_s.tr("_", " ").titleize)
|
70
|
+
|
71
|
+
fetch_from_server(message_truststore_path_src, truststore_path)
|
72
|
+
end
|
73
|
+
|
74
|
+
def fetch_ca_cert_from_server
|
75
|
+
say(__method__.to_s.tr("_", " ").titleize)
|
76
|
+
|
77
|
+
fetch_from_server(message_ca_cert_path_src, ca_cert_path)
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
def fetch_from_server(src_file, dst_file)
|
83
|
+
return if file_found?(dst_file)
|
84
|
+
|
85
|
+
Net::SCP.start(message_server_host, message_server_username, :password => message_server_password) do |scp|
|
86
|
+
scp.download!(src_file, dst_file)
|
87
|
+
end
|
88
|
+
|
89
|
+
File.exist?(dst_file)
|
90
|
+
rescue => e
|
91
|
+
say("Failed to fetch #{src_file} from server: #{e.message}")
|
92
|
+
false
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,319 @@
|
|
1
|
+
require "awesome_spawn"
|
2
|
+
require "fileutils"
|
3
|
+
require "linux_admin"
|
4
|
+
require "manageiq/appliance_console/message_configuration"
|
5
|
+
|
6
|
+
module ManageIQ
|
7
|
+
module ApplianceConsole
|
8
|
+
class MessageServerConfiguration < MessageConfiguration
|
9
|
+
attr_reader :jaas_config_path,
|
10
|
+
:server_properties_path, :server_properties_sample_path,
|
11
|
+
:ca_cert_srl_path, :ca_key_path, :cert_file_path, :cert_signed_path,
|
12
|
+
:keystore_files, :installed_files, :message_persistent_disk
|
13
|
+
|
14
|
+
PERSISTENT_DIRECTORY = Pathname.new("/var/lib/kafka/persistent_data").freeze
|
15
|
+
PERSISTENT_NAME = "kafka_messages".freeze
|
16
|
+
|
17
|
+
def initialize(options = {})
|
18
|
+
super(options)
|
19
|
+
|
20
|
+
@message_server_host = options[:message_server_use_ipaddr] == true ? my_ipaddr : options[:message_server_host] || my_hostname
|
21
|
+
@message_persistent_disk = LinuxAdmin::Disk.new(:path => options[:message_persistent_disk]) unless options[:message_persistent_disk].nil?
|
22
|
+
|
23
|
+
@jaas_config_path = config_dir_path.join("kafka_server_jaas.conf")
|
24
|
+
@server_properties_path = config_dir_path.join("server.properties")
|
25
|
+
@server_properties_sample_path = sample_config_dir_path.join("server.properties")
|
26
|
+
|
27
|
+
@ca_cert_srl_path = keystore_dir_path.join("ca-cert.srl")
|
28
|
+
@ca_key_path = keystore_dir_path.join("ca-key")
|
29
|
+
@cert_file_path = keystore_dir_path.join("cert-file")
|
30
|
+
@cert_signed_path = keystore_dir_path.join("cert-signed")
|
31
|
+
|
32
|
+
@keystore_files = [ca_cert_path, ca_cert_srl_path, ca_key_path, cert_file_path, cert_signed_path, truststore_path, keystore_path]
|
33
|
+
@installed_files = [jaas_config_path, client_properties_path, server_properties_path, messaging_yaml_path, LOGS_DIR] + keystore_files
|
34
|
+
end
|
35
|
+
|
36
|
+
def configure
|
37
|
+
begin
|
38
|
+
configure_persistent_disk # Configure the persistent message store on a different disk
|
39
|
+
create_jaas_config # Create the message server jaas config file
|
40
|
+
create_client_properties # Create the client.properties config
|
41
|
+
create_logs_directory # Create the logs directory:
|
42
|
+
configure_firewall # Open the firewall for message port 9093
|
43
|
+
configure_keystore # Populate the Java Keystore
|
44
|
+
create_server_properties # Update the /opt/message/config/server.properties
|
45
|
+
configure_messaging_yaml # Set up the local message client in case EVM is actually running on this, Message Server
|
46
|
+
configure_messaging_type("kafka") # Settings.prototype.messaging_type = 'kafka'
|
47
|
+
restart_services
|
48
|
+
rescue AwesomeSpawn::CommandResultError => e
|
49
|
+
say(e.result.output)
|
50
|
+
say(e.result.error)
|
51
|
+
say("")
|
52
|
+
say("Failed to Configure the Message Server- #{e}")
|
53
|
+
return false
|
54
|
+
rescue => e
|
55
|
+
say("Failed to Configure the Message Server- #{e}")
|
56
|
+
return false
|
57
|
+
end
|
58
|
+
true
|
59
|
+
end
|
60
|
+
|
61
|
+
def restart_services
|
62
|
+
say("Starting zookeeper and configure it to start on reboots ...")
|
63
|
+
LinuxAdmin::Service.new("zookeeper").start.enable
|
64
|
+
|
65
|
+
say("Starting kafka and configure it to start on reboots ...")
|
66
|
+
LinuxAdmin::Service.new("kafka").start.enable
|
67
|
+
|
68
|
+
restart_evmserverd
|
69
|
+
end
|
70
|
+
|
71
|
+
def ask_for_parameters
|
72
|
+
say("\nMessage Server Parameters:\n\n")
|
73
|
+
|
74
|
+
@message_server_host = ask_for_string("Message Server Hostname or IP address", message_server_host)
|
75
|
+
@message_keystore_username = ask_for_string("Message Keystore Username", message_keystore_username)
|
76
|
+
@message_keystore_password = ask_for_password("Message Keystore Password")
|
77
|
+
@message_persistent_disk = ask_for_persistent_disk
|
78
|
+
end
|
79
|
+
|
80
|
+
def ask_for_persistent_disk
|
81
|
+
choose_disk if use_new_disk
|
82
|
+
end
|
83
|
+
|
84
|
+
def use_new_disk
|
85
|
+
agree("Configure a new persistent disk volume? (Y/N): ")
|
86
|
+
end
|
87
|
+
|
88
|
+
def choose_disk
|
89
|
+
ask_for_disk("Persistent disk")
|
90
|
+
end
|
91
|
+
|
92
|
+
def show_parameters
|
93
|
+
say("\nMessage Server Configuration:\n")
|
94
|
+
say("Message Server Details:\n")
|
95
|
+
say(" Message Server Hostname: #{message_server_host}\n")
|
96
|
+
say(" Message Keystore Username: #{message_keystore_username}\n")
|
97
|
+
say(" Persistent message disk: #{message_persistent_disk.path}\n") if message_persistent_disk
|
98
|
+
end
|
99
|
+
|
100
|
+
def unconfigure
|
101
|
+
super
|
102
|
+
|
103
|
+
unconfigure_firewall
|
104
|
+
deactivate_services
|
105
|
+
end
|
106
|
+
|
107
|
+
def self.configured?
|
108
|
+
LinuxAdmin::Service.new("kafka").running? ||
|
109
|
+
LinuxAdmin::Service.new("zookeeper").running?
|
110
|
+
end
|
111
|
+
|
112
|
+
private
|
113
|
+
|
114
|
+
def my_ipaddr
|
115
|
+
LinuxAdmin::IpAddress.new.address
|
116
|
+
end
|
117
|
+
|
118
|
+
def my_hostname
|
119
|
+
LinuxAdmin::Hosts.new.hostname
|
120
|
+
end
|
121
|
+
|
122
|
+
def configure_persistent_disk
|
123
|
+
return true unless message_persistent_disk
|
124
|
+
|
125
|
+
say(__method__.to_s.tr("_", " ").titleize)
|
126
|
+
|
127
|
+
deactivate_services # Just in case they are running.
|
128
|
+
|
129
|
+
FileUtils.mkdir_p(PERSISTENT_DIRECTORY)
|
130
|
+
LogicalVolumeManagement.new(:disk => message_persistent_disk, :mount_point => PERSISTENT_DIRECTORY, :name => PERSISTENT_NAME).setup
|
131
|
+
FileUtils.chmod(0o755, PERSISTENT_DIRECTORY)
|
132
|
+
FileUtils.chown("kafka", "kafka", PERSISTENT_DIRECTORY)
|
133
|
+
|
134
|
+
true
|
135
|
+
end
|
136
|
+
|
137
|
+
def activate_new_persistent_disk
|
138
|
+
return true unless message_persistent_disk
|
139
|
+
|
140
|
+
say(__method__.to_s.tr("_", " ").titleize)
|
141
|
+
|
142
|
+
data = File.read(server_properties_path)
|
143
|
+
data.gsub!(/^log.dirs=.*$/, "log.dirs=#{PERSISTENT_DIRECTORY}")
|
144
|
+
File.write(server_properties_path, data)
|
145
|
+
|
146
|
+
true
|
147
|
+
end
|
148
|
+
|
149
|
+
def create_jaas_config
|
150
|
+
say(__method__.to_s.tr("_", " ").titleize)
|
151
|
+
|
152
|
+
content = <<~JAAS
|
153
|
+
KafkaServer {
|
154
|
+
org.apache.kafka.common.security.plain.PlainLoginModule required
|
155
|
+
username=#{message_keystore_username}
|
156
|
+
password=#{message_keystore_password}
|
157
|
+
user_admin=#{message_keystore_password} ;
|
158
|
+
};
|
159
|
+
JAAS
|
160
|
+
|
161
|
+
File.write(jaas_config_path, content) unless file_found?(jaas_config_path)
|
162
|
+
end
|
163
|
+
|
164
|
+
def create_logs_directory
|
165
|
+
say(__method__.to_s.tr("_", " ").titleize)
|
166
|
+
|
167
|
+
return if file_found?(LOGS_DIR)
|
168
|
+
|
169
|
+
FileUtils.mkdir_p(LOGS_DIR)
|
170
|
+
FileUtils.chmod(0o755, LOGS_DIR)
|
171
|
+
FileUtils.chown("kafka", "kafka", LOGS_DIR)
|
172
|
+
end
|
173
|
+
|
174
|
+
def configure_firewall
|
175
|
+
say(__method__.to_s.tr("_", " ").titleize)
|
176
|
+
|
177
|
+
modify_firewall(:add_port)
|
178
|
+
end
|
179
|
+
|
180
|
+
def configure_keystore
|
181
|
+
say(__method__.to_s.tr("_", " ").titleize)
|
182
|
+
|
183
|
+
return if files_found?(keystore_files)
|
184
|
+
|
185
|
+
keystore_params = assemble_keystore_params
|
186
|
+
|
187
|
+
# Generte a Java keystore and key pair, creating keystore.jks
|
188
|
+
# :stdin_data provides the -storepass twice to confirm and an extra CR to accept the same password for -keypass
|
189
|
+
AwesomeSpawn.run!("keytool", :params => keystore_params, :stdin_data => "#{message_keystore_password}\n#{message_keystore_password}\n\n")
|
190
|
+
|
191
|
+
# Use openssl to create a new CA cert, creating ca-cert and ca-key
|
192
|
+
AwesomeSpawn.run!("openssl", :env => {"PASSWORD" => message_keystore_password},
|
193
|
+
:params => ["req", "-new", "-x509", {"-keyout" => ca_key_path,
|
194
|
+
"-out" => ca_cert_path,
|
195
|
+
"-days" => 10_000,
|
196
|
+
"-passout" => "env:PASSWORD",
|
197
|
+
"-subj" => '/CN=something'}])
|
198
|
+
|
199
|
+
# Import the CA cert into the trust store, creating truststore.jks
|
200
|
+
# :stdin_data provides the -storepass argument and yes to confirm
|
201
|
+
AwesomeSpawn.run!("keytool", :params => {"-keystore" => truststore_path,
|
202
|
+
"-alias" => "CARoot",
|
203
|
+
"-import" => nil,
|
204
|
+
"-file" => ca_cert_path},
|
205
|
+
:stdin_data => "#{message_keystore_password}\n#{message_keystore_password}\nyes\n")
|
206
|
+
|
207
|
+
# Generate a certificate signing request (CSR) for an existing Java keystore, creating cert-file
|
208
|
+
# :stdin_data provides the -storepass argument
|
209
|
+
AwesomeSpawn.run!("keytool", :params => {"-keystore" => keystore_path,
|
210
|
+
"-alias" => keystore_params["-alias"],
|
211
|
+
"-certreq" => nil,
|
212
|
+
"-file" => cert_file_path},
|
213
|
+
:stdin_data => "#{message_keystore_password}\n")
|
214
|
+
|
215
|
+
# Use openssl to sign the certificate with the "CA" certificate, creating ca-cert.srl and cert-signed
|
216
|
+
AwesomeSpawn.run!("openssl", :env => {"PASSWORD" => message_keystore_password},
|
217
|
+
:params => ["x509", "-req", {"-CA" => ca_cert_path,
|
218
|
+
"-CAkey" => ca_key_path,
|
219
|
+
"-in" => cert_file_path,
|
220
|
+
"-out" => cert_signed_path,
|
221
|
+
"-days" => 10_000,
|
222
|
+
"-CAcreateserial" => nil,
|
223
|
+
"-passin" => "env:PASSWORD"}])
|
224
|
+
|
225
|
+
# Import a root or intermediate CA certificate to an existing Java keystore, updating keystore.jks
|
226
|
+
# :stdin_data provides the -storepass argument and yes to confirm
|
227
|
+
AwesomeSpawn.run!("keytool", :params => {"-keystore" => keystore_path,
|
228
|
+
"-alias" => "CARoot",
|
229
|
+
"-import" => nil,
|
230
|
+
"-file" => ca_cert_path},
|
231
|
+
:stdin_data => "#{message_keystore_password}\nyes\n")
|
232
|
+
|
233
|
+
# Import a signed primary certificate to an existing Java keystore, updating keystore.jks
|
234
|
+
# :stdin_data provides the -storepass argument
|
235
|
+
AwesomeSpawn.run!("keytool", :params => {"-keystore" => keystore_path,
|
236
|
+
"-alias" => keystore_params["-alias"],
|
237
|
+
"-import" => nil,
|
238
|
+
"-file" => cert_signed_path},
|
239
|
+
:stdin_data => "#{message_keystore_password}\n")
|
240
|
+
end
|
241
|
+
|
242
|
+
def create_server_properties
|
243
|
+
say(__method__.to_s.tr("_", " ").titleize)
|
244
|
+
|
245
|
+
if message_server_host.ipaddress?
|
246
|
+
ident_algorithm = ""
|
247
|
+
client_auth = "none"
|
248
|
+
else
|
249
|
+
ident_algorithm = "HTTPS"
|
250
|
+
client_auth = "required"
|
251
|
+
end
|
252
|
+
|
253
|
+
content = <<~SERVER_PROPERTIES
|
254
|
+
|
255
|
+
listeners=SASL_SSL://:#{message_server_port}
|
256
|
+
|
257
|
+
ssl.endpoint.identification.algorithm=#{ident_algorithm}
|
258
|
+
ssl.keystore.location=#{keystore_path}
|
259
|
+
ssl.keystore.password=#{message_keystore_password}
|
260
|
+
ssl.key.password=#{message_keystore_password}
|
261
|
+
|
262
|
+
ssl.truststore.location=#{truststore_path}
|
263
|
+
ssl.truststore.password=#{message_keystore_password}
|
264
|
+
|
265
|
+
ssl.client.auth=#{client_auth}
|
266
|
+
|
267
|
+
sasl.enabled.mechanisms=PLAIN
|
268
|
+
sasl.mechanism.inter.broker.protocol=PLAIN
|
269
|
+
|
270
|
+
security.inter.broker.protocol=SASL_SSL
|
271
|
+
SERVER_PROPERTIES
|
272
|
+
|
273
|
+
return if file_contains?(server_properties_path, content)
|
274
|
+
|
275
|
+
FileUtils.cp(server_properties_sample_path, server_properties_path)
|
276
|
+
File.write(server_properties_path, content, :mode => "a")
|
277
|
+
|
278
|
+
activate_new_persistent_disk
|
279
|
+
end
|
280
|
+
|
281
|
+
def unconfigure_firewall
|
282
|
+
say(__method__.to_s.tr("_", " ").titleize)
|
283
|
+
|
284
|
+
modify_firewall(:remove_port)
|
285
|
+
end
|
286
|
+
|
287
|
+
def deactivate_services
|
288
|
+
say(__method__.to_s.tr("_", " ").titleize)
|
289
|
+
|
290
|
+
LinuxAdmin::Service.new("zookeeper").stop
|
291
|
+
LinuxAdmin::Service.new("kafka").stop
|
292
|
+
end
|
293
|
+
|
294
|
+
def assemble_keystore_params
|
295
|
+
keystore_params = {"-keystore" => keystore_path,
|
296
|
+
"-validity" => 10_000,
|
297
|
+
"-genkey" => nil,
|
298
|
+
"-keyalg" => "RSA"}
|
299
|
+
|
300
|
+
if message_server_host.ipaddress?
|
301
|
+
keystore_params["-alias"] = "localhost"
|
302
|
+
keystore_params["-ext"] = "san=ip:#{message_server_host}"
|
303
|
+
else
|
304
|
+
keystore_params["-alias"] = message_server_host
|
305
|
+
keystore_params["-ext"] = "san=dns:#{message_server_host}"
|
306
|
+
end
|
307
|
+
|
308
|
+
keystore_params["-dname"] = "cn=#{keystore_params["-alias"]}"
|
309
|
+
|
310
|
+
keystore_params
|
311
|
+
end
|
312
|
+
|
313
|
+
def modify_firewall(action)
|
314
|
+
AwesomeSpawn.run!("firewall-cmd", :params => {action => "#{message_server_port}/tcp", :permanent => nil})
|
315
|
+
AwesomeSpawn.run!("firewall-cmd --reload")
|
316
|
+
end
|
317
|
+
end
|
318
|
+
end
|
319
|
+
end
|
@@ -1,3 +1,6 @@
|
|
1
|
+
require "net/http"
|
2
|
+
require "uri"
|
3
|
+
|
1
4
|
module ManageIQ
|
2
5
|
module ApplianceConsole
|
3
6
|
class OIDCAuthentication
|
@@ -5,6 +8,10 @@ module ManageIQ
|
|
5
8
|
|
6
9
|
attr_accessor :host, :options
|
7
10
|
|
11
|
+
URL_SUFFIX = /\/\.well-known\/openid-configuration$/.freeze
|
12
|
+
INTROSPECT_SUFFIX = "/protocol/openid-connect/token/introspect".freeze
|
13
|
+
INTROSPECT_ENDPOINT_ERROR = "Unable to derive the OpenID-Connect Client Introspection Endpoint. Use --oidc-introspection-endpoint".freeze
|
14
|
+
|
8
15
|
def initialize(options)
|
9
16
|
@options = options
|
10
17
|
end
|
@@ -12,6 +19,7 @@ module ManageIQ
|
|
12
19
|
def configure(host)
|
13
20
|
@host = host
|
14
21
|
validate_oidc_options
|
22
|
+
derive_introspection_endpoint
|
15
23
|
|
16
24
|
say("Configuring OpenID-Connect Authentication for https://#{host} ...")
|
17
25
|
copy_apache_oidc_configfiles
|
@@ -52,10 +60,18 @@ module ManageIQ
|
|
52
60
|
debug_msg("Copying Apache OpenID-Connect Config files ...")
|
53
61
|
copy_template(HTTPD_CONFIG_DIRECTORY, "manageiq-remote-user-openidc.conf")
|
54
62
|
copy_template(HTTPD_CONFIG_DIRECTORY, "manageiq-external-auth-openidc.conf.erb",
|
55
|
-
:miq_appliance
|
56
|
-
:oidc_provider_metadata_url
|
57
|
-
:oidc_client_id
|
58
|
-
:oidc_client_secret
|
63
|
+
:miq_appliance => host,
|
64
|
+
:oidc_provider_metadata_url => options[:oidc_url],
|
65
|
+
:oidc_client_id => options[:oidc_client_id],
|
66
|
+
:oidc_client_secret => options[:oidc_client_secret],
|
67
|
+
:oidc_introspection_endpoint => options[:oidc_introspection_endpoint])
|
68
|
+
|
69
|
+
if options[:oidc_insecure]
|
70
|
+
File.open("#{HTTPD_CONFIG_DIRECTORY}/manageiq-external-auth-openidc.conf", "a") do |f|
|
71
|
+
f.write("\nOIDCSSLValidateServer Off\n")
|
72
|
+
f.write("OIDCOAuthSSLValidateServer Off\n")
|
73
|
+
end
|
74
|
+
end
|
59
75
|
end
|
60
76
|
|
61
77
|
def remove_apache_oidc_configfiles
|
@@ -76,6 +92,29 @@ module ManageIQ
|
|
76
92
|
raise "Must specify the OpenID-Connect Client Secret via --oidc-client-secret" if options[:oidc_client_secret].blank?
|
77
93
|
end
|
78
94
|
|
95
|
+
def derive_introspection_endpoint
|
96
|
+
return if options[:oidc_introspection_endpoint].present?
|
97
|
+
|
98
|
+
options[:oidc_introspection_endpoint] = fetch_introspection_endpoint
|
99
|
+
raise INTROSPECT_ENDPOINT_ERROR if options[:oidc_introspection_endpoint].blank?
|
100
|
+
end
|
101
|
+
|
102
|
+
def fetch_introspection_endpoint
|
103
|
+
uri = URI.parse(options[:oidc_url])
|
104
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
105
|
+
http.use_ssl = (uri.scheme == "https")
|
106
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE if options[:oidc_insecure]
|
107
|
+
|
108
|
+
request = Net::HTTP::Get.new(uri.request_uri)
|
109
|
+
request.basic_auth(options[:oidc_client_id], options[:oidc_client_secret])
|
110
|
+
response = http.request(request)
|
111
|
+
|
112
|
+
JSON.parse(response.body)["introspection_endpoint"]
|
113
|
+
rescue => err
|
114
|
+
say("Failed to fetch introspection endpoint - #{err}")
|
115
|
+
nil
|
116
|
+
end
|
117
|
+
|
79
118
|
# Appliance Settings
|
80
119
|
|
81
120
|
def configure_auth_settings_oidc
|