identikey 0.8.2 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 66d43ba4ae2d3edfe361a94fe99fb85485fd90d804fd252bb03ab6d56541fc42
4
- data.tar.gz: 723cf154216947148230acd05ba900b9ae4da15e06be73d2f2092a14034d3fbc
3
+ metadata.gz: 8b12db6aa0435e14bd281a73d2ab1c50edc993ecb41cfe8933d180607bb22c36
4
+ data.tar.gz: 322412ff65c22664df05aa4e6e7c69d9da9a7851e827b97519a19b22162ab387
5
5
  SHA512:
6
- metadata.gz: e6f2c933ab1c131c879555fb1d34a51159ea4ff022782b9cd65d59fff7f1569b3c7ab7584035d8388ddc9ea153751216aafef622d59731168490aa4a686b9676
7
- data.tar.gz: ebe4c8dbef838a97f21710350c345280750ba11bb25d070946d823e5d01b1ceb4425a73d3a9ae5a6e22755743288704694f8fca6ad6b73013e9ff68d9c1f49dd
6
+ metadata.gz: d71931f68cbca537fdecbe4771d1aa4ef393d365a1654cfc1864ea6e3a43926d80a2dfee770f7d493eb211bbfeef8010e6b4f0bdad15c47c53d527abce3d2340
7
+ data.tar.gz: f42408a94e658295522ddbfcfc9ffc90668c5e8a1d30cc0beac1f3463e2ecc12d1ade779df010236dbe9e682c476270d983f6b85774188f3db2eb095010713bb
@@ -17,6 +17,13 @@ end
17
17
 
18
18
  puts "Configured Admin WSDL #{ENV.fetch('IK_WSDL_ADMIN')} against #{ENV.fetch('IK_HOST')}"
19
19
 
20
+ Identikey::Provisioning.configure do
21
+ wsdl ENV.fetch('IK_WSDL_PROVN')
22
+ endpoint ENV.fetch('IK_HOST')
23
+ end
24
+
25
+ puts "Configured Provisioning WSDL #{ENV.fetch('IK_WSDL_PROVN')} against #{ENV.fetch('IK_HOST')}"
26
+
20
27
  $ik = Identikey::Administration::Session.new(
21
28
  username: ENV.fetch('IK_USER'),
22
29
  password: ENV.fetch('IK_PASS'),
@@ -18,11 +18,10 @@ Gem::Specification.new do |spec|
18
18
  spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
19
19
  `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
20
20
  end
21
- spec.bindir = "exe"
22
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
23
21
  spec.require_paths = ["lib"]
24
22
 
25
23
  spec.add_dependency "savon", "~> 2.0"
24
+ spec.add_dependency "wasabi", "~> 3.5.0"
26
25
 
27
26
  spec.add_development_dependency "bundler", "~> 2.0"
28
27
  spec.add_development_dependency "rake", ">= 12.3.3"
@@ -5,3 +5,4 @@ require 'identikey/error'
5
5
  require 'identikey/unsigned'
6
6
  require 'identikey/authentication'
7
7
  require 'identikey/administration'
8
+ require 'identikey/provisioning'
@@ -18,6 +18,10 @@ module Identikey
18
18
  :admin_session_query, :user_execute, :user_query,
19
19
  :digipass_execute, :digipass_query, :digipassappl_execute
20
20
 
21
+ ###
22
+ ## LOGON/LOGOFF/PING
23
+ ###
24
+
21
25
  def logon(username:, password:, domain:)
22
26
  resp = super(message: {
23
27
  attributeSet: {
@@ -95,6 +99,10 @@ module Identikey
95
99
  parse_response resp, :admin_session_query_response
96
100
  end
97
101
 
102
+ ###
103
+ ## USER_EXECUTE
104
+ ###
105
+
98
106
  def user_execute(session_id:, cmd:, attributes: [])
99
107
  resp = super(message: {
100
108
  sessionID: session_id,
@@ -180,6 +188,10 @@ module Identikey
180
188
  )
181
189
  end
182
190
 
191
+ ###
192
+ ## USER_QUERY
193
+ ###
194
+
183
195
  # Executes a userQuery command that searches users. By default, it doesn't
184
196
  # log anywhere. To enable logging to a specific destination, pass a logger
185
197
  # as the log: option. To log to the default destination, pass `true` as
@@ -199,6 +211,9 @@ module Identikey
199
211
  end
200
212
  end
201
213
 
214
+ ###
215
+ ## DIGIPASS_EXECUTE
216
+ ###
202
217
 
203
218
  def digipass_execute(session_id:, cmd:, attributes: [])
204
219
  resp = super(message: {
@@ -245,6 +260,9 @@ module Identikey
245
260
  )
246
261
  end
247
262
 
263
+ ###
264
+ ## DIGIPASS_QUERY
265
+ ###
248
266
 
249
267
  def digipass_query(session_id:, attributes:, query_options:)
250
268
  resp = super(message: {
@@ -258,6 +276,9 @@ module Identikey
258
276
  parse_response resp, :digipass_query_response
259
277
  end
260
278
 
279
+ ###
280
+ ## DIGIPASSAPPL_EXECUTE
281
+ ###
261
282
 
262
283
  def digipassappl_execute(session_id:, cmd:, attributes:)
263
284
  resp = super(message: {
@@ -314,6 +335,5 @@ module Identikey
314
335
  client.globals[:log] = old_log
315
336
  end
316
337
 
317
-
318
338
  end
319
339
  end
@@ -54,5 +54,16 @@ module Identikey
54
54
  def self.otp_validated_ok?(status, result)
55
55
  status == 'STAT_SUCCESS' && !result.key?('CREDFLD_STATUS_MESSAGE')
56
56
  end
57
+
58
+
59
+ protected
60
+ def parse_result_root(body, root_element)
61
+ root = super
62
+
63
+ # The authentication API wraps the results with another element
64
+ #
65
+ results_key = root_element.to_s.sub(/_response$/, '_results').to_sym
66
+ return root[results_key]
67
+ end
57
68
  end
58
69
  end
@@ -100,7 +100,7 @@ module Identikey
100
100
 
101
101
  # Parse the generic response types that the API returns.
102
102
  #
103
- # The returned attributes (up to now...) are always:
103
+ # The returned attributes in the Administration API are:
104
104
  #
105
105
  # - The given root element, whose name is derived from the SOAP command
106
106
  # that was invoked
@@ -111,6 +111,11 @@ module Identikey
111
111
  # or multiple ones.
112
112
  # - :error_stack, a list of error that occurred
113
113
  #
114
+ # The authentication API wraps the results element in another one
115
+ #
116
+ # The provisioning API uses a status element for the result code and
117
+ # error stack, and a result element for the results.
118
+ #
114
119
  # The returned value is a three-elements array, containing:
115
120
  #
116
121
  # [Response code, Attribute(s) list, Errors list]
@@ -129,11 +134,19 @@ module Identikey
129
134
  # formats. TODO maybe create a separate class for errors, that includes
130
135
  # the error code.
131
136
  #
132
- # TODO refactor and split in separate methods
133
- #
134
137
  def parse_response(resp, root_element)
135
- body = resp.body
138
+ root = parse_result_root(resp.body, root_element)
139
+
140
+ results = parse_result_element(root, root_element)
141
+
142
+ result_code = parse_result_code(results, root_element)
143
+ result_attributes = parse_result_attributes(results, root_element)
144
+ result_errors = parse_result_errors(results, root_element)
136
145
 
146
+ return result_code, result_attributes, result_errors
147
+ end
148
+
149
+ def parse_result_root(body, root_element)
137
150
  if body.size.zero?
138
151
  raise Identikey::ParseError, "Empty response received"
139
152
  end
@@ -144,40 +157,35 @@ module Identikey
144
157
 
145
158
  # The root results element
146
159
  #
147
- root = body[root_element]
148
-
149
- # ... that the authentication API wraps with another element
150
- #
151
- results_key = root_element.to_s.sub(/_response$/, '_results').to_sym
152
- if root.keys.size == 1 && root.key?(results_key)
153
- root = root[results_key]
154
- end
160
+ return body[root_element]
161
+ end
155
162
 
163
+ def parse_result_element(root, root_element)
156
164
  # The results element
157
165
  #
158
166
  unless root.key?(:results)
159
167
  raise Identikey::ParseError, "Results element not found below #{root_element}"
160
168
  end
161
169
 
162
- results = root[:results]
170
+ return root[:results]
171
+ end
163
172
 
164
- # Result code
165
- #
173
+ def parse_result_code(results, root_element)
166
174
  unless results.key?(:result_codes)
167
175
  raise Identikey::ParseError, "Result codes not found below #{root_element}"
168
176
  end
169
177
 
170
- result_code = results[:result_codes][:status_code_enum] || 'STAT_UNKNOWN'
178
+ results[:result_codes][:status_code_enum] || 'STAT_UNKNOWN'
179
+ end
171
180
 
172
- # Result attributes
173
- #
181
+ def parse_result_attributes(results, root_element)
174
182
  unless results.key?(:result_attribute)
175
183
  raise Identikey::ParseError, "Result attribute not found below #{root_element}"
176
184
  end
177
185
 
178
186
  results_attr = results[:result_attribute]
179
187
 
180
- result_attributes = if results_attr.key?(:attributes)
188
+ if results_attr.key?(:attributes)
181
189
  entries = [ results_attr[:attributes] ].flatten
182
190
  parse_attributes entries
183
191
 
@@ -193,16 +201,14 @@ module Identikey
193
201
  else
194
202
  nil
195
203
  end
204
+ end
196
205
 
197
- # Errors
198
- #
199
- errors = if results[:error_stack].key?(:errors)
206
+ def parse_result_errors(results, root_element)
207
+ if results[:error_stack].key?(:errors)
200
208
  parse_errors results[:error_stack][:errors]
201
209
  else
202
210
  nil
203
211
  end
204
-
205
- return result_code, result_attributes, errors
206
212
  end
207
213
 
208
214
  def parse_attributes(attributes)
@@ -0,0 +1,150 @@
1
+ require 'identikey/base'
2
+
3
+ module Identikey
4
+ # This class wraps the Provisioning API.
5
+ #
6
+ class Provisioning < Base
7
+ client wsdl: './sdk/wsdl/provisioning.wsdl'
8
+
9
+ operations :provisioning_execute, :dsapp_srp_register
10
+
11
+ ###
12
+ ## PROVISIONING_EXECUTE
13
+ ###
14
+
15
+ def provisioning_execute(cmd:, attributes:)
16
+ resp = super(message: {
17
+ cmd: cmd,
18
+ attributeSet: {
19
+ attributes: attributes
20
+ }
21
+ })
22
+
23
+ parse_response resp, :provisioning_execute_response
24
+ end
25
+
26
+ def provisioning_execute_MDL_REGISTER(component:, user:, domain:, password:)
27
+ provisioning_execute(
28
+ cmd: 'PROVISIONCMD_MDL_REGISTER',
29
+ attributes: typed_attributes_list_from(
30
+ PROVFLD_USERID: user,
31
+ PROVFLD_DOMAIN: domain,
32
+ PROVFLD_COMPONENT_TYPE: component,
33
+ PROVFLD_STATIC_PASSWORD: password,
34
+ PROVFLD_ACTIVATION_TYPE: Unsigned(0),
35
+ )
36
+ )
37
+ end
38
+
39
+ ###
40
+ ## dsappSRPRegister
41
+ ###
42
+
43
+ def dsapp_srp_register(component:, user:, domain:, password:)
44
+ resp = super(message: {
45
+ componentType: component,
46
+ user: {
47
+ userID: user,
48
+ domain: domain,
49
+ },
50
+ credential: {
51
+ staticPassword: password
52
+ }
53
+ })
54
+
55
+ parse_response resp, :dsapp_srp_register_response
56
+ end
57
+
58
+ ###
59
+ ## Wraps dsapp_srp_register and returns directly the activation
60
+ ## message through which a CRONTO image can be generated, to be
61
+ ## used for push notifications setups in combination with a MDC
62
+ ## configured on your OneSpan control panel and on Identikey.
63
+ ##
64
+ ## You may want to look into https://github.com/ifad/cronto for
65
+ ## a generator to produce PNGs to deliver to your clients.
66
+ ####
67
+ def self.cronto_code_for_srp_registration(gateway:, **kwargs)
68
+ status, result, error = new.dsapp_srp_register(**kwargs)
69
+
70
+ if status != 'STAT_SUCCESS'
71
+ raise Identikey::OperationFailed, "Error while assigning DAL: #{status} - #{[error].flatten.join('; ')}"
72
+ end
73
+
74
+ # Compose proprietary string
75
+ message = '01;01;%s;%s;%s;%s;%s' % [
76
+ result[:user][:user_id],
77
+ result[:user][:domain],
78
+ result[:registration_id],
79
+ result[:activation_password],
80
+ gateway
81
+ ]
82
+
83
+ # Encode it as hex
84
+ return message.split(//).map {|c| '%x' % c.ord}.join
85
+ end
86
+
87
+ protected
88
+ # The provisioningExecute command has the same
89
+ # design as the rest of the API, with a single
90
+ # multi-purpose `results` element that carries
91
+ # key-value results.
92
+ #
93
+ # Instead, dsappSRPRegister and other commands
94
+ # use a different design with return types and
95
+ # values predefined in the WSDL.
96
+ #
97
+ # So if we have a `results` element, this is a
98
+ # old-style response, and we delegate parsing
99
+ # to the parent class, otherwise if we detect
100
+ # the `result` and `status` elements, we parse
101
+ # in this class, basically just returning the
102
+ # values that Savon parsed for us.
103
+ #
104
+ def parse_result_element(root, root_element)
105
+ if root.key?(:results)
106
+ root[:results]
107
+ else
108
+ root
109
+ end
110
+ end
111
+
112
+ def parse_result_code(root, root_element)
113
+ if root.key?(:status)
114
+ super root[:status], root_element
115
+ else
116
+ super
117
+ end
118
+ end
119
+
120
+ # This may be an old or a new style response.
121
+ #
122
+ # New style responses may have both `result`
123
+ # and `status` elements, or only a `status`
124
+ # element.
125
+ #
126
+ # If there is no `result` but there is a
127
+ # `status`, then consider this a new style
128
+ # response and return an empty result. Else,
129
+ # pass along to the superclass to parse the
130
+ # old style response.
131
+ #
132
+ def parse_result_attributes(root, root_element)
133
+ if root.key?(:result)
134
+ root[:result]
135
+ elsif root.key?(:status)
136
+ nil
137
+ else
138
+ super
139
+ end
140
+ end
141
+
142
+ def parse_result_errors(root, root_element)
143
+ if root.key?(:status)
144
+ super root[:status], root_element
145
+ else
146
+ super
147
+ end
148
+ end
149
+ end
150
+ end
@@ -1,3 +1,3 @@
1
1
  module Identikey
2
- VERSION = "0.8.2"
2
+ VERSION = "0.9.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: identikey
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.2
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marcello Barnaba
8
8
  autorequire:
9
- bindir: exe
9
+ bindir: bin
10
10
  cert_chain: []
11
- date: 2020-08-22 00:00:00.000000000 Z
11
+ date: 2020-10-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: savon
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '2.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: wasabi
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 3.5.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 3.5.0
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: bundler
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -206,6 +220,7 @@ files:
206
220
  - lib/identikey/authentication.rb
207
221
  - lib/identikey/base.rb
208
222
  - lib/identikey/error.rb
223
+ - lib/identikey/provisioning.rb
209
224
  - lib/identikey/unsigned.rb
210
225
  - lib/identikey/version.rb
211
226
  - log/.keep