sepafm 1.1.8 → 1.1.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +8 -6
- data/Rakefile +1 -1
- data/lib/sepa/application_request.rb +12 -18
- data/lib/sepa/application_response.rb +0 -2
- data/lib/sepa/attribute_checks.rb +33 -28
- data/lib/sepa/banks/danske/danske_response.rb +9 -25
- data/lib/sepa/banks/danske/soap_danske.rb +1 -1
- data/lib/sepa/banks/nordea/nordea_response.rb +2 -16
- data/lib/sepa/banks/op/op_response.rb +5 -23
- data/lib/sepa/banks/samlink/samlink_response.rb +35 -0
- data/lib/sepa/banks/samlink/soap_samlink.rb +14 -0
- data/lib/sepa/certificates/samlink_certificate.pem +29 -0
- data/lib/sepa/certificates/samlink_root_certificate.pem +32 -0
- data/lib/sepa/client.rb +35 -8
- data/lib/sepa/error_messages.rb +16 -18
- data/lib/sepa/response.rb +7 -11
- data/lib/sepa/soap_builder.rb +7 -17
- data/lib/sepa/utilities.rb +4 -5
- data/lib/sepa/version.rb +1 -1
- data/lib/sepa/wsdl/wsdl_samlink_cert_production.xml +82 -0
- data/lib/sepa/wsdl/wsdl_samlink_cert_test.xml +82 -0
- data/lib/sepa/wsdl/wsdl_samlink_production.xml +160 -0
- data/lib/sepa/wsdl/wsdl_samlink_test.xml +160 -0
- data/lib/sepa/xml_schemas/samlink/CertApplicationRequest.xsd +105 -0
- data/lib/sepa/xml_schemas/samlink/CertApplicationResponse.xsd +88 -0
- data/lib/sepa/xml_templates/application_request/download_file.xml +0 -1
- data/lib/sepa/xml_templates/application_request/download_file_list.xml +0 -1
- data/lib/sepa/xml_templates/application_request/samlink/get_certificate.xml +12 -0
- data/lib/sepa/xml_templates/application_request/samlink/renew_certificate.xml +29 -0
- data/lib/sepa/xml_templates/soap/samlink/get_certificate.xml +14 -0
- data/lib/sepa/xml_templates/soap/samlink/renew_certificate.xml +14 -0
- data/lib/sepafm.rb +43 -31
- data/readme.md +1 -0
- data/sepafm.gemspec +2 -2
- data/test/custom_assertions.rb +30 -28
- data/test/sepa/banks/danske/danske_cert_response_test.rb +13 -10
- data/test/sepa/banks/danske/danske_generic_soap_builder_test.rb +9 -31
- data/test/sepa/banks/danske/danske_get_bank_cert_test.rb +4 -5
- data/test/sepa/banks/danske/danske_response_test.rb +2 -3
- data/test/sepa/banks/danske/responses/create_cert_corrupted.xml +15 -0
- data/test/sepa/banks/nordea/nordea_application_request_test.rb +4 -6
- data/test/sepa/banks/nordea/nordea_application_response_test.rb +14 -15
- data/test/sepa/banks/nordea/nordea_cert_request_soap_builder_test.rb +1 -3
- data/test/sepa/banks/nordea/nordea_generic_soap_builder_test.rb +6 -16
- data/test/sepa/banks/nordea/nordea_response_test.rb +11 -11
- data/test/sepa/banks/op/op_cert_application_request_test.rb +1 -1
- data/test/sepa/banks/op/op_cert_request_soap_builder_test.rb +0 -1
- data/test/sepa/banks/op/op_response_test.rb +2 -2
- data/test/sepa/banks/samlink/responses/dfl.xml +21 -0
- data/test/sepa/banks/samlink/responses/gc_error_30.xml +21 -0
- data/test/sepa/banks/samlink/responses/rc.xml +21 -0
- data/test/sepa/banks/samlink/samlink_application_request_test.rb +36 -0
- data/test/sepa/banks/samlink/samlink_cert_application_request_test.rb +13 -0
- data/test/sepa/banks/samlink/samlink_cert_request_soap_builder_test.rb +13 -0
- data/test/sepa/banks/samlink/samlink_generic_soap_builder_test.rb +34 -0
- data/test/sepa/banks/samlink/samlink_renew_cert_application_request_test.rb +36 -0
- data/test/sepa/banks/samlink/samlink_renew_cert_request_soap_builder_test.rb +26 -0
- data/test/sepa/banks/samlink/samlink_response_test.rb +71 -0
- data/test/sepa/client_test.rb +32 -6
- data/test/sepa/fixtures.rb +169 -7
- data/test/sepa/sepa_test.rb +1 -1
- data/test/test_helper.rb +8 -7
- data/test_client/data/certs_example.rb +9 -9
- data/test_client/data/params_example.rb +18 -19
- data/test_client/test_client.rb +6 -0
- metadata +41 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d7953437ff7a58f58b2f7df4b1e9541ceb409000
|
4
|
+
data.tar.gz: ac839e70c1644adb076586e5ac98fa78779fd8a3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8c8b5f59d6bac6b85f71d893039f1ffe707c78258c1f65546c7b64c650f27bc7b389196ae62513b0c0e933c20ec488370b7aa220c5b3297375b602d07aada7f0
|
7
|
+
data.tar.gz: ed2acb7fa7b253c93cd36be5eca1750e40e709b43914baa876ee68b5bea5a242ac3d46b12672a4659301b554afe276ea374dc45e7a7667bd18cfe26d61f5f11e
|
data/.rubocop.yml
CHANGED
@@ -5,7 +5,7 @@ Metrics/AbcSize:
|
|
5
5
|
Max: 37
|
6
6
|
|
7
7
|
Metrics/ClassLength:
|
8
|
-
Max:
|
8
|
+
Max: 350
|
9
9
|
|
10
10
|
Metrics/CyclomaticComplexity:
|
11
11
|
Max: 8
|
@@ -17,7 +17,7 @@ Metrics/MethodLength:
|
|
17
17
|
Max: 69
|
18
18
|
|
19
19
|
Metrics/ModuleLength:
|
20
|
-
Max:
|
20
|
+
Max: 150
|
21
21
|
|
22
22
|
Style/Documentation:
|
23
23
|
Exclude:
|
@@ -25,11 +25,13 @@ Style/Documentation:
|
|
25
25
|
- 'test/**/*'
|
26
26
|
|
27
27
|
Style/IndentationConsistency:
|
28
|
-
|
28
|
+
EnforcedStyle: rails
|
29
29
|
|
30
30
|
Style/StringLiterals:
|
31
|
-
|
32
|
-
ConsistentQuotesInMultiline: true
|
31
|
+
Enabled: false
|
33
32
|
|
34
33
|
Style/TrailingCommaInLiteral:
|
35
|
-
|
34
|
+
EnforcedStyleForMultiline: comma
|
35
|
+
|
36
|
+
Style/TrailingCommaInArguments:
|
37
|
+
EnforcedStyleForMultiline: comma
|
data/Rakefile
CHANGED
@@ -74,7 +74,7 @@ module Sepa
|
|
74
74
|
# @example Example input and output
|
75
75
|
# :get_user_info --> GetUserInfo
|
76
76
|
def pretty_command
|
77
|
-
@command.to_s.split(/[\W_]/).map
|
77
|
+
@command.to_s.split(/[\W_]/).map(&:capitalize).join
|
78
78
|
end
|
79
79
|
|
80
80
|
# Determines which content setting method to call depending on {#command}
|
@@ -86,8 +86,8 @@ module Sepa
|
|
86
86
|
|
87
87
|
# Sets nodes' values for download file request
|
88
88
|
def set_download_file_nodes
|
89
|
-
|
90
|
-
|
89
|
+
add_node_after('FileReferences', 'TargetId', content: @target_id) if @bank == :nordea
|
90
|
+
add_node_after('Timestamp', 'Status', content: @status) if @status.present?
|
91
91
|
add_node_to_root 'FileType', content: @file_type if @file_type.present?
|
92
92
|
set_node("FileReference", @file_reference)
|
93
93
|
end
|
@@ -110,20 +110,20 @@ module Sepa
|
|
110
110
|
def set_upload_file_nodes
|
111
111
|
set_node_b("Content", @content)
|
112
112
|
set_node("FileType", @file_type)
|
113
|
-
|
113
|
+
add_node_after('Environment', 'TargetId', content: @target_id) if @bank == :nordea
|
114
114
|
end
|
115
115
|
|
116
116
|
# Sets nodes' contents for download file list request
|
117
117
|
def set_download_file_list_nodes
|
118
|
-
|
119
|
-
|
118
|
+
add_node_after('Environment', 'TargetId', content: @target_id) if @bank == :nordea
|
119
|
+
add_node_after('Timestamp', 'Status', content: @status) if @status.present?
|
120
120
|
add_node_to_root 'FileType', content: @file_type if @file_type.present?
|
121
121
|
end
|
122
122
|
|
123
123
|
# Sets nodes' contents for Nordea's and OP's get certificate request
|
124
124
|
def set_get_certificate_nodes
|
125
125
|
set_node "Service", "MATU" if @bank == :op
|
126
|
-
set_node "TransferKey", @pin if @bank
|
126
|
+
set_node "TransferKey", @pin if [:op, :samlink].include?(@bank)
|
127
127
|
set_node "HMAC", hmac(@pin, csr_to_binary(@signing_csr)) if @bank == :nordea
|
128
128
|
set_node "Content", format_cert_request(@signing_csr)
|
129
129
|
end
|
@@ -131,7 +131,7 @@ module Sepa
|
|
131
131
|
# Sets nodes' contents for renew certificate request
|
132
132
|
def set_renew_certificate_nodes
|
133
133
|
case @bank
|
134
|
-
when :nordea, :op
|
134
|
+
when :nordea, :op, :samlink
|
135
135
|
set_node "Service", "service" if @bank == :nordea
|
136
136
|
set_node "Content", format_cert_request(@signing_csr)
|
137
137
|
when :danske
|
@@ -255,16 +255,10 @@ module Sepa
|
|
255
255
|
add_value_to_signature('X509Certificate', format_cert(@own_signing_certificate))
|
256
256
|
end
|
257
257
|
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
def add_target_id_after(node)
|
263
|
-
return unless @bank == :nordea
|
264
|
-
|
265
|
-
target_id = Nokogiri::XML::Node.new 'TargetId', @application_request
|
266
|
-
target_id.content = @target_id
|
267
|
-
@application_request.at(node).add_next_sibling target_id
|
258
|
+
def add_node_after(node, new_node, content:)
|
259
|
+
new_node = Nokogiri::XML::Node.new(new_node, @application_request)
|
260
|
+
new_node.content = content
|
261
|
+
@application_request.at(node).add_next_sibling(new_node)
|
268
262
|
end
|
269
263
|
|
270
264
|
def canonicalization_mode
|
@@ -1,5 +1,4 @@
|
|
1
1
|
module Sepa
|
2
|
-
|
3
2
|
# Contains functionality for the application response embedded in {Response}
|
4
3
|
# @todo Use functionality from this class more when validating response
|
5
4
|
class ApplicationResponse
|
@@ -96,6 +95,5 @@ module Sepa
|
|
96
95
|
def response_must_validate_against_schema
|
97
96
|
check_validity_against_schema(doc, 'application_response.xsd')
|
98
97
|
end
|
99
|
-
|
100
98
|
end
|
101
99
|
end
|
@@ -13,7 +13,7 @@ module Sepa
|
|
13
13
|
[
|
14
14
|
STANDARD_COMMANDS,
|
15
15
|
:get_certificate,
|
16
|
-
:renew_certificate
|
16
|
+
:renew_certificate,
|
17
17
|
].flatten
|
18
18
|
when :danske
|
19
19
|
[
|
@@ -28,6 +28,12 @@ module Sepa
|
|
28
28
|
:get_certificate,
|
29
29
|
:get_service_certificates,
|
30
30
|
].flatten
|
31
|
+
when :samlink
|
32
|
+
[
|
33
|
+
STANDARD_COMMANDS - [:get_user_info],
|
34
|
+
:get_certificate,
|
35
|
+
:renew_certificate,
|
36
|
+
].flatten
|
31
37
|
else
|
32
38
|
[]
|
33
39
|
end
|
@@ -53,11 +59,9 @@ module Sepa
|
|
53
59
|
errors.add(:signing_private_key, "Invalid signing private key")
|
54
60
|
end
|
55
61
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
errors.add(:own_signing_certificate, "Invalid signing certificate")
|
60
|
-
end
|
62
|
+
x509_certificate own_signing_certificate
|
63
|
+
rescue
|
64
|
+
errors.add(:own_signing_certificate, "Invalid signing certificate")
|
61
65
|
end
|
62
66
|
|
63
67
|
# Checks that signing certificate signing request can be initialized properly.
|
@@ -82,8 +86,7 @@ module Sepa
|
|
82
86
|
if file_type.present?
|
83
87
|
valid = file_type.size < 35
|
84
88
|
else
|
85
|
-
return if bank == :op && %i(download_file
|
86
|
-
download_file_list).include?(command)
|
89
|
+
return if bank == :op && %i(download_file download_file_list).include?(command)
|
87
90
|
|
88
91
|
valid = !(%i(
|
89
92
|
download_file
|
@@ -97,17 +100,21 @@ module Sepa
|
|
97
100
|
|
98
101
|
# Checks that {Client#target_id} is valid.
|
99
102
|
def check_target_id
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
103
|
+
exclude_commands = [
|
104
|
+
:create_certificate,
|
105
|
+
:get_bank_certificate,
|
106
|
+
:get_certificate,
|
107
|
+
:get_user_info,
|
108
|
+
:renew_certificate,
|
109
|
+
]
|
110
|
+
|
111
|
+
exclude_banks = [
|
112
|
+
:danske,
|
113
|
+
:op,
|
114
|
+
:samlink,
|
115
|
+
]
|
116
|
+
|
117
|
+
return if exclude_commands.include?(command) || exclude_banks.include?(bank)
|
111
118
|
|
112
119
|
check_presence_and_length(:target_id, 80, TARGET_ID_ERROR_MESSAGE)
|
113
120
|
end
|
@@ -122,7 +129,7 @@ module Sepa
|
|
122
129
|
check &&= send(attribute)
|
123
130
|
check &&= send(attribute).respond_to? :size
|
124
131
|
check &&= send(attribute).size < length
|
125
|
-
check &&= send(attribute).
|
132
|
+
check &&= !send(attribute).empty?
|
126
133
|
|
127
134
|
errors.add(attribute, error_message) unless check
|
128
135
|
end
|
@@ -135,7 +142,7 @@ module Sepa
|
|
135
142
|
check = true
|
136
143
|
check &&= content
|
137
144
|
check &&= content.respond_to? :length
|
138
|
-
check &&= content.
|
145
|
+
check &&= !content.empty?
|
139
146
|
|
140
147
|
errors.add(:content, CONTENT_ERROR_MESSAGE) unless check
|
141
148
|
end
|
@@ -151,10 +158,9 @@ module Sepa
|
|
151
158
|
# {Client#command} is `:get_bank_certificate`.
|
152
159
|
def check_environment
|
153
160
|
return if command == :get_bank_certificate
|
161
|
+
return if Client::ENVIRONMENTS.include?(environment)
|
154
162
|
|
155
|
-
|
156
|
-
errors.add(:environment, ENVIRONMENT_ERROR_MESSAGE)
|
157
|
-
end
|
163
|
+
errors.add(:environment, ENVIRONMENT_ERROR_MESSAGE)
|
158
164
|
end
|
159
165
|
|
160
166
|
# Checks that {Client#customer_id} is valid
|
@@ -182,11 +188,11 @@ module Sepa
|
|
182
188
|
|
183
189
|
# Checks that {Client#status} is included in {Client::STATUSES}.
|
184
190
|
def check_status
|
191
|
+
return if bank == :samlink && command != :download_file_list
|
185
192
|
return unless [:download_file_list, :download_file].include? command
|
193
|
+
return if status && Client::STATUSES.include?(status)
|
186
194
|
|
187
|
-
|
188
|
-
errors.add :status, STATUS_ERROR_MESSAGE
|
189
|
-
end
|
195
|
+
errors.add :status, STATUS_ERROR_MESSAGE
|
190
196
|
end
|
191
197
|
|
192
198
|
# Checks presence and length of {Client#file_reference} if {Client#command} is `:download_file`
|
@@ -208,6 +214,5 @@ module Sepa
|
|
208
214
|
rescue
|
209
215
|
errors.add :encryption_private_key, ENCRYPTION_PRIVATE_KEY_ERROR_MESSAGE
|
210
216
|
end
|
211
|
-
|
212
217
|
end
|
213
218
|
end
|
@@ -2,6 +2,8 @@ module Sepa
|
|
2
2
|
# Handles Danske Bank specific {Response} functionality. Mainly decryption and certificate
|
3
3
|
# specific stuff.
|
4
4
|
class DanskeResponse < Response
|
5
|
+
CERTIFICATE_COMMANDS = [:get_bank_certificate, :create_certificate, :renew_certificate].freeze
|
6
|
+
|
5
7
|
validate :valid_get_bank_certificate_response
|
6
8
|
validate :can_be_decrypted_with_given_key
|
7
9
|
|
@@ -84,41 +86,23 @@ module Sepa
|
|
84
86
|
# @return [OpenSSL::X509::Certificate]
|
85
87
|
# @raise [OpenSSL::X509::CertificateError] if certificate cannot be processed
|
86
88
|
def certificate
|
87
|
-
return super unless
|
89
|
+
return super unless CERTIFICATE_COMMANDS.include? @command
|
88
90
|
|
89
91
|
@certificate ||= extract_cert(doc, 'X509Certificate', DSIG)
|
90
92
|
end
|
91
93
|
|
92
|
-
# Extract response code from the response. Overrides super method when {#command} is
|
93
|
-
# `:get_bank_certificate`, `:create_certificate` or `:renew_certificate` because response code node is named
|
94
|
-
# differently in those responses.
|
95
|
-
#
|
96
|
-
# @return [String] if response code is found
|
97
|
-
# @return [nil] if response code cannot be found
|
98
94
|
# @see Response#response_code
|
99
95
|
def response_code
|
100
|
-
return super unless
|
101
|
-
|
102
|
-
node = doc.at('xmlns|ReturnCode', xmlns: DANSKE_PKI)
|
103
|
-
node = doc.at('xmlns|ReturnCode', xmlns: DANSKE_PKIF) unless node
|
96
|
+
return super unless CERTIFICATE_COMMANDS.include? @command
|
104
97
|
|
105
|
-
|
98
|
+
super(namespace: DANSKE_PKI, node_name: 'ReturnCode') || super(namespace: DANSKE_PKIF, node_name: 'ReturnCode')
|
106
99
|
end
|
107
100
|
|
108
|
-
# Extract response text from the response. Overrides super method when {#command} is
|
109
|
-
# `:get_bank_certificate`, `:create_certificate` or `:renew_certificate` because response text node is named
|
110
|
-
# differently in those responses.
|
111
|
-
#
|
112
|
-
# @return [String] if response text is found
|
113
|
-
# @return [nil] if response text cannot be found
|
114
101
|
# @see Response#response_text
|
115
102
|
def response_text
|
116
|
-
return super unless
|
117
|
-
|
118
|
-
node = doc.at('xmlns|ReturnText', xmlns: DANSKE_PKI)
|
119
|
-
node = doc.at('xmlns|ReturnText', xmlns: DANSKE_PKIF) unless node
|
103
|
+
return super unless CERTIFICATE_COMMANDS.include? @command
|
120
104
|
|
121
|
-
|
105
|
+
super(namespace: DANSKE_PKI, node_name: 'ReturnText') || super(namespace: DANSKE_PKIF, node_name: 'ReturnText')
|
122
106
|
end
|
123
107
|
|
124
108
|
# Checks whether certificate embedded in the response has been signed with the bank's root
|
@@ -144,7 +128,7 @@ module Sepa
|
|
144
128
|
# @return [Nokogiri::XML::Node] node with signature removed from its document since signature
|
145
129
|
# has to be removed for canonicalization and hash calculation
|
146
130
|
def find_node_by_uri(uri)
|
147
|
-
return super unless
|
131
|
+
return super unless CERTIFICATE_COMMANDS.include? @command
|
148
132
|
|
149
133
|
doc_without_signature = doc.dup
|
150
134
|
doc_without_signature.at('xmlns|Signature', xmlns: DSIG).remove
|
@@ -203,7 +187,7 @@ module Sepa
|
|
203
187
|
# Validates that the encrypted key in the response can be decrypted with the private key given
|
204
188
|
# to the response in the parameters. Response is invalid if this cannot be done.
|
205
189
|
def can_be_decrypted_with_given_key
|
206
|
-
return if
|
190
|
+
return if CERTIFICATE_COMMANDS.include? @command
|
207
191
|
return unless encrypted_application_response.css('CipherValue', 'xmlns' => XMLENC)[0]
|
208
192
|
return if decrypt_embedded_key
|
209
193
|
|
@@ -1,5 +1,4 @@
|
|
1
1
|
module Sepa
|
2
|
-
|
3
2
|
# Handles Nordea specific response logic. Mainly certificate specific stuff.
|
4
3
|
class NordeaResponse < Response
|
5
4
|
include Utilities
|
@@ -20,30 +19,18 @@ module Sepa
|
|
20
19
|
cert.to_s
|
21
20
|
end
|
22
21
|
|
23
|
-
# Returns the response code in the response. Overrides {Response#response_code} if {#command} is
|
24
|
-
# `:get_certificate`, because the namespace is different with that command.
|
25
|
-
#
|
26
|
-
# @return [String] response code if it is found
|
27
|
-
# @return [nil] if response code cannot be found
|
28
22
|
# @see Response#response_code
|
29
23
|
def response_code
|
30
24
|
return super unless [:get_certificate, :renew_certificate].include? command
|
31
25
|
|
32
|
-
|
33
|
-
node.content if node
|
26
|
+
super(namespace: NORDEA_PKI)
|
34
27
|
end
|
35
28
|
|
36
|
-
# Returns the response text in the response. Overrides {Response#response_text} if {#command} is
|
37
|
-
# `:get_certificate`, because the namespace is different with that command.
|
38
|
-
#
|
39
|
-
# @return [String] response text if it is found
|
40
|
-
# @return [nil] if response text cannot be found
|
41
29
|
# @see Response#response_text
|
42
30
|
def response_text
|
43
31
|
return super unless [:get_certificate, :renew_certificate].include? command
|
44
32
|
|
45
|
-
|
46
|
-
node.content if node
|
33
|
+
super(namespace: NORDEA_PKI)
|
47
34
|
end
|
48
35
|
|
49
36
|
# Checks whether the certificate embedded in the response soap has been signed with Nordea's
|
@@ -55,6 +42,5 @@ module Sepa
|
|
55
42
|
def certificate_is_trusted?
|
56
43
|
verify_certificate_against_root_certificate(certificate, NORDEA_ROOT_CERTIFICATE)
|
57
44
|
end
|
58
|
-
|
59
45
|
end
|
60
46
|
end
|
@@ -6,7 +6,7 @@ module Sepa
|
|
6
6
|
BYPASS_COMMANDS = %i(
|
7
7
|
get_certificate
|
8
8
|
get_service_certificates
|
9
|
-
)
|
9
|
+
).freeze
|
10
10
|
|
11
11
|
# Extracts own signing certificate from the response.
|
12
12
|
#
|
@@ -24,36 +24,18 @@ module Sepa
|
|
24
24
|
cert.to_s
|
25
25
|
end
|
26
26
|
|
27
|
-
# Returns the response code in the response. Overrides {Response#response_code} if {#command} is
|
28
|
-
# `:get_certificate`, because the namespace is different with that command.
|
29
|
-
#
|
30
|
-
# @return [String] response code if it is found
|
31
|
-
# @return [nil] if response code cannot be found
|
32
27
|
# @see Response#response_code
|
33
28
|
def response_code
|
34
|
-
return super unless
|
35
|
-
get_certificate
|
36
|
-
get_service_certificates
|
37
|
-
).include? command
|
29
|
+
return super unless [:get_certificate, :get_service_certificates].include? command
|
38
30
|
|
39
|
-
|
40
|
-
node.content if node
|
31
|
+
super(namespace: OP_PKI)
|
41
32
|
end
|
42
33
|
|
43
|
-
# Returns the response text in the response. Overrides {Response#response_text} if {#command} is
|
44
|
-
# `:get_certificate`, because the namespace is different with that command.
|
45
|
-
#
|
46
|
-
# @return [String] response text if it is found
|
47
|
-
# @return [nil] if response text cannot be found
|
48
34
|
# @see Response#response_text
|
49
35
|
def response_text
|
50
|
-
return super unless
|
51
|
-
get_certificate
|
52
|
-
get_service_certificates
|
53
|
-
).include? command
|
36
|
+
return super unless [:get_certificate, :get_service_certificates].include? command
|
54
37
|
|
55
|
-
|
56
|
-
node.content if node
|
38
|
+
super(namespace: OP_PKI)
|
57
39
|
end
|
58
40
|
|
59
41
|
# Checks whether the certificate embedded in the response soap has been signed with OP's
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Sepa
|
2
|
+
# Handles Samlink specific response logic. Mainly certificate specific stuff.
|
3
|
+
class SamlinkResponse < Response
|
4
|
+
# @see Response#response_code
|
5
|
+
def response_code
|
6
|
+
[:get_certificate, :renew_certificate].include?(command) ? super(namespace: SAMLINK_PKI) : super
|
7
|
+
end
|
8
|
+
|
9
|
+
# @see Response#response_code
|
10
|
+
def response_text
|
11
|
+
[:get_certificate, :renew_certificate].include?(command) ? super(namespace: SAMLINK_PKI) : super
|
12
|
+
end
|
13
|
+
|
14
|
+
def application_response
|
15
|
+
[:get_certificate, :renew_certificate].include?(command) ? super(namespace: SAMLINK_PKI) : super
|
16
|
+
end
|
17
|
+
|
18
|
+
def own_signing_certificate
|
19
|
+
(node = Nokogiri::XML(application_response).at('xmlns|Certificate > xmlns|Certificate', xmlns: OP_XML_DATA)) &&
|
20
|
+
(content = node.content) &&
|
21
|
+
x509_certificate(decode(content)).to_s
|
22
|
+
end
|
23
|
+
|
24
|
+
def certificate_is_trusted?
|
25
|
+
case environment
|
26
|
+
when :production
|
27
|
+
# Samlink doesn't provide a CA certificate for production environment and that's why we check that the
|
28
|
+
# certificate provided is equal to the known trusted certificate.
|
29
|
+
certificate.to_s == SAMLINK_CERTIFICATE.to_s
|
30
|
+
when :test
|
31
|
+
verify_certificate_against_root_certificate(certificate, SAMLINK_ROOT_CERTIFICATE)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
2
|
+
MIIE6TCCAtGgAwIBAgIQA3WFy1naV3PkFL0hKYOZ3TANBgkqhkiG9w0BAQsFADA9
|
3
|
+
MQswCQYDVQQGEwJGSTEQMA4GA1UECgwHU2FtbGluazEcMBoGA1UEAwwTU2FtbGlu
|
4
|
+
ayBDdXN0b21lciBDQTAeFw0xNDA5MjQwODI0MjJaFw0xNzA5MjMwODI0MjJaMFYx
|
5
|
+
CzAJBgNVBAYTAkZJMSEwHwYDVQQKDBhBaW5laXN0b3BhbHZlbHV0LVNhbWxpbmsx
|
6
|
+
ETAPBgNVBAMMCFNFUEFXRUJTMREwDwYDVQQEDAgwMDAwMDAwMTCCASIwDQYJKoZI
|
7
|
+
hvcNAQEBBQADggEPADCCAQoCggEBANpDNrC4C+2vUuDvDYpvRn14AWW48JlOC8M/
|
8
|
+
w5k5/fu8B+sV70qt/no3JKBKNvNpqDr34hILBtCc3TppGDz+Uv/W347Q/N42B1Z9
|
9
|
+
8cAKMEkoKvLcQVotlLSzxXeG5nhsZKw79uiyNx8VePHnnPVjjH1+daOG0xEPZqcL
|
10
|
+
XqtJh2dI9OjHs+HWkgy8Eudv0GrO0g5ArrEN1sfNfp9WdhZ7nzHtYcIYVApZB9oV
|
11
|
+
MpBkWXBAV3XZNbu+3gHbAs7JNi+c90MOmuhlzUIF6DNUU0ahrTQR55LynkGVuY/v
|
12
|
+
jlQvIdzD71bC3MoNZ1yJgoWDi1DjakkdSijiH2lLJtYlKQ/VTVcCAwEAAaOByzCB
|
13
|
+
yDAfBgNVHSMEGDAWgBTKgDgzk4pjBJGNBWlWaEI15cf/vDB2BgNVHR8EbzBtMGug
|
14
|
+
aaBnhmVsZGFwOi8vMTk0LjI1Mi4xMjQuMjQxOjM4OS9jbj1TYW1saW5rJTIwQ3Vz
|
15
|
+
dG9tZXIlMjBDQSxvPVNhbWxpbmssYz1maT9jZXJ0aWZpY2F0ZXJldm9jYXRpb25s
|
16
|
+
aXN0O2JpbmFyeTAOBgNVHQ8BAf8EBAMCBPAwHQYDVR0OBBYEFEAoDpdUQbW9K35l
|
17
|
+
2K3ywgNemLeWMA0GCSqGSIb3DQEBCwUAA4ICAQBr0+3BfuQacQ9esTZpny08lagu
|
18
|
+
FMttI47i8AUwkJkKnvhROysBke77UoO6jyHDxskFOHd9yZdnPfzpJ6AVXzqwUxdL
|
19
|
+
Uakk38Wk8ODAyF6leRuy+I/biO+jRa52C0Ai4+XF5VNa1UUrsvjYJl6BqKJmI8aO
|
20
|
+
34ArzOcFocUF9UBQNC/eqL/AIx8mp5HC6fWA58kvWwiwdC5CQILbMMADpDjmEpkg
|
21
|
+
2ueBsLudrxXw1uNktY2wUv95KcfmlqdeAPkb0ra5x7p5SM1bJYFh8MMpm9BwnJ3a
|
22
|
+
q/l1+qFMmL0GCcevNQP5Dp3Vkrsf601aQcYyaptHMfiv6ryLfVq3487gUPNPUwWn
|
23
|
+
x24K1A5j1aQBmF8TLZl8MRkDeeEIwbXJxgoZZXAJSO2Yf/JO/vPCalBJflosiNgg
|
24
|
+
o9oxE8LCjqbJ26HeiNoeNUC1cnv15yhb6O+eSgZbkAYfuKgLWeOele3oC2QWqqT7
|
25
|
+
TSHaEipRz3TifdzpzKuXRvQaPv6lra28nbyc+OeJlnr/A7ZH3VF6OkasAoIC5wmU
|
26
|
+
tJgcQW5eD5jmaQZYktZljNWKXEm6tXmXOnDoRib0yzqUA9s6ReD7sBHBUaTDZFfy
|
27
|
+
/qrAHfYk4Pe/9seeBmbTnkdi5VnoNQT70boqaVsa/OK8eE2EWjTYs++ocfWaGSpN
|
28
|
+
pUI4al2qFueN8ji+nw==
|
29
|
+
-----END CERTIFICATE-----
|
@@ -0,0 +1,32 @@
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
2
|
+
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
|
31
|
+
yMgRk0vap01P6bNkJgj/PrkOw/ECDQ==
|
32
|
+
-----END CERTIFICATE-----
|
data/lib/sepa/client.rb
CHANGED
@@ -162,11 +162,27 @@ module Sepa
|
|
162
162
|
# @see #signing_csr The format is the same as in signing csr
|
163
163
|
attr_accessor :encryption_csr
|
164
164
|
|
165
|
+
# Options to be passed directly to the underlying savon client. Format is as follows:
|
166
|
+
# {
|
167
|
+
# globals: {
|
168
|
+
# ssl_verify_mode: :none,
|
169
|
+
# ...,
|
170
|
+
# },
|
171
|
+
# locals: {
|
172
|
+
# xml: "<envelope></envelope>",
|
173
|
+
# ...,
|
174
|
+
# },
|
175
|
+
# }
|
176
|
+
#
|
177
|
+
# @return [Hash]
|
178
|
+
attr_accessor :savon_options
|
179
|
+
|
165
180
|
# The list of banks that are currently supported by this gem
|
166
181
|
BANKS = %i(
|
167
182
|
danske
|
168
183
|
nordea
|
169
184
|
op
|
185
|
+
samlink
|
170
186
|
).freeze
|
171
187
|
|
172
188
|
# Languages that are currently supported by the gem
|
@@ -204,9 +220,13 @@ module Sepa
|
|
204
220
|
# @param hash [Hash] All the attributes of the client can be given to the construcor in a hash
|
205
221
|
def initialize(hash = {})
|
206
222
|
attributes(hash)
|
207
|
-
self.environment
|
208
|
-
self.language
|
209
|
-
self.status
|
223
|
+
self.environment ||= :production
|
224
|
+
self.language ||= 'EN'
|
225
|
+
self.status ||= 'NEW'
|
226
|
+
self.savon_options ||= {
|
227
|
+
globals: {},
|
228
|
+
locals: {},
|
229
|
+
}
|
210
230
|
end
|
211
231
|
|
212
232
|
def bank=(value)
|
@@ -249,12 +269,11 @@ module Sepa
|
|
249
269
|
def send_request
|
250
270
|
raise ArgumentError, errors.messages unless valid?
|
251
271
|
|
252
|
-
|
253
|
-
client = Savon.client(wsdl: wsdl)
|
272
|
+
client = Savon.client(savon_globals)
|
254
273
|
|
255
274
|
begin
|
256
275
|
error = nil
|
257
|
-
response = client.call(soap_command,
|
276
|
+
response = client.call(soap_command, savon_locals)
|
258
277
|
response &&= response.to_xml
|
259
278
|
rescue Savon::Error => e
|
260
279
|
response = nil
|
@@ -318,7 +337,7 @@ module Sepa
|
|
318
337
|
command: command,
|
319
338
|
environment: environment,
|
320
339
|
error: error,
|
321
|
-
response: response
|
340
|
+
response: response,
|
322
341
|
}
|
323
342
|
if encryption_private_key && !encryption_private_key.empty?
|
324
343
|
options[:encryption_private_key] = rsa_key(encryption_private_key)
|
@@ -328,11 +347,19 @@ module Sepa
|
|
328
347
|
end
|
329
348
|
|
330
349
|
def soap_command
|
331
|
-
if @command == :renew_certificate && [:nordea, :op].include?(@bank)
|
350
|
+
if @command == :renew_certificate && [:nordea, :op, :samlink].include?(@bank)
|
332
351
|
:get_certificate
|
333
352
|
else
|
334
353
|
@command
|
335
354
|
end
|
336
355
|
end
|
356
|
+
|
357
|
+
def savon_globals
|
358
|
+
{ wsdl: wsdl }.merge(savon_options[:globals] || {})
|
359
|
+
end
|
360
|
+
|
361
|
+
def savon_locals
|
362
|
+
{ xml: SoapBuilder.new(create_hash).to_xml }.merge(savon_options[:locals] || {})
|
363
|
+
end
|
337
364
|
end
|
338
365
|
end
|