ruby-jss 1.2.10 → 1.3.2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of ruby-jss might be problematic. Click here for more details.

Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES.md +92 -1
  3. data/lib/jamf/api/abstract_classes/json_object.rb +1 -1
  4. data/lib/jamf/api/abstract_classes/prestage.rb +1 -1
  5. data/lib/jamf/api/connection.rb +7 -3
  6. data/lib/jamf/configuration.rb +7 -9
  7. data/lib/jamf/ruby_extensions.rb +1 -0
  8. data/lib/jamf/ruby_extensions/array.rb +1 -1
  9. data/lib/jamf/ruby_extensions/array/utils.rb +3 -3
  10. data/lib/jamf/ruby_extensions/dig.rb +52 -0
  11. data/lib/jss.rb +2 -0
  12. data/lib/jss/api_connection.rb +2 -29
  13. data/lib/jss/api_object.rb +15 -2
  14. data/lib/jss/api_object/directory_binding.rb +273 -0
  15. data/lib/jss/api_object/directory_binding_type.rb +90 -0
  16. data/lib/jss/api_object/directory_binding_type/active_directory.rb +502 -0
  17. data/lib/jss/api_object/directory_binding_type/admitmac.rb +525 -0
  18. data/lib/jss/api_object/directory_binding_type/centrify.rb +212 -0
  19. data/lib/jss/api_object/directory_binding_type/open_directory.rb +178 -0
  20. data/lib/jss/api_object/directory_binding_type/powerbroker_identity_services.rb +73 -0
  21. data/lib/jss/api_object/disk_encryption_configurations.rb +114 -0
  22. data/lib/jss/api_object/distribution_point.rb +95 -35
  23. data/lib/jss/api_object/dock_item.rb +137 -0
  24. data/lib/jss/api_object/mobile_device_application.rb +12 -0
  25. data/lib/jss/api_object/network_segment.rb +152 -58
  26. data/lib/jss/api_object/package.rb +106 -41
  27. data/lib/jss/api_object/policy.rb +379 -4
  28. data/lib/jss/api_object/printer.rb +440 -0
  29. data/lib/jss/api_object/scopable/scope.rb +24 -24
  30. data/lib/jss/composer.rb +1 -1
  31. data/lib/jss/utility.rb +8 -22
  32. data/lib/jss/version.rb +1 -1
  33. metadata +13 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0734256ff4d9e553418ff9e0189e85cbb455751e682af0278dfff3f85f9a6070
4
- data.tar.gz: 40fde852a9d6f4cc22a804b0240038bdb17d319e1d51edaa8c974ad50d05861d
3
+ metadata.gz: fa838d9a9f35421383049454edc0add9cac32ce63adffdeeaa968b82a7553ab3
4
+ data.tar.gz: c26dd00287dbafb8cf573d0a610183e6110032cd5e0726d07290096861330fc8
5
5
  SHA512:
6
- metadata.gz: 721bc4ef63c7c1114a66bb772a609c4589879977e65922eb008dacf478ea17cc09a78e367e4a8297b46139b9d08f5d16fa6ffa7e0516af6c7ccc571ab37e39da
7
- data.tar.gz: 0d8788ff29178d488fc11da8fa4c77c3ca5b40c8a770979cc7bf11bb8ab727f43315e2632ed74c8ae9685d79142e2536e1239624c236ba218fc2de5c70adddd4
6
+ metadata.gz: 17dbb8ba3b2da2d781b9218eb8491f7f6c627e8ed97a275589be3e62a57bd2cbab572af4f3621611c03c10f430312256fdb6faab14dbb61a5ba7e60076caebfa
7
+ data.tar.gz: 93c6c8bd3c8db99e7de2f40f3234cfeb83a0a517495251bbf99b60f597ef3a6b7b59cbd6ca4997d35b7a1a07a9fdcf3c42b367da28797d44b08467060f4ce6cc
data/CHANGES.md CHANGED
@@ -4,6 +4,94 @@ All notable changes to this project will be documented in this file.
4
4
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5
5
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## \[1.3.2] - 2020-07-31
8
+ Many thanks to @cybertunnel for adding a huge amount of code to get JSS::Policy fully implimented, as well as other fixes and updates!
9
+
10
+ ### Added
11
+ - new class JSS::DockItem
12
+ - new classes JSS::DirectoryBinding and JSS::DirectoryBindingType
13
+ - new class JSS::Printer
14
+ - new class JSS::DiskEncryptionConfiguration
15
+ - JSS::Policy:
16
+ - getters and setters for `#user_message_start` and `#user_message_end`
17
+ - `#set_management_account` and `#verify_management_password`
18
+ - `#add_dock_item` and `#remove_dock_item`
19
+ - `#directory_bindings`, `#add_directory_binding` and `#remove_directory_binding`
20
+ - `#add_printer` and `#remove_printer`
21
+ - `#reissue_key`, `#apply_encryption_configuration`, and `#remove_encryption_configuration`
22
+
23
+
24
+ ### Changed
25
+ - JSS::Package:
26
+ - no longer issues a warning when changing the file_name of a package
27
+ - Updated the CPU type string from 'x86' to 'Intel/x86'
28
+ - Methods which used to always use the master distribution point now accept a parameter `dist_point: dp` where dp is the name or id of a fileshare distribution point. If not specified, it still defaults to the Master Distribution Point. This is needed because if the Cloud Distribution Point is the master, there is no access to it via the Classic API, and any use of DistributionPoint.master_distribution_point will raise an error.
29
+
30
+ ## \[1.3.1] - 2020-06-21
31
+
32
+ ### Changed
33
+
34
+ - JSS::MobileDeviceApplication when using PrettyPrint (pp) in irb, no longer shows the base64 data for the ipa file.
35
+
36
+ - JSS::DistributionPoint.my_distribution_point and .master_distribution_point now have options for dealing with the Cloud Distribution Point (which is not available in the classic API) being the master.
37
+
38
+ ### Fixed
39
+
40
+ - JSS::NetworkSegment.distribution_point= now takes nil or an empty string to unset the dist point.
41
+
42
+ ## \[1.3.0] - 2020-06-05
43
+
44
+ ### Added
45
+
46
+ - JSS::NetworkSegment.network_ranges_as_integers method, Similar to NetworkSegment.network_ranges, but the ranges are of Integers, not IPAddr instances. This makes for *MUCH* faster range calculations, needed to implement improvements to NetworkSegment.network_segment_for_ip
47
+
48
+ - JSS::Package.all_filenames_by, returns a Hash of all distribution point filenames for all packages, keyed by either the package id, or the package name. NOTE: as with JSS::Package.all_filenames, this method must instantiate all JSS::Package objects, so it will be slow.
49
+
50
+ ### Changed
51
+
52
+ - JSS.expand_min_os now expands to macOS 10.30.x, which should hold us for a while
53
+
54
+ - JSS::NetworkSegment.network_segment_for_ip and .my_network_segment are no longer deprecated, but now return an integer NetSeg id (or nil). The plural forms of those methods still return an Array of ids for all the matching network segments.
55
+
56
+ - The logic for JSS::NetworkSegment.network_segment_for_ip (and .my_network_segment) now matches how the Jamf server does it: when you IP address is in more than one Network Segment, Jamf uses the smallest/narrowest one (the one containing fewest IP addresses). If more than one of your Network Segments are that same width, the one with the lowest starting IP address is used.
57
+
58
+ - In some networking situations (e.g. Split-tunnel VPN with multiple active network ports) the JSS::APIObject.delete method will raise a 404 NotFound error, seemingly because the object was already deleted but a second http DELETE is sent (I think). We now just rescue and ignore that error, since the fact that it's not found means it was indeed deleted.
59
+
60
+ ### Fixed
61
+
62
+ - A copy/paste bug in Jamf::Prestage.serials_for_prestage
63
+
64
+ ## \[1.2.15] - 2020-04-30
65
+
66
+ ### Fixed
67
+
68
+ - USER_CONF_FILE is always a pathname, never nil
69
+
70
+ - issues with Array#j_ci_* methods related to removing safe navigation
71
+
72
+ ## \[1.2.13] - 2020-04-29
73
+
74
+ ### Fixed
75
+
76
+ - Ruby 2.6 needs parens in more places than 2.3, apparently
77
+
78
+ ## \[1.2.12] - 2020-04-29
79
+
80
+ ### Added
81
+
82
+ - Backport of `#dig` for Arrays, Hashes and OpenStructs, for compatibiliy with older rubiesd (for a while longer anyway). Gratefully borrowed from https://github.com/Invoca/ruby_dig
83
+
84
+ ### Changed
85
+
86
+ - Removed all safe navigation operators (`&.`) for compatibility with older rubies (for a while longer anyway)
87
+
88
+
89
+ ## \[1.2.11] - 2020-04-26
90
+
91
+ ### Fixed
92
+
93
+ - Bug in Package#install that prevented installs from 'alt_download_url'.
94
+
7
95
  ## \[1.2.10] - 2020-04-25
8
96
 
9
97
  ### Added
@@ -55,7 +143,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
55
143
 
56
144
  - Classic API (JSS module)
57
145
  - Sitable objects now recognize the string "None" as meaning no site is assigned. Thanks @cybertunnel for this fix!
146
+
58
147
  - Scopable::Scope now deals with some bugs in the API regarding Jamf & LDAP users & user groups in targets, limitations, & exclusions. Please see the documentation/comments for the class in the file or the online documentation. Thanks @cybertunnel again!
148
+
59
149
  - Criteriable::Criteria can now be empty - containing no criterion objects. When criteriable objects are created (such as Advanced Searches) the default JSS::Criteriable::Criteria object has no criteria. To remove all criteria, use `criteria.clear`, `criteria = nil`, or `criteria = JSS::Criteriable::Criteria.new` and then save. Once again, thanks to @cybertunnel for finding this.
60
150
 
61
151
  - Jamf Pro API (Jamf module)
@@ -99,7 +189,8 @@ Note that the `last_inventory_update` value does NOT indicate such communication
99
189
 
100
190
  - All APIObject Subclasses (Policy, Computer, MobileDevice, ComputerGroup, etc..) now have `get_raw`, `post_raw` & `put_raw` class methods, which are simpler wrappers for APIConnection#get_rsrc, #post_rsrc, and #put_rsrc.
101
191
  - `get_raw` takes an object's id, and returns the 'raw' JSON (parsed into a ruby Hash with symbolized keys) or a REXML::Document (from which you'll probably want to use the `root` element). If you pass `as_string: true` you'll get the un-parsed JSON or XML string directly from the API
102
- This can be useful when you need to retrieve the full object, to get some data not available in the summary-list, but instantiating the full ruby class is too slow.
192
+ This can be useful when you need to retrieve the full object, to get some data not available in the summary-list, but instantiating the full ruby class is too slow
193
+
103
194
  - `post_raw` & `put_raw` can send raw XML to the API without instantiating objects. In some cases, where you're making simple changes to simple XML, this can be faster than fetching a full instance and the re-saving it.
104
195
  WARNING You must create or acquire the XML to be sent, and no validation will be performed on it. It must be a String of XML, or something that returns such a string with #to_s, such as a REXML::Document, or a REXML::Element.
105
196
 
@@ -524,7 +524,7 @@ module Jamf
524
524
  #
525
525
  def self.attr_key_for_alias(als)
526
526
  validate_not_abstract
527
- self::OBJECT_MODEL.each { |k, deets| return k if k == als || deets[:aliases]&.include?(als) }
527
+ self::OBJECT_MODEL.each { |k, deets| return k if k == als || deets[:aliases].to_a.include?(als) }
528
528
  nil
529
529
  end
530
530
 
@@ -235,7 +235,7 @@ module Jamf
235
235
  #
236
236
  def self.serials_for_prestage(prestage_ident, refresh = false, cnx: Jamf.cnx)
237
237
  id = valid_id prestage_ident, cnx: cnx
238
- raise Jamf::NoSuchItemError, "No #{self} matching '#{ident}'" unless id
238
+ raise Jamf::NoSuchItemError, "No #{self} matching '#{prestage_ident}'" unless id
239
239
 
240
240
  serials_by_prestage_id(refresh, cnx: cnx).select { |_sn, psid| id == psid }.keys
241
241
  end
@@ -454,7 +454,9 @@ module Jamf
454
454
 
455
455
  # Are we keeping the connection alive?
456
456
  def keep_alive?
457
- @keep_alive_thread&.alive? || false
457
+ return false unless @keep_alive_thread
458
+
459
+ @keep_alive_thread.alive?
458
460
  end
459
461
 
460
462
  # @return [Jamf::Timestamp, nil]
@@ -806,7 +808,9 @@ module Jamf
806
808
  # @return [void]
807
809
  #
808
810
  def stop_keep_alive
809
- @keep_alive_thread&.kill
811
+ return unless @keep_alive_thread
812
+
813
+ @keep_alive_thread.kill if @keep_alive_thread.alive?
810
814
  @keep_alive_thread = nil
811
815
  end
812
816
 
@@ -853,7 +857,7 @@ module Jamf
853
857
  end
854
858
 
855
859
  def self.disconnect
856
- @active_connection&.disconnect
860
+ @active_connection.disconnect if @active_connection
857
861
  end
858
862
 
859
863
  end # module Jamf
@@ -103,8 +103,8 @@ module Jamf
103
103
  # The Pathname to the machine-wide preferences
104
104
  GLOBAL_CONF_FILE = Pathname.new "/etc/#{CONF_FILENAME}"
105
105
 
106
- # The Pathname to the user-specific preferences plist
107
- USER_CONF_FILE = ENV['HOME'] ? Pathname.new("~/.#{CONF_FILENAME}").expand_path : nil
106
+ # The Pathname to the user-specific preferences plist if there is one
107
+ USER_CONF_FILE = Pathname.new("#{ENV['HOME']}/.#{CONF_FILENAME}")
108
108
 
109
109
  # The attribute keys we maintain, and the type they should be stored as
110
110
  CONF_KEYS = {
@@ -134,7 +134,6 @@ module Jamf
134
134
  # Constructor
135
135
  #####################################
136
136
 
137
-
138
137
  # Initialize!
139
138
  #
140
139
  def initialize
@@ -145,7 +144,6 @@ module Jamf
145
144
  # Public Instance Methods
146
145
  #####################################
147
146
 
148
-
149
147
  # Clear all values
150
148
  #
151
149
  # @return [void]
@@ -159,7 +157,7 @@ module Jamf
159
157
  # @return [void]
160
158
  #
161
159
  def read_global
162
- read GLOBAL_CONF_FILE if GLOBAL_CONF_FILE&.file? && GLOBAL_CONF_FILE.readable?
160
+ read GLOBAL_CONF_FILE if GLOBAL_CONF_FILE.file? && GLOBAL_CONF_FILE.readable?
163
161
  end
164
162
 
165
163
  # (Re)read the user prefs, if it exists.
@@ -167,7 +165,7 @@ module Jamf
167
165
  # @return [void]
168
166
  #
169
167
  def read_user
170
- read USER_CONF_FILE if USER_CONF_FILE&.file? && USER_CONF_FILE.readable?
168
+ read USER_CONF_FILE if USER_CONF_FILE.file? && USER_CONF_FILE.readable?
171
169
  end
172
170
 
173
171
  # Clear the settings and reload the prefs files, or another file if provided
@@ -196,9 +194,9 @@ module Jamf
196
194
  def save(file)
197
195
  path =
198
196
  case file
199
- when :global then GLOBAL_CONF_FILE
200
- when :user then USER_CONF_FILE
201
- else Pathname.new(file)
197
+ when :global then GLOBAL_CONF_FILE
198
+ when :user then USER_CONF_FILE
199
+ else Pathname.new(file)
202
200
  end
203
201
 
204
202
  raise Jamf::MissingDataError, "No HOME environment variable, can't write to user conf file." if path.nil?
@@ -34,3 +34,4 @@ require 'jamf/ruby_extensions/object.rb'
34
34
  require 'jamf/ruby_extensions/pathname.rb'
35
35
  require 'jamf/ruby_extensions/string.rb'
36
36
  require 'jamf/ruby_extensions/array.rb'
37
+ require 'jamf/ruby_extensions/dig.rb'
@@ -26,7 +26,7 @@
26
26
  require 'jamf/ruby_extensions/array/predicates'
27
27
  require 'jamf/ruby_extensions/array/utils'
28
28
 
29
- #
29
+ # an array
30
30
  class Array
31
31
 
32
32
  include JamfRubyExtensions::Array::Predicates
@@ -25,6 +25,7 @@ module JamfRubyExtensions
25
25
 
26
26
  module Array
27
27
 
28
+ # Useful monkey patches for Array
28
29
  module Utils
29
30
 
30
31
  # Fetch a string from an Array case-insensitively,
@@ -40,8 +41,7 @@ module JamfRubyExtensions
40
41
  # nil if it doesn't exist
41
42
  #
42
43
  def j_ci_fetch(somestring)
43
- # select { |s| s&.casecmp? somestring }.first
44
- each { |s| return s if s&.casecmp?(somestring) }
44
+ each { |s| return s if s.respond_to?(:casecmp?) && s.casecmp?(somestring) }
45
45
  nil
46
46
  end
47
47
 
@@ -52,7 +52,7 @@ module JamfRubyExtensions
52
52
  # @return [Boolean]
53
53
  #
54
54
  def j_ci_include?(somestring)
55
- any? { |s| s&.casecmp? somestring }
55
+ any? { |s| s.respond_to?(:casecmp?) && s.casecmp?(somestring) }
56
56
  end
57
57
 
58
58
  end # module
@@ -0,0 +1,52 @@
1
+ # Copyright 2020 Pixar
2
+
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "Apache License")
5
+ # with the following modification; you may not use this file except in
6
+ # compliance with the Apache License and the following modification to it:
7
+ # Section 6. Trademarks. is deleted and replaced with:
8
+ #
9
+ # 6. Trademarks. This License does not grant permission to use the trade
10
+ # names, trademarks, service marks, or product names of the Licensor
11
+ # and its affiliates, except as required to comply with Section 4(c) of
12
+ # the License and to reproduce the content of the NOTICE file.
13
+ #
14
+ # You may obtain a copy of the Apache License at
15
+ #
16
+ # http://www.apache.org/licenses/LICENSE-2.0
17
+ #
18
+ # Unless required by applicable law or agreed to in writing, software
19
+ # distributed under the Apache License with the above modification is
20
+ # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21
+ # KIND, either express or implied. See the Apache License for the specific
22
+ # language governing permissions and limitations under the Apache License.
23
+
24
+ # Gratefully borrowed from https://github.com/Invoca/ruby_dig
25
+
26
+ # modulize monkey patches
27
+ module RubyDig
28
+
29
+ def dig(key, *rest)
30
+ value = self[key]
31
+ if value.nil? || rest.empty?
32
+ value
33
+ elsif value.respond_to?(:dig)
34
+ value.dig(*rest)
35
+ else
36
+ raise TypeError, "#{value.class} does not have #dig method"
37
+ end
38
+ end
39
+
40
+ end
41
+
42
+ if RUBY_VERSION < '2.3'
43
+
44
+ # arrays
45
+ class Array; include RubyDig; end
46
+
47
+ # hashes
48
+ class Hash; include RubyDig; end
49
+
50
+ # ostructs
51
+ class OpenStruct; include RubyDig; end
52
+ end
data/lib/jss.rb CHANGED
@@ -197,7 +197,9 @@ module JSS
197
197
  class DistributionPoint < JSS::APIObject; end
198
198
  class EBook < JSS::APIObject; end
199
199
  class IBeacon < JSS::APIObject; end
200
+ class DockItem < JSS::APIObject; end
200
201
  class LDAPServer < JSS::APIObject; end
202
+ class DirectoryBinding < JSS::APIObject; end
201
203
  class MacApplication < JSS::APIObject; end
202
204
  class MobileDevice < JSS::APIObject; end
203
205
  class MobileDeviceApplication < JSS::APIObject; end
@@ -896,22 +896,7 @@ module JSS
896
896
  # @return [JSS::DistributionPoint]
897
897
  #
898
898
  def master_distribution_point(refresh = false)
899
- @master_distribution_point = nil if refresh
900
- return @master_distribution_point if @master_distribution_point
901
-
902
- JSS::DistributionPoint.all_ids.each do |dp_id|
903
- dp = JSS::DistributionPoint.fetch id: dp_id, api: self
904
- if dp.master?
905
- @master_distribution_point = dp
906
- break
907
- end
908
- end
909
-
910
- return @master_distribution_point if @master_distribution_point
911
-
912
- # If we're here, the Cloud DP might be master, but there's no
913
- # access to it in the API :/
914
- raise JSS::NoSuchItemError, 'No Master Distribtion Point defined. It could be the Cloud Dist Point, which is not available in the classic API'
899
+ JSS::DistributionPoint.master_distribution_point refresh, api: self
915
900
  end
916
901
 
917
902
  # Get the DistributionPoint instance for the machine running
@@ -923,19 +908,7 @@ module JSS
923
908
  # @return [JSS::DistributionPoint]
924
909
  #
925
910
  def my_distribution_point(refresh = false)
926
- @my_distribution_point = nil if refresh
927
- return @my_distribution_point if @my_distribution_point
928
-
929
- my_net_seg_id = my_network_segments[0]
930
-
931
- if my_net_seg_id
932
- my_net_seg = JSS::NetworkSegment.fetch(id: my_net_seg_id, api: self)
933
- my_dp_name = my_net_seg.distribution_point
934
- @my_distribution_point = JSS::DistributionPoint.fetch(name: my_dp_name) if my_dp_name
935
- end # if my_net_seg_id
936
-
937
- @my_distribution_point ||= master_distribution_point refresh
938
- @my_distribution_point
911
+ JSS::DistributionPoint.my_distribution_point refresh, api: self
939
912
  end
940
913
 
941
914
  # @deprecated
@@ -1222,8 +1222,16 @@ module JSS
1222
1222
  # @return [void]
1223
1223
  #
1224
1224
  def delete
1225
- return nil unless @in_jss
1226
- @api.delete_rsrc @rest_rsrc
1225
+ return unless @in_jss
1226
+ begin
1227
+ @api.delete_rsrc @rest_rsrc
1228
+ rescue RestClient::NotFound, RestClient::ResourceNotFound
1229
+ # over slow connections (?) or more likely
1230
+ # split-tunnel VPN connections, sometimes the thing gets deleted
1231
+ # the call gets a 404 anyway
1232
+ nil
1233
+ end
1234
+
1227
1235
  @rest_rsrc = "#{self.class::RSRC_BASE}/name/#{CGI.escape @name.to_s}"
1228
1236
  @id = nil
1229
1237
  @in_jss = false
@@ -1655,9 +1663,13 @@ require 'jss/api_object/category'
1655
1663
  require 'jss/api_object/computer'
1656
1664
  require 'jss/api_object/computer_invitation'
1657
1665
  require 'jss/api_object/department'
1666
+ require 'jss/api_object/disk_encryption_configurations'
1667
+ require "jss/api_object/directory_binding_type"
1668
+ require 'jss/api_object/directory_binding'
1658
1669
  require 'jss/api_object/distribution_point'
1659
1670
  require 'jss/api_object/ebook'
1660
1671
  require 'jss/api_object/ibeacon'
1672
+ require 'jss/api_object/dock_item'
1661
1673
  require 'jss/api_object/ldap_server'
1662
1674
  require 'jss/api_object/mac_application'
1663
1675
  require 'jss/api_object/mobile_device'
@@ -1677,5 +1689,6 @@ require 'jss/api_object/site'
1677
1689
  require 'jss/api_object/software_update_server'
1678
1690
  require 'jss/api_object/user'
1679
1691
  require 'jss/api_object/webhook'
1692
+ require 'jss/api_object/printer'
1680
1693
 
1681
1694
  JSS::APIObject.define_identifier_list_methods
@@ -0,0 +1,273 @@
1
+ ### Copyright 2019 Rixar
2
+
3
+ ###
4
+ ### Licensed under the Apache License, Version 2.0 (the "Apache License")
5
+ ### with the following modification; you may not use this file except in
6
+ ### compliance with the Apache License and the following modification to it:
7
+ ### Section 6. Trademarks. is deleted and replaced with:
8
+ ###
9
+ ### 6. Trademarks. This License does not grant permission to use the trade
10
+ ### names, trademarks, service marks, or product names of the Licensor
11
+ ### and its affiliates, except as required to comply with Section 4(c) of
12
+ ### the License and to reproduce the content of the NOTICE file.
13
+ ###
14
+ ### You may obtain a copy of the Apache License at
15
+ ###
16
+ ### http://www.apache.org/licenses/LICENSE-2.0
17
+ ###
18
+ ### Unless required by applicable law or agreed to in writing, software
19
+ ### distributed under the Apache License with the above modification is
20
+ ### distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21
+ ### KIND, either express or implied. See the Apache License for the specific
22
+ ### language governing permissions and limitations under the Apache License.
23
+ ###
24
+ ###
25
+
26
+ module JSS
27
+
28
+ # Module Variables
29
+ #####################################
30
+
31
+ # Module Methods
32
+ #####################################
33
+
34
+ # Classes
35
+ #####################################
36
+
37
+ # A Directory Binding object in the JSS
38
+ # These are rather complex objects, and contain settings specific to the directory object's type.
39
+ #
40
+ # @see JSS::APIObject
41
+ # @see JSS::DirectoryBindingType
42
+ # @note "JSS::DirectoryBinding.fetch name: 'BindingName'" seems to be returning a 500 error in my test evironment. Use "JSS::DirectoryBinding.fetch 'BindingName' instead."
43
+ #
44
+ class DirectoryBinding < JSS::APIObject
45
+
46
+ # Mix-Ins
47
+ #####################################
48
+ include JSS::Creatable
49
+ include JSS::Updatable
50
+ include JSS::DirectoryBindingType
51
+
52
+ # Class Methods
53
+ #####################################
54
+
55
+ # Class Constants
56
+ #####################################
57
+
58
+ #! You CAN update this
59
+ DIRECTORY_BINDING_TYPE = {
60
+ open_directory: "Open Directory",
61
+ active_directory: "Active Directory",
62
+ powerbroker_identity_services: "PowerBroker Identity Services",
63
+ admitmac: "ADmitMac",
64
+ centrify: "Centrify"
65
+ }.freeze
66
+
67
+ DIRECTORY_BINDING_TYPE_CLASSES = {
68
+ "Open Directory" => JSS::DirectoryBindingType::OpenDirectory,
69
+ "Active Directory" => JSS::DirectoryBindingType::ActiveDirectory,
70
+ "PowerBroker Identity Services" => JSS::DirectoryBindingType::PowerBroker,
71
+ "ADmitMac" => JSS::DirectoryBindingType::ADmitMac,
72
+ "Centrify" => JSS::DirectoryBindingType::Centrify
73
+ }
74
+
75
+ # The base for REST resources of this class
76
+ RSRC_BASE = 'directorybindings'.freeze
77
+
78
+ # the hash key used for the JSON list output of all objects in the JSS
79
+ RSRC_LIST_KEY = :directory_bindings
80
+
81
+ # The hash key used for the JSON object output.
82
+ # It's also used in various error messages
83
+ RSRC_OBJECT_KEY = :directory_binding
84
+
85
+ # the object type for this object in
86
+ # the object history table.
87
+ # See {APIObject#add_object_history_entry}
88
+ # OBJECT_HISTORY_OBJECT_TYPE = 41
89
+
90
+ # Attributes
91
+ #####################################
92
+ attr_reader :id
93
+ attr_reader :name
94
+ attr_reader :priority
95
+ attr_reader :domain
96
+ attr_reader :username
97
+ attr_reader :password_sha256
98
+ attr_reader :computer_ou
99
+ attr_reader :type
100
+ attr_reader :type_settings
101
+ attr_reader :password
102
+
103
+ # Constructor
104
+ # @see JSS::APIObject.initialize
105
+ # @note When creating an object with specific properties use the
106
+ # objects name and then the settings.
107
+ # Ex: Creating an Active Directory object:
108
+ # JSS::DirectoryBinding.make name: "Example Binding", username: "BindingUser", password: "SuperMonkey123", computer_ou: "computers", active_directory: { multiple_domains: false }, domain: your.domain.server
109
+ #####################################
110
+ def initialize(args = {})
111
+ super args
112
+
113
+ if self.in_jss?
114
+ @priority = @init_data[:priority]
115
+ @domain = @init_data[:domain]
116
+ @username = @init_data[:username]
117
+ @password_sha256 = @init_data[:password_sha256]
118
+ @computer_ou = @init_data[:computer_ou]
119
+ @type = @init_data[:type]
120
+
121
+ class_key = DIRECTORY_BINDING_TYPE.select { |k,v| v == @type }.map { |k,v| k }.first
122
+ self.set_type_settings (DIRECTORY_BINDING_TYPE_CLASSES[@type.to_s].new @init_data[class_key])
123
+ else
124
+ # Build
125
+ raise JSS::MissingDataError, "domain must be provided." if @init_data[:domain].nil?
126
+ raise JSS::MissingDataError, "username must be provided." if @init_data[:username].nil?
127
+ raise JSS::MissingDataError, "computer_ou must be provided." if @init_data[:computer_ou].nil?
128
+ raise JSS::MissingDataError, "password must be provided when creating a DirectoryBinding object." if @init_data[:password].nil?
129
+ raise JSS::MissingDataError, "Type must be provided, one of \":#{DIRECTORY_BINDING_TYPE.keys.join(",:")}\"." if @init_data[:type].nil?
130
+ raise JSS::InvalidDataError, "Type must be one of \":#{DIRECTORY_BINDING_TYPE.keys.join(",:")}\"." unless DIRECTORY_BINDING_TYPE.keys.include? @init_data[:type]
131
+ raise JSS::InvalidDataError, "Priority must be between 1 and 10" if !@init_data[:priority].nil? && (@init_data[:priority] <= 1 || @init_data[:priority] >= 10)
132
+
133
+ @domain = @init_data[:domain]
134
+ @username = @init_data[:username]
135
+ @computer_ou = @init_data[:computer_ou]
136
+ @type = DIRECTORY_BINDING_TYPE[@init_data[:type]]
137
+ @password = @init_data[:password]
138
+ @priority = @init_data[:priority]
139
+
140
+ @priority = 1 if @priority.nil?
141
+
142
+
143
+ class_key = DIRECTORY_BINDING_TYPE.select { |k,v| v == @type }.map { |k,v| k }.first
144
+ self.set_type_settings (DIRECTORY_BINDING_TYPE_CLASSES[@type.to_s].new @init_data[class_key])
145
+
146
+ end
147
+
148
+ end
149
+
150
+ # Public Instance Methods
151
+ #####################################
152
+
153
+ # The domain the device will be bound to.
154
+ #
155
+ # @author Tyler Morgan
156
+ #
157
+ # @param newvalue [String]
158
+ #
159
+ # @raise [JSS::InvalidDataError] If newvalue is not a String
160
+ #
161
+ # @return [void]
162
+ def domain=(newvalue)
163
+ raise JSS::InvalidDataError, "Domain must be a String" unless newvalue.is_a? String
164
+
165
+ @domain = newvalue.to_s
166
+ @need_to_update = true
167
+ end
168
+
169
+
170
+ # The username used to attempt to bind the device to the domain.
171
+ #
172
+ # @author Tyler Morgan
173
+ #
174
+ # @param newvalue [String]
175
+ #
176
+ # @raise [JSS::InvalidDataError] If newvalue is not a String
177
+ #
178
+ # @return [void]
179
+ def username=(newvalue)
180
+ raise JSS::InvalidDataError, "Username must be a String" unless newvalue.is_a? String
181
+
182
+ @username = newvalue
183
+ @need_to_update = true
184
+ end
185
+
186
+
187
+ # The priority the domain has over another one.
188
+ #
189
+ # @author Tyler Morgan
190
+ #
191
+ # @param newvalue [Integer]
192
+ #
193
+ # @raise [JSS::InvalidDataError] If newvalue is not an Integer
194
+ # @raise [JSS::InvalidDataError] If newvalue is not between 1 and 10
195
+ #
196
+ # @return [void]
197
+ def priority=(newvalue)
198
+ raise JSS::InvalidDataError, "Priority must be a Integer" unless newvalue.is_a? Integer
199
+ raise JSS::InvalidDataError, "Priority cannot exceed 10" unless newvalue <= 10
200
+ raise JSS::InvalidDataError, "Priority must be greater than 0" unless newvalue > 0
201
+
202
+ @priority = newvalue
203
+ @need_to_update = true
204
+ end
205
+
206
+
207
+ # The OU path the computer object is to be placed
208
+ #
209
+ # @author Tyler Morgan
210
+ #
211
+ # @param newvalue [String]
212
+ #
213
+ # @raise [JSS::InvalidDataError] If newvalue is not a String
214
+ #
215
+ # @return [void]
216
+ def computer_ou=(newvalue)
217
+ raise JSS::InvalidDataError, "Computer OU must be a String" unless newvalue.is_a? String
218
+
219
+ @computer_ou = newvalue
220
+ @need_to_update = true
221
+ end
222
+
223
+
224
+ # Sets the password used in conjunction with the username to attempt to bind
225
+ # the computer to the domain.
226
+ #
227
+ # @author Tyler Morgan
228
+ #
229
+ # @param newvalue [String]
230
+ #
231
+ # @raise [JSS::InvalidDataError] If newvalue is not a String
232
+ #
233
+ # @return [void]
234
+ def password=(newvalue)
235
+ raise JSS::InvalidDataError, "Password must be a string" unless newvalue.is_a? String
236
+
237
+ @password = newvalue
238
+ @need_to_update = true
239
+ end
240
+
241
+ # private instance methods
242
+ ######################
243
+ private
244
+
245
+ # the xml formated data for adding or updating this in the JSS
246
+ #
247
+ # This method constructs a properly formatted XML document to be handled by the Jamf Pro API
248
+ #
249
+ # @author Tyler Morgan
250
+ #
251
+ # @return [String]
252
+ def rest_xml
253
+ doc = REXML::Document.new APIConnection::XML_HEADER
254
+ ns = doc.add_element RSRC_OBJECT_KEY.to_s
255
+ ns.add_element('id').text = @id.to_s
256
+ ns.add_element('name').text = @name
257
+ ns.add_element('priority').text = @priority.to_s
258
+ ns.add_element('domain').text = @domain.to_s
259
+ ns.add_element('username').text = @username.to_s
260
+ ns.add_element('computer_ou').text = @computer_ou.to_s
261
+ ns.add_element('type').text = @type.to_s
262
+ if !@password.nil?
263
+ ns.add_element('password').text = @password.to_s
264
+ end
265
+
266
+ ns << @type_settings.type_setting_xml
267
+
268
+ return doc.to_s
269
+ end # rest_xml
270
+ end
271
+
272
+
273
+ end