ibanity 1.4 → 1.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +3 -0
- data/CHANGELOG.md +9 -0
- data/lib/ibanity/http_signature.rb +23 -18
- data/lib/ibanity/version.rb +1 -1
- data/spec/lib/ibanity/http_signature_spec.rb +39 -0
- data/spec/spec_helper.rb +2 -0
- data/spec/support/crypto_helper.rb +21 -0
- data/spec/support/fixtures/signature/test-certificate.pem +21 -0
- data/spec/support/fixtures/signature/test-private_key.pem +28 -0
- data/spec/support/fixtures/signature/test-public_key.pem +9 -0
- metadata +12 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8764b1c890efb8ca4d619b84264ba4fcd0a10cdbd6d1fd505da2b733662d329c
|
4
|
+
data.tar.gz: a44447ecf5aec8045ade36f08702f8a134f98d5eff010843ba730902dfd0552e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8a30ada191b9256e197c851ff8c09dd9cfc89c3b72ac28c0c726da288dd925868c944f7f461cd40af55a28499ae7581718e2ef4a471dd36531e312b776c7fca1
|
7
|
+
data.tar.gz: 94d709de117a166321a587cf5db08b2fea8657547fc4a3dd1cf2844c68db4d9fa63d72ed3a2d56f43639c31400831ab611ac6081d545835af2146bfd09f60248
|
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## 1.5
|
4
|
+
|
5
|
+
* Proper release of previous enhancements
|
6
|
+
|
7
|
+
## 1.4
|
8
|
+
|
9
|
+
*Don't use this version as it was not properly released !*
|
10
|
+
|
3
11
|
## 1.3
|
4
12
|
|
5
13
|
### Enhancements
|
@@ -10,6 +18,7 @@
|
|
10
18
|
|
11
19
|
### Enhancements
|
12
20
|
|
21
|
+
* Default signature algorithm is now ["hs2019"](https://tools.ietf.org/html/draft-cavage-http-signatures-12#appendix-E.2)
|
13
22
|
* Add support for periodic and bulk payments
|
14
23
|
* Add snake-case transformation for deeply nested data structures
|
15
24
|
|
@@ -2,6 +2,9 @@ require "base64"
|
|
2
2
|
|
3
3
|
module Ibanity
|
4
4
|
class HttpSignature
|
5
|
+
PSS_DIGEST_ALGORITHM = "SHA256"
|
6
|
+
SIGNATURE_ALGORITHM = "hs2019"
|
7
|
+
|
5
8
|
def initialize(certificate:, certificate_id:, key:, method:, uri:, query_params:, headers:, payload:)
|
6
9
|
@certificate = certificate
|
7
10
|
@certificate_id = certificate_id
|
@@ -13,6 +16,21 @@ module Ibanity
|
|
13
16
|
@query_params = query_params
|
14
17
|
end
|
15
18
|
|
19
|
+
def signature_headers
|
20
|
+
{
|
21
|
+
"Digest" => payload_digest,
|
22
|
+
"Signature" => [
|
23
|
+
%(keyId="#{@certificate_id}"),
|
24
|
+
%(created="#{date}"),
|
25
|
+
%(algorithm="#{SIGNATURE_ALGORITHM}"),
|
26
|
+
%(headers="#{headers_to_sign.join(" ")}"),
|
27
|
+
%(signature="#{base64_signature}"),
|
28
|
+
].join(",")
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
16
34
|
def payload_digest
|
17
35
|
digest = OpenSSL::Digest::SHA512.new
|
18
36
|
string_payload = @payload.nil? ? "" : @payload
|
@@ -21,12 +39,8 @@ module Ibanity
|
|
21
39
|
"SHA-512=#{base64}"
|
22
40
|
end
|
23
41
|
|
24
|
-
def signature_algorithm
|
25
|
-
@certificate.signature_algorithm.match("sha256") ? "rsa-sha256" : "rsa-sha512"
|
26
|
-
end
|
27
|
-
|
28
42
|
def headers_to_sign
|
29
|
-
result = ["(request-target)", "host", "digest", "
|
43
|
+
result = ["(request-target)", "host", "digest", "(created)"]
|
30
44
|
result << "authorization" unless @headers["Authorization"].nil?
|
31
45
|
@headers.keys.each do |header|
|
32
46
|
result << header.to_s.downcase if header.to_s.match(/ibanity/i)
|
@@ -40,8 +54,7 @@ module Ibanity
|
|
40
54
|
end
|
41
55
|
|
42
56
|
def base64_signature
|
43
|
-
|
44
|
-
signature = @key.sign(digest, signing_string)
|
57
|
+
signature = @key.sign_pss(PSS_DIGEST_ALGORITHM, signing_string, salt_length: :digest, mgf1_hash: PSS_DIGEST_ALGORITHM)
|
45
58
|
Base64.urlsafe_encode64(signature)
|
46
59
|
end
|
47
60
|
|
@@ -50,13 +63,13 @@ module Ibanity
|
|
50
63
|
end
|
51
64
|
|
52
65
|
def date
|
53
|
-
@date ||= Time.now.
|
66
|
+
@date ||= Time.now.to_i
|
54
67
|
end
|
55
68
|
|
56
69
|
def signing_string
|
57
70
|
result = []
|
58
71
|
headers_to_sign.each do |header_to_sign|
|
59
|
-
value
|
72
|
+
value = header_value(header_to_sign)
|
60
73
|
result << "#{header_to_sign}: #{value}"
|
61
74
|
end
|
62
75
|
result.join("\n")
|
@@ -70,20 +83,12 @@ module Ibanity
|
|
70
83
|
host
|
71
84
|
when "digest"
|
72
85
|
payload_digest
|
73
|
-
when "
|
86
|
+
when "(created)"
|
74
87
|
date
|
75
88
|
else
|
76
89
|
camelized_header = header.split("-").collect(&:capitalize).join("-")
|
77
90
|
@headers[camelized_header]
|
78
91
|
end
|
79
92
|
end
|
80
|
-
|
81
|
-
def signature_headers
|
82
|
-
{
|
83
|
-
"Date" => date,
|
84
|
-
"Digest" => payload_digest,
|
85
|
-
"Signature" => "keyId=\"#{@certificate_id}\" algorithm=\"#{signature_algorithm}\" headers=\"#{headers_to_sign.join(" ")}\" signature=\"#{base64_signature}\""
|
86
|
-
}
|
87
|
-
end
|
88
93
|
end
|
89
94
|
end
|
data/lib/ibanity/version.rb
CHANGED
@@ -0,0 +1,39 @@
|
|
1
|
+
require "ibanity/http_signature"
|
2
|
+
|
3
|
+
RSpec.describe Ibanity::HttpSignature do
|
4
|
+
|
5
|
+
describe ".signature_headers" do
|
6
|
+
let(:signature) do
|
7
|
+
Ibanity::HttpSignature.new(
|
8
|
+
certificate: CryptoHelper.load_certificate("test"),
|
9
|
+
certificate_id: "ec0c29ef-3b39-4b6f-93ff-866bed032399",
|
10
|
+
key: CryptoHelper.load_private_key("test"),
|
11
|
+
method: "post",
|
12
|
+
uri: "https://api.ibanity.com/xs2a/customer-access-tokens",
|
13
|
+
headers: {"ibanity-idempotency-key" => "cf17b515-5f6f-4213-a8fe-e4cd40653d00"},
|
14
|
+
payload: "{\"foo\": \"bar\"}",
|
15
|
+
query_params: {}
|
16
|
+
)
|
17
|
+
end
|
18
|
+
|
19
|
+
let(:parts_regex) do
|
20
|
+
/keyId="(?<keyId>.*)",\s?created="(?<created>.*)?",?\s?algorithm="(?<algorithm>.*)",\s?headers="(?<headers>.*)",?\s?signature="(?<signature>.*)"/
|
21
|
+
end
|
22
|
+
|
23
|
+
let(:signature_parts) do
|
24
|
+
signature.signature_headers["Signature"].match(parts_regex).named_captures
|
25
|
+
end
|
26
|
+
|
27
|
+
["Digest", "Signature"].each do |header|
|
28
|
+
it "contains the '#{header}' header" do
|
29
|
+
expect(signature.signature_headers).to include(header)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
["keyId", "algorithm", "headers", "signature", "created"].each do |part|
|
34
|
+
it "has a signature containing the part '#{part}'" do
|
35
|
+
expect(signature_parts).to include(part)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -13,6 +13,8 @@
|
|
13
13
|
# it.
|
14
14
|
#
|
15
15
|
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
16
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
|
17
|
+
|
16
18
|
RSpec.configure do |config|
|
17
19
|
# rspec-expectations config goes here. You can use an alternate
|
18
20
|
# assertion/expectation library such as wrong or the stdlib/minitest
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require "pathname"
|
2
|
+
require "openssl"
|
3
|
+
|
4
|
+
module CryptoHelper
|
5
|
+
FIXTURE_DIRECTORY = Pathname.getwd().join("spec", "support", "fixtures", "signature")
|
6
|
+
|
7
|
+
def self.load_certificate(name)
|
8
|
+
pem = File.read(FIXTURE_DIRECTORY.join("#{name}-certificate.pem"))
|
9
|
+
::OpenSSL::X509::Certificate.new(pem)
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.load_public_key(name)
|
13
|
+
pem = File.read(FIXTURE_DIRECTORY.join("#{name}-public_key.pem"))
|
14
|
+
::OpenSSL::PKey::RSA.new(pem)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.load_private_key(name)
|
18
|
+
pem = File.read(FIXTURE_DIRECTORY.join("#{name}-private_key.pem"))
|
19
|
+
::OpenSSL::PKey::RSA.new(pem)
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
2
|
+
MIIDdjCCAl4CCQCxpvuEfl5slTANBgkqhkiG9w0BAQsFADB9MQswCQYDVQQGEwJC
|
3
|
+
RTERMA8GA1UECAwIQnJ1c3NlbHMxETAPBgNVBAcMCEJydXNzZWxzMRAwDgYDVQQK
|
4
|
+
DAdJYmFuaXR5MRMwEQYDVQQDDAppYmFuaXR5LmJlMSEwHwYJKoZIhvcNAQkBFhJj
|
5
|
+
b21wYW55QGliYW5pdHkuYmUwHhcNMTkwNjI3MTE1NjAyWhcNMjkwNjI0MTE1NjAy
|
6
|
+
WjB9MQswCQYDVQQGEwJCRTERMA8GA1UECAwIQnJ1c3NlbHMxETAPBgNVBAcMCEJy
|
7
|
+
dXNzZWxzMRAwDgYDVQQKDAdJYmFuaXR5MRMwEQYDVQQDDAppYmFuaXR5LmJlMSEw
|
8
|
+
HwYJKoZIhvcNAQkBFhJjb21wYW55QGliYW5pdHkuYmUwggEiMA0GCSqGSIb3DQEB
|
9
|
+
AQUAA4IBDwAwggEKAoIBAQDcaDiqP4EkTYXzDqCLZGiEEQnx0iazY/f3IMZNnYVf
|
10
|
+
BDSLl3m2x1+3ch4Pe/E35Aag1webnvDh/VVRch0+n4KV/4Toe0Oq9VP6xKqOXYtZ
|
11
|
+
ZAVWXzs1TjdT/dk+rRXa+wnyq2KklPJ0aowzAyr3EzivW1v19uhWdqguhPEPopr/
|
12
|
+
2sue3vloZrigamOov29iFkiFLtSqAyEZI7x48w/3X2nkZ1UivYxBRrLnulVMUJDZ
|
13
|
+
zvydu3stlu6mSlaQ3Mpdgzyz4V41NImzNeJnW1F6riwd6hud9xokDZSvredC/XhM
|
14
|
+
byl0LdrKABzyHnOFSBlIkIHDeQUPa9YKBESRMtOVmyrvAgMBAAEwDQYJKoZIhvcN
|
15
|
+
AQELBQADggEBAKMwFzfoXXxasB/6ZlnAMy7aWmb8xp55E6aZZoZXhoHHA03z+Jj2
|
16
|
+
cVy/PMgNDOk5MLf4ddpj7iVf42iLAGpgqo0oQjE11UCwYBBDIQ3vjR+MctoN2B+L
|
17
|
+
Qpx7OGDoqSnVucVTS9KmWbJM3PAfbeexSRfqRJ3Jn2DvQDx1k32L//KtP1FRMtku
|
18
|
+
Dqoizz7NSLjrmIkXLAuepKdfDSVKnLHD1fB6gKvDNPBNivlFqceZe0XoXdlGwZcC
|
19
|
+
7aTdzYzZNCbg1w1bTxv7dom3ubAM1DPKUEA3afW25691ZsBf9W52hb/tOlVOw78j
|
20
|
+
+gUJtiEKTkcfmrfCgPDrcDjsm+iaQclAhK4=
|
21
|
+
-----END CERTIFICATE-----
|
@@ -0,0 +1,28 @@
|
|
1
|
+
-----BEGIN PRIVATE KEY-----
|
2
|
+
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDcaDiqP4EkTYXz
|
3
|
+
DqCLZGiEEQnx0iazY/f3IMZNnYVfBDSLl3m2x1+3ch4Pe/E35Aag1webnvDh/VVR
|
4
|
+
ch0+n4KV/4Toe0Oq9VP6xKqOXYtZZAVWXzs1TjdT/dk+rRXa+wnyq2KklPJ0aowz
|
5
|
+
Ayr3EzivW1v19uhWdqguhPEPopr/2sue3vloZrigamOov29iFkiFLtSqAyEZI7x4
|
6
|
+
8w/3X2nkZ1UivYxBRrLnulVMUJDZzvydu3stlu6mSlaQ3Mpdgzyz4V41NImzNeJn
|
7
|
+
W1F6riwd6hud9xokDZSvredC/XhMbyl0LdrKABzyHnOFSBlIkIHDeQUPa9YKBESR
|
8
|
+
MtOVmyrvAgMBAAECggEAOS3olXJIJIzgFUBUMhVob+qjs9KbK6rhp4EfMP+OnCnR
|
9
|
+
H+26K8rpcAPw/H9hAujrN0rRtHO1dktsmOaL47UqAZP6fP2NfoqKsOHYhXqLLjOe
|
10
|
+
ltu51ohmHioa9AGfS+IYoJYJzzy88aq6mHlX6iVYbVW8M8FMYTIDS549k5rRr1Iu
|
11
|
+
SqGQSoIo8vGKhMyp6UbIvBhx1CRs2xeoknL0H5uEHnqB6oJTqfnbkQ1sVX4vZuHl
|
12
|
+
+WOIKQPlFKy74Lcs9ap1Dr9llD/PoVB3b2KbLRJTda352ezMLspb6CVUOFw7S0eB
|
13
|
+
vHVFlR+V922GaMvEmxZ58ZY+DwqBGPeuiG7/kYFNAQKBgQD8e64NptLgw7Wk8mvn
|
14
|
+
tGTB28ycUkc9wT/NdiePqlUT56ynD4oCBGcbEu6hH5ntYR93Kpi7fINTKglkVGdK
|
15
|
+
MkU/QOV0bs7wItqmQvkMeUbypnWXeQPICs3z/synytwbDYl7/FslTPxdjAgodQZJ
|
16
|
+
FY3Lui9bqe05VjvefEtEb9/yrwKBgQDfeimt/bVmA6Ldg4k+K72aAwP+g8l8Dyg1
|
17
|
+
Fba2vSFoS/MyvhCqTgP6Uh2fl8qXOqGJEv0koD3yRADa5/FlHSCeLhsyYqsLd/Zm
|
18
|
+
0Ogts7dhVm2v9jvVdmnWUQnGp/mPAGX6gB6Q1WHHEAdUNp6qAG7GatrJcttU0+7U
|
19
|
+
9cYKyc9bwQKBgC7oi53dsLAxrD3JDGMwEMgzngAtCS9gCAqUOSVn8AaStHEVYf6d
|
20
|
+
8soE6nDk/iQsNzxcnaO3rm51EOmjBM20KUlnNTo8nBXhY94f80VuAtByPMa3pQw1
|
21
|
+
da4vWLaT6fDcwv5WFFkJxJlcuudJVrGdX4rKPKI7H+fXLahYT2OXpXPhAoGBAIO9
|
22
|
+
Vli1WXw75ITFB+DYlDr4UCB3vA0gOkmg9Ucgk1MSgtmE5fofZ4TnZ4MvTkR8UcGm
|
23
|
+
qggvVpU8tWxWkx1SYGofL/Ux6Tcnjt/pgxV9/jqpYpv6gidCWP34Y9TyLNG6IGPd
|
24
|
+
pycmQy/AKTHhyQLaonLhhvx+cwG8texgvlCZy12BAoGAYsahYudgvuUi/IKjQvkH
|
25
|
+
0F/kwBnd0mRHttsEMIVjrG1Y82EUh5Ja05IGpOSSMeBVhIlJ/DnwFOoSmIVzGfsA
|
26
|
+
4GHtXmHd1xByxjW4nbr4NH7u8ElULkOPjcxSLgXhDb5KtG1XwCPEMUqvApcM6cfv
|
27
|
+
CQn8vQRR2J42gXEcTmt0zVQ=
|
28
|
+
-----END PRIVATE KEY-----
|
@@ -0,0 +1,9 @@
|
|
1
|
+
-----BEGIN PUBLIC KEY-----
|
2
|
+
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3Gg4qj+BJE2F8w6gi2Ro
|
3
|
+
hBEJ8dIms2P39yDGTZ2FXwQ0i5d5tsdft3IeD3vxN+QGoNcHm57w4f1VUXIdPp+C
|
4
|
+
lf+E6HtDqvVT+sSqjl2LWWQFVl87NU43U/3ZPq0V2vsJ8qtipJTydGqMMwMq9xM4
|
5
|
+
r1tb9fboVnaoLoTxD6Ka/9rLnt75aGa4oGpjqL9vYhZIhS7UqgMhGSO8ePMP919p
|
6
|
+
5GdVIr2MQUay57pVTFCQ2c78nbt7LZbupkpWkNzKXYM8s+FeNTSJszXiZ1tReq4s
|
7
|
+
HeobnfcaJA2Ur63nQv14TG8pdC3aygAc8h5zhUgZSJCBw3kFD2vWCgREkTLTlZsq
|
8
|
+
7wIDAQAB
|
9
|
+
-----END PUBLIC KEY-----
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ibanity
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 1.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ibanity
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-10-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rest-client
|
@@ -101,8 +101,13 @@ files:
|
|
101
101
|
- lib/ibanity/http_signature.rb
|
102
102
|
- lib/ibanity/util.rb
|
103
103
|
- lib/ibanity/version.rb
|
104
|
+
- spec/lib/ibanity/http_signature_spec.rb
|
104
105
|
- spec/lib/ibanity/util_spec.rb
|
105
106
|
- spec/spec_helper.rb
|
107
|
+
- spec/support/crypto_helper.rb
|
108
|
+
- spec/support/fixtures/signature/test-certificate.pem
|
109
|
+
- spec/support/fixtures/signature/test-private_key.pem
|
110
|
+
- spec/support/fixtures/signature/test-public_key.pem
|
106
111
|
homepage: https://documentation.ibanity.com/api/ruby
|
107
112
|
licenses:
|
108
113
|
- MIT
|
@@ -127,5 +132,10 @@ signing_key:
|
|
127
132
|
specification_version: 4
|
128
133
|
summary: Ibanity Ruby Client
|
129
134
|
test_files:
|
135
|
+
- spec/lib/ibanity/http_signature_spec.rb
|
130
136
|
- spec/lib/ibanity/util_spec.rb
|
131
137
|
- spec/spec_helper.rb
|
138
|
+
- spec/support/crypto_helper.rb
|
139
|
+
- spec/support/fixtures/signature/test-certificate.pem
|
140
|
+
- spec/support/fixtures/signature/test-private_key.pem
|
141
|
+
- spec/support/fixtures/signature/test-public_key.pem
|