ruby-jss 1.2.4a4 → 1.3.3

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.
Files changed (248) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES.md +185 -1
  3. data/README.md +3 -1
  4. data/bin/cgrouper +1 -1
  5. data/bin/jamfHelperBackgrounder +1 -1
  6. data/bin/netseg-update +1 -1
  7. data/data/ruby-jss.conf.example +1 -1
  8. data/lib/jamf.rb +1 -1
  9. data/lib/jamf/api/abstract_classes/advanced_search.rb +1 -1
  10. data/lib/jamf/api/abstract_classes/collection_resource.rb +31 -26
  11. data/lib/jamf/api/abstract_classes/generic_reference.rb +1 -1
  12. data/lib/jamf/api/abstract_classes/json_object.rb +15 -5
  13. data/lib/jamf/api/abstract_classes/prestage.rb +2 -2
  14. data/lib/jamf/api/abstract_classes/prestage_skip_setup_items.rb +1 -1
  15. data/lib/jamf/api/abstract_classes/resource.rb +1 -1
  16. data/lib/jamf/api/abstract_classes/singleton_resource.rb +1 -1
  17. data/lib/jamf/api/attribute_classes/ip_address.rb +1 -1
  18. data/lib/jamf/api/attribute_classes/timestamp.rb +1 -1
  19. data/lib/jamf/api/connection.rb +106 -60
  20. data/lib/jamf/api/connection/api_error.rb +1 -1
  21. data/lib/jamf/api/connection/api_error_styleguide.rb +1 -1
  22. data/lib/jamf/api/connection/token.rb +80 -13
  23. data/lib/jamf/api/json_objects/account_prefs.rb +1 -1
  24. data/lib/jamf/api/json_objects/android_details.rb +1 -1
  25. data/lib/jamf/api/json_objects/appletv_details.rb +1 -1
  26. data/lib/jamf/api/json_objects/attachment.rb +1 -1
  27. data/lib/jamf/api/json_objects/cellular_network.rb +1 -1
  28. data/lib/jamf/api/json_objects/change_log_entry.rb +1 -1
  29. data/lib/jamf/api/json_objects/computer_prestage_skip_setup_items.rb +1 -1
  30. data/lib/jamf/api/json_objects/country.rb +1 -1
  31. data/lib/jamf/api/json_objects/criterion.rb +1 -1
  32. data/lib/jamf/api/json_objects/device_enrollment_device.rb +1 -1
  33. data/lib/jamf/api/json_objects/device_enrollment_sync_status.rb +1 -1
  34. data/lib/jamf/api/json_objects/extension_attribute_value.rb +1 -1
  35. data/lib/jamf/api/json_objects/installed_application.rb +1 -1
  36. data/lib/jamf/api/json_objects/installed_certificate.rb +1 -1
  37. data/lib/jamf/api/json_objects/installed_configuration_profile.rb +1 -1
  38. data/lib/jamf/api/json_objects/installed_ebook.rb +1 -1
  39. data/lib/jamf/api/json_objects/installed_provisioning_profile.rb +1 -1
  40. data/lib/jamf/api/json_objects/inventory_preload_extension_attribute.rb +1 -1
  41. data/lib/jamf/api/json_objects/ios_details.rb +1 -1
  42. data/lib/jamf/api/json_objects/location.rb +1 -1
  43. data/lib/jamf/api/json_objects/md_prestage_name.rb +1 -1
  44. data/lib/jamf/api/json_objects/md_prestage_names.rb +1 -1
  45. data/lib/jamf/api/json_objects/md_prestage_skip_setup_items.rb +1 -1
  46. data/lib/jamf/api/json_objects/mobile_device_details.rb +1 -1
  47. data/lib/jamf/api/json_objects/mobile_device_security.rb +1 -1
  48. data/lib/jamf/api/json_objects/prestage_assignment.rb +1 -1
  49. data/lib/jamf/api/json_objects/prestage_location.rb +1 -1
  50. data/lib/jamf/api/json_objects/prestage_purchasing_data.rb +1 -1
  51. data/lib/jamf/api/json_objects/prestage_scope.rb +1 -1
  52. data/lib/jamf/api/json_objects/prestage_sync_status.rb +1 -1
  53. data/lib/jamf/api/json_objects/purchasing_data.rb +1 -1
  54. data/lib/jamf/api/mixins/abstract.rb +1 -1
  55. data/lib/jamf/api/mixins/bulk_deletable.rb +1 -1
  56. data/lib/jamf/api/mixins/change_log.rb +1 -1
  57. data/lib/jamf/api/mixins/extendable.rb +1 -1
  58. data/lib/jamf/api/mixins/immutable.rb +1 -1
  59. data/lib/jamf/api/mixins/locatable.rb +1 -1
  60. data/lib/jamf/api/mixins/lockable.rb +1 -1
  61. data/lib/jamf/api/mixins/referable.rb +1 -1
  62. data/lib/jamf/api/mixins/searchable.rb +1 -1
  63. data/lib/jamf/api/mixins/uncreatable.rb +1 -1
  64. data/lib/jamf/api/mixins/undeletable.rb +1 -1
  65. data/lib/jamf/api/resources/collection_resources/account.rb +1 -1
  66. data/lib/jamf/api/resources/collection_resources/advanced_mobile_device_search.rb +1 -1
  67. data/lib/jamf/api/resources/collection_resources/advanced_user_search.rb +1 -1
  68. data/lib/jamf/api/resources/collection_resources/building.rb +1 -1
  69. data/lib/jamf/api/resources/collection_resources/category.rb +1 -1
  70. data/lib/jamf/api/resources/collection_resources/computer.rb +1 -1
  71. data/lib/jamf/api/resources/collection_resources/computer_prestage.rb +1 -1
  72. data/lib/jamf/api/resources/collection_resources/department.rb +1 -1
  73. data/lib/jamf/api/resources/collection_resources/device_enrollment.rb +1 -1
  74. data/lib/jamf/api/resources/collection_resources/extension_attribute.rb +1 -1
  75. data/lib/jamf/api/resources/collection_resources/inventory_preload_record.rb +9 -2
  76. data/lib/jamf/api/resources/collection_resources/mobile_device.rb +1 -1
  77. data/lib/jamf/api/resources/collection_resources/mobile_device_prestage.rb +1 -1
  78. data/lib/jamf/api/resources/collection_resources/script.rb +1 -1
  79. data/lib/jamf/api/resources/collection_resources/site.rb +1 -1
  80. data/lib/jamf/api/resources/collection_resources/time_zone.rb +1 -1
  81. data/lib/jamf/api/resources/singleton_resources/app_store_country_codes.rb +1 -1
  82. data/lib/jamf/api/resources/singleton_resources/authorization.rb +1 -1
  83. data/lib/jamf/api/resources/singleton_resources/client_checkin_settings.rb +1 -1
  84. data/lib/jamf/api/resources/singleton_resources/reenrollment_settings.rb +1 -1
  85. data/lib/jamf/client.rb +1 -1
  86. data/lib/jamf/client/jamf_binary.rb +1 -1
  87. data/lib/jamf/client/jamf_helper.rb +1 -1
  88. data/lib/jamf/client/management_action.rb +1 -1
  89. data/lib/jamf/compatibility.rb +1 -1
  90. data/lib/jamf/composer.rb +1 -1
  91. data/lib/jamf/configuration.rb +8 -10
  92. data/lib/jamf/exceptions.rb +6 -1
  93. data/lib/jamf/ruby_extensions.rb +2 -1
  94. data/lib/jamf/ruby_extensions/array.rb +2 -2
  95. data/lib/jamf/ruby_extensions/array/predicates.rb +1 -1
  96. data/lib/jamf/ruby_extensions/array/utils.rb +4 -4
  97. data/lib/jamf/ruby_extensions/dig.rb +52 -0
  98. data/lib/jamf/ruby_extensions/filetest.rb +1 -1
  99. data/lib/jamf/ruby_extensions/filetest/predicates.rb +1 -1
  100. data/lib/jamf/ruby_extensions/hash.rb +1 -1
  101. data/lib/jamf/ruby_extensions/hash/backports.rb +2 -2
  102. data/lib/jamf/ruby_extensions/ipaddr.rb +1 -1
  103. data/lib/jamf/ruby_extensions/ipaddr/utils.rb +1 -1
  104. data/lib/jamf/ruby_extensions/object.rb +1 -1
  105. data/lib/jamf/ruby_extensions/object/predicates.rb +1 -1
  106. data/lib/jamf/ruby_extensions/pathname.rb +1 -1
  107. data/lib/jamf/ruby_extensions/pathname/predicates.rb +1 -1
  108. data/lib/jamf/ruby_extensions/pathname/utils.rb +1 -1
  109. data/lib/jamf/ruby_extensions/string.rb +1 -1
  110. data/lib/jamf/ruby_extensions/string/backports.rb +1 -1
  111. data/lib/jamf/ruby_extensions/string/conversions.rb +1 -1
  112. data/lib/jamf/ruby_extensions/string/predicates.rb +14 -4
  113. data/lib/jamf/utility.rb +1 -1
  114. data/lib/jamf/validate.rb +1 -1
  115. data/lib/jamf/version.rb +2 -2
  116. data/lib/jpapi.rb +1 -1
  117. data/lib/jss-api.rb +1 -1
  118. data/lib/jss.rb +5 -2
  119. data/lib/jss/api_connection.rb +3 -30
  120. data/lib/jss/api_object.rb +16 -3
  121. data/lib/jss/api_object/account.rb +1 -1
  122. data/lib/jss/api_object/advanced_search.rb +1 -1
  123. data/lib/jss/api_object/advanced_search/advanced_computer_search.rb +1 -1
  124. data/lib/jss/api_object/advanced_search/advanced_mobile_device_search.rb +1 -1
  125. data/lib/jss/api_object/advanced_search/advanced_user_search.rb +1 -1
  126. data/lib/jss/api_object/building.rb +1 -1
  127. data/lib/jss/api_object/categorizable.rb +1 -1
  128. data/lib/jss/api_object/category.rb +1 -1
  129. data/lib/jss/api_object/computer.rb +12 -6
  130. data/lib/jss/api_object/computer/application_installs.rb +1 -1
  131. data/lib/jss/api_object/computer_invitation.rb +1 -1
  132. data/lib/jss/api_object/configuration_profile.rb +4 -2
  133. data/lib/jss/api_object/configuration_profile/mobile_device_configuration_profile.rb +1 -1
  134. data/lib/jss/api_object/configuration_profile/osx_configuration_profile.rb +1 -1
  135. data/lib/jss/api_object/creatable.rb +1 -1
  136. data/lib/jss/api_object/criteriable.rb +10 -5
  137. data/lib/jss/api_object/criteriable/criteria.rb +26 -10
  138. data/lib/jss/api_object/criteriable/criterion.rb +1 -1
  139. data/lib/jss/api_object/department.rb +1 -1
  140. data/lib/jss/api_object/directory_binding.rb +273 -0
  141. data/lib/jss/api_object/directory_binding_type.rb +90 -0
  142. data/lib/jss/api_object/directory_binding_type/active_directory.rb +502 -0
  143. data/lib/jss/api_object/directory_binding_type/admitmac.rb +525 -0
  144. data/lib/jss/api_object/directory_binding_type/centrify.rb +212 -0
  145. data/lib/jss/api_object/directory_binding_type/open_directory.rb +178 -0
  146. data/lib/jss/api_object/directory_binding_type/powerbroker_identity_services.rb +73 -0
  147. data/lib/jss/api_object/disk_encryption_configurations.rb +114 -0
  148. data/lib/jss/api_object/distribution_point.rb +96 -36
  149. data/lib/jss/api_object/dock_item.rb +137 -0
  150. data/lib/jss/api_object/ebook.rb +1 -1
  151. data/lib/jss/api_object/extendable.rb +67 -28
  152. data/lib/jss/api_object/extension_attribute.rb +1 -1
  153. data/lib/jss/api_object/extension_attribute/computer_extension_attribute.rb +1 -1
  154. data/lib/jss/api_object/extension_attribute/mobile_device_extension_attribute.rb +1 -1
  155. data/lib/jss/api_object/extension_attribute/user_extension_attribute.rb +1 -1
  156. data/lib/jss/api_object/group.rb +1 -1
  157. data/lib/jss/api_object/group/computer_group.rb +1 -1
  158. data/lib/jss/api_object/group/mobile_device_group.rb +1 -1
  159. data/lib/jss/api_object/group/user_group.rb +1 -1
  160. data/lib/jss/api_object/ibeacon.rb +1 -1
  161. data/lib/jss/api_object/ldap_server.rb +1 -1
  162. data/lib/jss/api_object/locatable.rb +1 -1
  163. data/lib/jss/api_object/mac_application.rb +1 -1
  164. data/lib/jss/api_object/management_history.rb +23 -22
  165. data/lib/jss/api_object/management_history/audit_event.rb +1 -1
  166. data/lib/jss/api_object/management_history/casper_imaging_log.rb +1 -1
  167. data/lib/jss/api_object/management_history/casper_remote_log.rb +1 -1
  168. data/lib/jss/api_object/management_history/computer_usage_log.rb +1 -1
  169. data/lib/jss/api_object/management_history/ebook.rb +1 -1
  170. data/lib/jss/api_object/management_history/hashlike.rb +1 -1
  171. data/lib/jss/api_object/management_history/mac_app_store_app.rb +1 -1
  172. data/lib/jss/api_object/management_history/mdm_command.rb +1 -1
  173. data/lib/jss/api_object/management_history/mobile_device_app.rb +1 -1
  174. data/lib/jss/api_object/management_history/policy_log.rb +1 -1
  175. data/lib/jss/api_object/management_history/screen_sharing_log.rb +1 -1
  176. data/lib/jss/api_object/management_history/user_location_change.rb +1 -1
  177. data/lib/jss/api_object/matchable.rb +1 -1
  178. data/lib/jss/api_object/mdm.rb +1 -1
  179. data/lib/jss/api_object/mobile_device.rb +29 -6
  180. data/lib/jss/api_object/mobile_device_application.rb +13 -1
  181. data/lib/jss/api_object/netboot_server.rb +1 -1
  182. data/lib/jss/api_object/network_segment.rb +153 -59
  183. data/lib/jss/api_object/package.rb +106 -41
  184. data/lib/jss/api_object/patch_policy.rb +1 -1
  185. data/lib/jss/api_object/patch_source.rb +1 -1
  186. data/lib/jss/api_object/patch_source/patch_external_source.rb +1 -1
  187. data/lib/jss/api_object/patch_source/patch_internal_source.rb +1 -1
  188. data/lib/jss/api_object/patch_title.rb +1 -1
  189. data/lib/jss/api_object/patch_title/version.rb +1 -1
  190. data/lib/jss/api_object/peripheral.rb +1 -1
  191. data/lib/jss/api_object/peripheral_type.rb +1 -1
  192. data/lib/jss/api_object/policy.rb +380 -5
  193. data/lib/jss/api_object/printer.rb +440 -0
  194. data/lib/jss/api_object/purchasable.rb +1 -1
  195. data/lib/jss/api_object/removable_macaddr.rb +1 -1
  196. data/lib/jss/api_object/restricted_software.rb +1 -1
  197. data/lib/jss/api_object/scopable.rb +1 -1
  198. data/lib/jss/api_object/scopable/scope.rb +257 -37
  199. data/lib/jss/api_object/script.rb +1 -1
  200. data/lib/jss/api_object/self_servable.rb +7 -7
  201. data/lib/jss/api_object/self_servable/icon.rb +1 -1
  202. data/lib/jss/api_object/sitable.rb +6 -2
  203. data/lib/jss/api_object/site.rb +1 -1
  204. data/lib/jss/api_object/software_update_server.rb +1 -1
  205. data/lib/jss/api_object/updatable.rb +1 -1
  206. data/lib/jss/api_object/uploadable.rb +1 -1
  207. data/lib/jss/api_object/user.rb +5 -3
  208. data/lib/jss/api_object/vppable.rb +1 -1
  209. data/lib/jss/api_object/webhook.rb +1 -1
  210. data/lib/jss/client.rb +1 -1
  211. data/lib/jss/client/jamf_binary.rb +1 -1
  212. data/lib/jss/client/jamf_helper.rb +1 -1
  213. data/lib/jss/client/management_action.rb +1 -1
  214. data/lib/jss/compatibility.rb +1 -1
  215. data/lib/jss/composer.rb +2 -2
  216. data/lib/jss/configuration.rb +1 -1
  217. data/lib/jss/db_connection.rb +1 -1
  218. data/lib/jss/exceptions.rb +1 -1
  219. data/lib/jss/ruby_extensions.rb +1 -1
  220. data/lib/jss/ruby_extensions/array.rb +1 -1
  221. data/lib/jss/ruby_extensions/filetest.rb +1 -1
  222. data/lib/jss/ruby_extensions/hash.rb +1 -1
  223. data/lib/jss/ruby_extensions/ipaddr.rb +1 -1
  224. data/lib/jss/ruby_extensions/pathname.rb +1 -1
  225. data/lib/jss/ruby_extensions/string.rb +1 -1
  226. data/lib/jss/ruby_extensions/string/backports.rb +1 -1
  227. data/lib/jss/ruby_extensions/string/conversions.rb +1 -1
  228. data/lib/jss/ruby_extensions/string/predicates.rb +14 -4
  229. data/lib/jss/ruby_extensions/time.rb +1 -1
  230. data/lib/jss/server.rb +1 -1
  231. data/lib/jss/utility.rb +9 -23
  232. data/lib/jss/validate.rb +1 -1
  233. data/lib/jss/version.rb +2 -2
  234. data/lib/jss/xml_workaround.rb +1 -1
  235. data/lib/ruby-jss.rb +1 -1
  236. data/test/bin/runtests +1 -1
  237. data/test/lib/testhelper.rb +1 -1
  238. data/test/lib/testhelper/auth.rb +1 -1
  239. data/test/lib/testhelper/patch_mgmt.rb +1 -1
  240. data/test/specs/api_connection_spec.rb +1 -1
  241. data/test/specs/patch01_source_spec.rb +1 -1
  242. data/test/specs/patch02_internal_source_spec.rb +1 -1
  243. data/test/specs/patch03_external_source_spec.rb +1 -1
  244. data/test/specs/patch04_titles_spec.rb +1 -1
  245. data/test/specs/patch05_policies_spec.rb +1 -1
  246. data/test/specs/patch06_cleanup_spec.rb +1 -1
  247. data/test/specs/policy_spec.rb +1 -1
  248. metadata +15 -4
@@ -1,4 +1,4 @@
1
- # Copyright 2019 Pixar
1
+ # Copyright 2020 Pixar
2
2
 
3
3
  #
4
4
  # Licensed under the Apache License, Version 2.0 (the "Apache License")
@@ -1,4 +1,4 @@
1
- # Copyright 2019 Pixar
1
+ # Copyright 2020 Pixar
2
2
 
3
3
  #
4
4
  # Licensed under the Apache License, Version 2.0 (the "Apache License")
@@ -1,4 +1,4 @@
1
- # Copyright 2019 Pixar
1
+ # Copyright 2020 Pixar
2
2
 
3
3
  #
4
4
  # Licensed under the Apache License, Version 2.0 (the "Apache License")
@@ -1,4 +1,4 @@
1
- # Copyright 2019 Pixar
1
+ # Copyright 2020 Pixar
2
2
 
3
3
  #
4
4
  # Licensed under the Apache License, Version 2.0 (the "Apache License")
@@ -1,4 +1,4 @@
1
- # Copyright 2019 Pixar
1
+ # Copyright 2020 Pixar
2
2
 
3
3
  #
4
4
  # Licensed under the Apache License, Version 2.0 (the "Apache License")
@@ -1,4 +1,4 @@
1
- # Copyright 2019 Pixar
1
+ # Copyright 2020 Pixar
2
2
 
3
3
  #
4
4
  # Licensed under the Apache License, Version 2.0 (the "Apache License")
@@ -48,7 +48,7 @@ module Jamf
48
48
  RSRC_BASE = 'uapi'.freeze
49
49
 
50
50
  # The API version must be this or higher
51
- MIN_API_VERSION = Gem::Version.new('1.0')
51
+ MIN_JAMF_VERSION = Gem::Version.new('10.15.0')
52
52
 
53
53
  HTTPS_SCHEME = 'https'.freeze
54
54
 
@@ -111,6 +111,7 @@ module Jamf
111
111
  @login_time
112
112
  @keep_alive
113
113
  @token_refresh
114
+ @pw_fallback
114
115
  ].freeze
115
116
 
116
117
  # Attributes
@@ -140,6 +141,10 @@ module Jamf
140
141
  # @return [String, nil]
141
142
  attr_reader :base_url
142
143
 
144
+ # @return [Boolean] if token refresh/keepaliave fails, try to get a new one
145
+ # with the passwd used with .connect. Defaults to true
146
+ attr_reader :pw_fallback
147
+
143
148
  # @return [Boolean]
144
149
  attr_reader :connected
145
150
  alias connected? connected
@@ -227,14 +232,13 @@ module Jamf
227
232
  # ### Tokens
228
233
  # Instead of a user and password, you may specify a valid 'token:', either:
229
234
  #
230
- # A Jamf::Connection::Token object, which can be extracted from an active
235
+ # A Jamf::Connection::Token object, which can be extracted from an active
231
236
  # Jamf::Connection via its #token method
232
237
  #
233
238
  # or
234
239
  #
235
240
  # A token string e.g. "eyJhdXR...6EKoo" from any source can also be used.
236
241
  #
237
- #
238
242
  # Any values available via Jamf.config will be used if they are not provided
239
243
  # in the parameters.
240
244
  #
@@ -251,6 +255,19 @@ module Jamf
251
255
  #
252
256
  # @param token: [Jamf::Connection::Token, String] An existing, valid token.
253
257
  # When used, there's no need to provide user: or pw:.
258
+ # NOTE if using pw_fallback:true (the default) while providing a token
259
+ # you will also need to provide the password for the token user in the pw:
260
+ # parameter, or be prompted for it. If you don't have the pw for the
261
+ # token user, be sure to set pw_fallback to false.
262
+ #
263
+ # @param token_refresh: [Integer] Refresh the token this many seconds before
264
+ # it expires. Must be >= DFT_TOKEN_REFRESH
265
+ #
266
+ # @pararm pw_fallback: [Boolean] Default is true. Use the password provided
267
+ # to refresh the token if regular refresh doesn't work (e.g. token is expired).
268
+ # NOTE: This causes the password to be kept in memory. If you don't want
269
+ # this, explicitly set pw_fallback to false, however long-running processes
270
+ # may lose connection if token refresh fails for any reason.
254
271
  #
255
272
  # @param open_timeout: [Integer] The number of seconds for initial contact
256
273
  # with the host.
@@ -268,7 +285,8 @@ module Jamf
268
285
  # This sets all the instance vars to nil, and flushes/creates the caches
269
286
  disconnect
270
287
 
271
- # This sets @token, and adds host, port, user to params from a Token object
288
+ # If there's a Token object in :token, this sets @token,
289
+ # and adds host, port, user from that token
272
290
  parse_token params
273
291
 
274
292
  # Get host, port, user and pw from a URL, add to params if needed
@@ -277,6 +295,8 @@ module Jamf
277
295
  # apply defaults from config, client, and then this class.
278
296
  apply_connection_defaults params
279
297
 
298
+ # Once we're here, all params have been parsed & defaulted into the
299
+ # params hash, so
280
300
  # make sure we have the minimum needed params for a connection
281
301
  verify_basic_params params
282
302
 
@@ -285,15 +305,20 @@ module Jamf
285
305
 
286
306
  # if no @token already, get one from from
287
307
  # either a token string or a pw
288
- @token ||=
308
+ unless @token
289
309
  if params[:token].is_a? String
290
- tk = token_from :token_string, params[:token]
310
+ @token = token_from :token_string, params[:token]
291
311
  # get the user from the token
292
- @user = tk.user
293
- tk
312
+ @user = @toke.user
313
+ # if @pw_fallback, the pw must be acquired, since it isn't in
314
+ # the token
315
+ @pw = acquire_password(params[:pw]) if @pw_fallback
294
316
  else
295
- token_from :pw, acquire_password(params[:pw])
317
+ pw = acquire_password(params[:pw])
318
+ @token = token_from :pw, pw
319
+ @pw = pw if @pw_fallback
296
320
  end
321
+ end
297
322
 
298
323
  # Now get some values from our token
299
324
  @base_url = @token.base_url
@@ -303,43 +328,49 @@ module Jamf
303
328
  @rest_cnx = create_connection
304
329
 
305
330
  # make sure versions are good
306
- validate_api_version
331
+ validate_jamf_version
307
332
 
308
333
  @connected = true
309
334
 
310
335
  # start keepalive if needed
311
- @keep_alive = params[:keep_alive].nil? ? false : params[:keep_alive]
312
336
  start_keep_alive if @keep_alive
313
337
 
314
338
  # return our string output
315
339
  to_s
316
340
  end # connect
317
341
 
342
+ # reset all values to nil or empty
318
343
  def disconnect
319
- # reset everything except the timeouts
320
- stop_keep_alive
321
-
322
344
  @connected = false
323
345
  @name = NOT_CONNECTED
324
346
  @login_time = nil
347
+
348
+ stop_keep_alive
349
+
325
350
  @host = nil
326
351
  @port = nil
327
352
  @user = nil
328
- @token = nil
353
+ @timeout = nil
354
+ @open_timeout = nil
329
355
  @base_url = nil
356
+ @token = nil
330
357
  @rest_cnx = nil
331
358
  @ssl_options = {}
332
359
  @keep_alive = nil
360
+ @token_refresh = nil
361
+ @pw_fallback = nil
362
+ @pw = nil
333
363
 
334
364
  flushcache
335
365
  end
336
366
 
337
- # Same as disconnect, but invalidates the token
367
+ # Same as disconnect, but invalidates the token on the server first
338
368
  def logout
339
369
  @token.destroy
340
370
  disconnect
341
371
  end
342
372
 
373
+ # Get a resource
343
374
  def get(rsrc)
344
375
  validate_connected
345
376
  resp = @rest_cnx.get rsrc
@@ -423,7 +454,9 @@ module Jamf
423
454
 
424
455
  # Are we keeping the connection alive?
425
456
  def keep_alive?
426
- @keep_alive_thread&.alive? || false
457
+ return false unless @keep_alive_thread
458
+
459
+ @keep_alive_thread.alive?
427
460
  end
428
461
 
429
462
  # @return [Jamf::Timestamp, nil]
@@ -461,8 +494,12 @@ module Jamf
461
494
  @token_refresh = secs
462
495
  end
463
496
 
464
- def api_version
465
- @token.api_version
497
+ def jamf_version
498
+ @token.jamf_version
499
+ end
500
+
501
+ def jamf_build
502
+ @token.jamf_build
466
503
  end
467
504
 
468
505
  # Flush the collection and/or ea cache for the given class,
@@ -503,11 +540,11 @@ module Jamf
503
540
  end
504
541
 
505
542
  # raise exception if API version is too low.
506
- def validate_api_version
507
- vers = api_version
508
- return if Gem::Version.new(vers) >= MIN_API_VERSION
543
+ def validate_jamf_version
544
+ vers = jamf_version
545
+ return if Gem::Version.new(vers) >= MIN_JAMF_VERSION
509
546
 
510
- raise Jamf::InvalidConnectionError, "API version '#{vers}' too low, must be >= '#{MIN_API_VERSION}'"
547
+ raise Jamf::InvalidConnectionError, "API version '#{vers}' too low, must be >= '#{MIN_JAMF_VERSION}'"
511
548
  end
512
549
 
513
550
  ##### Parse Params
@@ -537,7 +574,7 @@ module Jamf
537
574
  raise "Cannot use token: it expires in less than #{TOKEN_REUSE_MIN_LIFE} seconds" if token.secs_remaining < TOKEN_REUSE_MIN_LIFE
538
575
  end
539
576
 
540
- # Get host, port, user and pw from a URL, unless they are already in the params
577
+ # Get host, port, user and pw from a URL, overriding any already in the params
541
578
  #
542
579
  # @return [String, nil] the pw if present
543
580
  #
@@ -547,27 +584,29 @@ module Jamf
547
584
  url = URI.parse url.to_s
548
585
  raise ArgumentError, 'Invalid url, scheme must be https' unless url.scheme == HTTPS_SCHEME
549
586
 
550
- params[:host] ||= url.host
551
- params[:port] ||= url.port
552
- params[:user] ||= url.user if url.user
553
- params[:pw] ||= url.password if url.password
587
+ params[:host] = url.host
588
+ params[:port] = url.port
589
+ params[:user] = url.user if url.user
590
+ params[:pw] = url.password if url.password
554
591
  end
555
592
 
556
- # Apply defaults from the Jamf.config,
557
- # then from the Jamf::Client,
593
+ # Apply defaults to the unset params for the #connect method
594
+ # First apply them from from the Jamf.config,
595
+ # then from the Jamf::Client (read from the jamf binary config),
558
596
  # then from the Jamf module defaults
559
- # to the unset params for the #connect method
560
597
  #
561
598
  # @param params[Hash] The params for #connect
562
599
  #
563
600
  # @return [Hash] The params with defaults applied
564
601
  #
565
602
  def apply_connection_defaults(params)
566
- # if no port given, either directly or via URL, and the host
567
- # is a jamfcloud host, always set the port to 443
568
- # This should happen before the config is applied, so
569
- # on-prem users can still get to jamfcoud without specifying the port
570
- params[:port] = JAMFCLOUD_PORT if params[:port].nil? && params[:host].to_s.end_with?(JAMFCLOUD_DOMAIN)
603
+ # must have a host, but accept legacy :server as well as :host
604
+ params[:host] ||= params[:server]
605
+
606
+ # if we have no port set by this point, set to cloud port
607
+ # if host is a cloud host. But leave port nil for other hosts
608
+ # (will be set via client defaults or module defaults)
609
+ params[:port] ||= JAMFCLOUD_PORT if params[:host].to_s.end_with?(JAMFCLOUD_DOMAIN)
571
610
 
572
611
  apply_defaults_from_config(params)
573
612
 
@@ -621,11 +660,12 @@ module Jamf
621
660
  # @return [Hash] The params with defaults applied
622
661
  #
623
662
  def apply_module_defaults(params)
624
- # if we have no port set by this point, assume on-prem
663
+ # if we have no port set by this point, assume on-prem.
625
664
  params[:port] ||= ON_PREM_SSL_PORT
626
665
  params[:timeout] ||= DFT_TIMEOUT
627
666
  params[:open_timeout] ||= DFT_OPEN_TIMEOUT
628
667
  params[:ssl_version] ||= DFT_SSL_VERSION
668
+ params[:token_refresh] ||= DFT_TOKEN_REFRESH
629
669
  # if we have a TTY, pw defaults to :prompt
630
670
  params[:pw] ||= :prompt if STDIN.tty?
631
671
  end
@@ -641,36 +681,38 @@ module Jamf
641
681
  # and is already parsed
642
682
  return if @token
643
683
 
644
- # must have a host, but accept legacy :server as well as :host
645
- params[:host] ||= params[:server]
684
+ # must have a host
646
685
  raise Jamf::MissingDataError, 'No Jamf :host specified, or in configuration.' unless params[:host]
647
686
 
648
687
  # no need for user or pass if using a token string
649
688
  return if params[:token].is_a? String
650
689
 
690
+ # must have user and pw
651
691
  raise Jamf::MissingDataError, 'No Jamf :user specified, or in configuration.' unless params[:user]
652
692
  raise Jamf::MissingDataError, "No :pw specified for user '#{params[:user]}'" unless params[:pw]
653
693
  end
654
694
 
695
+ # Turn the connection parameters into instance vars
655
696
  def parse_connect_params(params)
656
697
  @host = params[:host]
657
698
  @port = params[:port]
658
- @port ||= @host.end_with?(JAMFCLOUD_DOMAIN) ? JAMFCLOUD_PORT : ON_PREM_SSL_PORT
659
699
  @user = params[:user]
660
700
 
661
- @token_refresh = params[:token_refresh].to_i || DFT_TOKEN_REFRESH
662
- # token refresh must be at least DFT_TOKEN_REFRESH
663
- @token_refresh = DFT_TOKEN_REFRESH if @token_refresh < DFT_TOKEN_REFRESH
701
+ @keep_alive = params[:keep_alive].nil? ? false : params[:keep_alive]
702
+ @pw_fallback = params[:pw_fallback].nil? ? true : params[:pw_fallback]
703
+ @token_refresh = params[:token_refresh].to_i
664
704
 
665
- @timeout = params[:timeout] || DFT_TIMEOUT
666
- @open_timeout = params[:open_timeout] || DFT_TIMEOUT
705
+ @timeout = params[:timeout]
706
+ @open_timeout = params[:open_timeout]
667
707
  @base_url = URI.parse "https://#{@host}:#{@port}/#{RSRC_BASE}"
708
+
668
709
  # ssl opts for faraday
669
710
  # TODO: implement all of faraday's options
670
711
  @ssl_options = {
671
712
  verify: params[:verify_cert],
672
713
  version: params[:ssl_version]
673
714
  }
715
+
674
716
  @name = "#{@user}@#{@host}:#{@port}" if @name == NOT_CONNECTED
675
717
  end
676
718
 
@@ -701,16 +743,18 @@ module Jamf
701
743
  # @return [String] The password for the connection
702
744
  #
703
745
  def acquire_password(param_pw)
704
- if param_pw == :prompt
705
- Jamf.prompt_for_password "Enter the password for Jamf user #{@user}@#{@host}:"
706
- elsif param_pw.is_a?(Symbol) && param_pw.to_s.start_with?('stdin')
707
- param_pw.to_s =~ /^stdin(\d+)$/
708
- line = Regexp.last_match(1)
709
- line ||= 1
710
- Jamf.stdin line
711
- else
712
- param_pw
713
- end # if
746
+ pw =
747
+ if param_pw == :prompt
748
+ Jamf.prompt_for_password "Enter the password for Jamf user #{@user}@#{@host}:"
749
+ elsif param_pw.is_a?(Symbol) && param_pw.to_s.start_with?('stdin')
750
+ param_pw.to_s =~ /^stdin(\d+)$/
751
+ line = Regexp.last_match(1)
752
+ line ||= 1
753
+ Jamf.stdin line
754
+ else
755
+ param_pw
756
+ end # if
757
+ pw
714
758
  end # acquire pw
715
759
 
716
760
  # create the faraday connection object
@@ -747,11 +791,11 @@ module Jamf
747
791
  begin
748
792
  next if @token.secs_remaining > @token_refresh
749
793
 
750
- @token.refresh
794
+ @token.refresh @pw
751
795
  # make sure faraday uses the new token
752
796
  @rest_cnx.headers[:authorization] = @token.auth_token
753
797
  rescue
754
- # TODO: Some kind of error reporting??
798
+ # TODO: Some kind of error reporting
755
799
  next
756
800
  end
757
801
  end # loop
@@ -764,7 +808,9 @@ module Jamf
764
808
  # @return [void]
765
809
  #
766
810
  def stop_keep_alive
767
- @keep_alive_thread&.kill
811
+ return unless @keep_alive_thread
812
+
813
+ @keep_alive_thread.kill if @keep_alive_thread.alive?
768
814
  @keep_alive_thread = nil
769
815
  end
770
816
 
@@ -811,7 +857,7 @@ module Jamf
811
857
  end
812
858
 
813
859
  def self.disconnect
814
- @active_connection&.disconnect
860
+ @active_connection.disconnect if @active_connection
815
861
  end
816
862
 
817
863
  end # module Jamf
@@ -1,4 +1,4 @@
1
- # Copyright 2019 Pixar
1
+ # Copyright 2020 Pixar
2
2
 
3
3
  #
4
4
  # Licensed under the Apache License, Version 2.0 (the "Apache License")
@@ -1,4 +1,4 @@
1
- # Copyright 2019 Pixar
1
+ # Copyright 2020 Pixar
2
2
 
3
3
  #
4
4
  # Licensed under the Apache License, Version 2.0 (the "Apache License")
@@ -1,4 +1,4 @@
1
- # Copyright 2019 Pixar
1
+ # Copyright 2020 Pixar
2
2
 
3
3
  #
4
4
  # Licensed under the Apache License, Version 2.0 (the "Apache License")
@@ -30,6 +30,8 @@ module Jamf
30
30
  # A token used for a JSS connection
31
31
  class Token
32
32
 
33
+ JAMF_VERSION_RSRC = 'v1/jamf-pro-version'.freeze
34
+
33
35
  AUTH_RSRC = 'auth'.freeze
34
36
 
35
37
  NEW_TOKEN_RSRC = "#{AUTH_RSRC}/tokens".freeze
@@ -56,9 +58,22 @@ module Jamf
56
58
  # @return [URI] The base API url, e.g. https://myjamf.jamfcloud.com/uapi
57
59
  attr_reader :base_url
58
60
 
59
- # when was this token created?
61
+ # @return [Jamf::Timestamp] when was this token created?
60
62
  attr_reader :login_time
61
63
 
64
+ # What happened the last time we tried to refresh?
65
+ # :expired_refreshed - token was expired, a new token was created with the pw
66
+ # :expired_pw_failed - token was expired, pw failed to make a new token
67
+ # :expired_no_pw - token was expired, but no pw was given to make a new one
68
+ # :refreshed - the token refresh worked with no need for the pw
69
+ # :refresh_failed - the token refresh failed, and no pw was given to make a new one
70
+ # :refreshed_with_pw - the token refresh failed, pw worked to make a new token
71
+ # :refresh_failed_no_pw - the token refresh failed, pw also failed to make a new token
72
+ # nil - no refresh has been attempted for this token.
73
+ #
74
+ # @return [Symbol, nil] :refreshed, :pw, :expired,:failed, or nil if never refreshed
75
+ attr_reader :last_refresh_result
76
+
62
77
  def initialize(**params)
63
78
  @valid = false
64
79
  @user = params[:user]
@@ -90,7 +105,7 @@ module Jamf
90
105
  raise Jamf::AuthenticationError, 'Incorrect name or password'
91
106
  else
92
107
  # TODO: better error reporting here
93
- raise 'An error occurred while authenticating'
108
+ raise Jamf::AuthenticationError, 'An error occurred while authenticating'
94
109
  end
95
110
  end # init_from_pw
96
111
 
@@ -118,8 +133,13 @@ module Jamf
118
133
  end
119
134
 
120
135
  # @return [String]
121
- def api_version
122
- token_connection(Jamf::Connection::SLASH, token: @auth_token).get.body[:version]
136
+ def jamf_version
137
+ raw_jamf_version.split('-').first
138
+ end
139
+
140
+ # @return [String]
141
+ def jamf_build
142
+ raw_jamf_version.split('-').last
123
143
  end
124
144
 
125
145
  # @return [Boolean]
@@ -165,18 +185,39 @@ module Jamf
165
185
  @account = Jamf::APIAccount.new resp.body
166
186
  end
167
187
 
168
- # Use this token to get a fresh one
169
- # TODO: better error reporting
170
- def refresh
171
- raise 'Token has expired' if expired?
188
+ # Use this token to get a fresh one. If a pw is provided
189
+ # try to use it to get a new token if a proper refresh fails.
190
+ #
191
+ # @param pw [String] Optional password to use if token refresh fails.
192
+ # Must be the correct passwd or the token's user (obviously)
193
+ #
194
+ # @return [Jamf::Timestamp] the new expiration time
195
+ #
196
+ def refresh(pw = nil)
197
+ # gotta have a pw if expired
198
+ if expired?
199
+ # try the passwd
200
+ return refresh_with_passwd(pw, :expired_refreshed, :expired_pw_failed) if pw
201
+
202
+ # no passwd? no chance!
203
+ @last_refresh_result = :expired_no_pw
204
+ raise Jamf::InvalidTokenError, 'Token has expired'
205
+ end
172
206
 
207
+ # Now try a normal refresh of our non-expired token
173
208
  keep_alive_token_resp = token_connection(KEEP_ALIVE_RSRC, token: @auth_token).post
209
+ if keep_alive_token_resp.success?
210
+ parse_token_from_response keep_alive_token_resp
211
+ @last_refresh_result = :refreshed
212
+ return expires
213
+ end
174
214
 
175
- raise 'An error occurred while authenticating' unless keep_alive_token_resp.success?
215
+ # if we're here, the normal refresh failed, so try the pw
216
+ return refresh_with_passwd(pw, :refreshed_with_pw, :refresh_failed_no_pw) if pw
176
217
 
177
- parse_token_from_response keep_alive_token_resp
178
- # parse_token_from_response keep_alive_rsrc.post('')
179
- expires
218
+ # if we're here, no pw? no chance!
219
+ @last_refresh_result = :refresh_failed
220
+ raise 'An error occurred while refreshing the token' unless pw
180
221
  end
181
222
  alias keep_alive refresh
182
223
 
@@ -190,6 +231,32 @@ module Jamf
190
231
  #################################
191
232
  private
192
233
 
234
+ # refresh a token using a password, return a result
235
+ # @param pw[String] the password to use
236
+ # @return [JamfTimestamp] the new expiration
237
+ def refresh_with_passwd(pw, success, failure)
238
+ init_from_pw(pw)
239
+ @last_refresh_result = success
240
+ expires
241
+ rescue => e
242
+ @last_refresh_result = failure
243
+ raise e, "#{e}. Status: :#{failure}"
244
+ end
245
+
246
+ # @return [String]
247
+ def raw_jamf_version
248
+ # TODO: Remove this once we require Jamf Pro 10.19 and up
249
+ # the rsrc for getting the version used to be nothing (the
250
+ # base url itself returnedit) but now its JAMF_VERSION_RSRC
251
+ resp = token_connection(Jamf::BLANK, token: @auth_token).get # .body # [:version]
252
+ return resp.body[:version] if resp.success?
253
+
254
+ resp = token_connection(JAMF_VERSION_RSRC, token: @auth_token).get
255
+ return resp.body[:version] if resp.success?
256
+
257
+ raise Jamf::InvalidConnectionError, 'Unable to read Jamf version from the API'
258
+ end
259
+
193
260
  # a generic, one-time Faraday connection for token
194
261
  # acquision & manipulation
195
262
  #