duo_api 1.4.0 → 1.5.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/ca_certs.pem +453 -85
- data/lib/duo_api/accounts.rb +70 -0
- data/lib/duo_api/admin.rb +832 -0
- data/lib/duo_api/api_client.rb +204 -0
- data/lib/duo_api/api_helpers.rb +195 -0
- data/lib/duo_api/auth.rb +63 -0
- data/lib/duo_api/device.rb +62 -0
- data/lib/duo_api.rb +7 -163
- metadata +38 -18
@@ -0,0 +1,832 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'api_client'
|
4
|
+
require_relative 'api_helpers'
|
5
|
+
|
6
|
+
class DuoApi
|
7
|
+
##
|
8
|
+
# Duo Admin API (https://duo.com/docs/adminapi)
|
9
|
+
#
|
10
|
+
class Admin < DuoApi
|
11
|
+
##
|
12
|
+
# Users
|
13
|
+
#
|
14
|
+
def get_users(**optional_params)
|
15
|
+
# optional_params: username, email, user_id_list, username_list
|
16
|
+
optional_params.tap do |p|
|
17
|
+
p[:user_id_list] = json_serialized_array(p[:user_id_list]) if p[:user_id_list]
|
18
|
+
p[:username_list] = json_serialized_array(p[:username_list]) if p[:username_list]
|
19
|
+
end
|
20
|
+
get_all('/admin/v1/users', optional_params)[:response]
|
21
|
+
end
|
22
|
+
|
23
|
+
def create_user(username:, **optional_params)
|
24
|
+
# optional_params: alias1, alias2, alias3, alias4, aliases, realname, email,
|
25
|
+
# enable_auto_prompt, status, notes, firstname, lastname
|
26
|
+
optional_params.tap do |p|
|
27
|
+
p[:aliases] = serialized_aliases(p[:aliases]) if p[:aliases]
|
28
|
+
end
|
29
|
+
params = optional_params.merge({ username: username })
|
30
|
+
post('/admin/v1/users', params)[:response]
|
31
|
+
end
|
32
|
+
|
33
|
+
def bulk_create_users(users:)
|
34
|
+
# Each user hash in users array requires :username and supports the following
|
35
|
+
# optional keys: realname, emaiml, status, notes, firstname, lastname
|
36
|
+
params = { users: json_serialized_array(users) }
|
37
|
+
post('/admin/v1/users/bulk_create', params)[:response]
|
38
|
+
end
|
39
|
+
|
40
|
+
def bulk_restore_users(user_id_list:)
|
41
|
+
params = { user_id_list: json_serialized_array(user_id_list) }
|
42
|
+
post('/admin/v1/users/bulk_restore', params)[:response]
|
43
|
+
end
|
44
|
+
|
45
|
+
def bulk_trash_users(user_id_list:)
|
46
|
+
params = { user_id_list: json_serialized_array(user_id_list) }
|
47
|
+
post('/admin/v1/users/bulk_send_to_trash', params)[:response]
|
48
|
+
end
|
49
|
+
|
50
|
+
def get_user(user_id:)
|
51
|
+
get("/admin/v1/users/#{user_id}")[:response]
|
52
|
+
end
|
53
|
+
|
54
|
+
def update_user(user_id:, **optional_params)
|
55
|
+
# optional_params: alias1, alias2, alias3, alias4, aliases, realname, email,
|
56
|
+
# enable_auto_prompt, status, notes, firstname, lastname,
|
57
|
+
# username
|
58
|
+
optional_params.tap do |p|
|
59
|
+
p[:aliases] = serialized_aliases(p[:aliases]) if p[:aliases]
|
60
|
+
end
|
61
|
+
post("/admin/v1/users/#{user_id}", optional_params)[:response]
|
62
|
+
end
|
63
|
+
|
64
|
+
def delete_user(user_id:)
|
65
|
+
delete("/admin/v1/users/#{user_id}")[:response]
|
66
|
+
end
|
67
|
+
|
68
|
+
def enroll_user(username:, email:, **optional_params)
|
69
|
+
# optional_params: valid_secs
|
70
|
+
params = optional_params.merge({ username: username, email: email })
|
71
|
+
post('/admin/v1/users/enroll', params)[:response]
|
72
|
+
end
|
73
|
+
|
74
|
+
def create_user_bypass_codes(user_id:, **optional_params)
|
75
|
+
# optional_params: count, codes, preserve_existing, reuse_count, valid_secs
|
76
|
+
optional_params.tap do |p|
|
77
|
+
p[:codes] = csv_serialized_array(p[:codes]) if p[:codes]
|
78
|
+
end
|
79
|
+
post("/admin/v1/users/#{user_id}/bypass_codes", optional_params)[:response]
|
80
|
+
end
|
81
|
+
|
82
|
+
def get_user_bypass_codes(user_id:)
|
83
|
+
get_all("/admin/v1/users/#{user_id}/bypass_codes")[:response]
|
84
|
+
end
|
85
|
+
|
86
|
+
def get_user_groups(user_id:)
|
87
|
+
get_all("/admin/v1/users/#{user_id}/groups")[:response]
|
88
|
+
end
|
89
|
+
|
90
|
+
def add_user_group(user_id:, group_id:)
|
91
|
+
params = { group_id: group_id }
|
92
|
+
post("/admin/v1/users/#{user_id}/groups", params)[:response]
|
93
|
+
end
|
94
|
+
|
95
|
+
def remove_user_group(user_id:, group_id:)
|
96
|
+
delete("/admin/v1/users/#{user_id}/groups/#{group_id}")[:response]
|
97
|
+
end
|
98
|
+
|
99
|
+
def get_user_phones(user_id:)
|
100
|
+
get_all("/admin/v1/users/#{user_id}/phones")[:response]
|
101
|
+
end
|
102
|
+
|
103
|
+
def add_user_phone(user_id:, phone_id:)
|
104
|
+
params = { phone_id: phone_id }
|
105
|
+
post("/admin/v1/users/#{user_id}/phones", params)[:response]
|
106
|
+
end
|
107
|
+
|
108
|
+
def remove_user_phone(user_id:, phone_id:)
|
109
|
+
delete("/admin/v1/users/#{user_id}/phones/#{phone_id}")[:response]
|
110
|
+
end
|
111
|
+
|
112
|
+
def get_user_hardware_tokens(user_id:)
|
113
|
+
get_all("/admin/v1/users/#{user_id}/tokens")[:response]
|
114
|
+
end
|
115
|
+
|
116
|
+
def add_user_hardware_token(user_id:, token_id:)
|
117
|
+
params = { token_id: token_id }
|
118
|
+
post("/admin/v1/users/#{user_id}/tokens", params)[:response]
|
119
|
+
end
|
120
|
+
|
121
|
+
def remove_user_hardware_token(user_id:, token_id:)
|
122
|
+
delete("/admin/v1/users/#{user_id}/tokens/#{token_id}")[:response]
|
123
|
+
end
|
124
|
+
|
125
|
+
def get_user_webauthn_credentials(user_id:)
|
126
|
+
get_all("/admin/v1/users/#{user_id}/webauthncredentials")[:response]
|
127
|
+
end
|
128
|
+
|
129
|
+
def get_user_desktop_authenticators(user_id:)
|
130
|
+
get_all("/admin/v1/users/#{user_id}/desktopauthenticators")[:response]
|
131
|
+
end
|
132
|
+
|
133
|
+
def sync_user(username:, directory_key:)
|
134
|
+
params = { username: username }
|
135
|
+
post("/admin/v1/users/directorysync/#{directory_key}/syncuser", params)[:response]
|
136
|
+
end
|
137
|
+
|
138
|
+
def send_verification_push(user_id:, phone_id:)
|
139
|
+
params = { phone_id: phone_id }
|
140
|
+
post("/admin/v1/users/#{user_id}/send_verification_push", params)[:response]
|
141
|
+
end
|
142
|
+
|
143
|
+
def get_verification_push_response(user_id:, push_id:)
|
144
|
+
params = { push_id: push_id }
|
145
|
+
get("/admin/v1/users/#{user_id}/verification_push_response", params)[:response]
|
146
|
+
end
|
147
|
+
|
148
|
+
##
|
149
|
+
# Bulk Operations
|
150
|
+
#
|
151
|
+
def bulk_operations(operations:)
|
152
|
+
# Each hash in user_operations array requires :method, :path, and :body
|
153
|
+
# Each :body has the same parameter requirements as the individual operation
|
154
|
+
# Supported operations:
|
155
|
+
# Create User: POST /admin/v1/users
|
156
|
+
# Modify User: POST /admin/v1/users/[user_id]
|
157
|
+
# Delete User: DELETE /admin/v1/users/[user_id]
|
158
|
+
# Add User Group: POST /admin/v1/users/[user_id]/groups
|
159
|
+
# Remove User Group: POST /admin/v1/users/[user_id]/groups/[group_id]
|
160
|
+
operations.each{ |o| o[:body][:aliases] = serialized_aliases(o[:body][:aliases]) if o[:body][:aliases] }
|
161
|
+
params = { operations: json_serialized_array(operations) }
|
162
|
+
post('/admin/v1/bulk', params)[:response]
|
163
|
+
end
|
164
|
+
|
165
|
+
##
|
166
|
+
# Groups
|
167
|
+
#
|
168
|
+
def get_groups(**optional_params)
|
169
|
+
# optional_params: group_id_list
|
170
|
+
get_all('/admin/v1/groups', optional_params)[:response]
|
171
|
+
end
|
172
|
+
|
173
|
+
def create_group(name:, **optional_params)
|
174
|
+
# optional_params: desc, status
|
175
|
+
params = optional_params.merge({ name: name })
|
176
|
+
post('/admin/v1/groups', params)[:response]
|
177
|
+
end
|
178
|
+
|
179
|
+
def get_group(group_id:)
|
180
|
+
get("/admin/v2/groups/#{group_id}")[:response]
|
181
|
+
end
|
182
|
+
|
183
|
+
def get_group_users(group_id:)
|
184
|
+
get_all("/admin/v2/groups/#{group_id}/users")[:response]
|
185
|
+
end
|
186
|
+
|
187
|
+
def update_group(group_id:, **optional_params)
|
188
|
+
# optional_params: desc, status, name
|
189
|
+
post("/admin/v1/groups/#{group_id}", optional_params)[:response]
|
190
|
+
end
|
191
|
+
|
192
|
+
def delete_group(group_id:)
|
193
|
+
delete("/admin/v1/groups/#{group_id}")[:response]
|
194
|
+
end
|
195
|
+
|
196
|
+
##
|
197
|
+
# Phones
|
198
|
+
#
|
199
|
+
def get_phones(**optional_params)
|
200
|
+
# optional_params: number, extension
|
201
|
+
get_all('/admin/v1/phones', optional_params)[:response]
|
202
|
+
end
|
203
|
+
|
204
|
+
def create_phone(**optional_params)
|
205
|
+
# optional_params: number, name, extension, type, platform, predelay, postdelay
|
206
|
+
post('/admin/v1/phones', optional_params)[:response]
|
207
|
+
end
|
208
|
+
|
209
|
+
def get_phone(phone_id:)
|
210
|
+
get("/admin/v1/phones/#{phone_id}")[:response]
|
211
|
+
end
|
212
|
+
|
213
|
+
def update_phone(phone_id:, **optional_params)
|
214
|
+
# optional_params: number, name, extension, type, platform, predelay, postdelay
|
215
|
+
post("/admin/v1/phones/#{phone_id}", optional_params)[:response]
|
216
|
+
end
|
217
|
+
|
218
|
+
def delete_phone(phone_id:)
|
219
|
+
delete("/admin/v1/phones/#{phone_id}")[:response]
|
220
|
+
end
|
221
|
+
|
222
|
+
def create_activation_url(phone_id:, **optional_params)
|
223
|
+
# optional_params: valid_secs, install
|
224
|
+
post("/admin/v1/phones/#{phone_id}/activation_url", optional_params)[:response]
|
225
|
+
end
|
226
|
+
|
227
|
+
def send_sms_activation(phone_id:, **optional_params)
|
228
|
+
# optional_params: valid_secs, install, installation_msg, activation_msg
|
229
|
+
post("/admin/v1/phones/#{phone_id}/send_sms_activation", optional_params)[:response]
|
230
|
+
end
|
231
|
+
|
232
|
+
def send_sms_installation(phone_id:, **optional_params)
|
233
|
+
# optional_params: installation_msg
|
234
|
+
post("/admin/v1/phones/#{phone_id}/send_sms_installation", optional_params)[:response]
|
235
|
+
end
|
236
|
+
|
237
|
+
def send_sms_passcodes(phone_id:)
|
238
|
+
post("/admin/v1/phones/#{phone_id}/send_sms_passcodes")[:response]
|
239
|
+
end
|
240
|
+
|
241
|
+
##
|
242
|
+
# Tokens
|
243
|
+
#
|
244
|
+
def get_tokens(**optional_params)
|
245
|
+
# optional_params: type, serial
|
246
|
+
get_all('/admin/v1/tokens', optional_params)[:response]
|
247
|
+
end
|
248
|
+
|
249
|
+
def create_token(type:, serial:, **optional_params)
|
250
|
+
# optional_params: secret, counter, private_id, aes_key
|
251
|
+
params = optional_params.merge({ type: type, serial: serial })
|
252
|
+
post('/admin/v1/tokens', params)[:response]
|
253
|
+
end
|
254
|
+
|
255
|
+
def get_token(token_id:)
|
256
|
+
get("/admin/v1/tokens/#{token_id}")[:response]
|
257
|
+
end
|
258
|
+
|
259
|
+
def resync_token(token_id:, code1:, code2:, code3:)
|
260
|
+
params = { code1: code1, code2: code2, code3: code3 }
|
261
|
+
post("/admin/v1/tokens/#{token_id}/resync", params)[:response]
|
262
|
+
end
|
263
|
+
|
264
|
+
def delete_token(token_id:)
|
265
|
+
delete("/admin/v1/tokens/#{token_id}")[:response]
|
266
|
+
end
|
267
|
+
|
268
|
+
##
|
269
|
+
# WebAuthn Credentials
|
270
|
+
#
|
271
|
+
def get_webauthncredentials
|
272
|
+
get_all('/admin/v1/webauthncredentials')[:response]
|
273
|
+
end
|
274
|
+
|
275
|
+
def get_webauthncredential(webauthnkey:)
|
276
|
+
get("/admin/v1/webauthncredentials/#{webauthnkey}")[:response]
|
277
|
+
end
|
278
|
+
|
279
|
+
def delete_webauthncredential(webauthnkey:)
|
280
|
+
delete("/admin/v1/webauthncredentials/#{webauthnkey}")[:response]
|
281
|
+
end
|
282
|
+
|
283
|
+
##
|
284
|
+
# Desktop Authenticators
|
285
|
+
#
|
286
|
+
def get_desktop_authenticators
|
287
|
+
get_all('/admin/v1/desktop_authenticators')[:response]
|
288
|
+
end
|
289
|
+
|
290
|
+
def get_desktop_authenticator(dakey:)
|
291
|
+
get("/admin/v1/desktop_authenticators/#{dakey}")[:response]
|
292
|
+
end
|
293
|
+
|
294
|
+
def delete_desktop_authenticator(dakey:)
|
295
|
+
delete("/admin/v1/desktop_authenticators/#{dakey}")[:response]
|
296
|
+
end
|
297
|
+
|
298
|
+
def get_shared_desktop_authenticators
|
299
|
+
get_all('/admin/v1/desktop_authenticators/shared_device_auth')[:response]
|
300
|
+
end
|
301
|
+
|
302
|
+
def get_shared_desktop_authenticator(shared_device_key:)
|
303
|
+
get("/admin/v1/desktop_authenticators/shared_device_auth/#{shared_device_key}")[:response]
|
304
|
+
end
|
305
|
+
|
306
|
+
def create_shared_desktop_authenticator(group_id_list:, trusted_endpoint_integration_id_list:,
|
307
|
+
**optional_params)
|
308
|
+
# optional_params: active, name
|
309
|
+
params = optional_params.merge({
|
310
|
+
group_id_list: group_id_list,
|
311
|
+
trusted_endpoint_integration_id_list: trusted_endpoint_integration_id_list
|
312
|
+
})
|
313
|
+
post('/admin/v1/desktop_authenticators/shared_device_auth', params)[:response]
|
314
|
+
end
|
315
|
+
|
316
|
+
def update_shared_desktop_authenticator(shared_device_key:, **optional_params)
|
317
|
+
# optional_params: active, name, group_id_list, trusted_endpoint_integration_id_list
|
318
|
+
put("/admin/v1/desktop_authenticators/shared_device_auth/#{shared_device_key}",
|
319
|
+
optional_params)[:response]
|
320
|
+
end
|
321
|
+
|
322
|
+
def delete_shared_desktop_authenticator(shared_device_key:)
|
323
|
+
delete("/admin/v1/desktop_authenticators/shared_device_auth/#{shared_device_key}")[:response]
|
324
|
+
end
|
325
|
+
|
326
|
+
##
|
327
|
+
# Bypass Codes
|
328
|
+
#
|
329
|
+
def get_bypass_codes
|
330
|
+
get_all('/admin/v1/bypass_codes')[:response]
|
331
|
+
end
|
332
|
+
|
333
|
+
def get_bypass_code(bypass_code_id:)
|
334
|
+
get("/admin/v1/bypass_codes/#{bypass_code_id}")[:response]
|
335
|
+
end
|
336
|
+
|
337
|
+
def delete_bypass_code(bypass_code_id:)
|
338
|
+
delete("/admin/v1/bypass_codes/#{bypass_code_id}")[:response]
|
339
|
+
end
|
340
|
+
|
341
|
+
##
|
342
|
+
# Integrations
|
343
|
+
#
|
344
|
+
def get_integrations
|
345
|
+
get_all('/admin/v3/integrations')[:response]
|
346
|
+
end
|
347
|
+
|
348
|
+
def create_integration(name:, type:, **optional_params)
|
349
|
+
# optional_params: adminapi_admins, adminapi_admins_read, adminapi_allow_to_set_permissions,
|
350
|
+
# adminapi_info, adminapi_integrations, adminapi_read_log,
|
351
|
+
# adminapi_read_resource, adminapi_settings, adminapi_write_resource,
|
352
|
+
# enroll_policy, greeting, groups_allowed, ip_whitelist,
|
353
|
+
# ip_whitelist_enroll_policy, networks_for_api_access, notes,
|
354
|
+
# trusted_device_days, self_service_allowed, sso, username_normalization_policy
|
355
|
+
#
|
356
|
+
# sso params: https://duo.com/docs/adminapi#sso-parameters
|
357
|
+
params = optional_params.merge({ name: name, type: type })
|
358
|
+
post('/admin/v3/integrations', params)[:response]
|
359
|
+
end
|
360
|
+
|
361
|
+
def get_integration(integration_key:)
|
362
|
+
get("/admin/v3/integrations/#{integration_key}")[:response]
|
363
|
+
end
|
364
|
+
|
365
|
+
def update_integration(integration_key:, **optional_params)
|
366
|
+
# optional_params: adminapi_admins, adminapi_admins_read, adminapi_allow_to_set_permissions,
|
367
|
+
# adminapi_info, adminapi_integrations, adminapi_read_log,
|
368
|
+
# adminapi_read_resource, adminapi_settings, adminapi_write_resource,
|
369
|
+
# enroll_policy, greeting, groups_allowed, ip_whitelist,
|
370
|
+
# ip_whitelist_enroll_policy, networks_for_api_access, notes,
|
371
|
+
# trusted_device_days, self_service_allowed, sso, username_normalization_policy,
|
372
|
+
# name, policy_key, prompt_v4_enabled, reset_secret_key
|
373
|
+
#
|
374
|
+
# sso params: https://duo.com/docs/adminapi#sso-parameters
|
375
|
+
post("/admin/v3/integrations/#{integration_key}", optional_params)[:response]
|
376
|
+
end
|
377
|
+
|
378
|
+
def delete_integration(integration_key:)
|
379
|
+
delete("/admin/v3/integrations/#{integration_key}")[:response]
|
380
|
+
end
|
381
|
+
|
382
|
+
def get_integration_secret_key(integration_key:)
|
383
|
+
get("/admin/v1/integrations/#{integration_key}/skey")[:response]
|
384
|
+
end
|
385
|
+
|
386
|
+
def get_oauth_integration_client_secret(integration_key:, client_id:)
|
387
|
+
get("/admin/v2/integrations/oauth_cc/#{integration_key}/client_secret/#{client_id}")[:response]
|
388
|
+
end
|
389
|
+
|
390
|
+
def reset_oauth_integration_client_secret(integration_key:, client_id:)
|
391
|
+
post("/admin/v2/integrations/oauth_cc/#{integration_key}/client_secret/#{client_id}")[:response]
|
392
|
+
end
|
393
|
+
|
394
|
+
def get_oidc_integration_client_secret(integration_key:)
|
395
|
+
get("/admin/v2/integrations/oidc/#{integration_key}/client_secret")[:response]
|
396
|
+
end
|
397
|
+
|
398
|
+
def reset_oidc_integration_client_secret(integration_key:)
|
399
|
+
post("/admin/v2/integrations/oidc/#{integration_key}/client_secret")[:response]
|
400
|
+
end
|
401
|
+
|
402
|
+
##
|
403
|
+
# Policies
|
404
|
+
#
|
405
|
+
def get_policies_summary
|
406
|
+
get('/admin/v2/policies/summary')[:response]
|
407
|
+
end
|
408
|
+
|
409
|
+
def get_policies
|
410
|
+
get_all('/admin/v2/policies')[:response]
|
411
|
+
end
|
412
|
+
|
413
|
+
def get_global_policy
|
414
|
+
get('/admin/v2/policies/global')[:response]
|
415
|
+
end
|
416
|
+
|
417
|
+
def get_policy(policy_key:)
|
418
|
+
get("/admin/v2/policies/#{policy_key}")[:response]
|
419
|
+
end
|
420
|
+
|
421
|
+
def calculate_policy(user_id:, integration_key:)
|
422
|
+
params = { user_id: user_id, integration_key: integration_key }
|
423
|
+
get('/admin/v2/policies/calculate', params)[:response]
|
424
|
+
end
|
425
|
+
|
426
|
+
def copy_policy(policy_key:, **optional_params)
|
427
|
+
# optional_params: new_policy_names_list
|
428
|
+
params = optional_params.merge({ policy_key: policy_key })
|
429
|
+
post('/admin/v2/policies/copy', params)[:response]
|
430
|
+
end
|
431
|
+
|
432
|
+
def create_policy(policy_name:, **optional_params)
|
433
|
+
# optional_params: apply_to_apps, apply_to_groups_in_apps, sections
|
434
|
+
params = optional_params.merge({ policy_name: policy_name })
|
435
|
+
post('/admin/v2/policies', params)[:response]
|
436
|
+
end
|
437
|
+
|
438
|
+
def update_policies(policies_to_update:, policy_changes:)
|
439
|
+
# parameter formatting: https://duo.com/docs/adminapi#update-policies
|
440
|
+
params = { policies_to_update: policies_to_update, policy_changes: policy_changes }
|
441
|
+
put('/admin/v2/policies/update', params)[:response]
|
442
|
+
end
|
443
|
+
|
444
|
+
def update_policy(policy_key:, **optional_params)
|
445
|
+
# optional_params: apply_to_apps, apply_to_groups_in_apps, sections,
|
446
|
+
# policy_name, sections_to_delete
|
447
|
+
params = optional_params.merge({ policy_key: policy_key })
|
448
|
+
put("/admin/v2/policies/#{policy_key}", params)[:response]
|
449
|
+
end
|
450
|
+
|
451
|
+
def delete_policy(policy_key:)
|
452
|
+
delete("/admin/v2/policies/#{policy_key}")[:response]
|
453
|
+
end
|
454
|
+
|
455
|
+
##
|
456
|
+
# Endpoints
|
457
|
+
#
|
458
|
+
def get_endpoints
|
459
|
+
get_all('/admin/v1/endpoints')[:response]
|
460
|
+
end
|
461
|
+
|
462
|
+
def get_endpoint(epkey:)
|
463
|
+
get("/admin/v1/endpoints/#{epkey}")[:response]
|
464
|
+
end
|
465
|
+
|
466
|
+
##
|
467
|
+
# Registered Devices
|
468
|
+
#
|
469
|
+
def get_registered_devices
|
470
|
+
get_all('/admin/v1/registered_devices')[:response]
|
471
|
+
end
|
472
|
+
|
473
|
+
def get_registered_device(compkey:)
|
474
|
+
get("/admin/v1/registered_devices/#{compkey}")[:response]
|
475
|
+
end
|
476
|
+
|
477
|
+
def delete_registered_device(compkey:)
|
478
|
+
delete("/admin/v1/registered_devices/#{compkey}")[:response]
|
479
|
+
end
|
480
|
+
|
481
|
+
def get_blocked_registered_devices
|
482
|
+
get_all('/admin/v1/registered_devices/blocked')[:response]
|
483
|
+
end
|
484
|
+
|
485
|
+
def get_blocked_registered_device(compkey:)
|
486
|
+
get("/admin/v1/registered_devices/blocked/#{compkey}")[:response]
|
487
|
+
end
|
488
|
+
|
489
|
+
def block_registered_devices(registered_device_key_list:)
|
490
|
+
params = { registered_device_key_list: registered_device_key_list }
|
491
|
+
post('/admin/v1/registered_devices/blocked', params)[:response]
|
492
|
+
end
|
493
|
+
|
494
|
+
def block_registered_device(compkey:)
|
495
|
+
post("/admin/v1/registered_devices/blocked/#{compkey}")[:response]
|
496
|
+
end
|
497
|
+
|
498
|
+
def unblock_registered_devices(registered_device_key_list:)
|
499
|
+
params = { registered_device_key_list: registered_device_key_list }
|
500
|
+
delete('/admin/v1/registered_devices/blocked', params)[:response]
|
501
|
+
end
|
502
|
+
|
503
|
+
def unblock_registered_device(compkey:)
|
504
|
+
delete("/admin/v1/registered_devices/blocked/#{compkey}")[:response]
|
505
|
+
end
|
506
|
+
|
507
|
+
##
|
508
|
+
# Passport
|
509
|
+
#
|
510
|
+
def get_passport_config
|
511
|
+
get('/admin/v2/passport/config')[:response]
|
512
|
+
end
|
513
|
+
|
514
|
+
def update_passport_config(disabled_groups:, enabled_groups:, enabled_status:)
|
515
|
+
params = { disabled_groups: disabled_groups, enabled_groups: enabled_groups,
|
516
|
+
enabled_status: enabled_status }
|
517
|
+
post('/admin/v2/passport/config', params)[:response]
|
518
|
+
end
|
519
|
+
|
520
|
+
##
|
521
|
+
# Administrators
|
522
|
+
#
|
523
|
+
def get_admins
|
524
|
+
get_all('/admin/v1/admins')[:response]
|
525
|
+
end
|
526
|
+
|
527
|
+
def create_admin(email:, name:, **optional_params)
|
528
|
+
# optional_params: phone, role, restricted_by_admin_units, send_email, token_id, valid_days
|
529
|
+
params = optional_params.merge({ email: email, name: name })
|
530
|
+
post('/admin/v1/admins', params)[:response]
|
531
|
+
end
|
532
|
+
|
533
|
+
def get_admin(admin_id:)
|
534
|
+
get("/admin/v1/admins/#{admin_id}")[:response]
|
535
|
+
end
|
536
|
+
|
537
|
+
def update_admin(admin_id:, **optional_params)
|
538
|
+
# optional_params: phone, role, restricted_by_admin_units, token_id, name, status
|
539
|
+
post("/admin/v1/admins/#{admin_id}", optional_params)[:response]
|
540
|
+
end
|
541
|
+
|
542
|
+
def delete_admin(admin_id:)
|
543
|
+
delete("/admin/v1/admins/#{admin_id}")[:response]
|
544
|
+
end
|
545
|
+
|
546
|
+
def reset_admin_auth_attempts(admin_id:)
|
547
|
+
post("/admin/v1/admins/#{admin_id}/reset")[:response]
|
548
|
+
end
|
549
|
+
|
550
|
+
def clear_admin_inactivity(admin_id:)
|
551
|
+
post("/admin/v1/admins/#{admin_id}/clear_inactivity")[:response]
|
552
|
+
end
|
553
|
+
|
554
|
+
def create_existing_admin_activation_link(admin_id:)
|
555
|
+
post("/admin/v1/admins/#{admin_id}/activation_link")[:response]
|
556
|
+
end
|
557
|
+
|
558
|
+
def delete_existing_admin_activation_link(admin_id:)
|
559
|
+
delete("/admin/v1/admins/#{admin_id}/activation_link")[:response]
|
560
|
+
end
|
561
|
+
|
562
|
+
def email_existing_admin_activation_link(admin_id:)
|
563
|
+
post("/admin/v1/admins/#{admin_id}/activation_link/email")[:response]
|
564
|
+
end
|
565
|
+
|
566
|
+
def create_new_admin_activation_link(email:, **optional_params)
|
567
|
+
# optional_params: admin_name, admin_role, send_email, valid_days
|
568
|
+
params = optional_params.merge({ email: email })
|
569
|
+
post('/admin/v1/admins/activations', params)[:response]
|
570
|
+
end
|
571
|
+
|
572
|
+
def get_new_admin_pending_activations
|
573
|
+
get_all('/admin/v1/admins/activations')[:response]
|
574
|
+
end
|
575
|
+
|
576
|
+
def delete_new_admin_pending_activations(admin_activation_id:)
|
577
|
+
delete("/admin/v1/admins/activations/#{admin_activation_id}")[:response]
|
578
|
+
end
|
579
|
+
|
580
|
+
def sync_admin(directory_key:, email:)
|
581
|
+
params = { email: email }
|
582
|
+
post("/admin/v1/admins/directorysync/#{directory_key}/syncadmin", params)[:response]
|
583
|
+
end
|
584
|
+
|
585
|
+
def get_admin_password_mgmt_statuses
|
586
|
+
get_all('/admin/v1/admins/password_mgmt')[:response]
|
587
|
+
end
|
588
|
+
|
589
|
+
def get_admin_password_mgmt_status(admin_id:)
|
590
|
+
get("/admin/v1/admins/#{admin_id}/password_mgmt")[:response]
|
591
|
+
end
|
592
|
+
|
593
|
+
def update_admin_password_mgmt_status(admin_id:, **optional_params)
|
594
|
+
# optional_params: has_external_password_mgmt, password
|
595
|
+
post("/admin/v1/admins/#{admin_id}/password_mgmt", optional_params)[:response]
|
596
|
+
end
|
597
|
+
|
598
|
+
def get_admin_allowed_auth_factors
|
599
|
+
get('/admin/v1/admins/allowed_auth_methods')[:response]
|
600
|
+
end
|
601
|
+
|
602
|
+
def update_admin_allowed_auth_factors(**optional_params)
|
603
|
+
# optional_params: hardware_token_enabled, mobile_otp_enabled, push_enabled, sms_enabled,
|
604
|
+
# verified_push_enabled, verified_push_length, voice_enabled, webauthn_enabled,
|
605
|
+
# yubikey_enabled
|
606
|
+
post('/admin/v1/admins/allowed_auth_methods', optional_params)[:response]
|
607
|
+
end
|
608
|
+
|
609
|
+
##
|
610
|
+
# Administrative Units
|
611
|
+
#
|
612
|
+
def get_administrative_units(**optional_params)
|
613
|
+
# optional_params: admin_id, group_id, integration_key
|
614
|
+
get_all('/admin/v1/administrative_units', optional_params)[:response]
|
615
|
+
end
|
616
|
+
|
617
|
+
def get_administrative_unit(admin_unit_id:)
|
618
|
+
get("/admin/v1/administrative_units/#{admin_unit_id}")[:response]
|
619
|
+
end
|
620
|
+
|
621
|
+
def create_administrative_unit(name:, description:, restrict_by_groups:, **optional_params)
|
622
|
+
# optional_params: restrict_by_integrations, admins, groups, integrations
|
623
|
+
params = optional_params.merge({ name: name, description: description,
|
624
|
+
restrict_by_groups: restrict_by_groups })
|
625
|
+
post('/admin/v1/administrative_units', params)[:response]
|
626
|
+
end
|
627
|
+
|
628
|
+
def update_administrative_unit(admin_unit_id:, **optional_params)
|
629
|
+
# optional_params: restrict_by_integrations, admins, groups, integrations,
|
630
|
+
# name, description, restrict_by_groups
|
631
|
+
post("/admin/v1/administrative_units/#{admin_unit_id}", optional_params)[:response]
|
632
|
+
end
|
633
|
+
|
634
|
+
def add_administrative_unit_admin(admin_unit_id:, admin_id:)
|
635
|
+
post("/admin/v1/administrative_units/#{admin_unit_id}/admin/#{admin_id}")[:response]
|
636
|
+
end
|
637
|
+
|
638
|
+
def remove_administrative_unit_admin(admin_unit_id:, admin_id:)
|
639
|
+
delete("/admin/v1/administrative_units/#{admin_unit_id}/admin/#{admin_id}")[:response]
|
640
|
+
end
|
641
|
+
|
642
|
+
def add_administrative_unit_group(admin_unit_id:, group_id:)
|
643
|
+
post("/admin/v1/administrative_units/#{admin_unit_id}/group/#{group_id}")[:response]
|
644
|
+
end
|
645
|
+
|
646
|
+
def remove_administrative_unit_group(admin_unit_id:, group_id:)
|
647
|
+
delete("/admin/v1/administrative_units/#{admin_unit_id}/group/#{group_id}")[:response]
|
648
|
+
end
|
649
|
+
|
650
|
+
def add_administrative_unit_integration(admin_unit_id:, integration_key:)
|
651
|
+
post("/admin/v1/administrative_units/#{admin_unit_id}/integration/#{integration_key}")[:response]
|
652
|
+
end
|
653
|
+
|
654
|
+
def remove_administrative_unit_integration(admin_unit_id:, integration_key:)
|
655
|
+
delete("/admin/v1/administrative_units/#{admin_unit_id}/integration/#{integration_key}")[:response]
|
656
|
+
end
|
657
|
+
|
658
|
+
def delete_administrative_unit(admin_unit_id:)
|
659
|
+
delete("/admin/v1/administrative_units/#{admin_unit_id}")[:response]
|
660
|
+
end
|
661
|
+
|
662
|
+
##
|
663
|
+
# Logs
|
664
|
+
#
|
665
|
+
def get_authentication_logs(mintime:, maxtime:, **optional_params)
|
666
|
+
# optional_params: applications, users, assessment, detections, event_types, factors, formatter,
|
667
|
+
# groups, phone_numbers, reasons, results, tokens, sort
|
668
|
+
#
|
669
|
+
# more info: https://duo.com/docs/adminapi#authentication-logs
|
670
|
+
params = optional_params.merge({ mintime: mintime, maxtime: maxtime })
|
671
|
+
data_array_path = %i[response authlogs]
|
672
|
+
metadata_path = %i[response metadata]
|
673
|
+
get_all('/admin/v2/logs/authentication', params, data_array_path: data_array_path,
|
674
|
+
metadata_path: metadata_path).dig(*data_array_path)
|
675
|
+
end
|
676
|
+
|
677
|
+
def get_activity_logs(mintime:, maxtime:, **optional_params)
|
678
|
+
# optional_params: sort
|
679
|
+
params = optional_params.merge({ mintime: mintime, maxtime: maxtime })
|
680
|
+
data_array_path = %i[response items]
|
681
|
+
metadata_path = %i[response metadata]
|
682
|
+
get_all('/admin/v2/logs/activity', params, data_array_path: data_array_path,
|
683
|
+
metadata_path: metadata_path).dig(*data_array_path)
|
684
|
+
end
|
685
|
+
|
686
|
+
def get_admin_logs(**optional_params)
|
687
|
+
# optional_params: mintime
|
688
|
+
get('/admin/v1/logs/administrator', optional_params)[:response]
|
689
|
+
end
|
690
|
+
|
691
|
+
def get_telephony_logs(mintime:, maxtime:, **optional_params)
|
692
|
+
# optional_params: sort
|
693
|
+
params = optional_params.merge({ mintime: mintime, maxtime: maxtime })
|
694
|
+
data_array_path = %i[response items]
|
695
|
+
metadata_path = %i[response metadata]
|
696
|
+
get_all('/admin/v2/logs/telephony', params, data_array_path: data_array_path,
|
697
|
+
metadata_path: metadata_path).dig(*data_array_path)
|
698
|
+
end
|
699
|
+
|
700
|
+
def get_offline_enrollment_logs(**optional_params)
|
701
|
+
# optional_params: mintime
|
702
|
+
get('/admin/v1/logs/offline_enrollment', optional_params)[:response]
|
703
|
+
end
|
704
|
+
|
705
|
+
##
|
706
|
+
# Trust Monitor
|
707
|
+
#
|
708
|
+
def get_trust_monitor_events(mintime:, maxtime:, **optional_params)
|
709
|
+
# optional_params: formatter, type
|
710
|
+
params = optional_params.merge({ mintime: mintime, maxtime: maxtime })
|
711
|
+
params[:limit] = 200 if !params[:limit] || (params[:limit].to_i > 200)
|
712
|
+
data_array_path = %i[response events]
|
713
|
+
metadata_path = %i[response metadata]
|
714
|
+
get_all('/admin/v1/trust_monitor/events', params, data_array_path: data_array_path,
|
715
|
+
metadata_path: metadata_path).dig(*data_array_path)
|
716
|
+
end
|
717
|
+
|
718
|
+
##
|
719
|
+
# Settings
|
720
|
+
#
|
721
|
+
def get_settings
|
722
|
+
get('/admin/v1/settings')[:response]
|
723
|
+
end
|
724
|
+
|
725
|
+
def update_settings(**optional_params)
|
726
|
+
# optional_params: caller_id, duo_mobile_otp_type, email_activity_notification_enabled,
|
727
|
+
# enrollment_universal_prompt_enabled, fraud_email, fraud_email_enabled,
|
728
|
+
# global_ssp_policy_enforced, helpdesk_bypass, helpdesk_bypass_expiration,
|
729
|
+
# helpdesk_can_send_enroll_email, inactive_user_expiration, keypress_confirm,
|
730
|
+
# keypress_fraud, language, lockout_expire_duration, lockout_threshold,
|
731
|
+
# log_retention_days, minimum_password_length, name,
|
732
|
+
# password_requires_lower_alpha, password_requires_numeric,
|
733
|
+
# password_requires_special, password_requires_upper_alpha,
|
734
|
+
# push_activity_notification_enabled, sms_batch, sms_expiration, sms_message,
|
735
|
+
# sms_refresh, telephony_warning_min, timezone, unenrolled_user_lockout_threshold,
|
736
|
+
# user_managers_can_put_users_in_bypass, user_telephony_cost_max
|
737
|
+
post('/admin/v1/settings', optional_params)[:response]
|
738
|
+
end
|
739
|
+
|
740
|
+
def get_logo
|
741
|
+
get_image('/admin/v1/logo')
|
742
|
+
end
|
743
|
+
|
744
|
+
def update_logo(logo:)
|
745
|
+
# logo should be raw png data or base64 strict encoded raw png data
|
746
|
+
encoded_logo = base64?(logo) ? logo : Base64.strict_encode64(logo)
|
747
|
+
params = { logo: encoded_logo }
|
748
|
+
post('/admin/v1/logo', params)[:response]
|
749
|
+
end
|
750
|
+
|
751
|
+
def delete_logo
|
752
|
+
delete('/admin/v1/logo')[:response]
|
753
|
+
end
|
754
|
+
|
755
|
+
##
|
756
|
+
# Custom Branding
|
757
|
+
#
|
758
|
+
def get_custom_branding
|
759
|
+
get('/admin/v1/branding')[:response]
|
760
|
+
end
|
761
|
+
|
762
|
+
def update_custom_branding(**optional_params)
|
763
|
+
# optional_params: background_img, card_accent_color, logo, page_background_color,
|
764
|
+
# powered_by_duo, sso_custom_username_label
|
765
|
+
post('/admin/v1/branding', optional_params)[:response]
|
766
|
+
end
|
767
|
+
|
768
|
+
def get_custom_branding_draft
|
769
|
+
get('/admin/v1/branding/draft')[:response]
|
770
|
+
end
|
771
|
+
|
772
|
+
def update_custom_branding_draft(**optional_params)
|
773
|
+
# optional_params: background_img, card_accent_color, logo, page_background_color,
|
774
|
+
# powered_by_duo, sso_custom_username_label, user_ids
|
775
|
+
post('/admin/v1/branding/draft', optional_params)[:response]
|
776
|
+
end
|
777
|
+
|
778
|
+
def add_custom_branding_draft_user(user_id:)
|
779
|
+
post("/admin/v1/branding/draft/users/#{user_id}")[:response]
|
780
|
+
end
|
781
|
+
|
782
|
+
def remove_custom_branding_draft_user(user_id:)
|
783
|
+
delete("/admin/v1/branding/draft/users/#{user_id}")[:response]
|
784
|
+
end
|
785
|
+
|
786
|
+
def publish_custom_branding_draft
|
787
|
+
post('/admin/v1/branding/draft/publish')[:response]
|
788
|
+
end
|
789
|
+
|
790
|
+
def get_custom_branding_messaging
|
791
|
+
get('/admin/v1/branding/custom_messaging')[:response]
|
792
|
+
end
|
793
|
+
|
794
|
+
def update_custom_branding_messaging(**optional_params)
|
795
|
+
# optional_params: help_links, help_text, locale
|
796
|
+
post('/admin/v1/branding/custom_messaging', optional_params)[:response]
|
797
|
+
end
|
798
|
+
|
799
|
+
##
|
800
|
+
# Account Info
|
801
|
+
#
|
802
|
+
def get_account_info_summary
|
803
|
+
get('/admin/v1/info/summary')[:response]
|
804
|
+
end
|
805
|
+
|
806
|
+
def get_telephony_credits_used_report(**optional_params)
|
807
|
+
# optional_params: maxtime, mintime
|
808
|
+
get('/admin/v1/info/telephony_credits_used', optional_params)[:response]
|
809
|
+
end
|
810
|
+
|
811
|
+
def get_authentication_attempts_report(**optional_params)
|
812
|
+
get('/admin/v1/info/authentication_attempts', optional_params)[:response]
|
813
|
+
end
|
814
|
+
|
815
|
+
def get_user_authentication_attempts_report(**optional_params)
|
816
|
+
get('/admin/v1/info/user_authentication_attempts', optional_params)[:response]
|
817
|
+
end
|
818
|
+
|
819
|
+
private
|
820
|
+
|
821
|
+
def serialized_aliases(aliases)
|
822
|
+
case aliases
|
823
|
+
when Array
|
824
|
+
aliases.map.with_index{ |a, i| "alias#{i + 1}=#{a}" }.join('&')
|
825
|
+
when Hash
|
826
|
+
aliases.map{ |k, v| "#{k}=#{v}" }.join('&')
|
827
|
+
else
|
828
|
+
aliases
|
829
|
+
end
|
830
|
+
end
|
831
|
+
end
|
832
|
+
end
|