sepafm 1.1.8 → 1.1.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +8 -6
  3. data/Rakefile +1 -1
  4. data/lib/sepa/application_request.rb +12 -18
  5. data/lib/sepa/application_response.rb +0 -2
  6. data/lib/sepa/attribute_checks.rb +33 -28
  7. data/lib/sepa/banks/danske/danske_response.rb +9 -25
  8. data/lib/sepa/banks/danske/soap_danske.rb +1 -1
  9. data/lib/sepa/banks/nordea/nordea_response.rb +2 -16
  10. data/lib/sepa/banks/op/op_response.rb +5 -23
  11. data/lib/sepa/banks/samlink/samlink_response.rb +35 -0
  12. data/lib/sepa/banks/samlink/soap_samlink.rb +14 -0
  13. data/lib/sepa/certificates/samlink_certificate.pem +29 -0
  14. data/lib/sepa/certificates/samlink_root_certificate.pem +32 -0
  15. data/lib/sepa/client.rb +35 -8
  16. data/lib/sepa/error_messages.rb +16 -18
  17. data/lib/sepa/response.rb +7 -11
  18. data/lib/sepa/soap_builder.rb +7 -17
  19. data/lib/sepa/utilities.rb +4 -5
  20. data/lib/sepa/version.rb +1 -1
  21. data/lib/sepa/wsdl/wsdl_samlink_cert_production.xml +82 -0
  22. data/lib/sepa/wsdl/wsdl_samlink_cert_test.xml +82 -0
  23. data/lib/sepa/wsdl/wsdl_samlink_production.xml +160 -0
  24. data/lib/sepa/wsdl/wsdl_samlink_test.xml +160 -0
  25. data/lib/sepa/xml_schemas/samlink/CertApplicationRequest.xsd +105 -0
  26. data/lib/sepa/xml_schemas/samlink/CertApplicationResponse.xsd +88 -0
  27. data/lib/sepa/xml_templates/application_request/download_file.xml +0 -1
  28. data/lib/sepa/xml_templates/application_request/download_file_list.xml +0 -1
  29. data/lib/sepa/xml_templates/application_request/samlink/get_certificate.xml +12 -0
  30. data/lib/sepa/xml_templates/application_request/samlink/renew_certificate.xml +29 -0
  31. data/lib/sepa/xml_templates/soap/samlink/get_certificate.xml +14 -0
  32. data/lib/sepa/xml_templates/soap/samlink/renew_certificate.xml +14 -0
  33. data/lib/sepafm.rb +43 -31
  34. data/readme.md +1 -0
  35. data/sepafm.gemspec +2 -2
  36. data/test/custom_assertions.rb +30 -28
  37. data/test/sepa/banks/danske/danske_cert_response_test.rb +13 -10
  38. data/test/sepa/banks/danske/danske_generic_soap_builder_test.rb +9 -31
  39. data/test/sepa/banks/danske/danske_get_bank_cert_test.rb +4 -5
  40. data/test/sepa/banks/danske/danske_response_test.rb +2 -3
  41. data/test/sepa/banks/danske/responses/create_cert_corrupted.xml +15 -0
  42. data/test/sepa/banks/nordea/nordea_application_request_test.rb +4 -6
  43. data/test/sepa/banks/nordea/nordea_application_response_test.rb +14 -15
  44. data/test/sepa/banks/nordea/nordea_cert_request_soap_builder_test.rb +1 -3
  45. data/test/sepa/banks/nordea/nordea_generic_soap_builder_test.rb +6 -16
  46. data/test/sepa/banks/nordea/nordea_response_test.rb +11 -11
  47. data/test/sepa/banks/op/op_cert_application_request_test.rb +1 -1
  48. data/test/sepa/banks/op/op_cert_request_soap_builder_test.rb +0 -1
  49. data/test/sepa/banks/op/op_response_test.rb +2 -2
  50. data/test/sepa/banks/samlink/responses/dfl.xml +21 -0
  51. data/test/sepa/banks/samlink/responses/gc_error_30.xml +21 -0
  52. data/test/sepa/banks/samlink/responses/rc.xml +21 -0
  53. data/test/sepa/banks/samlink/samlink_application_request_test.rb +36 -0
  54. data/test/sepa/banks/samlink/samlink_cert_application_request_test.rb +13 -0
  55. data/test/sepa/banks/samlink/samlink_cert_request_soap_builder_test.rb +13 -0
  56. data/test/sepa/banks/samlink/samlink_generic_soap_builder_test.rb +34 -0
  57. data/test/sepa/banks/samlink/samlink_renew_cert_application_request_test.rb +36 -0
  58. data/test/sepa/banks/samlink/samlink_renew_cert_request_soap_builder_test.rb +26 -0
  59. data/test/sepa/banks/samlink/samlink_response_test.rb +71 -0
  60. data/test/sepa/client_test.rb +32 -6
  61. data/test/sepa/fixtures.rb +169 -7
  62. data/test/sepa/sepa_test.rb +1 -1
  63. data/test/test_helper.rb +8 -7
  64. data/test_client/data/certs_example.rb +9 -9
  65. data/test_client/data/params_example.rb +18 -19
  66. data/test_client/test_client.rb +6 -0
  67. metadata +41 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4495553a8331dc839714be9d80f714bcdad98a00
4
- data.tar.gz: 60935bd6d5859e8e812943c40c64854671b365c4
3
+ metadata.gz: d7953437ff7a58f58b2f7df4b1e9541ceb409000
4
+ data.tar.gz: ac839e70c1644adb076586e5ac98fa78779fd8a3
5
5
  SHA512:
6
- metadata.gz: f8cad4589cb2968fa5ff25dbf14542584973549dd5d3836e404dea824bdfecaed3deceeaddd62d8f191734040910f6d810617d40fce84762931c7e24d73ceec7
7
- data.tar.gz: 726a6d88274b0f076f86ba1798c46649e304f6da1f5a23f6f8669eab07c5e96fef2a52b0257b47cc3755e4bf3e1771fa929b7ec69b38548dd5aedbbc68b2a45e
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: 348
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: 146
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
- SupportedStyles: rails
28
+ EnforcedStyle: rails
29
29
 
30
30
  Style/StringLiterals:
31
- SupportedStyles: single_quotes, double_quotes
32
- ConsistentQuotesInMultiline: true
31
+ Enabled: false
33
32
 
34
33
  Style/TrailingCommaInLiteral:
35
- SupportedStyles: comma
34
+ EnforcedStyleForMultiline: comma
35
+
36
+ Style/TrailingCommaInArguments:
37
+ EnforcedStyleForMultiline: comma
data/Rakefile CHANGED
@@ -12,4 +12,4 @@ task :console do
12
12
  sh "bundle exec irb -I lib -r sepafm.rb"
13
13
  end
14
14
 
15
- task :default => :test
15
+ task default: :test
@@ -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 {|c| c.capitalize}.join
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
- add_target_id_after 'FileReferences'
90
- set_node("Status", @status)
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
- add_target_id_after 'Environment'
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
- add_target_id_after 'Environment'
119
- set_node("Status", @status)
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 == :op
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
- # Adds target id to the application request after a specific node because the schema defines a
259
- # sequence. Target id is only added if {#bank} is `:nordea`
260
- #
261
- # @param node [String] the name of the node after which the target id node will be added
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
- begin
57
- x509_certificate own_signing_certificate
58
- rescue
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
- return if %i(
101
- create_certificate
102
- get_bank_certificate
103
- get_certificate
104
- renew_certificate
105
- get_user_info
106
- ).include?(command) ||
107
- %i(
108
- danske
109
- op
110
- ).include?(bank)
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).size > 0
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.length > 0
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
- unless Client::ENVIRONMENTS.include? environment
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
- unless status && Client::STATUSES.include?(status)
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 [:get_bank_certificate, :create_certificate, :renew_certificate].include? @command
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 [:get_bank_certificate, :create_certificate, :renew_certificate].include? @command
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
- node.content if node
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 [:get_bank_certificate, :create_certificate, :renew_certificate].include? @command
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
- node.content if node
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 [:get_bank_certificate, :create_certificate, :renew_certificate].include? @command
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 [:get_bank_certificate, :create_certificate, :renew_certificate].include? @command
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
 
@@ -65,7 +65,7 @@ module Sepa
65
65
  encrypted_data = iv + encrypted_data
66
66
  encrypted_data = encode encrypted_data
67
67
 
68
- return encrypted_data, key
68
+ [encrypted_data, key]
69
69
  end
70
70
 
71
71
  # Builds the xml structure for the encrypted application request that can be base64 encoded
@@ -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
- node = doc.at('xmlns|ResponseCode', xmlns: NORDEA_PKI)
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
- node = doc.at('xmlns|ResponseText', xmlns: NORDEA_PKI)
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 %i(
35
- get_certificate
36
- get_service_certificates
37
- ).include? command
29
+ return super unless [:get_certificate, :get_service_certificates].include? command
38
30
 
39
- node = doc.at('xmlns|ResponseCode', xmlns: OP_PKI)
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 %i(
51
- get_certificate
52
- get_service_certificates
53
- ).include? command
36
+ return super unless [:get_certificate, :get_service_certificates].include? command
54
37
 
55
- node = doc.at('xmlns|ResponseText', xmlns: OP_PKI)
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,14 @@
1
+ module Sepa
2
+ # Contains Samlink specific soap building functionality
3
+ module SamlinkSoapRequest
4
+ private
5
+
6
+ def set_receiver_id
7
+ set_node @template, 'bxd|ReceiverId', @target_id
8
+ end
9
+
10
+ def cert_ns
11
+ SAMLINK_PKI
12
+ end
13
+ end
14
+ 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 ||= :production
208
- self.language ||= 'EN'
209
- self.status ||= 'NEW'
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
- soap = SoapBuilder.new(create_hash).to_xml
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, xml: soap)
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