httpclient 2.8.2.4 → 2.9.0
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 +5 -5
- data/lib/hexdump.rb +12 -12
- data/lib/httpclient/http.rb +8 -8
- data/lib/httpclient/jruby_ssl_socket.rb +90 -39
- data/lib/httpclient/session.rb +13 -7
- data/lib/httpclient/ssl_config.rb +75 -123
- data/lib/httpclient/ssl_socket.rb +26 -24
- data/lib/httpclient/util.rb +1 -1
- data/lib/httpclient/version.rb +1 -1
- data/lib/httpclient.rb +7 -1
- data/lib/jsonclient.rb +8 -5
- data/sample/auth.rb +1 -1
- data/sample/generate_test_keys.rb +99 -0
- data/test/ca-chain.pem +32 -36
- data/test/ca.cert +16 -19
- data/test/ca.key +27 -0
- data/test/ca.srl +1 -0
- data/test/client-pass.key +30 -18
- data/test/client.cert +17 -16
- data/test/client.key +25 -13
- data/test/fixtures/verify.alt.cert +20 -0
- data/test/fixtures/verify.foo.cert +20 -0
- data/test/fixtures/verify.key +27 -0
- data/test/fixtures/verify.localhost.cert +20 -0
- data/test/helper.rb +5 -7
- data/test/jruby_ssl_socket/test_pemutils.rb +32 -0
- data/test/server.cert +16 -15
- data/test/server.key +25 -13
- data/test/subca.cert +16 -17
- data/test/subca.key +27 -0
- data/test/subca.srl +1 -0
- data/test/test_auth.rb +21 -17
- data/test/test_hexdump.rb +1 -2
- data/test/test_http-access2.rb +31 -23
- data/test/test_httpclient.rb +69 -58
- data/test/test_jsonclient.rb +18 -0
- data/test/test_ssl.rb +99 -90
- metadata +32 -9
@@ -39,26 +39,28 @@ class HTTPClient
|
|
39
39
|
if SSLEnabled
|
40
40
|
include OpenSSL
|
41
41
|
|
42
|
-
|
43
|
-
module
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
42
|
+
if defined? JRUBY_VERSION
|
43
|
+
module ::OpenSSL
|
44
|
+
module X509
|
45
|
+
class Store
|
46
|
+
attr_reader :_httpclient_cert_store_items
|
47
|
+
|
48
|
+
# TODO: use prepend instead when we drop JRuby + 1.9.x support
|
49
|
+
wrapped = {}
|
50
|
+
|
51
|
+
wrapped[:initialize] = instance_method(:initialize)
|
52
|
+
define_method(:initialize) do |*args|
|
53
|
+
wrapped[:initialize].bind(self).call(*args)
|
54
|
+
@_httpclient_cert_store_items = [ENV['SSL_CERT_FILE'] || :default]
|
55
|
+
end
|
55
56
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
57
|
+
[:add_cert, :add_file, :add_path].each do |m|
|
58
|
+
wrapped[m] = instance_method(m)
|
59
|
+
define_method(m) do |cert|
|
60
|
+
res = wrapped[m].bind(self).call(cert)
|
61
|
+
@_httpclient_cert_store_items << cert
|
62
|
+
res
|
63
|
+
end
|
62
64
|
end
|
63
65
|
end
|
64
66
|
end
|
@@ -66,58 +68,81 @@ class HTTPClient
|
|
66
68
|
end
|
67
69
|
end
|
68
70
|
|
71
|
+
class << self
|
72
|
+
private
|
73
|
+
def attr_config(symbol)
|
74
|
+
name = symbol.to_s
|
75
|
+
ivar_name = "@#{name}"
|
76
|
+
define_method(name) {
|
77
|
+
instance_variable_get(ivar_name)
|
78
|
+
}
|
79
|
+
define_method("#{name}=") { |rhs|
|
80
|
+
if instance_variable_get(ivar_name) != rhs
|
81
|
+
instance_variable_set(ivar_name, rhs)
|
82
|
+
change_notify
|
83
|
+
end
|
84
|
+
}
|
85
|
+
symbol
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
|
69
90
|
CIPHERS_DEFAULT = "ALL:!aNULL:!eNULL:!SSLv2" # OpenSSL >1.0.0 default
|
70
91
|
|
71
92
|
# Which TLS protocol version (also called method) will be used. Defaults
|
72
|
-
# to :auto which means that OpenSSL decides (In my tests this resulted
|
93
|
+
# to :auto which means that OpenSSL decides (In my tests this resulted
|
73
94
|
# with always the highest available protocol being used).
|
74
95
|
# String name of OpenSSL's SSL version method name: TLSv1_2, TLSv1_1, TLSv1,
|
75
96
|
# SSLv2, SSLv23, SSLv3 or :auto (and nil) to allow version negotiation (default).
|
76
97
|
# See {OpenSSL::SSL::SSLContext::METHODS} for a list of available versions
|
77
98
|
# in your specific Ruby environment.
|
78
|
-
|
99
|
+
attr_config :ssl_version
|
79
100
|
# OpenSSL::X509::Certificate:: certificate for SSL client authentication.
|
80
101
|
# nil by default. (no client authentication)
|
81
|
-
|
102
|
+
attr_config :client_cert
|
82
103
|
# OpenSSL::PKey::PKey:: private key for SSL client authentication.
|
83
104
|
# nil by default. (no client authentication)
|
84
|
-
|
85
|
-
|
105
|
+
attr_config :client_key
|
106
|
+
# OpenSSL::PKey::PKey:: private key pass phrase for client_key.
|
107
|
+
# nil by default. (no pass phrase)
|
108
|
+
attr_config :client_key_pass
|
86
109
|
|
87
110
|
# A number which represents OpenSSL's verify mode. Default value is
|
88
111
|
# OpenSSL::SSL::VERIFY_PEER | OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT.
|
89
|
-
|
112
|
+
attr_config :verify_mode
|
90
113
|
# A number of verify depth. Certification path which length is longer than
|
91
114
|
# this depth is not allowed.
|
92
115
|
# CAUTION: this is OpenSSL specific option and ignored on JRuby.
|
93
|
-
|
116
|
+
attr_config :verify_depth
|
94
117
|
# A callback handler for custom certificate verification. nil by default.
|
95
118
|
# If the handler is set, handler.call is invoked just after general
|
96
119
|
# OpenSSL's verification. handler.call is invoked with 2 arguments,
|
97
120
|
# ok and ctx; ok is a result of general OpenSSL's verification. ctx is a
|
98
121
|
# OpenSSL::X509::StoreContext.
|
99
|
-
|
122
|
+
attr_config :verify_callback
|
100
123
|
# SSL timeout in sec. nil by default.
|
101
|
-
|
124
|
+
attr_config :timeout
|
102
125
|
# A number of OpenSSL's SSL options. Default value is
|
103
126
|
# OpenSSL::SSL::OP_ALL | OpenSSL::SSL::OP_NO_SSLv2
|
104
127
|
# CAUTION: this is OpenSSL specific option and ignored on JRuby.
|
105
128
|
# Use ssl_version to specify the TLS version you want to use.
|
106
|
-
|
129
|
+
attr_config :options
|
107
130
|
# A String of OpenSSL's cipher configuration. Default value is
|
108
131
|
# ALL:!ADH:!LOW:!EXP:!MD5:+SSLv2:@STRENGTH
|
109
132
|
# See ciphers(1) man in OpenSSL for more detail.
|
110
|
-
|
133
|
+
attr_config :ciphers
|
111
134
|
|
112
135
|
# OpenSSL::X509::X509::Store used for verification. You can reset the
|
113
136
|
# store with clear_cert_store and set the new store with cert_store=.
|
114
137
|
attr_reader :cert_store # don't use if you don't know what it is.
|
115
138
|
|
116
139
|
# For server side configuration. Ignore this.
|
117
|
-
|
140
|
+
attr_config :client_ca # :nodoc:
|
118
141
|
|
119
142
|
# These array keeps original files/dirs that was added to @cert_store
|
120
|
-
|
143
|
+
if defined? JRUBY_VERSION
|
144
|
+
def cert_store_items; @cert_store._httpclient_cert_store_items; end
|
145
|
+
end
|
121
146
|
attr_reader :cert_store_crl_items
|
122
147
|
|
123
148
|
# Creates a SSLConfig.
|
@@ -126,7 +151,7 @@ class HTTPClient
|
|
126
151
|
@client = client
|
127
152
|
@cert_store = X509::Store.new
|
128
153
|
@cert_store_crl_items = []
|
129
|
-
@client_cert = @client_key = @client_ca = nil
|
154
|
+
@client_cert = @client_key = @client_key_pass = @client_ca = nil
|
130
155
|
@verify_mode = SSL::VERIFY_PEER | SSL::VERIFY_FAIL_IF_NO_PEER_CERT
|
131
156
|
@verify_depth = nil
|
132
157
|
@verify_callback = nil
|
@@ -144,42 +169,18 @@ class HTTPClient
|
|
144
169
|
@cacerts_loaded = false
|
145
170
|
end
|
146
171
|
|
147
|
-
# Sets SSL version method String. Possible values: "SSLv2" for SSL2,
|
148
|
-
# "SSLv3" for SSL3 and TLS1.x, "SSLv23" for SSL3 with fallback to SSL2.
|
149
|
-
def ssl_version=(ssl_version)
|
150
|
-
@ssl_version = ssl_version
|
151
|
-
change_notify
|
152
|
-
end
|
153
|
-
|
154
|
-
# Sets certificate (OpenSSL::X509::Certificate) for SSL client
|
155
|
-
# authentication.
|
156
|
-
# client_key and client_cert must be a pair.
|
157
|
-
#
|
158
|
-
# Calling this method resets all existing sessions.
|
159
|
-
def client_cert=(client_cert)
|
160
|
-
@client_cert = client_cert
|
161
|
-
change_notify
|
162
|
-
end
|
163
|
-
|
164
|
-
# Sets private key (OpenSSL::PKey::PKey) for SSL client authentication.
|
165
|
-
# client_key and client_cert must be a pair.
|
166
|
-
#
|
167
|
-
# Calling this method resets all existing sessions.
|
168
|
-
def client_key=(client_key)
|
169
|
-
@client_key = client_key
|
170
|
-
change_notify
|
171
|
-
end
|
172
|
-
|
173
172
|
# Sets certificate and private key for SSL client authentication.
|
174
173
|
# cert_file:: must be a filename of PEM/DER formatted file.
|
175
174
|
# key_file:: must be a filename of PEM/DER formatted file. Key must be an
|
176
175
|
# RSA key. If you want to use other PKey algorithm,
|
177
176
|
# use client_key=.
|
178
177
|
#
|
179
|
-
# Calling this method resets all existing sessions.
|
178
|
+
# Calling this method resets all existing sessions if value is changed.
|
180
179
|
def set_client_cert_file(cert_file, key_file, pass = nil)
|
181
|
-
@client_cert
|
182
|
-
|
180
|
+
if (@client_cert != cert_file) || (@client_key != key_file) || (@client_key_pass != pass)
|
181
|
+
@client_cert, @client_key, @client_key_pass = cert_file, key_file, pass
|
182
|
+
change_notify
|
183
|
+
end
|
183
184
|
end
|
184
185
|
|
185
186
|
# Sets OpenSSL's default trusted CA certificates. Generally, OpenSSL is
|
@@ -207,7 +208,9 @@ class HTTPClient
|
|
207
208
|
def clear_cert_store
|
208
209
|
@cacerts_loaded = true # avoid lazy override
|
209
210
|
@cert_store = X509::Store.new
|
210
|
-
|
211
|
+
if defined? JRUBY_VERSION
|
212
|
+
@cert_store._httpclient_cert_store_items.clear
|
213
|
+
end
|
211
214
|
change_notify
|
212
215
|
end
|
213
216
|
|
@@ -216,9 +219,12 @@ class HTTPClient
|
|
216
219
|
#
|
217
220
|
# Calling this method resets all existing sessions.
|
218
221
|
def cert_store=(cert_store)
|
219
|
-
|
220
|
-
@cert_store
|
221
|
-
|
222
|
+
# This is object equality check, since OpenSSL::X509::Store doesn't overload ==
|
223
|
+
if !@cacerts_loaded || (@cert_store != cert_store)
|
224
|
+
@cacerts_loaded = true # avoid lazy override
|
225
|
+
@cert_store = cert_store
|
226
|
+
change_notify
|
227
|
+
end
|
222
228
|
end
|
223
229
|
|
224
230
|
# Sets trust anchor certificate(s) for verification.
|
@@ -276,62 +282,6 @@ class HTTPClient
|
|
276
282
|
end
|
277
283
|
alias set_crl add_crl
|
278
284
|
|
279
|
-
# Sets verify mode of OpenSSL. New value must be a combination of
|
280
|
-
# constants OpenSSL::SSL::VERIFY_*
|
281
|
-
#
|
282
|
-
# Calling this method resets all existing sessions.
|
283
|
-
def verify_mode=(verify_mode)
|
284
|
-
@verify_mode = verify_mode
|
285
|
-
change_notify
|
286
|
-
end
|
287
|
-
|
288
|
-
# Sets verify depth. New value must be a number.
|
289
|
-
#
|
290
|
-
# Calling this method resets all existing sessions.
|
291
|
-
def verify_depth=(verify_depth)
|
292
|
-
@verify_depth = verify_depth
|
293
|
-
change_notify
|
294
|
-
end
|
295
|
-
|
296
|
-
# Sets callback handler for custom certificate verification.
|
297
|
-
# See verify_callback.
|
298
|
-
#
|
299
|
-
# Calling this method resets all existing sessions.
|
300
|
-
def verify_callback=(verify_callback)
|
301
|
-
@verify_callback = verify_callback
|
302
|
-
change_notify
|
303
|
-
end
|
304
|
-
|
305
|
-
# Sets SSL timeout in sec.
|
306
|
-
#
|
307
|
-
# Calling this method resets all existing sessions.
|
308
|
-
def timeout=(timeout)
|
309
|
-
@timeout = timeout
|
310
|
-
change_notify
|
311
|
-
end
|
312
|
-
|
313
|
-
# Sets SSL options. New value must be a combination of # constants
|
314
|
-
# OpenSSL::SSL::OP_*
|
315
|
-
#
|
316
|
-
# Calling this method resets all existing sessions.
|
317
|
-
def options=(options)
|
318
|
-
@options = options
|
319
|
-
change_notify
|
320
|
-
end
|
321
|
-
|
322
|
-
# Sets cipher configuration. New value must be a String.
|
323
|
-
#
|
324
|
-
# Calling this method resets all existing sessions.
|
325
|
-
def ciphers=(ciphers)
|
326
|
-
@ciphers = ciphers
|
327
|
-
change_notify
|
328
|
-
end
|
329
|
-
|
330
|
-
def client_ca=(client_ca) # :nodoc:
|
331
|
-
@client_ca = client_ca
|
332
|
-
change_notify
|
333
|
-
end
|
334
|
-
|
335
285
|
def verify?
|
336
286
|
@verify_mode && (@verify_mode & OpenSSL::SSL::VERIFY_PEER != 0)
|
337
287
|
end
|
@@ -459,6 +409,9 @@ class HTTPClient
|
|
459
409
|
return true
|
460
410
|
end
|
461
411
|
|
412
|
+
if pathlen > 2
|
413
|
+
warn('pathlen > 2') if $DEBUG
|
414
|
+
end
|
462
415
|
return false
|
463
416
|
end
|
464
417
|
|
@@ -471,7 +424,6 @@ class HTTPClient
|
|
471
424
|
|
472
425
|
# Use 2048 bit certs trust anchor
|
473
426
|
def load_cacerts(cert_store)
|
474
|
-
ver = OpenSSL::OPENSSL_VERSION
|
475
427
|
file = File.join(File.dirname(__FILE__), 'cacert.pem')
|
476
428
|
add_trust_ca_to_store(cert_store, file)
|
477
429
|
end
|
@@ -14,43 +14,31 @@ class HTTPClient
|
|
14
14
|
# Wraps up OpenSSL::SSL::SSLSocket and offers debugging features.
|
15
15
|
class SSLSocket
|
16
16
|
def self.create_socket(session)
|
17
|
+
opts = {
|
18
|
+
:debug_dev => session.debug_dev
|
19
|
+
}
|
17
20
|
site = session.proxy || session.dest
|
18
21
|
socket = session.create_socket(site.host, site.port)
|
19
22
|
begin
|
20
23
|
if session.proxy
|
21
24
|
session.connect_ssl_proxy(socket, Util.urify(session.dest.to_s))
|
22
25
|
end
|
23
|
-
|
24
|
-
ssl_socket.ssl_connect(session.dest.host)
|
25
|
-
ssl_socket
|
26
|
+
new(socket, session.dest, session.ssl_config, opts)
|
26
27
|
rescue
|
27
28
|
socket.close
|
28
29
|
raise
|
29
30
|
end
|
30
31
|
end
|
31
32
|
|
32
|
-
def initialize(socket,
|
33
|
+
def initialize(socket, dest, config, opts = {})
|
33
34
|
unless SSLEnabled
|
34
35
|
raise ConfigurationError.new('Ruby/OpenSSL module is required')
|
35
36
|
end
|
36
37
|
@socket = socket
|
37
|
-
@
|
38
|
+
@config = config
|
38
39
|
@ssl_socket = create_openssl_socket(@socket)
|
39
|
-
@debug_dev = debug_dev
|
40
|
-
|
41
|
-
|
42
|
-
def ssl_connect(hostname = nil)
|
43
|
-
if hostname && @ssl_socket.respond_to?(:hostname=)
|
44
|
-
@ssl_socket.hostname = hostname
|
45
|
-
end
|
46
|
-
@ssl_socket.connect
|
47
|
-
if $DEBUG
|
48
|
-
if @ssl_socket.respond_to?(:ssl_version)
|
49
|
-
warn("Protocol version: #{@ssl_socket.ssl_version}")
|
50
|
-
end
|
51
|
-
warn("Cipher: #{@ssl_socket.cipher.inspect}")
|
52
|
-
end
|
53
|
-
post_connection_check(hostname)
|
40
|
+
@debug_dev = opts[:debug_dev]
|
41
|
+
ssl_connect(dest.host)
|
54
42
|
end
|
55
43
|
|
56
44
|
def peer_cert
|
@@ -108,8 +96,22 @@ class HTTPClient
|
|
108
96
|
|
109
97
|
private
|
110
98
|
|
99
|
+
def ssl_connect(hostname = nil)
|
100
|
+
if hostname && @ssl_socket.respond_to?(:hostname=)
|
101
|
+
@ssl_socket.hostname = hostname
|
102
|
+
end
|
103
|
+
@ssl_socket.connect
|
104
|
+
if $DEBUG
|
105
|
+
if @ssl_socket.respond_to?(:ssl_version)
|
106
|
+
warn("Protocol version: #{@ssl_socket.ssl_version}")
|
107
|
+
end
|
108
|
+
warn("Cipher: #{@ssl_socket.cipher.inspect}")
|
109
|
+
end
|
110
|
+
post_connection_check(hostname)
|
111
|
+
end
|
112
|
+
|
111
113
|
def post_connection_check(hostname)
|
112
|
-
verify_mode = @
|
114
|
+
verify_mode = @config.verify_mode || OpenSSL::SSL::VERIFY_NONE
|
113
115
|
if verify_mode == OpenSSL::SSL::VERIFY_NONE
|
114
116
|
return
|
115
117
|
elsif @ssl_socket.peer_cert.nil? and
|
@@ -119,7 +121,7 @@ class HTTPClient
|
|
119
121
|
if @ssl_socket.respond_to?(:post_connection_check) and RUBY_VERSION > "1.8.4"
|
120
122
|
@ssl_socket.post_connection_check(hostname)
|
121
123
|
else
|
122
|
-
@
|
124
|
+
@config.post_connection_check(@ssl_socket.peer_cert, hostname)
|
123
125
|
end
|
124
126
|
end
|
125
127
|
|
@@ -131,11 +133,11 @@ class HTTPClient
|
|
131
133
|
ssl_socket = nil
|
132
134
|
if OpenSSL::SSL.const_defined?("SSLContext")
|
133
135
|
ctx = OpenSSL::SSL::SSLContext.new
|
134
|
-
@
|
136
|
+
@config.set_context(ctx)
|
135
137
|
ssl_socket = OpenSSL::SSL::SSLSocket.new(socket, ctx)
|
136
138
|
else
|
137
139
|
ssl_socket = OpenSSL::SSL::SSLSocket.new(socket)
|
138
|
-
@
|
140
|
+
@config.set_context(ssl_socket)
|
139
141
|
end
|
140
142
|
ssl_socket
|
141
143
|
end
|
data/lib/httpclient/util.rb
CHANGED
data/lib/httpclient/version.rb
CHANGED
data/lib/httpclient.rb
CHANGED
@@ -355,6 +355,8 @@ class HTTPClient
|
|
355
355
|
# if your ruby is older than 2005-09-06, do not set socket_sync = false to
|
356
356
|
# avoid an SSL socket blocking bug in openssl/buffering.rb.
|
357
357
|
attr_proxy(:socket_sync, true)
|
358
|
+
# Enables TCP keepalive; no timing settings exist at present
|
359
|
+
attr_proxy(:tcp_keepalive, true)
|
358
360
|
# User-Agent header in HTTP request.
|
359
361
|
attr_proxy(:agent_name, true)
|
360
362
|
# From header in HTTP request.
|
@@ -751,6 +753,10 @@ class HTTPClient
|
|
751
753
|
request(:patch, uri, new_args, &block)
|
752
754
|
end
|
753
755
|
|
756
|
+
# :call-seq:
|
757
|
+
# post(uri, {query: query, body: body, header: header, follow_redirect: follow_redirect}) -> HTTP::Message
|
758
|
+
# post(uri, body, header, follow_redirect) -> HTTP::Message
|
759
|
+
#
|
754
760
|
# Sends POST request to the specified URL. See request for arguments.
|
755
761
|
# You should not depend on :follow_redirect => true for POST method. It
|
756
762
|
# sends the same POST method to the new location which is prohibited in HTTP spec.
|
@@ -1234,7 +1240,7 @@ private
|
|
1234
1240
|
conn.push(res)
|
1235
1241
|
return res
|
1236
1242
|
end
|
1237
|
-
content = block ? nil : ''
|
1243
|
+
content = block ? nil : ''.dup
|
1238
1244
|
res = HTTP::Message.new_response(content, req.header)
|
1239
1245
|
@debug_dev << "= Request\n\n" if @debug_dev
|
1240
1246
|
sess = @session_manager.query(req, proxy)
|
data/lib/jsonclient.rb
CHANGED
@@ -2,7 +2,7 @@ require 'httpclient'
|
|
2
2
|
require 'json'
|
3
3
|
|
4
4
|
# JSONClient auto-converts Hash <-> JSON in request and response.
|
5
|
-
# * For POST or PUT request, convert Hash body to JSON String with 'application/json; charset=utf-8' header.
|
5
|
+
# * For PATCH, POST or PUT request, convert Hash body to JSON String with 'application/json; charset=utf-8' header.
|
6
6
|
# * For response, convert JSON String to Hash when content-type is '(application|text)/(x-)?json'
|
7
7
|
class JSONClient < HTTPClient
|
8
8
|
CONTENT_TYPE_JSON_REGEX = /(application|text)\/(x-)?json/i
|
@@ -17,6 +17,10 @@ class JSONClient < HTTPClient
|
|
17
17
|
@content_type_json_response_regex = CONTENT_TYPE_JSON_REGEX
|
18
18
|
end
|
19
19
|
|
20
|
+
def patch(uri, *args, &block)
|
21
|
+
request(:patch, uri, argument_to_hash_for_json(args), &block)
|
22
|
+
end
|
23
|
+
|
20
24
|
def post(uri, *args, &block)
|
21
25
|
request(:post, uri, argument_to_hash_for_json(args), &block)
|
22
26
|
end
|
@@ -37,7 +41,7 @@ private
|
|
37
41
|
|
38
42
|
def argument_to_hash_for_json(args)
|
39
43
|
hash = argument_to_hash(args, :body, :header, :follow_redirect)
|
40
|
-
if hash[:body].is_a?(Hash)
|
44
|
+
if hash[:body].is_a?(Hash) || hash[:body].is_a?(Array)
|
41
45
|
hash[:header] = json_header(hash[:header])
|
42
46
|
hash[:body] = JSON.generate(hash[:body])
|
43
47
|
end
|
@@ -47,11 +51,10 @@ private
|
|
47
51
|
def json_header(header)
|
48
52
|
header ||= {}
|
49
53
|
if header.is_a?(Hash)
|
50
|
-
header
|
54
|
+
header.merge('Content-Type' => @content_type_json_request)
|
51
55
|
else
|
52
|
-
header
|
56
|
+
header + [['Content-Type', @content_type_json_request]]
|
53
57
|
end
|
54
|
-
header
|
55
58
|
end
|
56
59
|
|
57
60
|
def wrap_json_response(original)
|
data/sample/auth.rb
CHANGED
@@ -7,5 +7,5 @@ c.debug_dev = STDOUT
|
|
7
7
|
#c.set_proxy_auth("admin", "admin")
|
8
8
|
|
9
9
|
# for WWW authentication: supports Basic, Digest and Negotiate.
|
10
|
-
c.set_auth("http://dev.ctor.org/http-access2/", "
|
10
|
+
c.set_auth("http://dev.ctor.org/http-access2/", "username", "password")
|
11
11
|
p c.get("http://dev.ctor.org/http-access2/login")
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require "openssl"
|
2
|
+
|
3
|
+
def build_ca
|
4
|
+
root_key = OpenSSL::PKey::RSA.new 2048 # the CA's public/private key
|
5
|
+
root_ca = OpenSSL::X509::Certificate.new
|
6
|
+
root_ca.version = 2 # cf. RFC 5280 - to make it a "v3" certificate
|
7
|
+
root_ca.serial = 1
|
8
|
+
root_ca.subject = OpenSSL::X509::Name.parse "C=JP,O=JIN.GR.JP,OU=RRR,CN=CA"
|
9
|
+
root_ca.issuer = root_ca.subject # root CA's are "self-signed"
|
10
|
+
root_ca.public_key = root_key.public_key
|
11
|
+
root_ca.not_before = Time.now
|
12
|
+
root_ca.not_after = root_ca.not_before + 10 * 365 * 24 * 60 * 60 # 10 years validity
|
13
|
+
ef = OpenSSL::X509::ExtensionFactory.new
|
14
|
+
ef.subject_certificate = root_ca
|
15
|
+
ef.issuer_certificate = root_ca
|
16
|
+
root_ca.add_extension(ef.create_extension("basicConstraints","CA:TRUE",true))
|
17
|
+
root_ca.add_extension(ef.create_extension("keyUsage","keyCertSign, cRLSign", true))
|
18
|
+
root_ca.add_extension(ef.create_extension("subjectKeyIdentifier","hash",false))
|
19
|
+
root_ca.add_extension(ef.create_extension("authorityKeyIdentifier","keyid:always",false))
|
20
|
+
root_ca.sign(root_key, OpenSSL::Digest::SHA256.new)
|
21
|
+
[root_key, root_ca]
|
22
|
+
end
|
23
|
+
|
24
|
+
root_key, root_ca = build_ca
|
25
|
+
|
26
|
+
File.write("test/ca.cert", root_ca.to_s)
|
27
|
+
File.write("test/ca.key", root_key.to_s)
|
28
|
+
|
29
|
+
def sub_cert(root_key, root_ca, cn, intermediate: false)
|
30
|
+
key = OpenSSL::PKey::RSA.new 2048
|
31
|
+
cert = OpenSSL::X509::Certificate.new
|
32
|
+
cert.version = 2
|
33
|
+
cert.serial = 2
|
34
|
+
cert.subject = OpenSSL::X509::Name.parse "C=JP,O=JIN.GR.JP,OU=RRR,CN=#{cn}"
|
35
|
+
cert.issuer = root_ca.subject # root CA is the issuer
|
36
|
+
cert.public_key = key.public_key
|
37
|
+
cert.not_before = Time.now
|
38
|
+
cert.not_after = cert.not_before + 9 * 365 * 24 * 60 * 60 # 9 years validity
|
39
|
+
ef = OpenSSL::X509::ExtensionFactory.new
|
40
|
+
ef.subject_certificate = cert
|
41
|
+
ef.issuer_certificate = root_ca
|
42
|
+
cert.add_extension(ef.create_extension("subjectKeyIdentifier","hash",false))
|
43
|
+
if intermediate
|
44
|
+
cert.add_extension(ef.create_extension("keyUsage","keyCertSign, cRLSign", true))
|
45
|
+
cert.add_extension(ef.create_extension("basicConstraints","CA:TRUE",true))
|
46
|
+
else
|
47
|
+
cert.add_extension(ef.create_extension("keyUsage","digitalSignature, keyEncipherment", true))
|
48
|
+
cert.add_extension(ef.create_extension("extendedKeyUsage", "serverAuth"))
|
49
|
+
end
|
50
|
+
cert.sign(root_key, OpenSSL::Digest::SHA256.new)
|
51
|
+
[key, cert]
|
52
|
+
end
|
53
|
+
|
54
|
+
sub_key, sub_cert = sub_cert(root_key, root_ca, "SubCA", intermediate: true)
|
55
|
+
File.write("test/subca.cert", sub_cert.to_s)
|
56
|
+
File.write("test/subca.key", sub_key.to_s)
|
57
|
+
|
58
|
+
server_key, server_cert = sub_cert(sub_key, sub_cert, "localhost")
|
59
|
+
File.write("test/server.cert", server_cert.to_s)
|
60
|
+
File.write("test/server.key", server_key.to_s)
|
61
|
+
|
62
|
+
client_key, client_cert = sub_cert(root_key, root_ca, "localhost")
|
63
|
+
File.write("test/client.cert", client_cert.to_s)
|
64
|
+
File.write("test/client.key", client_key.to_s)
|
65
|
+
|
66
|
+
system(
|
67
|
+
"openssl", "rsa", "-aes256",
|
68
|
+
"-in", "test/client.key",
|
69
|
+
"-out", "test/client-pass.key",
|
70
|
+
"-passout", "pass:pass4key",
|
71
|
+
)
|
72
|
+
|
73
|
+
File.write("test/ca-chain.pem", root_ca.to_s + sub_cert.to_s)
|
74
|
+
|
75
|
+
verify_key = OpenSSL::PKey::RSA.new 2048
|
76
|
+
File.write("test/fixtures/verify.key", verify_key.to_s)
|
77
|
+
|
78
|
+
def build_self_signed(key, cn)
|
79
|
+
cert = OpenSSL::X509::Certificate.new
|
80
|
+
cert.version = 2
|
81
|
+
cert.serial = 2
|
82
|
+
cert.subject = OpenSSL::X509::Name.parse "C=JP,O=JIN.GR.JP,OU=RRR,CN=#{cn}"
|
83
|
+
cert.issuer = cert.subject
|
84
|
+
cert.public_key = key.public_key
|
85
|
+
cert.not_before = Time.now
|
86
|
+
cert.not_after = cert.not_before + 9 * 365 * 24 * 60 * 60 # 9 years validity
|
87
|
+
ef = OpenSSL::X509::ExtensionFactory.new
|
88
|
+
ef.subject_certificate = cert
|
89
|
+
ef.issuer_certificate = cert
|
90
|
+
cert.add_extension(ef.create_extension("subjectKeyIdentifier","hash",false))
|
91
|
+
cert.add_extension(ef.create_extension("keyUsage","digitalSignature, keyEncipherment", true))
|
92
|
+
cert.add_extension(ef.create_extension("extendedKeyUsage", "serverAuth"))
|
93
|
+
cert.sign(key, OpenSSL::Digest::SHA256.new)
|
94
|
+
cert
|
95
|
+
end
|
96
|
+
|
97
|
+
File.write("test/fixtures/verify.localhost.cert", build_self_signed(verify_key, "localhost").to_s)
|
98
|
+
File.write("test/fixtures/verify.foo.cert", build_self_signed(verify_key, "foo").to_s)
|
99
|
+
File.write("test/fixtures/verify.alt.cert", build_self_signed(verify_key, "alt").to_s)
|