[rubygem-rbovirt/f20] Fix unsafe use of rest-client (CVE-2014-0036).
Vít Ondruch
vondruch at fedoraproject.org
Thu Mar 6 09:56:52 UTC 2014
commit b9fe1b8d132a182df526f230b6d4ac826cf80fd0
Author: Vít Ondruch <vondruch at redhat.com>
Date: Thu Mar 6 10:56:33 2014 +0100
Fix unsafe use of rest-client (CVE-2014-0036).
...ded-support-for-https-peer-authentication.patch | 379 ++++++++++++++++++++
rubygem-rbovirt.spec | 12 +-
sources | 2 -
3 files changed, 390 insertions(+), 3 deletions(-)
---
diff --git a/rubygem-rbovirt-0.0.24-CVE-2014-0036-added-support-for-https-peer-authentication.patch b/rubygem-rbovirt-0.0.24-CVE-2014-0036-added-support-for-https-peer-authentication.patch
new file mode 100644
index 0000000..a594f12
--- /dev/null
+++ b/rubygem-rbovirt-0.0.24-CVE-2014-0036-added-support-for-https-peer-authentication.patch
@@ -0,0 +1,379 @@
+From cf2ca97dede402af8336821448792375e53aa8c6 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?V=C3=ADt=20Ondruch?= <vondruch at redhat.com>
+Date: Thu, 6 Mar 2014 10:45:16 +0100
+Subject: [PATCH] added support for https peer authentication.
+
+---
+ lib/rbovirt.rb | 53 +++++++++++++++++++++++++++--------
+ lib/restclient_ext/request.rb | 60 ++++++++++++++++++++++++++++++++++++++++
+ spec/endpoint.yml.example | 3 +-
+ spec/integration/api_spec.rb | 30 +++++++++++++++++---
+ spec/integration/vm_crud_spec.rb | 20 ++++++++------
+ spec/lib/endpoint.rb | 7 +----
+ spec/spec_helper.rb | 16 ++++++++++-
+ spec/unit/client_spec.rb | 25 +++++++++++++++++
+ 8 files changed, 182 insertions(+), 32 deletions(-)
+ create mode 100644 lib/restclient_ext/request.rb
+ create mode 100644 spec/unit/client_spec.rb
+
+diff --git a/lib/rbovirt.rb b/lib/rbovirt.rb
+index 7204bc7..9efdec5 100644
+--- a/lib/rbovirt.rb
++++ b/lib/rbovirt.rb
+@@ -18,6 +18,7 @@ require "client/storage_domain_api"
+
+ require "nokogiri"
+ require "rest_client"
++require "restclient_ext/request"
+
+ module OVIRT
+
+@@ -35,14 +36,35 @@ module OVIRT
+
+ class Client
+
+- attr_reader :credentials, :api_entrypoint, :datacenter_id, :cluster_id, :filtered_api
+-
+- def initialize(username, password, api_entrypoint, datacenter_id=nil, cluster_id=nil, filtered_api = false)
+- @credentials = { :username => username, :password => password }
+- @datacenter_id = datacenter_id
+- @cluster_id = cluster_id
++ attr_reader :credentials, :api_entrypoint, :datacenter_id, :cluster_id, :filtered_api, :ca_cert_file, :ca_cert_store
++
++ # Construct a new ovirt client class.
++ # mandatory parameters
++ # username, password, api_entrypoint - for example 'me at internal', 'secret', 'https://example.com/api'
++ # optional parameters
++ # datacenter_id, cluster_id and filtered_api can be sent in this order for backward
++ # compatibility, or as a hash in the 4th parameter.
++ # datacenter_id - setting the datacenter at initialization will add a default scope to any subsequent call
++ # to the client to the specified datacenter.
++ # cluster_id - setting the cluster at initialization will add a default scope to any subsequent call
++ # to the client to the specified cluster.
++ # filtered_api - when set to false (default) will use ovirt administrator api, else it will use the user
++ # api mode.
++ #
++ def initialize(username, password, api_entrypoint, options={}, backward_compatibility_cluster=nil, backward_compatibility_filtered=nil )
++ if !options.is_a?(Hash)
++ # backward compatibility optional parameters
++ options = {:datacenter_id => options,
++ :cluster_id => backward_compatibility_cluster,
++ :filtered_api => backward_compatibility_filtered}
++ end
+ @api_entrypoint = api_entrypoint
+- @filtered_api = filtered_api
++ @credentials = { :username => username, :password => password }
++ @datacenter_id = options[:datacenter_id]
++ @cluster_id = options[:cluster_id]
++ @filtered_api = options[:filtered_api]
++ @ca_cert_file = options[:ca_cert_file]
++ @ca_cert_store = options[:ca_cert_store]
+ end
+
+ def api_version
+@@ -76,7 +98,7 @@ module OVIRT
+
+ def http_get(suburl, headers={})
+ begin
+- Nokogiri::XML(RestClient::Resource.new(@api_entrypoint)[suburl].get(http_headers(headers)))
++ Nokogiri::XML(rest_client(suburl).get(http_headers(headers)))
+ rescue
+ handle_fault $!
+ end
+@@ -84,7 +106,7 @@ module OVIRT
+
+ def http_post(suburl, body, headers={})
+ begin
+- Nokogiri::XML(RestClient::Resource.new(@api_entrypoint)[suburl].post(body, http_headers(headers)))
++ Nokogiri::XML(rest_client(suburl).post(body, http_headers(headers)))
+ rescue
+ handle_fault $!
+ end
+@@ -92,7 +114,7 @@ module OVIRT
+
+ def http_put(suburl, body, headers={})
+ begin
+- Nokogiri::XML(RestClient::Resource.new(@api_entrypoint)[suburl].put(body, http_headers(headers)))
++ Nokogiri::XML(rest_client(suburl).put(body, http_headers(headers)))
+ rescue
+ handle_fault $!
+ end
+@@ -101,7 +123,7 @@ module OVIRT
+ def http_delete(suburl)
+ begin
+ headers = {:accept => 'application/xml'}.merge(auth_header).merge(filter_header)
+- Nokogiri::XML(RestClient::Resource.new(@api_entrypoint)[suburl].delete(headers))
++ Nokogiri::XML(rest_client(suburl).delete(headers))
+ rescue
+ handle_fault $!
+ end
+@@ -113,6 +135,15 @@ module OVIRT
+ { :authorization => "Basic " + encoded_credentials }
+ end
+
++ def rest_client(suburl)
++ if (URI.parse(@api_entrypoint)).scheme == 'https'
++ verify_options = {:verify_ssl => OpenSSL::SSL::VERIFY_PEER}
++ verify_options[:ssl_cert_store] = ca_cert_store if ca_cert_store
++ verify_options[:ssl_ca_file] = ca_cert_file if ca_cert_file
++ end
++ RestClient::Resource.new(@api_entrypoint, verify_options)[suburl]
++ end
++
+ def filter_header
+ filtered_api ? { :filter => "true" } : {}
+ end
+diff --git a/lib/restclient_ext/request.rb b/lib/restclient_ext/request.rb
+new file mode 100644
+index 0000000..0070b6b
+--- /dev/null
++++ b/lib/restclient_ext/request.rb
+@@ -0,0 +1,60 @@
++# rest-client extension
++module RestClient
++ # This class enhance the rest-client request by accepting a parameter for ca certificate store,
++ # this file can be removed once https://github.com/rest-client/rest-client/pull/254
++ # get merged upstream.
++ #
++ # :ssl_cert_store - an x509 certificate store.
++ class Request
++
++ def transmit uri, req, payload, & block
++ setup_credentials req
++
++ net = net_http_class.new(uri.host, uri.port)
++ net.use_ssl = uri.is_a?(URI::HTTPS)
++ if (@verify_ssl == false) || (@verify_ssl == OpenSSL::SSL::VERIFY_NONE)
++ net.verify_mode = OpenSSL::SSL::VERIFY_NONE
++ elsif @verify_ssl.is_a? Integer
++ net.verify_mode = @verify_ssl
++ net.verify_callback = lambda do |preverify_ok, ssl_context|
++ if (!preverify_ok) || ssl_context.error != 0
++ err_msg = "SSL Verification failed -- Preverify: #{preverify_ok}, Error: #{ssl_context.error_string} (#{ssl_context.error})"
++ raise SSLCertificateNotVerified.new(err_msg)
++ end
++ true
++ end
++ end
++ net.cert = @ssl_client_cert if @ssl_client_cert
++ net.key = @ssl_client_key if @ssl_client_key
++ net.ca_file = @ssl_ca_file if @ssl_ca_file
++ net.cert_store = args[:ssl_cert_store] if args[:ssl_cert_store]
++ net.read_timeout = @timeout if @timeout
++ net.open_timeout = @open_timeout if @open_timeout
++
++ # disable the timeout if the timeout value is -1
++ net.read_timeout = nil if @timeout == -1
++ net.out_timeout = nil if @open_timeout == -1
++
++ RestClient.before_execution_procs.each do |before_proc|
++ before_proc.call(req, args)
++ end
++
++ log_request
++
++ net.start do |http|
++ if @block_response
++ http.request(req, payload ? payload.to_s : nil, & @block_response)
++ else
++ res = http.request(req, payload ? payload.to_s : nil) { |http_response| fetch_body(http_response) }
++ log_response res
++ process_result res, & block
++ end
++ end
++ rescue EOFError
++ raise RestClient::ServerBrokeConnection
++ rescue Timeout::Error
++ raise RestClient::RequestTimeout
++ end
++
++ end
++end
+diff --git a/spec/endpoint.yml.example b/spec/endpoint.yml.example
+index 4730d00..77224aa 100644
+--- a/spec/endpoint.yml.example
++++ b/spec/endpoint.yml.example
+@@ -1,5 +1,4 @@
+
+ user: "admin at internal"
+ password: "secret"
+-hostname: "ovirt.example.com"
+-port: ""
++url: "http://ovirt.example.com/api"
+diff --git a/spec/integration/api_spec.rb b/spec/integration/api_spec.rb
+index 3fcb21a..1aa0b2e 100644
+--- a/spec/integration/api_spec.rb
++++ b/spec/integration/api_spec.rb
+@@ -38,11 +38,32 @@ shared_examples_for "API" do
+ end
+ end
+
++describe OVIRT, "Https authentication" do
++ context 'authenticate using the server ca certificate' do
++
++ it "test_should_get_ca_certificate" do
++ user, password, url, datacenter = endpoint
++ ::OVIRT::RSpec.ca_cert(url).class.should eql(String)
++ end
++
++ it "should_authenticate_with_ca_certificate" do
++ user, password, url, datacenter = endpoint
++ cert = ::OVIRT::RSpec.ca_cert(url)
++ store = OpenSSL::X509::Store.new().add_cert(
++ OpenSSL::X509::Certificate.new(cert))
++
++ client = ::OVIRT::Client.new(user, password, url, {:ca_cert_store => store})
++ client.api_version.class.should eql(String)
++ end
++ end
++end
++
+ describe OVIRT, "Admin API" do
+
+ before(:all) do
+- user, password, url = endpoint
+- @client = ::OVIRT::Client.new(user, password, url, nil, nil, false)
++ user, password, url, datacenter = endpoint
++ opts = {:datacenter_id => datacenter, :ca_cert_file => "#{File.dirname(__FILE__)}/../ca_cert.pem"}
++ @client = ::OVIRT::Client.new(user, password, url, opts )
+ end
+
+ after(:all) do
+@@ -61,8 +82,9 @@ end
+ describe OVIRT, "User API" do
+
+ before(:all) do
+- user, password, url = endpoint
+- @client = ::OVIRT::Client.new(user, password, url, nil, nil, support_user_level_api)
++ user, password, url, datacenter = endpoint
++ opts = {:datacenter_id => datacenter, :ca_cert_file => "#{File.dirname(__FILE__)}/../ca_cert.pem", :filtered_api => support_user_level_api}
++ @client = ::OVIRT::Client.new(user, password, url, opts)
+ end
+
+ after(:all) do
+diff --git a/spec/integration/vm_crud_spec.rb b/spec/integration/vm_crud_spec.rb
+index 42e9ca0..61c5293 100644
+--- a/spec/integration/vm_crud_spec.rb
++++ b/spec/integration/vm_crud_spec.rb
+@@ -3,12 +3,12 @@ require "#{File.dirname(__FILE__)}/../spec_helper"
+ shared_examples_for "Basic VM Life cycle" do
+
+ before(:all) do
+- @blank_template_id = "00000000-0000-0000-0000-000000000000"
+- @cluster = @client.clusters.first.id
++ @cluster = @client.clusters.last.id
++ @template_id = "00000000-0000-0000-0000-000000000000"
+ name = 'vm-'+Time.now.to_i.to_s
+- @vm = @client.create_vm(:name => name, :template => @blank_template_id, :cluster => @cluster)
++ @vm = @client.create_vm(:name => name, :template => @template_id, :cluster => @cluster)
+ @client.add_volume(@vm.id)
+- @client.add_interface(@vm.id)
++ @client.add_interface(@vm.id, :network_name => 'rhevm')
+ while !@client.vm(@vm.id).ready? do
+ end
+ end
+@@ -71,8 +71,9 @@ end
+ describe "Admin API VM Life cycle" do
+
+ before(:all) do
+- user, password, url = endpoint
+- @client = ::OVIRT::Client.new(user, password, url, nil, nil, false)
++ user, password, url, datacenter = endpoint
++ opts = {:datacenter_id => datacenter, :ca_cert_file => "#{File.dirname(__FILE__)}/../ca_cert.pem"}
++ @client = ::OVIRT::Client.new(user, password, url, opts)
+ end
+
+ context 'admin basic vm and templates operations' do
+@@ -83,8 +84,11 @@ end
+ describe "User API VM Life cycle" do
+
+ before(:all) do
+- user, password, url = endpoint
+- @client = ::OVIRT::Client.new(user, password, url, nil, nil, support_user_level_api)
++ user, password, url, datacenter = endpoint
++ opts = {:datacenter_id => datacenter,
++ :ca_cert_file => "#{File.dirname(__FILE__)}/../ca_cert.pem",
++ :filtered_api => support_user_level_api}
++ @client = ::OVIRT::Client.new(user, password, url, opts)
+ end
+
+ context 'user basic vm and templates operations' do
+diff --git a/spec/lib/endpoint.rb b/spec/lib/endpoint.rb
+index c85fbd1..e1f8e34 100644
+--- a/spec/lib/endpoint.rb
++++ b/spec/lib/endpoint.rb
+@@ -3,12 +3,7 @@ module OVIRT::RSpec::Endpoint
+ def endpoint
+ file = File.expand_path("../endpoint.yml", File.dirname(__FILE__))
+ @endpoint ||= YAML.load(File.read(file))
+- user = @endpoint['user']
+- password= @endpoint['password']
+- hostname = @endpoint['hostname']
+- port = @endpoint['port']
+- url = "http://#{hostname}:#{port}/api"
+- return user, password, url
++ return @endpoint['user'], @endpoint['password'], @endpoint['url'] , @endpoint['datacenter']
+ end
+
+ def support_user_level_api
+diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
+index 564b024..b89cc2e 100644
+--- a/spec/spec_helper.rb
++++ b/spec/spec_helper.rb
+@@ -4,7 +4,21 @@
+ require 'rspec'
+ require 'rbovirt'
+
+-module OVIRT::RSpec end
++module OVIRT::RSpec
++
++ # get ovirt ca certificate public key
++ # * url - ovirt server url
++ def self.ca_cert(url)
++ ca_url = URI.parse(url)
++ ca_url.path = "/ca.crt"
++ http = Net::HTTP.new(ca_url.host, ca_url.port)
++ http.use_ssl = (ca_url.scheme == 'https')
++ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
++ request = Net::HTTP::Get.new(ca_url.path)
++ http.request(request).body
++ end
++
++end
+
+ require "#{File.dirname(__FILE__)}/lib/endpoint"
+
+diff --git a/spec/unit/client_spec.rb b/spec/unit/client_spec.rb
+new file mode 100644
+index 0000000..9d2f7c8
+--- /dev/null
++++ b/spec/unit/client_spec.rb
+@@ -0,0 +1,25 @@
++require "#{File.dirname(__FILE__)}/../spec_helper"
++
++describe OVIRT::Client do
++ context 'client initialization' do
++ it 'should accept no option' do
++ OVIRT::Client::new('mockuser','mockpass','http://example.com/api')
++ end
++
++ it 'should accept no datacenter_id in options' do
++ OVIRT::Client::new('mockuser','mockpass','http://example.com/api', :datacenter_id => '123123')
++ end
++
++ it 'should support backward compatibility' do
++ OVIRT::Client::new('mockuser','mockpass','http://example.com/api', '123123', '123123', false)
++ end
++
++ it 'should support options hash in 4th parameter' do
++ OVIRT::Client::new('mockuser','mockpass','http://example.com/api',
++ {:datacenter_id => '123123',
++ :cluster_id => '123123',
++ :filtered_api => false,
++ :ca_cert_file => 'ca_cert.pem'})
++ end
++ end
++end
+--
+1.8.5.3
+
diff --git a/rubygem-rbovirt.spec b/rubygem-rbovirt.spec
index b6d193f..0c5cc50 100644
--- a/rubygem-rbovirt.spec
+++ b/rubygem-rbovirt.spec
@@ -4,11 +4,14 @@
Summary: A Ruby client for oVirt REST API
Name: rubygem-%{gem_name}
Version: 0.0.18
-Release: 3%{?dist}
+Release: 4%{?dist}
Group: Development/Languages
License: MIT
URL: http://github.com/abenari/rbovirt
Source0: http://rubygems.org/gems/%{gem_name}-%{version}.gem
+# Fix unsafe use of rest-client (CVE-2014-0036).
+# https://github.com/abenari/rbovirt/commit/494028e14948d89ab331e79d6e64fdfeec5bae4c
+Patch1: rubygem-rbovirt-0.0.24-CVE-2014-0036-added-support-for-https-peer-authentication.patch
Requires: ruby(release)
Requires: ruby(rubygems)
Requires: ruby
@@ -40,6 +43,10 @@ Documentation for %{name}
%setup -q -c -T
%gem_install -n %{SOURCE0}
+pushd .%{gem_instdir}
+%patch1 -p1
+popd
+
%build
%install
@@ -73,6 +80,9 @@ popd
%{gem_instdir}/spec/
%changelog
+* Thu Mar 06 2014 Vít Ondruch <vondruch at redhat.com> - 0.0.18-4
+- Fix unsafe use of rest-client (CVE-2014-0036).
+
* Sun Aug 04 2013 Fedora Release Engineering <rel-eng at lists.fedoraproject.org> - 0.0.18-3
- Rebuilt for https://fedoraproject.org/wiki/Fedora_20_Mass_Rebuild
diff --git a/sources b/sources
index e2a60e5..8abed78 100644
--- a/sources
+++ b/sources
@@ -1,3 +1 @@
-0e0f6c39499c952df3acb62924b7a3d2 rbovirt-0.0.14.gem
-579a0e02531f5e9a66491fd5bf0a4fac rbovirt-0.0.17.gem
b38215ac5fa74521653d2d27db96a209 rbovirt-0.0.18.gem
More information about the scm-commits
mailing list