identikey 0.8.2 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/bin/console +7 -0
- data/identikey.gemspec +1 -2
- data/lib/identikey.rb +1 -0
- data/lib/identikey/administration.rb +21 -1
- data/lib/identikey/authentication.rb +11 -0
- data/lib/identikey/base.rb +30 -24
- data/lib/identikey/provisioning.rb +150 -0
- data/lib/identikey/version.rb +1 -1
- metadata +18 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8b12db6aa0435e14bd281a73d2ab1c50edc993ecb41cfe8933d180607bb22c36
|
4
|
+
data.tar.gz: 322412ff65c22664df05aa4e6e7c69d9da9a7851e827b97519a19b22162ab387
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d71931f68cbca537fdecbe4771d1aa4ef393d365a1654cfc1864ea6e3a43926d80a2dfee770f7d493eb211bbfeef8010e6b4f0bdad15c47c53d527abce3d2340
|
7
|
+
data.tar.gz: f42408a94e658295522ddbfcfc9ffc90668c5e8a1d30cc0beac1f3463e2ecc12d1ade779df010236dbe9e682c476270d983f6b85774188f3db2eb095010713bb
|
data/bin/console
CHANGED
@@ -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'),
|
data/identikey.gemspec
CHANGED
@@ -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"
|
data/lib/identikey.rb
CHANGED
@@ -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
|
data/lib/identikey/base.rb
CHANGED
@@ -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
|
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
|
-
|
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
|
-
|
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
|
-
|
170
|
+
return root[:results]
|
171
|
+
end
|
163
172
|
|
164
|
-
|
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
|
-
|
178
|
+
results[:result_codes][:status_code_enum] || 'STAT_UNKNOWN'
|
179
|
+
end
|
171
180
|
|
172
|
-
|
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
|
-
|
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
|
-
|
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
|
data/lib/identikey/version.rb
CHANGED
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.
|
4
|
+
version: 0.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Marcello Barnaba
|
8
8
|
autorequire:
|
9
|
-
bindir:
|
9
|
+
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
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
|