httpi-adapter-openssl_gost 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 7246e71d3ac930e54148951c0f832c4e285fb70b
4
+ data.tar.gz: 0e1b4be04689555e7eeba4664beb366877713fe7
5
+ SHA512:
6
+ metadata.gz: 7fd06b785759998e6ec5893f7c2d5292e452f3c9416241c66cbed363861db8da28ab61acd0ff57f122c691f01c844ffc7a713921a9ce8acacefc79f119175349
7
+ data.tar.gz: e1c2581189f1bb79158f416c565b2b74ea4a678484c30c0092fcdcc665aec3e86d80a50a2c986e0e05cc317a62c896a6562ac22fdf30c77b946f46d891075e63
data/.gitignore ADDED
@@ -0,0 +1,22 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in httpi-adapter-openssl_gost.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Andrey Novikov
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,121 @@
1
+ OpenSSL GOST adapter for [HTTPI]
2
+ ================================
3
+
4
+ This gem allows to perform HTTP requests over secure connections, that requires russian GOST cryptoalgorithms to be used.
5
+ It allows to use client certificate and private key for authentication.
6
+
7
+ **WARNING!** This gem is kind of «last chance software». It uses `openssl s_client` command to perform requests.
8
+ As it's command for debug and testing purposes only, it's slow and unreliable. Use at your own risk only if nothing else is working for you (as it for me).
9
+
10
+ ## Installation
11
+
12
+ ### OpenSSL installation and configuration
13
+
14
+ You need to install OpenSSL 1.0.0 or newer (OpenSSL 1.0.1 or newer is better) with GOST engine installed (it's bundled starting from 1.0.0).
15
+
16
+ Usually in modern Lunux distributions it's installed already (at least in Ubuntu 12.04).
17
+ Mac OS X users should install it through Homebrew or MacPorts: `brew install openssl`
18
+
19
+ In `/etc/ssl/openssl.cnf` (`/usr/local/etc/openssl/openssl.cnf` for Mac OS X) add next line to _the very beginning of file_:
20
+
21
+ openssl_conf = openssl_def
22
+
23
+ Add next lines to _the very end of file_:
24
+
25
+ [openssl_def]
26
+ engines = engine_section
27
+ [engine_section]
28
+ gost = gost_section
29
+ [gost_section]
30
+ default_algorithms = ALL
31
+ dynamic_path = /usr/lib/x86_64-linux-gnu/openssl-1.0.0/engines/libgost.so
32
+ engine_id = gost
33
+ CRYPT_PARAMS = id-Gost28147-89-CryptoPro-A-ParamSet
34
+
35
+ `dynamic_path` isn't required in Mac OS X. Linux users can get it's value executing `locate libgost.so`.
36
+
37
+ After that, `openssl ciphers | tr ":" "\n" | grep GOST` should return following lines:
38
+
39
+ GOST2001-GOST89-GOST89
40
+ GOST94-GOST89-GOST89
41
+
42
+ ### Gem installation
43
+
44
+ Add this line to your application's Gemfile:
45
+
46
+ gem 'httpi-adapter-openssl_gost'
47
+
48
+ And then execute:
49
+
50
+ $ bundle
51
+
52
+ Or install it yourself as:
53
+
54
+ $ gem install httpi-adapter-openssl_gost
55
+
56
+ ## Usage
57
+
58
+ ```ruby
59
+ require 'httpi/adapter/openssl_gost'
60
+ request = HTTPI::Request.new
61
+ request.url = 'https://example.com/'
62
+ HTTPI.get(request, :openssl_gost)
63
+ ```
64
+
65
+ Or you can specify it as default adapter for all requests:
66
+
67
+ ```ruby
68
+ require 'httpi/adapter/openssl_gost'
69
+ HTTPI.adapter :openssl_gost
70
+ ```
71
+
72
+ If you need to specify client credentials (certificate and private key),
73
+ pass file paths to `cert_file=` and `cert_key_file=` methods of the `request.auth.ssl`:
74
+
75
+ ```ruby
76
+ request.auth.ssl.cert_file = '/full/path/to/client.crt'
77
+ request.auth.ssl.cert_key_file = '/full/path/to/client.pem'
78
+ ```
79
+
80
+ ### Usage with savon
81
+
82
+ You need to use custom branches of [savon] and [wasabi] until next pull requests are not merged in:
83
+ 1. [savonrb/wasabi#44](https://github.com/savonrb/wasabi/issues/44)
84
+ 2. [savonrb/savon#566](https://github.com/savonrb/savon/pull/566):
85
+
86
+ Place in your Gemfile:
87
+
88
+ ```ruby
89
+ gem 'wasabi', github: 'Envek/wasabi', branch: 'specify_adapter'
90
+ gem 'savon', github: 'Envek/savon', branch: 'specify_adapter'
91
+ ```
92
+
93
+ Specify `:adapter` in savon client global options:
94
+
95
+ ```ruby
96
+ require 'httpi/adapter/openssl_gost'
97
+ soap_client = Savon.client(
98
+ wsdl: 'https://service-requiring-gost.ru/service?wsdl',
99
+ ssl_cert_file: '/full/path/to/client.crt',
100
+ ssl_cert_key_file: '/full/path/to/client.pem',
101
+ adapter: :openssl_gost,
102
+ )
103
+ ```
104
+
105
+ And use it as usual:
106
+
107
+ ```ruby
108
+ soap_client.call(:method, message: {foo: 1})
109
+ ```
110
+
111
+ ## Contributing
112
+
113
+ 1. Fork it ( https://github.com/Envek/httpi-adapter-openssl_gost/fork )
114
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
115
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
116
+ 4. Push to the branch (`git push origin my-new-feature`)
117
+ 5. Create a new Pull Request
118
+
119
+ [HTTPI]: https://github.com/savonrb/httpi
120
+ [savon]: https://github.com/savonrb/savon
121
+ [wasabi]: https://github.com/savonrb/wasabi
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require 'bundler/gem_tasks'
2
+
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'httpi/adapter/openssl_gost/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'httpi-adapter-openssl_gost'
8
+ spec.version = HTTPI::Adapter::OpensslGost::VERSION
9
+ spec.authors = ['Andrey Novikov']
10
+ spec.email = ['envek@envek.name']
11
+ spec.summary = 'HTTPI adapter for accessing HTTPS servers with GOST algorithms and certificates'
12
+ spec.description = 'It uses OpenSSL `s_client` command to securely connect with server that requires usage of GOST algorithms and client certificates.'
13
+ spec.homepage = 'https://github.com/Envek/httpi-adapter-openssl_gost'
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ['lib']
20
+
21
+ spec.requirements << 'OpenSSL 1.0.0 and newer with GOST engine installed, enabled, and configured.'
22
+ spec.add_dependency 'httpi', '~> 2.0'
23
+
24
+ spec.add_development_dependency 'bundler', '~> 1.6'
25
+ spec.add_development_dependency 'rake', '~> 10'
26
+ end
@@ -0,0 +1,78 @@
1
+ require 'httpi'
2
+ require 'open3'
3
+ require 'httpi/adapter/openssl_gost/version'
4
+
5
+ module HTTPI
6
+ module Adapter
7
+ class OpensslGost < Base
8
+
9
+ register :openssl_gost
10
+
11
+ def initialize(request)
12
+ @request = request
13
+ @pubkey_path = request.auth.ssl.cert_file
14
+ @privkey_path = request.auth.ssl.cert_key_file
15
+ end
16
+
17
+ attr_reader :client
18
+ attr_accessor :pubkey_path
19
+ attr_accessor :privkey_path
20
+
21
+ def request(method)
22
+ uri = @request.url
23
+ cmd = "openssl s_client -engine gost -connect '#{uri.host}:#{uri.port}' -quiet"
24
+ cmd += " -cert '#{pubkey_path}'" if pubkey_path
25
+ cmd += " -key '#{privkey_path}'" if privkey_path
26
+
27
+ # Prepare request
28
+ req = "#{method.upcase} #{uri.request_uri} HTTP/1.1\r\n"
29
+ headers = @request.headers.map{|k,v| "#{k}: #{v}\r\n" }.join
30
+ # Set up Content-Length header if body present (HTTPI doesn't it for us)
31
+ if @request.body and !@request.headers['Content-Length']
32
+ headers += "Content-Length: #{@request.body.bytesize}\r\n"
33
+ end
34
+ # Add hostname header and explicitly close connection (we need command to exit immediately)
35
+ headers += "Host: #{uri.host}\r\nConnection: close\r\n\r\n"
36
+ req += headers
37
+ req += "#{@request.body}\r\n\r\n" if @request.body
38
+
39
+ # Send request, get answer
40
+ HTTPI.logger.debug "Connecting to server with command: #{cmd}"
41
+ HTTPI.logger.debug "Sending request:\r\n#{req}"
42
+ retries = 0
43
+ begin
44
+ raw_response, openssl_stderr, status = Open3.capture3(cmd, stdin_data: req, binmode: true)
45
+ rescue Errno::EPIPE # Sometimes fails with no reason
46
+ retry if retries+=1 < 3
47
+ end
48
+
49
+ # Check whether command finished correctly and prepare response
50
+ if status.success?
51
+ HTTPI.logger.debug "Received response:\r\n#{raw_response}"
52
+ status_string, headers_and_body = raw_response.split("\r\n", 2)
53
+ response_headers, response_body = headers_and_body.split("\r\n\r\n", 2)
54
+ response_code = status_string.scan(/\d{3}/).first
55
+ response_headers = Hash[response_headers.split("\r\n").map{|h| h.split(':', 2).map(&:strip) }]
56
+ HTTPI::Response.new(response_code, response_headers, response_body)
57
+ else
58
+ HTTPI.logger.fatal "While connecting to server #{uri.host} with command: #{cmd}"
59
+ HTTPI.logger.fatal "Command returned:\r\n#{status.inspect}"
60
+ HTTPI.logger.fatal "STDERR is:\n#{openssl_stderr}"
61
+ # OpenSSL's s_client always return 1 on fail, try to catch most common errors
62
+ case openssl_stderr
63
+ when /connect:errno=60/ then raise HTTPI::TimeoutError
64
+ when /connect:errno=61/ then raise (HTTPI::Error.new).extend(HTTPI::ConnectionError) # Connection refused
65
+ when /connect:errno=2/ then raise (HTTPI::Error.new).extend(HTTPI::ConnectionError) # No DNS name found
66
+ when /ssl handshake failure/ then raise HTTPI::SSLError, 'Seems like you trying to connect to HTTP, not HTTPS'
67
+ when /missing dsa signing cert/ then raise HTTPI::SSLError, 'Probably your OpenSSL lacks GOST configuration'
68
+ when /unable to load certificate/ then raise HTTPI::SSLError, 'Can not load client certificate, check file path and access rights'
69
+ when /unable to load .*? private key/ then raise HTTPI::SSLError, 'Can not load client certificate private key, check file path and access rights'
70
+ else raise HTTPI::Error
71
+ end
72
+ end
73
+
74
+ end
75
+
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,9 @@
1
+ require 'httpi'
2
+
3
+ module HTTPI
4
+ module Adapter
5
+ class OpensslGost < Base
6
+ VERSION = '0.0.1'
7
+ end
8
+ end
9
+ end
metadata ADDED
@@ -0,0 +1,96 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: httpi-adapter-openssl_gost
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Andrey Novikov
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-04-27 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: httpi
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '2.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '2.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '1.6'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '1.6'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '10'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '10'
55
+ description: It uses OpenSSL `s_client` command to securely connect with server that
56
+ requires usage of GOST algorithms and client certificates.
57
+ email:
58
+ - envek@envek.name
59
+ executables: []
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - .gitignore
64
+ - Gemfile
65
+ - LICENSE.txt
66
+ - README.md
67
+ - Rakefile
68
+ - httpi-adapter-openssl_gost.gemspec
69
+ - lib/httpi/adapter/openssl_gost.rb
70
+ - lib/httpi/adapter/openssl_gost/version.rb
71
+ homepage: https://github.com/Envek/httpi-adapter-openssl_gost
72
+ licenses:
73
+ - MIT
74
+ metadata: {}
75
+ post_install_message:
76
+ rdoc_options: []
77
+ require_paths:
78
+ - lib
79
+ required_ruby_version: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - '>='
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ required_rubygems_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - '>='
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ requirements:
90
+ - OpenSSL 1.0.0 and newer with GOST engine installed, enabled, and configured.
91
+ rubyforge_project:
92
+ rubygems_version: 2.2.2
93
+ signing_key:
94
+ specification_version: 4
95
+ summary: HTTPI adapter for accessing HTTPS servers with GOST algorithms and certificates
96
+ test_files: []