Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TLS verification & custom CA UI for oVirt and Container providers #450

Merged
merged 4 commits into from
Mar 3, 2017
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -19,6 +19,8 @@ ManageIQ.angular.app.controller('emsCommonFormController', ['$http', '$scope', '
metrics_api_port: '',
api_version: '',
default_security_protocol: '',
default_tls_verify: true,
default_tls_ca_certs: '',
realm: '',
security_protocol: '',
amqp_security_protocol: '',
@@ -112,7 +114,11 @@ ManageIQ.angular.app.controller('emsCommonFormController', ['$http', '$scope', '
$scope.emsCommonModel.default_security_protocol = data.default_security_protocol;
$scope.emsCommonModel.realm = data.realm;
$scope.emsCommonModel.security_protocol = data.security_protocol;
$scope.emsCommonModel.default_tls_verify = data.default_tls_verify;
$scope.emsCommonModel.default_tls_ca_certs = data.default_tls_ca_certs;
$scope.emsCommonModel.amqp_security_protocol = data.amqp_security_protocol !== '' ? data.amqp_security_protocol : 'non-ssl';
$scope.emsCommonModel.hawkular_security_protocol = data.hawkular_security_protocol;
$scope.emsCommonModel.hawkular_tls_ca_certs = data.hawkular_tls_ca_certs;
$scope.emsCommonModel.provider_region = data.provider_region;
$scope.emsCommonModel.default_userid = data.default_userid;
$scope.emsCommonModel.amqp_userid = data.amqp_userid;
@@ -322,6 +328,8 @@ ManageIQ.angular.app.controller('emsCommonFormController', ['$http', '$scope', '
$scope.emsCommonModel.default_api_port = "";
$scope.emsCommonModel.provider_region = "";
$scope.emsCommonModel.default_security_protocol = "";
$scope.emsCommonModel.default_tls_verify = true;
$scope.emsCommonModel.default_tls_ca_certs = "";
$scope.note = "";
if ($scope.emsCommonModel.emstype === 'openstack' || $scope.emsCommonModel.emstype === 'openstack_infra') {
$scope.emsCommonModel.default_api_port = $scope.getDefaultApiPort($scope.emsCommonModel.emstype);
@@ -340,6 +348,8 @@ ManageIQ.angular.app.controller('emsCommonFormController', ['$http', '$scope', '
$scope.emsCommonModel.metrics_database_name = "ovirt_engine_history";
} else if ($scope.emsCommonModel.ems_controller === 'ems_container') {
$scope.emsCommonModel.default_api_port = "8443";
$scope.emsCommonModel.default_security_protocol = 'ssl-with-validation';
$scope.emsCommonModel.hawkular_security_protocol = 'ssl-with-validation';
} else if ($scope.emsCommonModel.emstype === 'vmware_cloud') {
$scope.emsCommonModel.default_api_port = "443";
$scope.emsCommonModel.event_stream_selection = "none";
7 changes: 7 additions & 0 deletions app/controllers/ems_common.rb
Original file line number Diff line number Diff line change
@@ -717,6 +717,7 @@ def form_instance_vars
@openstack_security_protocols = retrieve_openstack_security_protocols
@amqp_security_protocols = retrieve_amqp_security_protocols
@nuage_security_protocols = retrieve_nuage_security_protocols
@container_security_protocols = retrieve_container_security_protocols
@scvmm_security_protocols = [[_('Basic (SSL)'), 'ssl'], ['Kerberos', 'kerberos']]
@openstack_api_versions = retrieve_openstack_api_versions
@vmware_cloud_api_versions = retrieve_vmware_cloud_api_versions
@@ -768,6 +769,12 @@ def retrieve_amqp_security_protocols
[[_('Non-SSL'), 'non-ssl']]
end

def retrieve_container_security_protocols
[[_('SSL'), 'ssl-with-validation'],
[_('SSL trusting custom CA'), 'ssl-with-validation-custom-ca'],
[_('SSL without validation'), 'ssl-without-validation']]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cben @jhernand these seems a little verbose to me. They could be: 'ssl', 'ssl-custom-ca' and 'ssl-insecure'.
I think it's not required to specify with-validation in general because SSL in fact has validation by default. Is the 'ssl' value clashing with a pre-existing one that implied no validation? Are these values the ones ending up in the db?
Anyway this is just a suggestion, the rest LGTM.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but. Alas, Openstack uses the values

[[_('SSL without validation'), 'ssl'], 
 [_('SSL'), 'ssl-with-validation'], 
 [_('Non-SSL'), 'non-ssl']]

where just ssl means insecure :-(
And AFAICT some other providers use ssl to mean secure.
It'd be good to fix, but would require migration(s), I don't want to block on that, and I don't want to add to the confusion now.
That only left the option of using 2 verbose but explicit values.

(If we do migrate openstack later, it'll be safer to never redefine ssl but switch to ssl-{with,without}-validation too.)

end

# Get variables from edit form
def get_form_vars
@ems = @edit[:ems_id] ? model.find_by_id(@edit[:ems_id]) : model.new
89 changes: 63 additions & 26 deletions app/controllers/mixins/ems_common_angular.rb
Original file line number Diff line number Diff line change
@@ -117,7 +117,10 @@ def ems_form_fields
assert_privileges("#{permission_prefix}_edit")
@ems = model.new if params[:id] == 'new'
@ems = find_by_id_filtered(model, params[:id]) if params[:id] != 'new'
default_security_protocol = @ems.default_endpoint.security_protocol ? @ems.default_endpoint.security_protocol : 'ssl'
default_endpoint = @ems.default_endpoint
default_security_protocol = default_endpoint.security_protocol ? default_endpoint.security_protocol : 'ssl'
default_tls_verify = default_endpoint.verify_ssl != 0 ? true : false
default_tls_ca_certs = default_endpoint.certificate_authority

if @ems.zone.nil? || @ems.my_zone == ""
zone = "default"
@@ -136,6 +139,8 @@ def ems_form_fields
keystone_v3_domain_id = ""
hawkular_hostname = ""
hawkular_api_port = ""
hawkular_security_protocol = ""
hawkular_tls_ca_certs = ""

if @ems.connection_configurations.amqp.try(:endpoint)
amqp_hostname = @ems.connection_configurations.amqp.endpoint.hostname
@@ -171,6 +176,8 @@ def ems_form_fields
hawkular_hostname = @ems.connection_configurations.hawkular.endpoint.hostname
hawkular_api_port = @ems.connection_configurations.hawkular.endpoint.port
hawkular_auth_status = @ems.authentication_status_ok?(:hawkular)
hawkular_security_protocol = @ems.connection_configurations.hawkular.endpoint.security_protocol
hawkular_tls_ca_certs = @ems.connection_configurations.hawkular.endpoint.certificate_authority
end

if @ems.connection_configurations.default.try(:endpoint)
@@ -249,6 +256,8 @@ def ems_form_fields
:metrics_api_port => metrics_port ? metrics_port : "",
:default_security_protocol => default_security_protocol,
:amqp_security_protocol => amqp_security_protocol,
:default_tls_verify => default_tls_verify,
:default_tls_ca_certs => default_tls_ca_certs,
:api_version => @ems.api_version ? @ems.api_version : "v2",
:provider_region => @ems.provider_region,
:default_userid => @ems.authentication_userid ? @ems.authentication_userid : "",
@@ -266,24 +275,27 @@ def ems_form_fields
:ssh_keypair_auth_status => ssh_keypair_auth_status.nil? ? true : ssh_keypair_auth_status
} if controller_name == "ems_infra"

render :json => {:name => @ems.name,
:emstype => @ems.emstype,
:zone => zone,
:provider_id => @ems.provider_id ? @ems.provider_id : "",
:hostname => @ems.hostname,
:default_hostname => @ems.connection_configurations.default.endpoint.hostname,
:hawkular_hostname => hawkular_hostname,
:default_api_port => @ems.connection_configurations.default.endpoint.port,
:hawkular_api_port => hawkular_api_port,
:api_version => @ems.api_version ? @ems.api_version : "v2",
:default_security_protocol => default_security_protocol,
:provider_region => @ems.provider_region,
:default_userid => @ems.authentication_userid ? @ems.authentication_userid : "",
:service_account => service_account ? service_account : "",
:bearer_token_exists => @ems.authentication_token(:bearer).nil? ? false : true,
:ems_controller => controller_name,
:default_auth_status => default_auth_status,
:hawkular_auth_status => hawkular_auth_status.nil? ? true : hawkular_auth_status,
render :json => {:name => @ems.name,
:emstype => @ems.emstype,
:zone => zone,
:provider_id => @ems.provider_id ? @ems.provider_id : "",
:hostname => @ems.hostname,
:default_hostname => @ems.connection_configurations.default.endpoint.hostname,
:hawkular_hostname => hawkular_hostname,
:default_api_port => @ems.connection_configurations.default.endpoint.port,
:hawkular_api_port => hawkular_api_port,
:api_version => @ems.api_version ? @ems.api_version : "v2",
:default_security_protocol => default_security_protocol,
:hawkular_security_protocol => hawkular_security_protocol,
:default_tls_ca_certs => default_tls_ca_certs,
:hawkular_tls_ca_certs => hawkular_tls_ca_certs,
:provider_region => @ems.provider_region,
:default_userid => @ems.authentication_userid ? @ems.authentication_userid : "",
:service_account => service_account ? service_account : "",
:bearer_token_exists => @ems.authentication_token(:bearer).nil? ? false : true,
:ems_controller => controller_name,
:default_auth_status => default_auth_status,
:hawkular_auth_status => hawkular_auth_status.nil? ? true : hawkular_auth_status,
} if controller_name == "ems_container"

render :json => {:name => @ems.name,
@@ -343,6 +355,9 @@ def set_ems_record_vars(ems, mode = nil)
metrics_database_name = params[:metrics_database_name].strip if params[:metrics_database_name]
hawkular_hostname = params[:hawkular_hostname].strip if params[:hawkular_hostname]
hawkular_api_port = params[:hawkular_api_port].strip if params[:hawkular_api_port]
hawkular_security_protocol = params[:hawkular_security_protocol].strip if params[:hawkular_security_protocol]
default_tls_ca_certs = params[:default_tls_ca_certs].strip if params[:default_tls_ca_certs]
hawkular_tls_ca_certs = params[:hawkular_tls_ca_certs].strip if params[:hawkular_tls_ca_certs]
default_endpoint = {}
amqp_endpoint = {}
ceilometer_endpoint = {}
@@ -363,7 +378,14 @@ def set_ems_record_vars(ems, mode = nil)
ssh_keypair_endpoint = {:role => :ssh_keypair} if ems.kind_of?(ManageIQ::Providers::Openstack::InfraManager)

if ems.kind_of?(ManageIQ::Providers::Redhat::InfraManager)
default_endpoint = {:role => :default, :hostname => hostname, :port => port, :security_protocol => ems.security_protocol}
default_endpoint = {
:role => :default,
:hostname => hostname,
:port => port,
:security_protocol => ems.security_protocol,
:verify_ssl => params[:default_tls_verify] == 'on' ? 1 : 0,
:certificate_authority => params[:default_tls_ca_certs],
}
metrics_endpoint = { :role => :metrics,
:hostname => metrics_hostname,
:port => metrics_port,
@@ -399,14 +421,15 @@ def set_ems_record_vars(ems, mode = nil)

if ems.kind_of?(ManageIQ::Providers::ContainerManager)
params[:cred_type] = ems.default_authentication_type if params[:cred_type] == "default"
ems.hostname = hostname
default_endpoint = {:role => :default, :hostname => hostname, :port => port}
default_endpoint.merge!(container_security_options(ems.security_protocol, default_tls_ca_certs))

if hawkular_hostname.blank?
default_key = params[:default_password] || ems.authentication_key
hawkular_hostname = get_hostname_from_routes(ems, hostname, port, default_key)
hawkular_hostname = get_hostname_from_routes(ems, default_endpoint, default_key)
end

default_endpoint = {:role => :default, :hostname => hostname, :port => port}
hawkular_endpoint = {:role => :hawkular, :hostname => hawkular_hostname, :port => hawkular_api_port}
hawkular_endpoint.merge!(container_security_options(hawkular_security_protocol, hawkular_tls_ca_certs))
end

if ems.kind_of?(ManageIQ::Providers::MiddlewareManager)
@@ -432,15 +455,29 @@ def set_ems_record_vars(ems, mode = nil)
build_connection(ems, endpoints, mode)
end

def get_hostname_from_routes(ems, hostname, port, token)
def get_hostname_from_routes(ems, endpoint_hash, token)
return nil unless ems.class.respond_to?(:openshift_connect)
client = ems.class.openshift_connect(hostname, port, :bearer => token)
endpoint = Endpoint.new(endpoint_hash)
ssl_options = {
:verify_ssl => ems.verify_ssl_mode(endpoint),
:cert_store => ems.ssl_cert_store(endpoint)
}
client = ems.class.raw_connect(endpoint.hostname, endpoint.port,
:service => :openshift, :bearer => token, :ssl_options => ssl_options)
client.get_route('hawkular-metrics', 'openshift-infra').try(:spec).try(:host)
rescue KubeException => e
$log.warn("MIQ(#{controller_name}_controller-#{action_name}): get_hostname_from_routes error: #{e}")
nil
end

def container_security_options(security_protocol, certificate_authority)
{
:security_protocol => security_protocol,
:verify_ssl => security_protocol != 'ssl-without-validation',
:certificate_authority => security_protocol == 'ssl-with-validation-custom-ca' ? certificate_authority : nil,
}
end

def build_connection(ems, endpoints, mode)
authentications = build_credentials(ems, mode)
configurations = []
Original file line number Diff line number Diff line change
@@ -83,7 +83,8 @@
"emsCommonModel.emstype == 'openstack_infra' || " + |
"emsCommonModel.emstype == 'nuage_network' || " + |
"(emsCommonModel.emstype == 'vmware_cloud' && '#{prefix}' === 'amqp') || " |
"emsCommonModel.emstype == 'scvmm'"} |
"emsCommonModel.emstype == 'scvmm' || " + |
"emsCommonModel.ems_controller == 'ems_container'"} |
%label.col-md-2.control-label{"for" => "#{prefix}_security_protocol"}
= _('Security Protocol')
.col-md-8{"ng-if" => "emsCommonModel.emstype == 'openstack' || emsCommonModel.emstype == 'openstack_infra' || emsCommonModel.emstype == 'vmware_cloud'"}
@@ -114,6 +115,49 @@
"selectpicker-for-select-tag" => "",
"prefix" => "#{prefix}",
"reset-validation-status" => "#{prefix}_auth_status")
.col-md-8{"ng-if" => "emsCommonModel.ems_controller == 'ems_container'"}
= select_tag("#{prefix}_security_protocol",
options_for_select([["<#{_('Choose')}>", nil]] + @container_security_protocols, disabled: ["<#{_('Choose')}>", nil]),
"ng-model" => "#{ng_model}.#{prefix}_security_protocol",
"checkchange" => "",
"required" => "",
"selectpicker-for-select-tag" => "",
"prefix" => "#{prefix}",
"reset-validation-status" => "#{prefix}_auth_status")

%div{"ng-if" => defined?(tls_verify_hide) ? false : true}
.form-group{"ng-if"=> "emsCommonModel.emstype == 'rhevm'"}
%label.col-md-2.control-label{"for" => "#{prefix}_tls_verify"}
= _('Verify TLS Certificates')
.col-md-8
%input{"type" => "checkbox",
"id" => "#{prefix}_tls_verify",
"name" => "#{prefix}_tls_verify",
"bs-switch" => "",
"switch-on-text" => _("Yes"),
"switch-off-text" => _("No"),
"ng-true-value" => "true",
"ng-false-value" => "false",
"ng-model" => "#{ng_model}.#{prefix}_tls_verify",
"prefix" => "#{prefix}"}

%div{"ng-if" => defined?(tls_ca_certs_hide) ? false : true}
.form-group{"ng-if"=> "emsCommonModel.emstype == 'rhevm' || " + |
"(emsCommonModel.ems_controller == 'ems_container' && " + |
" emsCommonModel.#{prefix}_security_protocol == 'ssl-with-validation-custom-ca')"} |
%label.col-md-2.control-label{"for" => "#{prefix}_tls_ca_certs"}
= _('Trusted CA Certificates')
.col-md-4
%textarea.form-control{"id" => "#{prefix}_tls_ca_certs",
"name" => "#{prefix}_tls_ca_certs",
"ng-model" => "#{ng_model}.#{prefix}_tls_ca_certs",
"ng-disabled" => "emsCommonModel.emstype == 'rhevm' && !#{ng_model}.#{prefix}_tls_verify",
"ng-required" => false,
"ng-trim" => false,
"prefix" => "#{prefix}"}
%span.help-block
= _("Paste here the trusted CA certificates, in PEM format.")

.form-group{"ng-class" => "{'has-error': angularForm.realm.$invalid}",
"ng-if" => "emsCommonModel.emstype == 'scvmm' && emsCommonModel.default_security_protocol == 'kerberos'"}
%label.col-md-2.control-label{"for" => "realm"}
Original file line number Diff line number Diff line change
@@ -150,6 +150,8 @@
:id => record.id,
:database_name_required => true,
:database_name_show => true,
:tls_verify_hide => true,
:tls_ca_certs_hide => true,
:prefix => "metrics",
:ng_reqd_hostname => "#{ng_model}.metrics_userid != '' && #{ng_model}.metrics_userid != undefined",
:ng_reqd_api_port => "false"}
@@ -260,7 +262,6 @@
:locals => {:ng_show => true,
:ng_model => "#{ng_model}",
:id => record.id,
:security_protocol_hide => true,
:ng_reqd_hostname => "false",
:ng_reqd_api_port => "false",
:prefix => "hawkular"}
34 changes: 22 additions & 12 deletions spec/controllers/ems_common_controller_spec.rb
Original file line number Diff line number Diff line change
@@ -235,20 +235,30 @@ def test_creating(emstype)
end

def test_setting_many_fields
controller.instance_variable_set(:@_params, :name => 'EMS 2',
:default_userid => '_',
:default_hostname => '10.10.10.11',
:default_api_port => '5000',
:default_password => 'valid-token',
:hawkular_hostname => '10.10.10.10',
:hawkular_api_port => '8443',
:emstype => @type)
controller.instance_variable_set(:@_params, :name => 'EMS 2',
:default_userid => '_',
:default_hostname => '10.10.10.11',
:default_api_port => '5000',
:default_security_protocol => 'ssl-with-validation-custom-ca',
:default_tls_ca_certs => '-----BEGIN DUMMY...',
:default_password => 'valid-token',
:hawkular_hostname => '10.10.10.10',
:hawkular_api_port => '8443',
:hawkular_security_protocol => 'ssl-with-validation',
:emstype => @type)
controller.send(:set_ems_record_vars, @ems)
expect(@flash_array).to be_nil
expect(@ems.connection_configurations.default.endpoint.hostname).to eq('10.10.10.11')
expect(@ems.connection_configurations.default.endpoint.port).to eq(5000)
expect(@ems.connection_configurations.hawkular.endpoint.hostname).to eq('10.10.10.10')
expect(@ems.connection_configurations.hawkular.endpoint.port).to eq(8443)
cc = @ems.connection_configurations
expect(cc.default.endpoint.hostname).to eq('10.10.10.11')
expect(cc.default.endpoint.port).to eq(5000)
expect(cc.default.endpoint.security_protocol).to eq('ssl-with-validation-custom-ca')
expect(cc.default.endpoint.verify_ssl?).to eq(true)
expect(cc.default.endpoint.certificate_authority).to eq('-----BEGIN DUMMY...')
expect(cc.hawkular.endpoint.hostname).to eq('10.10.10.10')
expect(cc.hawkular.endpoint.port).to eq(8443)
expect(cc.hawkular.endpoint.security_protocol).to eq('ssl-with-validation')
expect(cc.hawkular.endpoint.verify_ssl?).to eq(true)
expect(cc.hawkular.endpoint.certificate_authority).to eq(nil)
expect(@ems.authentication_token("bearer")).to eq('valid-token')
expect(@ems.authentication_type("default")).to be_nil
expect(@ems.hostname).to eq('10.10.10.11')