Project

General

Profile

Bug #15384 ยป unify-certification-bundler.patch

hsbt (Hiroshi SHIBATA), 03/14/2019 02:47 AM

View differences:

lib/bundler/fetcher.rb
2 2

  
3 3
require "bundler/vendored_persistent"
4 4
require "cgi"
5
require "rbconfig"
5 6
require "securerandom"
6 7
require "zlib"
7 8

  
......
293 294
        end
294 295
      else
295 296
        store.set_default_paths
296
        certs = File.expand_path("../ssl_certs/*/*.pem", __FILE__)
297

  
298
        rubygems_certs_dir = File.expand_path("../../rubygems/ssl_certs", __FILE__)
299
        unless File.exists?(rubygems_certs_dir)
300
          rubygems_certs_dir = File.join(RbConfig::CONFIG["rubylibdir"], "rubygems", "ssl_certs")
301
        end
302
        certs = File.join(rubygems_certs_dir, "*", "*.pem")
303

  
297 304
        Dir.glob(certs).each {|c| store.add_file c }
298 305
      end
299 306
      store
/dev/null
1
# Ignore all files in this directory
/dev/null
1
# frozen_string_literal: true
2

  
3
require "bundler/vendored_fileutils"
4
require "net/https"
5
require "openssl"
6

  
7
module Bundler
8
  module SSLCerts
9
    class CertificateManager
10
      attr_reader :bundler_cert_path, :bundler_certs, :rubygems_certs
11

  
12
      def self.update_from!(rubygems_path)
13
        new(rubygems_path).update!
14
      end
15

  
16
      def initialize(rubygems_path = nil)
17
        if rubygems_path
18
          rubygems_cert_path = File.join(rubygems_path, "lib/rubygems/ssl_certs")
19
          @rubygems_certs = certificates_in(rubygems_cert_path)
20
        end
21

  
22
        @bundler_cert_path = File.expand_path("..", __FILE__)
23
        @bundler_certs = certificates_in(bundler_cert_path)
24
      end
25

  
26
      def up_to_date?
27
        rubygems_certs.all? do |rc|
28
          bundler_certs.find do |bc|
29
            File.basename(bc) == File.basename(rc) && FileUtils.compare_file(bc, rc)
30
          end
31
        end
32
      end
33

  
34
      def update!
35
        return if up_to_date?
36

  
37
        FileUtils.rm bundler_certs
38
        FileUtils.cp rubygems_certs, bundler_cert_path
39
      end
40

  
41
      def connect_to(host)
42
        http = Net::HTTP.new(host, 443)
43
        http.use_ssl = true
44
        http.verify_mode = OpenSSL::SSL::VERIFY_PEER
45
        http.cert_store = store
46
        http.head("/")
47
      end
48

  
49
    private
50

  
51
      def certificates_in(path)
52
        Dir[File.join(path, "**/*.pem")].sort
53
      end
54

  
55
      def store
56
        @store ||= begin
57
          store = OpenSSL::X509::Store.new
58
          bundler_certs.each do |cert|
59
            store.add_file cert
60
          end
61
          store
62
        end
63
      end
64
    end
65
  end
66
end
/dev/null
1
-----BEGIN CERTIFICATE-----
2
MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG
3
A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv
4
b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw
5
MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i
6
YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT
7
aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ
8
jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp
9
xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp
10
1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG
11
snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ
12
U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8
13
9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E
14
BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B
15
AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz
16
yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE
17
38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP
18
AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad
19
DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME
20
HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==
21
-----END CERTIFICATE-----
/dev/null
1
-----BEGIN CERTIFICATE-----
2
MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs
3
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
4
d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
5
ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL
6
MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3
7
LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug
8
RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm
9
+9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW
10
PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM
11
xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB
12
Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3
13
hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg
14
EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF
15
MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA
16
FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec
17
nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z
18
eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF
19
hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2
20
Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe
21
vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep
22
+OkuE6N36B9K
23
-----END CERTIFICATE-----
/dev/null
1
-----BEGIN CERTIFICATE-----
2
MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU
3
MBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFs
4
IFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290
5
MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzELMAkGA1UEBhMCU0Ux
6
FDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5h
7
bCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9v
8
dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvt
9
H7xsD821+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9
10
uMq/NzgtHj6RQa1wVsfwTz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzX
11
mk6vBbOmcZSccbNQYArHE504B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LX
12
a0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzN
13
E0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0
14
WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYD
15
VR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0
16
Jvf6xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU
17
cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsx
18
IjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJKoZIhvcN
19
AQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZlj7DYd7usQWxH
20
YINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5
21
6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvC
22
Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX
23
c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a
24
mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ=
25
-----END CERTIFICATE-----
/dev/null
1
# frozen_string_literal: true
2

  
3
require "bundler/ssl_certs/certificate_manager"
4

  
5
RSpec.describe Bundler::SSLCerts::CertificateManager do
6
  let(:rubygems_path)      { root }
7
  let(:stub_cert)          { File.join(root.to_s, "lib", "rubygems", "ssl_certs", "rubygems.org", "ssl-cert.pem") }
8
  let(:rubygems_certs_dir) { File.join(root.to_s, "lib", "rubygems", "ssl_certs", "rubygems.org") }
9

  
10
  subject { described_class.new(rubygems_path) }
11

  
12
  # Pretend bundler root is rubygems root
13
  before do
14
    # Backing up rubygems ceriticates
15
    FileUtils.mv(rubygems_certs_dir, rubygems_certs_dir + ".back") if ruby_core?
16

  
17
    FileUtils.mkdir_p(rubygems_certs_dir)
18
    FileUtils.touch(stub_cert)
19
  end
20

  
21
  after do
22
    FileUtils.rm_rf(rubygems_certs_dir)
23

  
24
    # Restore rubygems certificates
25
    FileUtils.mv(rubygems_certs_dir + ".back", rubygems_certs_dir) if ruby_core?
26
  end
27

  
28
  describe "#update_from" do
29
    let(:cert_manager) { double(:cert_manager) }
30

  
31
    before { allow(described_class).to receive(:new).with(rubygems_path).and_return(cert_manager) }
32

  
33
    it "should update the certs through a new certificate manager" do
34
      allow(cert_manager).to receive(:update!)
35
      expect(described_class.update_from!(rubygems_path)).to be_nil
36
    end
37
  end
38

  
39
  describe "#initialize" do
40
    it "should set bundler_cert_path as path of the subdir with bundler ssl certs" do
41
      expect(subject.bundler_cert_path).to eq(File.join(root, "lib/bundler/ssl_certs"))
42
    end
43

  
44
    it "should set bundler_certs as the paths of the bundler ssl certs" do
45
      expect(subject.bundler_certs).to include(File.join(root, "lib/bundler/ssl_certs/rubygems.global.ssl.fastly.net/DigiCertHighAssuranceEVRootCA.pem"))
46
      expect(subject.bundler_certs).to include(File.join(root, "lib/bundler/ssl_certs/index.rubygems.org/GlobalSignRootCA.pem"))
47
    end
48

  
49
    context "when rubygems_path is not nil" do
50
      it "should set rubygems_certs" do
51
        expect(subject.rubygems_certs).to include(File.join(root, "lib", "rubygems", "ssl_certs", "rubygems.org", "ssl-cert.pem"))
52
      end
53
    end
54
  end
55

  
56
  describe "#up_to_date?" do
57
    context "when bundler certs and rubygems certs are the same" do
58
      before do
59
        bundler_certs = Dir[File.join(root.to_s, "lib", "bundler", "ssl_certs", "**", "*.pem")]
60
        FileUtils.rm(stub_cert)
61
        FileUtils.cp(bundler_certs, rubygems_certs_dir)
62
      end
63

  
64
      it "should return true" do
65
        expect(subject).to be_up_to_date
66
      end
67
    end
68

  
69
    context "when bundler certs and rubygems certs are not the same" do
70
      it "should return false" do
71
        expect(subject).to_not be_up_to_date
72
      end
73
    end
74
  end
75

  
76
  describe "#update!" do
77
    context "when certificate manager is not up to date" do
78
      before do
79
        allow(subject).to receive(:up_to_date?).and_return(false)
80
        allow(bundler_fileutils).to receive(:rm)
81
        allow(bundler_fileutils).to receive(:cp)
82
      end
83

  
84
      it "should remove the current bundler certs" do
85
        expect(bundler_fileutils).to receive(:rm).with(subject.bundler_certs)
86
        subject.update!
87
      end
88

  
89
      it "should copy the rubygems certs into bundler certs" do
90
        expect(bundler_fileutils).to receive(:cp).with(subject.rubygems_certs, subject.bundler_cert_path)
91
        subject.update!
92
      end
93

  
94
      it "should return nil" do
95
        expect(subject.update!).to be_nil
96
      end
97
    end
98

  
99
    context "when certificate manager is up to date" do
100
      before { allow(subject).to receive(:up_to_date?).and_return(true) }
101

  
102
      it "should return nil" do
103
        expect(subject.update!).to be_nil
104
      end
105
    end
106
  end
107

  
108
  describe "#connect_to" do
109
    let(:host)                 { "http://www.host.com" }
110
    let(:http)                 { Net::HTTP.new(host, 443) }
111
    let(:cert_store)           { OpenSSL::X509::Store.new }
112
    let(:http_header_response) { double(:http_header_response) }
113

  
114
    before do
115
      allow(Net::HTTP).to receive(:new).with(host, 443).and_return(http)
116
      allow(OpenSSL::X509::Store).to receive(:new).and_return(cert_store)
117
      allow(http).to receive(:head).with("/").and_return(http_header_response)
118
    end
119

  
120
    it "should use ssl for the http request" do
121
      expect(http).to receive(:use_ssl=).with(true)
122
      subject.connect_to(host)
123
    end
124

  
125
    it "use verify peer mode" do
126
      expect(http).to receive(:verify_mode=).with(OpenSSL::SSL::VERIFY_PEER)
127
      subject.connect_to(host)
128
    end
129

  
130
    it "set its cert store as a OpenSSL::X509::Store populated with bundler certs" do
131
      expect(cert_store).to receive(:add_file).at_least(:once)
132
      expect(http).to receive(:cert_store=).with(cert_store)
133
      subject.connect_to(host)
134
    end
135

  
136
    it "return the headers of the request response" do
137
      expect(subject.connect_to(host)).to eq(http_header_response)
138
    end
139
  end
140
end
/dev/null
1
# frozen_string_literal: true
2

  
3
require "bundler/ssl_certs/certificate_manager"
4

  
5
RSpec.describe "SSL Certificates", :rubygems_master do
6
  hosts = %w[
7
    rubygems.org
8
    index.rubygems.org
9
    rubygems.global.ssl.fastly.net
10
    staging.rubygems.org
11
  ]
12

  
13
  hosts.each do |host|
14
    it "can securely connect to #{host}", :realworld do
15
      Bundler::SSLCerts::CertificateManager.new.connect_to(host)
16
    end
17
  end
18
end
spec/bundler/quality_spec.rb
105 105
  end
106 106

  
107 107
  it "has no malformed whitespace" do
108
    exempt = /\.gitmodules|\.marshal|fixtures|vendor|ssl_certs|LICENSE|vcr_cassettes/
108
    exempt = /\.gitmodules|\.marshal|fixtures|vendor|LICENSE|vcr_cassettes/
109 109
    error_messages = []
110 110
    Dir.chdir(root) do
111 111
      lib_files = ruby_core? ? `git ls-files -z -- lib/bundler lib/bundler.rb spec/bundler` : `git ls-files -z -- lib`