sepafm 1.1.5 → 1.1.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +3 -0
- data/lib/sepa/application_request.rb +17 -8
- data/lib/sepa/attribute_checks.rb +23 -26
- data/lib/sepa/banks/danske/danske_response.rb +29 -41
- data/lib/sepa/banks/danske/soap_danske.rb +30 -23
- data/lib/sepa/client.rb +8 -11
- data/lib/sepa/response.rb +13 -23
- data/lib/sepa/utilities.rb +2 -6
- data/lib/sepa/version.rb +1 -1
- data/lib/sepa/xml_schemas/danske_pki.xsd +1 -1
- data/lib/sepa/xml_templates/application_request/danske/renew_certificate.xml +33 -0
- data/lib/sepa/xml_templates/soap/danske/renew_certificate.xml +17 -0
- data/readme.md +3 -3
- data/sepafm.gemspec +4 -4
- data/test/custom_assertions.rb +21 -0
- data/test/sepa/banks/danske/danske_cert_soap_builder_test.rb +1 -5
- data/test/sepa/banks/danske/danske_certificate_application_request_test.rb +6 -8
- data/test/sepa/banks/danske/danske_generic_soap_builder_test.rb +7 -23
- data/test/sepa/banks/danske/danske_get_bank_cert_test.rb +3 -13
- data/test/sepa/banks/danske/danske_renew_cert_application_request_test.rb +32 -0
- data/test/sepa/banks/danske/danske_renew_cert_request_soap_builder_test.rb +41 -0
- data/test/sepa/banks/nordea/nordea_application_request_test.rb +4 -16
- data/test/sepa/banks/nordea/nordea_cert_application_request_test.rb +1 -5
- data/test/sepa/banks/nordea/nordea_cert_request_soap_builder_test.rb +1 -4
- data/test/sepa/banks/nordea/nordea_generic_soap_builder_test.rb +7 -23
- data/test/sepa/banks/nordea/nordea_renew_cert_application_request_test.rb +1 -10
- data/test/sepa/banks/nordea/nordea_renew_cert_request_soap_builder_test.rb +1 -10
- data/test/sepa/banks/op/op_application_request_test.rb +3 -30
- data/test/sepa/banks/op/op_cert_application_request_test.rb +1 -10
- data/test/sepa/banks/op/op_cert_request_soap_builder_test.rb +1 -10
- data/test/sepa/banks/op/op_generic_soap_builder_test.rb +2 -20
- data/test/sepa/client_test.rb +42 -66
- data/test/sepa/fixtures.rb +72 -23
- data/test/sepa/sepa_test.rb +1 -1
- data/test_client/test_client.rb +23 -18
- metadata +16 -19
- data/.travis.yml +0 -16
- data/test/sepa/banks/danske/keys/danske_encryption.crt +0 -24
- data/test/sepa/banks/danske/keys/encryption_pkcs.csr +0 -0
- data/test/sepa/banks/danske/keys/signing_pkcs.csr +0 -0
- data/test/sepa/banks/danske/keys/signing_private_key.pem +0 -27
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c038dcb77ca225b13580f7f01c23ecf58fc00e23
|
4
|
+
data.tar.gz: aa11761b080c92183b185d997bb5c7e509e88171
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ea3ae75974fbbb309e959796d709dbf50209f03e8fe5d2b5d47b4028c08cd9dbecbeb2e0f835b84792ee5d71f43e16aae94b7ac69dbb09122c990cff6016435d
|
7
|
+
data.tar.gz: ad964633e3b736ade71ee6a64222311167a47f5f0b7d5406ac06b1f0bfd3012a232e782e798d86d6fe9e14c30afa9f1df549ccc2a1310054735daed5e71ebe3b
|
data/.rubocop.yml
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
module Sepa
|
2
|
-
|
3
2
|
# Contains functionality to build the application request
|
4
3
|
#
|
5
4
|
# @todo Add return values for content modifying methods to signal whether they succeeded or not
|
@@ -22,7 +21,7 @@ module Sepa
|
|
22
21
|
instance_variable_set("@#{key}", value)
|
23
22
|
end
|
24
23
|
|
25
|
-
@application_request = load_body_template
|
24
|
+
@application_request = load_body_template(AR_TEMPLATE_PATH)
|
26
25
|
end
|
27
26
|
|
28
27
|
# Sets the nodes in the application request, processes signature and then returns the
|
@@ -129,10 +128,21 @@ module Sepa
|
|
129
128
|
set_node "Content", format_cert_request(@signing_csr)
|
130
129
|
end
|
131
130
|
|
132
|
-
# Sets nodes' contents for
|
131
|
+
# Sets nodes' contents for renew certificate request
|
133
132
|
def set_renew_certificate_nodes
|
134
|
-
|
135
|
-
|
133
|
+
case @bank
|
134
|
+
when :nordea, :op
|
135
|
+
set_node "Service", "service" if @bank == :nordea
|
136
|
+
set_node "Content", format_cert_request(@signing_csr)
|
137
|
+
when :danske
|
138
|
+
@environment = 'customertest' if @environment == :test
|
139
|
+
|
140
|
+
set_node 'tns|CustomerId', @customer_id
|
141
|
+
set_node 'tns|EncryptionCertPKCS10', format_cert_request(@encryption_csr)
|
142
|
+
set_node 'tns|SigningCertPKCS10', format_cert_request(@signing_csr)
|
143
|
+
set_node 'tns|Timestamp', iso_time
|
144
|
+
set_node 'tns|Environment', @environment
|
145
|
+
end
|
136
146
|
end
|
137
147
|
|
138
148
|
# Sets nodes' contents for OP's get service certificates request
|
@@ -161,8 +171,8 @@ module Sepa
|
|
161
171
|
# Sets contents for nodes that are common to all requests except when {#command} is
|
162
172
|
# `:get_bank_certificate` or `:create_certificate`. {#environment} is upcased here.
|
163
173
|
def set_common_nodes
|
164
|
-
return if @command
|
165
|
-
return if @command == :
|
174
|
+
return if [:get_bank_certificate, :create_certificate].include?(@command)
|
175
|
+
return if @bank == :danske && @command == :renew_certificate
|
166
176
|
|
167
177
|
set_node('Environment', @environment.to_s.upcase)
|
168
178
|
set_node("CustomerId", @customer_id)
|
@@ -256,6 +266,5 @@ module Sepa
|
|
256
266
|
target_id.content = @target_id
|
257
267
|
@application_request.at(node).add_next_sibling target_id
|
258
268
|
end
|
259
|
-
|
260
269
|
end
|
261
270
|
end
|
@@ -1,5 +1,4 @@
|
|
1
1
|
module Sepa
|
2
|
-
|
3
2
|
# Contains functionality to check the attributes passed to {Client}. Uses
|
4
3
|
# ActiveModel::Validations for the actual validation.
|
5
4
|
module AttributeChecks
|
@@ -11,25 +10,24 @@ module Sepa
|
|
11
10
|
def allowed_commands
|
12
11
|
case bank
|
13
12
|
when :nordea
|
14
|
-
|
15
|
-
|
16
|
-
get_certificate
|
17
|
-
renew_certificate
|
18
|
-
|
13
|
+
[
|
14
|
+
STANDARD_COMMANDS,
|
15
|
+
:get_certificate,
|
16
|
+
:renew_certificate
|
17
|
+
].flatten
|
19
18
|
when :danske
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
19
|
+
[
|
20
|
+
STANDARD_COMMANDS - [:get_user_info],
|
21
|
+
:create_certificate,
|
22
|
+
:get_bank_certificate,
|
23
|
+
:renew_certificate,
|
24
|
+
].flatten
|
26
25
|
when :op
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
)
|
26
|
+
[
|
27
|
+
STANDARD_COMMANDS - [:get_user_info],
|
28
|
+
:get_certificate,
|
29
|
+
:get_service_certificates,
|
30
|
+
].flatten
|
33
31
|
else
|
34
32
|
[]
|
35
33
|
end
|
@@ -64,20 +62,19 @@ module Sepa
|
|
64
62
|
|
65
63
|
# Checks that signing certificate signing request can be initialized properly.
|
66
64
|
def check_signing_csr
|
67
|
-
return unless [:get_certificate, :create_certificate].include? command
|
65
|
+
return unless [:get_certificate, :create_certificate, :renew_certificate].include? command
|
66
|
+
return if cert_request_valid?(signing_csr)
|
68
67
|
|
69
|
-
|
70
|
-
errors.add(:signing_csr, SIGNING_CERT_REQUEST_ERROR_MESSAGE)
|
71
|
-
end
|
68
|
+
errors.add(:signing_csr, SIGNING_CERT_REQUEST_ERROR_MESSAGE)
|
72
69
|
end
|
73
70
|
|
74
71
|
# Checks that encryption certificate signing request can be initialized properly.
|
75
72
|
def check_encryption_cert_request
|
76
|
-
return unless
|
73
|
+
return unless bank == :danske
|
74
|
+
return unless [:create_certificate, :renew_certificate].include? command
|
75
|
+
return if cert_request_valid?(encryption_csr)
|
77
76
|
|
78
|
-
|
79
|
-
errors.add(:encryption_csr, ENCRYPTION_CERT_REQUEST_ERROR_MESSAGE)
|
80
|
-
end
|
77
|
+
errors.add(:encryption_csr, ENCRYPTION_CERT_REQUEST_ERROR_MESSAGE)
|
81
78
|
end
|
82
79
|
|
83
80
|
# Checks that {Client#file_type} is proper
|
@@ -1,9 +1,7 @@
|
|
1
1
|
module Sepa
|
2
|
-
|
3
2
|
# Handles Danske Bank specific {Response} functionality. Mainly decryption and certificate
|
4
3
|
# specific stuff.
|
5
4
|
class DanskeResponse < Response
|
6
|
-
|
7
5
|
validate :valid_get_bank_certificate_response
|
8
6
|
validate :can_be_decrypted_with_given_key
|
9
7
|
|
@@ -47,63 +45,59 @@ module Sepa
|
|
47
45
|
end
|
48
46
|
|
49
47
|
# Returns own encryption certificate which has been signed by the bank. Only present in
|
50
|
-
# `:create_certificate` responses
|
48
|
+
# `:create_certificate` & `:renew_certificate` responses
|
51
49
|
#
|
52
|
-
# @return [OpenSSL::X509::Certificate] if {#command} is `:create_certificate`
|
50
|
+
# @return [OpenSSL::X509::Certificate] if {#command} is `:create_certificate` or `:renew_certificate`
|
53
51
|
# @return [nil] if command is any other
|
54
52
|
def own_encryption_certificate
|
55
|
-
return unless @command
|
53
|
+
return unless [:create_certificate, :renew_certificate].include?(@command)
|
56
54
|
|
57
55
|
@own_encryption_certificate ||= extract_cert(doc, 'EncryptionCert', DANSKE_PKI)
|
58
56
|
end
|
59
57
|
|
60
58
|
# Returns own signing certificate which has been signed by the bank. Is used to sign requests
|
61
|
-
# sent to the bank. Is only present in `:create_certificate` responses.
|
59
|
+
# sent to the bank. Is only present in `:create_certificate` & `:renew_certificate` responses.
|
62
60
|
#
|
63
|
-
# @return [OpenSSL::X509::Certificate] if {#command} is `:create_certificate`
|
61
|
+
# @return [OpenSSL::X509::Certificate] if {#command} is `:create_certificate` or `:renew_certificate`
|
64
62
|
# @return [nil] if command is any other
|
65
63
|
def own_signing_certificate
|
66
|
-
return unless @command
|
64
|
+
return unless [:create_certificate, :renew_certificate].include?(@command)
|
67
65
|
|
68
66
|
@own_signing_certificate ||= extract_cert(doc, 'SigningCert', DANSKE_PKI)
|
69
67
|
end
|
70
68
|
|
71
69
|
# Returns the CA certificate that has been used to sign own signing and encryption certificates.
|
72
|
-
# Only present in `:create_certificate` responses
|
70
|
+
# Only present in `:create_certificate` & `:renew_certificate` responses
|
73
71
|
#
|
74
|
-
# @return [OpenSSL::X509::Certificate] if {#command} is `:create_certificate`
|
72
|
+
# @return [OpenSSL::X509::Certificate] if {#command} is `:create_certificate` or `:renew_certificate`
|
75
73
|
# @return [nil] if command is any other
|
76
74
|
def ca_certificate
|
77
|
-
return unless @command
|
75
|
+
return unless [:create_certificate, :renew_certificate].include?(@command)
|
78
76
|
|
79
77
|
@ca_certificate ||= extract_cert(doc, 'CACert', DANSKE_PKI)
|
80
78
|
end
|
81
79
|
|
82
80
|
# Extract certificate that has been used to sign the response. This overrides
|
83
|
-
# {Response#certificate} method with specific functionality for `:get_bank_certificate
|
84
|
-
# `:create_certificate` commands. Otherwise just calls {Response#certificate}
|
81
|
+
# {Response#certificate} method with specific functionality for `:get_bank_certificate`,
|
82
|
+
# `:create_certificate` & `:renew_certificate` commands. Otherwise just calls {Response#certificate}
|
85
83
|
#
|
86
84
|
# @return [OpenSSL::X509::Certificate]
|
87
85
|
# @raise [OpenSSL::X509::CertificateError] if certificate cannot be processed
|
88
86
|
def certificate
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
end
|
93
|
-
else
|
94
|
-
super
|
95
|
-
end
|
87
|
+
return super unless [:get_bank_certificate, :create_certificate, :renew_certificate].include? @command
|
88
|
+
|
89
|
+
@certificate ||= extract_cert(doc, 'X509Certificate', DSIG)
|
96
90
|
end
|
97
91
|
|
98
92
|
# Extract response code from the response. Overrides super method when {#command} is
|
99
|
-
# `:get_bank_certificate` or `:
|
93
|
+
# `:get_bank_certificate`, `:create_certificate` or `:renew_certificate` because response code node is named
|
100
94
|
# differently in those responses.
|
101
95
|
#
|
102
96
|
# @return [String] if response code is found
|
103
97
|
# @return [nil] if response code cannot be found
|
104
98
|
# @see Response#response_code
|
105
99
|
def response_code
|
106
|
-
return super unless [:get_bank_certificate, :create_certificate].include? @command
|
100
|
+
return super unless [:get_bank_certificate, :create_certificate, :renew_certificate].include? @command
|
107
101
|
|
108
102
|
node = doc.at('xmlns|ReturnCode', xmlns: DANSKE_PKI)
|
109
103
|
node = doc.at('xmlns|ReturnCode', xmlns: DANSKE_PKIF) unless node
|
@@ -112,17 +106,14 @@ module Sepa
|
|
112
106
|
end
|
113
107
|
|
114
108
|
# Extract response text from the response. Overrides super method when {#command} is
|
115
|
-
# `:get_bank_certificate` or `:
|
109
|
+
# `:get_bank_certificate`, `:create_certificate` or `:renew_certificate` because response text node is named
|
116
110
|
# differently in those responses.
|
117
111
|
#
|
118
112
|
# @return [String] if response text is found
|
119
113
|
# @return [nil] if response text cannot be found
|
120
114
|
# @see Response#response_text
|
121
115
|
def response_text
|
122
|
-
return super unless
|
123
|
-
create_certificate
|
124
|
-
get_bank_certificate
|
125
|
-
).include? @command
|
116
|
+
return super unless [:get_bank_certificate, :create_certificate, :renew_certificate].include? @command
|
126
117
|
|
127
118
|
node = doc.at('xmlns|ReturnText', xmlns: DANSKE_PKI)
|
128
119
|
node = doc.at('xmlns|ReturnText', xmlns: DANSKE_PKIF) unless node
|
@@ -145,7 +136,7 @@ module Sepa
|
|
145
136
|
private
|
146
137
|
|
147
138
|
# Finds a node by its reference URI from Danske Bank's certificate responses. If {#command} is
|
148
|
-
# other than `:get_bank_certificate` or `:
|
139
|
+
# other than `:get_bank_certificate`, `:create_certificate` or `:renew_certificate` returns super. This method is
|
149
140
|
# needed because Danske Bank uses a different way to reference nodes in their certificate
|
150
141
|
# responses.
|
151
142
|
#
|
@@ -153,7 +144,7 @@ module Sepa
|
|
153
144
|
# @return [Nokogiri::XML::Node] node with signature removed from its document since signature
|
154
145
|
# has to be removed for canonicalization and hash calculation
|
155
146
|
def find_node_by_uri(uri)
|
156
|
-
return super unless [:get_bank_certificate, :create_certificate].include? @command
|
147
|
+
return super unless [:get_bank_certificate, :create_certificate, :renew_certificate].include? @command
|
157
148
|
|
158
149
|
doc_without_signature = doc.dup
|
159
150
|
doc_without_signature.at('xmlns|Signature', xmlns: DSIG).remove
|
@@ -173,11 +164,11 @@ module Sepa
|
|
173
164
|
key = decrypt_embedded_key
|
174
165
|
|
175
166
|
encypted_data = encrypted_application_response
|
176
|
-
|
177
|
-
|
167
|
+
.css('CipherValue', 'xmlns' => XMLENC)[1]
|
168
|
+
.content
|
178
169
|
|
179
170
|
encypted_data = decode encypted_data
|
180
|
-
iv
|
171
|
+
iv = encypted_data[0, 8]
|
181
172
|
encypted_data = encypted_data[8, encypted_data.length]
|
182
173
|
|
183
174
|
decipher = OpenSSL::Cipher.new('DES-EDE3-CBC')
|
@@ -192,10 +183,9 @@ module Sepa
|
|
192
183
|
# from the bank.
|
193
184
|
def valid_get_bank_certificate_response
|
194
185
|
return unless @command == :get_bank_certificate
|
186
|
+
return unless doc.at('xmlns|PKIFactoryServiceFault', xmlns: DANSKE_PKIF)
|
195
187
|
|
196
|
-
|
197
|
-
errors.add(:base, "Did not get a proper response when trying to get bank's certificates")
|
198
|
-
end
|
188
|
+
errors.add(:base, "Did not get a proper response when trying to get bank's certificates")
|
199
189
|
end
|
200
190
|
|
201
191
|
# Extracts the encrypted application response from the response and returns it as a nokogiri
|
@@ -206,19 +196,18 @@ module Sepa
|
|
206
196
|
def encrypted_application_response
|
207
197
|
@encrypted_application_response ||= begin
|
208
198
|
encrypted_application_response = extract_application_response(BXD)
|
209
|
-
xml_doc
|
199
|
+
xml_doc(encrypted_application_response)
|
210
200
|
end
|
211
201
|
end
|
212
202
|
|
213
203
|
# Validates that the encrypted key in the response can be decrypted with the private key given
|
214
204
|
# to the response in the parameters. Response is invalid if this cannot be done.
|
215
205
|
def can_be_decrypted_with_given_key
|
216
|
-
return if [:get_bank_certificate, :create_certificate].include? @command
|
206
|
+
return if [:get_bank_certificate, :create_certificate, :renew_certificate].include? @command
|
217
207
|
return unless encrypted_application_response.css('CipherValue', 'xmlns' => XMLENC)[0]
|
208
|
+
return if decrypt_embedded_key
|
218
209
|
|
219
|
-
|
220
|
-
errors.add(:encryption_private_key, DECRYPTION_ERROR_MESSAGE)
|
221
|
-
end
|
210
|
+
errors.add(:encryption_private_key, DECRYPTION_ERROR_MESSAGE)
|
222
211
|
end
|
223
212
|
|
224
213
|
# Decrypts (assymetrically) the symmetric encryption key embedded in the response with the
|
@@ -235,6 +224,5 @@ module Sepa
|
|
235
224
|
rescue OpenSSL::PKey::RSAError
|
236
225
|
nil
|
237
226
|
end
|
238
|
-
|
239
227
|
end
|
240
228
|
end
|
@@ -1,8 +1,6 @@
|
|
1
1
|
module Sepa
|
2
|
-
|
3
2
|
# Contains Danske Bank specific soap building functionality
|
4
3
|
module DanskeSoapRequest
|
5
|
-
|
6
4
|
private
|
7
5
|
|
8
6
|
# Determines which kind of request to build depending on command. Certificate requests differ
|
@@ -13,11 +11,13 @@ module Sepa
|
|
13
11
|
def find_correct_build
|
14
12
|
case @command
|
15
13
|
when :create_certificate
|
16
|
-
|
14
|
+
build_create_certificate_request
|
17
15
|
when :upload_file, :download_file, :get_user_info, :download_file_list
|
18
16
|
build_danske_generic_request
|
19
17
|
when :get_bank_certificate
|
20
18
|
build_get_bank_certificate_request
|
19
|
+
when :renew_certificate
|
20
|
+
build_renew_certificate_request
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
@@ -85,16 +85,16 @@ module Sepa
|
|
85
85
|
ar
|
86
86
|
end
|
87
87
|
|
88
|
-
# Sets contents for
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
set_node
|
93
|
-
set_node
|
94
|
-
set_node
|
95
|
-
set_node
|
96
|
-
set_node
|
97
|
-
set_node
|
88
|
+
# Sets contents for certificate requests.
|
89
|
+
def set_cert_contents
|
90
|
+
@environment = :customertest if @environment == :test
|
91
|
+
|
92
|
+
set_node @template, 'pkif|SenderId', @customer_id
|
93
|
+
set_node @template, 'pkif|CustomerId', @customer_id
|
94
|
+
set_node @template, 'pkif|RequestId', request_id
|
95
|
+
set_node @template, 'pkif|Timestamp', iso_time
|
96
|
+
set_node @template, 'pkif|InterfaceVersion', 1
|
97
|
+
set_node @template, 'pkif|Environment', @environment
|
98
98
|
end
|
99
99
|
|
100
100
|
# Sets contents for get bank certificate requests
|
@@ -130,12 +130,9 @@ module Sepa
|
|
130
130
|
# if set to `:test`. This request is encrypted but not signed.
|
131
131
|
#
|
132
132
|
# @return [Nokogiri::XML] the complete soap
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
set_create_cert_contents
|
137
|
-
encrypted_request = encrypt_application_request
|
138
|
-
add_encrypted_request_to_soap(encrypted_request)
|
133
|
+
def build_create_certificate_request
|
134
|
+
set_cert_contents
|
135
|
+
add_encrypted_request_to_soap(encrypt_application_request)
|
139
136
|
end
|
140
137
|
|
141
138
|
# Builds get bank certificate request soap. This request is neither signed nor encrypted.
|
@@ -146,16 +143,27 @@ module Sepa
|
|
146
143
|
add_bank_certificate_body_to_soap
|
147
144
|
end
|
148
145
|
|
146
|
+
# Builds Danske Bank's renew certificate request soap. Environment is set to `:customertest`
|
147
|
+
# if set to `:test`. This request is encrypted and signed
|
148
|
+
#
|
149
|
+
# @return [Nokogiri::XML] the complete soap
|
150
|
+
def build_renew_certificate_request
|
151
|
+
set_cert_contents
|
152
|
+
add_encrypted_request_to_soap(encrypt_application_request, parent_node: 'pkif|RenewCertificateIn')
|
153
|
+
process_header
|
154
|
+
add_body_to_header
|
155
|
+
end
|
156
|
+
|
149
157
|
# Adds encrypted application request xml structure to the soap. This method is used when
|
150
|
-
# building create certificate requests and the encrypted application request xml structure
|
158
|
+
# building create & renew certificate requests and the encrypted application request xml structure
|
151
159
|
# will not be base64 encoded.
|
152
160
|
#
|
153
161
|
# @param encrypted_request [Nokogiri::XML] the encrypted application request xml structure
|
154
162
|
# @return [Nokogiri::XML] the soap with the encrypted application request added to it
|
155
|
-
def add_encrypted_request_to_soap(encrypted_request)
|
163
|
+
def add_encrypted_request_to_soap(encrypted_request, parent_node: 'pkif|CreateCertificateIn')
|
156
164
|
encrypted_request = Nokogiri::XML(encrypted_request.to_xml)
|
157
165
|
encrypted_request = encrypted_request.root
|
158
|
-
@template.at_css(
|
166
|
+
@template.at_css(parent_node).add_child(encrypted_request)
|
159
167
|
|
160
168
|
@template
|
161
169
|
end
|
@@ -199,6 +207,5 @@ module Sepa
|
|
199
207
|
end
|
200
208
|
|
201
209
|
def set_application_request; end
|
202
|
-
|
203
210
|
end
|
204
211
|
end
|
data/lib/sepa/client.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
# Main module for this gem
|
2
2
|
module Sepa
|
3
|
-
|
4
3
|
# Handles parameter validation, key initialization, {SoapBuilder} initialization, communicating
|
5
4
|
# with the bank and {Response} initialization.
|
6
5
|
class Client
|
@@ -9,7 +8,6 @@ module Sepa
|
|
9
8
|
include ErrorMessages
|
10
9
|
include AttributeChecks
|
11
10
|
|
12
|
-
|
13
11
|
# The bank that is used in this client. One of {BANKS}.
|
14
12
|
#
|
15
13
|
# @return [Symbol]
|
@@ -169,18 +167,18 @@ module Sepa
|
|
169
167
|
danske
|
170
168
|
nordea
|
171
169
|
op
|
172
|
-
)
|
170
|
+
).freeze
|
173
171
|
|
174
172
|
# Languages that are currently supported by the gem
|
175
|
-
LANGUAGES =
|
173
|
+
LANGUAGES = %w(FI SE EN).freeze
|
176
174
|
|
177
175
|
# Environments that are currently supported by the gem
|
178
|
-
ENVIRONMENTS = [:production, :test]
|
176
|
+
ENVIRONMENTS = [:production, :test].freeze
|
179
177
|
|
180
178
|
# Statuses that can be given to download file list command. When NEW is given, only those files
|
181
179
|
# that have not yet been downloaded will be listed. DOWNLOADED will list only downloaded files
|
182
180
|
# and ALL will list every file
|
183
|
-
STATUSES =
|
181
|
+
STATUSES = %w(NEW DOWNLOADED ALL).freeze
|
184
182
|
|
185
183
|
validates :bank, inclusion: { in: BANKS }
|
186
184
|
validates :language, inclusion: { in: LANGUAGES }, allow_nil: true
|
@@ -205,10 +203,10 @@ module Sepa
|
|
205
203
|
#
|
206
204
|
# @param hash [Hash] All the attributes of the client can be given to the construcor in a hash
|
207
205
|
def initialize(hash = {})
|
208
|
-
|
206
|
+
attributes(hash)
|
209
207
|
self.environment ||= :production
|
210
|
-
self.language
|
211
|
-
self.status
|
208
|
+
self.language ||= 'EN'
|
209
|
+
self.status ||= 'NEW'
|
212
210
|
end
|
213
211
|
|
214
212
|
def bank=(value)
|
@@ -330,8 +328,7 @@ module Sepa
|
|
330
328
|
end
|
331
329
|
|
332
330
|
def soap_command
|
333
|
-
|
334
|
-
when :renew_certificate
|
331
|
+
if @command == :renew_certificate && [:nordea, :op].include?(@bank)
|
335
332
|
:get_certificate
|
336
333
|
else
|
337
334
|
@command
|
data/lib/sepa/response.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
module Sepa
|
2
|
-
|
3
2
|
# Handles soap responses got back from the bank. Bank specific functionality is defined in
|
4
3
|
# subclasses. Handles i.e. logic to make sure the response's integrity has not been compromised
|
5
4
|
# and has methods to extract content from the response.
|
@@ -276,9 +275,10 @@ module Sepa
|
|
276
275
|
# @return [nil] if application response cannot be found
|
277
276
|
def extract_application_response(namespace)
|
278
277
|
ar_node = doc.at('xmlns|ApplicationResponse', xmlns: namespace)
|
279
|
-
|
280
|
-
|
281
|
-
|
278
|
+
|
279
|
+
return unless ar_node
|
280
|
+
|
281
|
+
decode(ar_node.content)
|
282
282
|
end
|
283
283
|
|
284
284
|
# Handles errors that have been passed from client
|
@@ -297,43 +297,34 @@ module Sepa
|
|
297
297
|
|
298
298
|
# Validates response code in response. "00" and "24" are currently considered valid.
|
299
299
|
def validate_response_code
|
300
|
-
|
301
|
-
|
302
|
-
|
300
|
+
return if %w(00 24).include? response_code
|
301
|
+
|
302
|
+
errors.add(:base, response_code: response_code, response_text: response_text)
|
303
303
|
end
|
304
304
|
|
305
305
|
# Validates hashes in the response. {#hashes_match?} must return true for validation to pass.
|
306
306
|
# Is not run if {#error} is present or response code is not ok.
|
307
307
|
def validate_hashes
|
308
|
-
return if @error
|
309
|
-
return unless response_code_is_ok?
|
308
|
+
return if @error || !response_code_is_ok? || hashes_match?
|
310
309
|
|
311
|
-
|
312
|
-
errors.add(:base, HASH_ERROR_MESSAGE)
|
313
|
-
end
|
310
|
+
errors.add(:base, HASH_ERROR_MESSAGE)
|
314
311
|
end
|
315
312
|
|
316
313
|
# Validate signature in the response. Validation is not run if {#error} is present or response
|
317
314
|
# is not ok.
|
318
315
|
def verify_signature
|
319
|
-
return if @error
|
320
|
-
return unless response_code_is_ok?
|
316
|
+
return if @error || !response_code_is_ok? || signature_is_valid?
|
321
317
|
|
322
|
-
|
323
|
-
errors.add(:base, SIGNATURE_ERROR_MESSAGE)
|
324
|
-
end
|
318
|
+
errors.add(:base, SIGNATURE_ERROR_MESSAGE)
|
325
319
|
end
|
326
320
|
|
327
321
|
# Validates certificate in the soap. The certificate must be present and signed by the bank's
|
328
322
|
# root certificate for the validation to pass. Is not run if {#error} is present or response
|
329
323
|
# code is not ok.
|
330
324
|
def verify_certificate
|
331
|
-
return if @error
|
332
|
-
return unless response_code_is_ok?
|
325
|
+
return if @error || !response_code_is_ok? || certificate_is_trusted?
|
333
326
|
|
334
|
-
|
335
|
-
errors.add(:base, 'The certificate in the response is not trusted')
|
336
|
-
end
|
327
|
+
errors.add(:base, 'The certificate in the response is not trusted')
|
337
328
|
end
|
338
329
|
|
339
330
|
# Checks whether response code in the response is ok. Response code is considered ok if it is
|
@@ -346,6 +337,5 @@ module Sepa
|
|
346
337
|
|
347
338
|
false
|
348
339
|
end
|
349
|
-
|
350
340
|
end
|
351
341
|
end
|
data/lib/sepa/utilities.rb
CHANGED
@@ -1,8 +1,6 @@
|
|
1
1
|
module Sepa
|
2
|
-
|
3
2
|
# Contains utility methods that are used in this gem.
|
4
3
|
module Utilities
|
5
|
-
|
6
4
|
# Calculates a SHA1 digest for a given node. Before the calculation, the node is canonicalized
|
7
5
|
# exclusively.
|
8
6
|
#
|
@@ -11,7 +9,7 @@ module Sepa
|
|
11
9
|
def calculate_digest(node)
|
12
10
|
sha1 = OpenSSL::Digest::SHA1.new
|
13
11
|
|
14
|
-
canon_node = canonicalize_exclusively
|
12
|
+
canon_node = canonicalize_exclusively(node)
|
15
13
|
|
16
14
|
encode(sha1.digest(canon_node)).gsub(/\s+/, "")
|
17
15
|
end
|
@@ -189,9 +187,7 @@ module Sepa
|
|
189
187
|
# @param value [Nokogiri::XML::Node, #canonicalize] the node to be canonicalized
|
190
188
|
# @return [String] the canonicalized node
|
191
189
|
def canonicalize_exclusively(value)
|
192
|
-
value.canonicalize(
|
193
|
-
inclusive_namespaces = nil,
|
194
|
-
with_comments = false)
|
190
|
+
value.canonicalize(Nokogiri::XML::XML_C14N_EXCLUSIVE_1_0)
|
195
191
|
end
|
196
192
|
|
197
193
|
# Creates a new OpenSSL X509 certificate from a string
|
data/lib/sepa/version.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
<?xml version="1.0" encoding="UTF-8"?>
|
2
2
|
<!-- edited with XMLSpy v2009 sp1 (http://www.altova.com) by Danske Bank (Danske Bank A/S) -->
|
3
3
|
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:tns="http://danskebank.dk/PKI/PKIFactoryService/elements" xmlns:xml="http://www.w3.org/XML/1998/namespace" targetNamespace="http://danskebank.dk/PKI/PKIFactoryService/elements" elementFormDefault="qualified" attributeFormDefault="unqualified">
|
4
|
-
<xs:import namespace="http://www.w3.org/2000/09/xmldsig#" schemaLocation="
|
4
|
+
<xs:import namespace="http://www.w3.org/2000/09/xmldsig#" schemaLocation="xmldsig-core-schema.xsd"/>
|
5
5
|
<!--xs:import namespace="http://www.w3.org/2000/09/xmldsig#" schemaLocation="store:///schemas/xmldsig-core-schema.xsd"/-->
|
6
6
|
<xs:import namespace="http://www.w3.org/XML/1998/namespace" schemaLocation="xml_id.xsd"/>
|
7
7
|
<!-- SHARED TYPES SECTION -->
|
@@ -0,0 +1,33 @@
|
|
1
|
+
<tns:RenewCertificateRequest xmlns:pkif="http://danskebank.dk/PKI/PKIFactoryService"
|
2
|
+
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
|
3
|
+
xmlns:xe="http://www.w3.org/2001/04/xmlenc#"
|
4
|
+
xmlns:xd="http://www.w3.org/2000/09/xmldsig#"
|
5
|
+
xmlns:tns="http://danskebank.dk/PKI/PKIFactoryService/elements">
|
6
|
+
<tns:CustomerId/>
|
7
|
+
<tns:KeyGeneratorType>software</tns:KeyGeneratorType>
|
8
|
+
<tns:EncryptionCertPKCS10/>
|
9
|
+
<tns:SigningCertPKCS10/>
|
10
|
+
<tns:Timestamp/>
|
11
|
+
<tns:RequestId/>
|
12
|
+
<tns:Environment/>
|
13
|
+
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
|
14
|
+
<SignedInfo>
|
15
|
+
<CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
|
16
|
+
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
|
17
|
+
<Reference URI="">
|
18
|
+
<Transforms>
|
19
|
+
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
|
20
|
+
<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
|
21
|
+
</Transforms>
|
22
|
+
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
|
23
|
+
<DigestValue/>
|
24
|
+
</Reference>
|
25
|
+
</SignedInfo>
|
26
|
+
<SignatureValue/>
|
27
|
+
<KeyInfo>
|
28
|
+
<X509Data>
|
29
|
+
<X509Certificate/>
|
30
|
+
</X509Data>
|
31
|
+
</KeyInfo>
|
32
|
+
</Signature>
|
33
|
+
</tns:RenewCertificateRequest>
|