ruby-jss 0.6.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.

Potentially problematic release.


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

Files changed (73) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +7 -0
  3. data/CHANGES.md +112 -0
  4. data/LICENSE.txt +174 -0
  5. data/README.md +426 -0
  6. data/THANKS.md +6 -0
  7. data/bin/cgrouper +485 -0
  8. data/bin/subnet-update +400 -0
  9. data/lib/jss-api.rb +2 -0
  10. data/lib/jss.rb +190 -0
  11. data/lib/jss/api_connection.rb +410 -0
  12. data/lib/jss/api_object.rb +616 -0
  13. data/lib/jss/api_object/advanced_search.rb +389 -0
  14. data/lib/jss/api_object/advanced_search/advanced_computer_search.rb +95 -0
  15. data/lib/jss/api_object/advanced_search/advanced_mobile_device_search.rb +96 -0
  16. data/lib/jss/api_object/advanced_search/advanced_user_search.rb +95 -0
  17. data/lib/jss/api_object/building.rb +92 -0
  18. data/lib/jss/api_object/category.rb +147 -0
  19. data/lib/jss/api_object/computer.rb +852 -0
  20. data/lib/jss/api_object/creatable.rb +98 -0
  21. data/lib/jss/api_object/criteriable.rb +189 -0
  22. data/lib/jss/api_object/criteriable/criteria.rb +231 -0
  23. data/lib/jss/api_object/criteriable/criterion.rb +228 -0
  24. data/lib/jss/api_object/department.rb +93 -0
  25. data/lib/jss/api_object/distribution_point.rb +560 -0
  26. data/lib/jss/api_object/extendable.rb +221 -0
  27. data/lib/jss/api_object/extension_attribute.rb +466 -0
  28. data/lib/jss/api_object/extension_attribute/computer_extension_attribute.rb +362 -0
  29. data/lib/jss/api_object/extension_attribute/mobile_device_extension_attribute.rb +189 -0
  30. data/lib/jss/api_object/extension_attribute/user_extension_attribute.rb +117 -0
  31. data/lib/jss/api_object/group.rb +380 -0
  32. data/lib/jss/api_object/group/computer_group.rb +124 -0
  33. data/lib/jss/api_object/group/mobile_device_group.rb +139 -0
  34. data/lib/jss/api_object/group/user_group.rb +139 -0
  35. data/lib/jss/api_object/ldap_server.rb +535 -0
  36. data/lib/jss/api_object/locatable.rb +286 -0
  37. data/lib/jss/api_object/matchable.rb +97 -0
  38. data/lib/jss/api_object/mobile_device.rb +556 -0
  39. data/lib/jss/api_object/netboot_server.rb +148 -0
  40. data/lib/jss/api_object/network_segment.rb +414 -0
  41. data/lib/jss/api_object/osx_configuration_profile.rb +262 -0
  42. data/lib/jss/api_object/package.rb +839 -0
  43. data/lib/jss/api_object/peripheral.rb +335 -0
  44. data/lib/jss/api_object/peripheral_type.rb +295 -0
  45. data/lib/jss/api_object/policy.rb +898 -0
  46. data/lib/jss/api_object/purchasable.rb +316 -0
  47. data/lib/jss/api_object/removable_macaddr.rb +98 -0
  48. data/lib/jss/api_object/scopable.rb +136 -0
  49. data/lib/jss/api_object/scopable/scope.rb +621 -0
  50. data/lib/jss/api_object/script.rb +631 -0
  51. data/lib/jss/api_object/self_servable.rb +356 -0
  52. data/lib/jss/api_object/site.rb +93 -0
  53. data/lib/jss/api_object/software_update_server.rb +109 -0
  54. data/lib/jss/api_object/updatable.rb +117 -0
  55. data/lib/jss/api_object/uploadable.rb +138 -0
  56. data/lib/jss/api_object/user.rb +272 -0
  57. data/lib/jss/client.rb +504 -0
  58. data/lib/jss/compatibility.rb +66 -0
  59. data/lib/jss/composer.rb +185 -0
  60. data/lib/jss/configuration.rb +306 -0
  61. data/lib/jss/db_connection.rb +298 -0
  62. data/lib/jss/exceptions.rb +95 -0
  63. data/lib/jss/ruby_extensions.rb +35 -0
  64. data/lib/jss/ruby_extensions/filetest.rb +43 -0
  65. data/lib/jss/ruby_extensions/hash.rb +79 -0
  66. data/lib/jss/ruby_extensions/ipaddr.rb +91 -0
  67. data/lib/jss/ruby_extensions/pathname.rb +77 -0
  68. data/lib/jss/ruby_extensions/string.rb +59 -0
  69. data/lib/jss/ruby_extensions/time.rb +63 -0
  70. data/lib/jss/server.rb +108 -0
  71. data/lib/jss/utility.rb +478 -0
  72. data/lib/jss/version.rb +31 -0
  73. metadata +187 -0
@@ -0,0 +1,124 @@
1
+ ### Copyright 2016 Pixar
2
+ ###
3
+ ### Licensed under the Apache License, Version 2.0 (the "Apache License")
4
+ ### with the following modification; you may not use this file except in
5
+ ### compliance with the Apache License and the following modification to it:
6
+ ### Section 6. Trademarks. is deleted and replaced with:
7
+ ###
8
+ ### 6. Trademarks. This License does not grant permission to use the trade
9
+ ### names, trademarks, service marks, or product names of the Licensor
10
+ ### and its affiliates, except as required to comply with Section 4(c) of
11
+ ### the License and to reproduce the content of the NOTICE file.
12
+ ###
13
+ ### You may obtain a copy of the Apache License at
14
+ ###
15
+ ### http://www.apache.org/licenses/LICENSE-2.0
16
+ ###
17
+ ### Unless required by applicable law or agreed to in writing, software
18
+ ### distributed under the Apache License with the above modification is
19
+ ### distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20
+ ### KIND, either express or implied. See the Apache License for the specific
21
+ ### language governing permissions and limitations under the Apache License.
22
+ ###
23
+ ###
24
+
25
+ ###
26
+ module JSS
27
+
28
+ #####################################
29
+ ### Module Constants
30
+ #####################################
31
+
32
+ #####################################
33
+ ### Module Variables
34
+ #####################################
35
+
36
+ #####################################
37
+ ### Module Methods
38
+ #####################################
39
+
40
+ #####################################
41
+ ### Classes
42
+ #####################################
43
+
44
+ ###
45
+ ### A computer group in the JSS
46
+ ###
47
+ ### See also the parent class JSS::Group
48
+ ###
49
+ ### @see JSS::APIObject
50
+ ###
51
+ ### @see JSS::Group
52
+ ###
53
+ class ComputerGroup < JSS::Group
54
+
55
+ #####################################
56
+ ### Mix-Ins
57
+ #####################################
58
+
59
+ #####################################
60
+ ### Class Methods
61
+ #####################################
62
+
63
+ #####################################
64
+ ### Class Constants
65
+ #####################################
66
+
67
+ ### The base for REST resources of this class
68
+ RSRC_BASE = "computergroups"
69
+
70
+ ### the hash key used for the JSON list output of all objects in the JSS
71
+ RSRC_LIST_KEY = :computer_groups
72
+
73
+ ### The hash key used for the JSON object output.
74
+ ### It's also used in various error messages
75
+ RSRC_OBJECT_KEY = :computer_group
76
+
77
+ ### these keys, as well as :id and :name, are present in valid API JSON data for this class
78
+ VALID_DATA_KEYS = [:is_smart, :computers ]
79
+
80
+ ### this allows the parent Group class to do things right
81
+ MEMBER_CLASS = JSS::Computer
82
+
83
+ #####################################
84
+ ### Class Variables
85
+ #####################################
86
+
87
+ #####################################
88
+ ### Class Methods
89
+ #####################################
90
+
91
+ #####################################
92
+ ### Attributes
93
+ #####################################
94
+
95
+ #####################################
96
+ ### Public Instance Methods
97
+ #####################################
98
+
99
+
100
+ ###
101
+ ### The serial numbers of members in this group
102
+ ###
103
+ ### @return [Array<String>] the member serial numbers
104
+ ###
105
+ def member_serial_numbers
106
+ @members.map{|m| m[:serial_number]}
107
+ end
108
+
109
+ ###
110
+ ### Return an array of the mac_addrs of members in this group
111
+ ###
112
+ ### @return [Array<String>] the member mac addresses
113
+ ###
114
+ def member_mac_addresses
115
+ @members.map{|m| m[:mac_address]} + @members.map{|m| m[:alt_mac_address]}
116
+ end
117
+
118
+ #####################################
119
+ ### Private Instance Methods
120
+ #####################################
121
+
122
+ end # class ComputerGroup
123
+
124
+ end # module
@@ -0,0 +1,139 @@
1
+ ### Copyright 2016 Pixar
2
+ ###
3
+ ### Licensed under the Apache License, Version 2.0 (the "Apache License")
4
+ ### with the following modification; you may not use this file except in
5
+ ### compliance with the Apache License and the following modification to it:
6
+ ### Section 6. Trademarks. is deleted and replaced with:
7
+ ###
8
+ ### 6. Trademarks. This License does not grant permission to use the trade
9
+ ### names, trademarks, service marks, or product names of the Licensor
10
+ ### and its affiliates, except as required to comply with Section 4(c) of
11
+ ### the License and to reproduce the content of the NOTICE file.
12
+ ###
13
+ ### You may obtain a copy of the Apache License at
14
+ ###
15
+ ### http://www.apache.org/licenses/LICENSE-2.0
16
+ ###
17
+ ### Unless required by applicable law or agreed to in writing, software
18
+ ### distributed under the Apache License with the above modification is
19
+ ### distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20
+ ### KIND, either express or implied. See the Apache License for the specific
21
+ ### language governing permissions and limitations under the Apache License.
22
+ ###
23
+ ###
24
+
25
+ ###
26
+ module JSS
27
+
28
+ #####################################
29
+ ### Module Constants
30
+ #####################################
31
+
32
+ #####################################
33
+ ### Module Variables
34
+ #####################################
35
+
36
+ #####################################
37
+ ### Module Methods
38
+ #####################################
39
+
40
+ #####################################
41
+ ### Classes
42
+ #####################################
43
+
44
+ ###
45
+ ### A Mobile Device group in the JSS
46
+ ###
47
+ ### See also the parent class JSS::Group
48
+ ###
49
+ ### @see JSS::APIObject
50
+ ###
51
+ ### @see JSS::Group
52
+ ###
53
+ class MobileDeviceGroup < JSS::Group
54
+
55
+ #####################################
56
+ ### Mix-Ins
57
+ #####################################
58
+
59
+
60
+ #####################################
61
+ ### Class Constants
62
+ #####################################
63
+
64
+ ### The base for REST resources of this class
65
+ RSRC_BASE = "mobiledevicegroups"
66
+
67
+ ### the hash key used for the JSON list output of all objects in the JSS
68
+ RSRC_LIST_KEY = :mobile_device_groups
69
+
70
+ ### The hash key used for the JSON object output.
71
+ ### It's also used in various error messages
72
+ RSRC_OBJECT_KEY = :mobile_device_group
73
+
74
+ ### these keys, as well as :id and :name, are present in valid API JSON data for this class
75
+ VALID_DATA_KEYS = [:is_smart, :mobile_devices ]
76
+
77
+ ### this allows the parent Group class to do things right
78
+ MEMBER_CLASS = JSS::MobileDevice
79
+
80
+ #####################################
81
+ ### Class Variables
82
+ #####################################
83
+
84
+ #####################################
85
+ ### Class Methods
86
+ #####################################
87
+
88
+ #####################################
89
+ ### Attributes
90
+ #####################################
91
+
92
+ #####################################
93
+ ### Public Instance Methods
94
+ #####################################
95
+
96
+ ###
97
+ ### Return an array of the udids of mobile_devices in this group
98
+ ###
99
+ ### @return [Array<String>] the member udids
100
+ ###
101
+ def member_udids
102
+ @members.map{|m| m[:udid]}
103
+ end
104
+
105
+ ###
106
+ ### Return an array of the serial numbers of mobile_devices in this group
107
+ ###
108
+ ### @return [Array<String>] the member serial numbers
109
+ ###
110
+ def member_serial_numbers
111
+ @members.map{|m| m[:serial_number]}
112
+ end
113
+
114
+ ###
115
+ ### Return an array of the mac_addrs of mobile_devices in this group
116
+ ###
117
+ ### @return [Array<String>] the member mac addresses
118
+ ###
119
+ def member_mac_addresses
120
+ @members.map{|m| m[:mac_address]}
121
+ end
122
+
123
+ ###
124
+ ### Return an array of the wifi mac_addrs of mobile_devices in this group
125
+ ###
126
+ ### @return [Array<String>] the member wifi mac addresses
127
+ ###
128
+ def member_wifi_mac_addresses
129
+ @members.map{|m| m[:wifi_mac_address]}
130
+ end
131
+
132
+ #####################################
133
+ ### Private Instance Methods
134
+ #####################################
135
+
136
+
137
+ end # class ComputerGroup
138
+
139
+ end # module
@@ -0,0 +1,139 @@
1
+ ### Copyright 2016 Pixar
2
+ ###
3
+ ### Licensed under the Apache License, Version 2.0 (the "Apache License")
4
+ ### with the following modification; you may not use this file except in
5
+ ### compliance with the Apache License and the following modification to it:
6
+ ### Section 6. Trademarks. is deleted and replaced with:
7
+ ###
8
+ ### 6. Trademarks. This License does not grant permission to use the trade
9
+ ### names, trademarks, service marks, or product names of the Licensor
10
+ ### and its affiliates, except as required to comply with Section 4(c) of
11
+ ### the License and to reproduce the content of the NOTICE file.
12
+ ###
13
+ ### You may obtain a copy of the Apache License at
14
+ ###
15
+ ### http://www.apache.org/licenses/LICENSE-2.0
16
+ ###
17
+ ### Unless required by applicable law or agreed to in writing, software
18
+ ### distributed under the Apache License with the above modification is
19
+ ### distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20
+ ### KIND, either express or implied. See the Apache License for the specific
21
+ ### language governing permissions and limitations under the Apache License.
22
+ ###
23
+ ###
24
+
25
+ ###
26
+ module JSS
27
+
28
+ #####################################
29
+ ### Module Constants
30
+ #####################################
31
+
32
+ #####################################
33
+ ### Module Variables
34
+ #####################################
35
+
36
+ #####################################
37
+ ### Module Methods
38
+ #####################################
39
+
40
+ #####################################
41
+ ### Classes
42
+ #####################################
43
+
44
+ ###
45
+ ### A Mobile Device group in the JSS
46
+ ###
47
+ ### See also the parent class JSS::Group
48
+ ###
49
+ ### @see JSS::APIObject
50
+ ###
51
+ ### @see JSS::Group
52
+ ###
53
+ class UserGroup < JSS::Group
54
+
55
+ #####################################
56
+ ### Mix-Ins
57
+ #####################################
58
+
59
+
60
+ #####################################
61
+ ### Class Constants
62
+ #####################################
63
+
64
+ ### The base for REST resources of this class
65
+ RSRC_BASE = "usergroups"
66
+
67
+ ### the hash key used for the JSON list output of all objects in the JSS
68
+ RSRC_LIST_KEY = :user_groups
69
+
70
+ ### The hash key used for the JSON object output.
71
+ ### It's also used in various error messages
72
+ RSRC_OBJECT_KEY = :user_group
73
+
74
+ ### these keys, as well as :id and :name, are present in valid API JSON data for this class
75
+ VALID_DATA_KEYS = [:is_smart, :users ]
76
+
77
+ ### this allows the parent Group class to do things right
78
+ MEMBER_CLASS = JSS::User
79
+
80
+ #####################################
81
+ ### Class Variables
82
+ #####################################
83
+
84
+ #####################################
85
+ ### Class Methods
86
+ #####################################
87
+
88
+ #####################################
89
+ ### Attributes
90
+ #####################################
91
+
92
+ #####################################
93
+ ### Public Instance Methods
94
+ #####################################
95
+
96
+ ###
97
+ ### Return an array of the usernames of users in this group
98
+ ###
99
+ ### @return [Array<String>] the member usernames
100
+ ###
101
+ def member_usernames
102
+ @members.map{|m| m[:username]}
103
+ end
104
+
105
+ ###
106
+ ### Return an array of the full names of users in this group
107
+ ###
108
+ ### @return [Array<String>] the member full names
109
+ ###
110
+ def member_full_names
111
+ @members.map{|m| m[:full_name]}
112
+ end
113
+
114
+ ###
115
+ ### Return an array of the phone numbers of users in this group
116
+ ###
117
+ ### @return [Array<String>] the member phone numbers
118
+ ###
119
+ def member_phone_numbers
120
+ @members.map{|m| m[:phone_number]}
121
+ end
122
+
123
+ ###
124
+ ### Return an array of the email addresses of users in this group
125
+ ###
126
+ ### @return [Array<String>] the member email addresses
127
+ ###
128
+ def member_email_addresses
129
+ @members.map{|m| m[:email_address]}
130
+ end
131
+
132
+ #####################################
133
+ ### Private Instance Methods
134
+ #####################################
135
+
136
+
137
+ end # class UserGroup
138
+
139
+ end # module
@@ -0,0 +1,535 @@
1
+ ### Copyright 2016 Pixar
2
+ ###
3
+ ### Licensed under the Apache License, Version 2.0 (the "Apache License")
4
+ ### with the following modification; you may not use this file except in
5
+ ### compliance with the Apache License and the following modification to it:
6
+ ### Section 6. Trademarks. is deleted and replaced with:
7
+ ###
8
+ ### 6. Trademarks. This License does not grant permission to use the trade
9
+ ### names, trademarks, service marks, or product names of the Licensor
10
+ ### and its affiliates, except as required to comply with Section 4(c) of
11
+ ### the License and to reproduce the content of the NOTICE file.
12
+ ###
13
+ ### You may obtain a copy of the Apache License at
14
+ ###
15
+ ### http://www.apache.org/licenses/LICENSE-2.0
16
+ ###
17
+ ### Unless required by applicable law or agreed to in writing, software
18
+ ### distributed under the Apache License with the above modification is
19
+ ### distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20
+ ### KIND, either express or implied. See the Apache License for the specific
21
+ ### language governing permissions and limitations under the Apache License.
22
+ ###
23
+ ###
24
+
25
+ ###
26
+ module JSS
27
+
28
+ #####################################
29
+ ### Module Variables
30
+ #####################################
31
+
32
+ #####################################
33
+ ### Module Methods
34
+ #####################################
35
+
36
+
37
+ #####################################
38
+ ### Classes
39
+ #####################################
40
+
41
+ ###
42
+ ### An LDAP server in the JSS.
43
+ ###
44
+ ### This class doesn't curretly provide creation or updaing of LDAP server
45
+ ### definitions in the JSS. Please use the JSS web UI.
46
+ ###
47
+ ### However, it does provide methods for querying users and usergroups from
48
+ ### LDAP servers, and checking group membership.
49
+ ###
50
+ ### When an LDAPServer instance is created, if it
51
+ ### uses anonymous binding for lookups (the Authentication Type is set to 'none') then
52
+ ### the LDAP connection is established immediately. Otherwise, you must use the {#connect}
53
+ ### method, and provide the appropriate password for the lookup account defined.
54
+ ###
55
+ ### Since LDAP server connections are used to verify the validity of LDAP users & groups used in
56
+ ### scopes, if you don't connect to all LDAP servers before modifying any scope's user & group
57
+ ### limitations or exceptions, those new values may not be verifiable. Unverified limitations and
58
+ ### exceptions, when sent to the API, will result in a REST 409 Conflict error if the user or
59
+ ### group doesn't exist. Unfortunately, 409 Conflict errors are very generic and don't indicate the
60
+ ### source of the problem (in this case, a non-existent user or group limitation or exception to the
61
+ ### scope). The {JSS::Scopable} module tries to catch these errors and raise a more useful
62
+ ### exception when they happen.
63
+ ###
64
+ ### The class method {LDAPServer.all_ldaps} returns a Hash of JSS::LDAPServer instances.
65
+ ### one for each server defined in the JSS.
66
+ ###
67
+ ### The class methods {LDAPServer.user_in_ldap?} and {LDAPServer.group_in_ldap?} can be
68
+ ### used to check all defined LDAP servers for a user or group. They are used by
69
+ ### {JSS::Scopable::Scope} when adding user and groups to scope limitations and exceptions.
70
+ ###
71
+ ### Within an LDAPServer instance, the methods {#find_user} and {#find_group} will return
72
+ ### all matches in the server for a given search term.
73
+ ###
74
+ ### @see JSS::APIObject
75
+ ###
76
+ class LDAPServer < JSS::APIObject
77
+
78
+ #####################################
79
+ ### Mix-Ins
80
+ #####################################
81
+
82
+ #####################################
83
+ ### Class Variables
84
+ #####################################
85
+
86
+ @@all_ldaps = nil
87
+
88
+ #####################################
89
+ ### Class Methods
90
+ #####################################
91
+
92
+ ###
93
+ ### @param refresh[Boolean] should the LDAP server data be re-read from the API?
94
+ ###
95
+ ### @return [Hash{String => JSS::LDAPServer}] JSS::LDAPServer instances for all defined servers
96
+ ###
97
+ def self.all_ldaps(refresh = false)
98
+ @@all_ldaps = nil if refresh
99
+ return @@all_ldaps if @@all_ldaps
100
+
101
+ @@all_ldaps = {}
102
+ JSS::LDAPServer.all.each { |svr| @@all_ldaps[svr[:name]] = JSS::LDAPServer.new(:id =>svr[:id])}
103
+
104
+ @@all_ldaps
105
+ end
106
+
107
+ ###
108
+ ### @param user[String] a username to search for in all LDAP servers
109
+ ###
110
+ ### @return [Boolean] does the user exist in any LDAP server?
111
+ ###
112
+ def self.user_in_ldap? (user)
113
+ gotuser = false
114
+ self.all_ldaps.values.each{|ldap| gotuser = true unless ldap.find_user(user, :exact).empty? }
115
+ return gotuser
116
+ end
117
+
118
+ ###
119
+ ### @param group[String] a group to search for in all LDAP servers
120
+ ###
121
+ ### @return [Boolean] does the group exist in any LDAP server?
122
+ ###
123
+ def self.group_in_ldap? (group)
124
+ gotgroup = false
125
+ self.all_ldaps.values.each{|ldap| gotgroup = true unless ldap.find_group(group, :exact).empty? }
126
+ return gotgroup
127
+ end
128
+
129
+
130
+
131
+ #####################################
132
+ ### Class Constants
133
+ #####################################
134
+
135
+ ### The base for REST resources of this class
136
+ RSRC_BASE = "ldapservers"
137
+
138
+ ### the hash key used for the JSON list output of all objects in the JSS
139
+ RSRC_LIST_KEY = :ldap_servers
140
+
141
+ ### The hash key used for the JSON object output.
142
+ ### It's also used in various error messages
143
+ RSRC_OBJECT_KEY = :ldap_server
144
+
145
+ ### these keys, as well as :id and :name, are present in valid API JSON data for this class
146
+ VALID_DATA_KEYS = []
147
+
148
+ ### the default LDAP port
149
+ DEFAULT_PORT = 389
150
+
151
+ ### possible values for search scope
152
+ SEARCH_SCOPES = ["All Subtrees", "First Level Only"]
153
+
154
+ ### possible authentication types
155
+ AUTH_TYPES = {'none' => :anonymous, 'simple' => :simple, 'CRAM-MD5' => :cram_md5, 'DIGEST-MD5' => :digest_md5 }
156
+
157
+ ### possible referral responses
158
+ REFERRAL_RESPONSES = ['', nil, 'follow', 'ignore']
159
+
160
+ ### possible objectclass mapping options
161
+ OBJECT_CLASS_MAPPING_OPTIONS = ["any", "all"]
162
+
163
+ #####################################
164
+ ### Attributes
165
+ #####################################
166
+
167
+ ### These attributes all come from the :connection hash of the
168
+ ### API data
169
+
170
+ ### @return [String] the hostname of the server
171
+ attr_reader :hostanme
172
+
173
+ ### @return [Integer] the port for ldap
174
+ attr_reader :port
175
+
176
+ ### @return [Boolean] should the connection use ssl?
177
+ attr_reader :use_ssl
178
+
179
+ ### @return [String] what authentication method should be used?
180
+ attr_reader :authentication_type
181
+
182
+ ### @return [String] the Distinguished Name of the account used for connections/lookups?
183
+ attr_reader :lookup_dn
184
+
185
+ ### @return [String] the password for the connection/lookup account, as a SHA256 digest.
186
+ attr_reader :lookup_pw_sha256
187
+
188
+ ### @return [Integer] timeout, in seconds, for opening LDAP connections
189
+ attr_reader :open_close_timeout
190
+
191
+ ### @return [Integer] timeout, in seconds, for search queries
192
+ attr_reader :search_timeout
193
+
194
+ ### @return [String] the referral response from the server
195
+ attr_reader :referral_response
196
+
197
+ ### @return [Boolean] should searches use wildcards?
198
+ attr_reader :use_wildcards
199
+
200
+
201
+ ### @return [Hash<Symbol=>String>]
202
+ ###
203
+ ### The LDAP attributes mapped to various user data
204
+ ###
205
+ ### The hash keys are:
206
+ ### - :search_base =>
207
+ ### - :search_scope =>
208
+ ### - :object_classes =>
209
+ ### - :map_object_class_to_any_or_all =>
210
+ ### - :map_username =>
211
+ ### - :map_user_id =>
212
+ ### - :map_department =>
213
+ ### - :map_building =>
214
+ ### - :map_room =>
215
+ ### - :map_realname =>
216
+ ### - :map_phone =>
217
+ ### - :map_email_address =>
218
+ ### - :map_position =>
219
+ ### - :map_user_uuid =>
220
+ ### - :append_to_email_results =>
221
+ ###
222
+ attr_reader :user_mappings
223
+
224
+
225
+ ### @return [Hash<Symbol=>String>]
226
+ ###
227
+ ### The LDAP attributes mapped to various user group data
228
+ ###
229
+ ### The hash keys are:
230
+ ### - :search_base =>
231
+ ### - :search_scope =>
232
+ ### - :object_classes =>
233
+ ### - :map_object_class_to_any_or_all =>
234
+ ### - :map_group_id =>
235
+ ### - :map_group_name =>
236
+ ### - :map_group_uuid =>
237
+ ###
238
+ attr_reader :user_group_mappings
239
+
240
+ ### @return [Hash<Symbol=>String>]
241
+ ###
242
+ ### The LDAP attributes used to identify a user as a member of a group
243
+ ###
244
+ ### The hash keys are:
245
+ ### - :user_group_membership_stored_in =>
246
+ ### - :map_user_membership_use_dn =>
247
+ ### - :map_group_membership_to_user_field =>
248
+ ### - :group_id =>
249
+ ### - :map_object_class_to_any_or_all =>
250
+ ### - :append_to_username =>
251
+ ### - :username =>
252
+ ### - :object_classes =>
253
+ ### - :use_dn =>
254
+ ### - :search_base =>
255
+ ### - :recursive_lookups =>
256
+ ### - :search_scope =>
257
+ ### - :map_user_membership_to_group_field =>
258
+ ###
259
+ attr_reader :user_group_membership_mappings
260
+
261
+ ### @return [Boolean] we we connected to this server at the moment?
262
+ attr_reader :connected
263
+
264
+ #####################################
265
+ ### Constructor
266
+ #####################################
267
+
268
+ ###
269
+ ### See JSS::APIObject#initialize
270
+ ###
271
+ def initialize (args = {})
272
+ require 'net/ldap'
273
+ super
274
+
275
+ @hostname = @init_data[:connection][:hostname]
276
+ @port = @init_data[:connection][:port]
277
+ @use_ssl = @init_data[:connection][:use_ssl]
278
+ @authentication_type = AUTH_TYPES[@init_data[:connection][:authentication_type]]
279
+ @open_close_timeout = @init_data[:connection][:open_close_timeout]
280
+ @search_timeout = @init_data[:connection][:search_timeout]
281
+ @referral_response = @init_data[:connection][:referral_response]
282
+ @use_wildcards = @init_data[:connection][:use_wildcards]
283
+
284
+ @lookup_dn = @init_data[:connection][:account][:distinguished_username]
285
+ @lookup_pw_sha256 = @init_data[:connection][:account][:password_sha256]
286
+
287
+ @user_mappings = @init_data[:mappings_for_users ][:user_mappings]
288
+ @user_group_mappings = @init_data[:mappings_for_users ][:user_group_mappings]
289
+ @user_group_membership_mappings = @init_data[:mappings_for_users ][:user_group_membership_mappings]
290
+
291
+ # the ldap attributes to retrieve with user lookups
292
+ # (all those defined in the user mappings)
293
+ @user_attrs_to_get = {
294
+ :username => @user_mappings[:map_username],
295
+ :user_id => @user_mappings[:map_user_id],
296
+ :department => @user_mappings[:map_department],
297
+ :building => @user_mappings[:map_building],
298
+ :room => @user_mappings[:map_room],
299
+ :realname => @user_mappings[:map_realname],
300
+ :phone => @user_mappings[:map_phone],
301
+ :email_address => @user_mappings[:map_email_address],
302
+ :position => @user_mappings[:map_position],
303
+ :user_uuid => @user_mappings[:map_user_uuid]
304
+ }.delete_if{|k,v| v.nil? }
305
+
306
+ # and for groups....
307
+ @user_group_attrs_to_get = {
308
+ :group_id => @user_group_mappings[:map_group_id],
309
+ :group_name => @user_group_mappings[:map_group_name],
310
+ :group_uuid => @user_group_mappings[:map_group_uuid]
311
+ }.delete_if{|k,v| v.nil? }
312
+
313
+ @connection = nil
314
+ @connected = false
315
+
316
+ # If we are using anonymous binding, connect now
317
+ connect if @authentication_type == :anonymous
318
+ end
319
+
320
+ #####################################
321
+ ### Public Instance Methods
322
+ #####################################
323
+
324
+ ###
325
+ ###
326
+ ### @param user[String] the username to search for
327
+ ###
328
+ ### @param exact[Boolean] if true, force an exact match, otherwise use wildcards if @use_wildcards is true
329
+ ###
330
+ ### @param additional_filter[Net::LDAP::Fliter] an additional filter to be AND'd to the existing filter.
331
+ ###
332
+ ### @return [Array<Hash>] The @user_attrs_to_get for all usernames matching the query
333
+ ###
334
+ def find_user(user, exact = false, additional_filter = nil)
335
+
336
+ raise JSS::InvalidConnectionError, "Not connected to LDAP server '#{@name}'. Please use #connect first." unless @connected
337
+
338
+ if @use_wildcards and not exact
339
+ user_filter = Net::LDAP::Filter.contains(@user_mappings[:map_username], user)
340
+ else
341
+ user_filter = Net::LDAP::Filter.eq(@user_mappings[:map_username], user)
342
+ end
343
+
344
+ # limit the object classes
345
+ ocs = @user_mappings[:object_classes].to_s.chomp.split(/,\s*/)
346
+ anyall = @user_mappings[:map_object_class_to_any_or_all]
347
+ oc_filter = Net::LDAP::Filter.eq("objectclass", ocs.shift)
348
+ ocs.each do |oc|
349
+ if anyall == "any"
350
+ oc_filter = oc_filter | Net::LDAP::Filter.eq("objectclass", oc)
351
+ else
352
+ oc_filter = oc_filter & Net::LDAP::Filter.eq("objectclass", oc)
353
+ end
354
+ end
355
+
356
+ full_filter = oc_filter & user_filter
357
+ full_filter = full_filter & additional_filter if additional_filter
358
+ treebase = @user_mappings[:search_base]
359
+ ldap_attribs = @user_attrs_to_get.values
360
+
361
+ # should we grab membership from the user?
362
+ if @user_group_membership_mappings[:user_group_membership_stored_in] == "user object" and \
363
+ @user_group_membership_mappings[:map_group_membership_to_user_field]
364
+ get_groups = true
365
+ ldap_attribs << @user_group_membership_mappings[:map_group_membership_to_user_field]
366
+ end
367
+
368
+ results = []
369
+
370
+ @connection.search(:base => treebase, :filter => full_filter, :attributes => ldap_attribs ) do |entry|
371
+ userhash = {:dn => entry.dn}
372
+ @user_attrs_to_get.each do |k,attr|
373
+ userhash[k] = entry[attr][0]
374
+ end
375
+ userhash[:groups] = entry[@user_group_membership_mappings[:map_group_membership_to_user_field]] if get_groups
376
+ # to do - if the groups are dns, convert to groupnames
377
+ results << userhash
378
+ end
379
+ results
380
+ end
381
+
382
+ ###
383
+ ###
384
+ ### @param group[String] the group name to search for
385
+ ###
386
+ ### @param exact[Boolean] if true, force an exact match, otherwuse use wildcards if @use_wildcards is true
387
+ ###
388
+ ### @param additional_filter[Net::LDAP::Fliter] an additional filter to be AND'd to the existing filter.
389
+ ###
390
+ ### @return [Array<Hash>] The @user_group_attrs_to_get for all groups matching the query
391
+ ###
392
+ def find_group(group, exact = false, additional_filter = nil)
393
+
394
+ raise JSS::InvalidConnectionError, "Not connected to LDAP server '#{@name}'. Please use #connect first." unless @connected
395
+
396
+ if @use_wildcards and not exact
397
+ group_filter = Net::LDAP::Filter.contains(@user_group_mappings[:map_group_name], group)
398
+ else
399
+ group_filter = Net::LDAP::Filter.eq(@user_group_mappings[:map_group_name], group)
400
+ end
401
+
402
+ # limit the object classes
403
+ ocs = @user_group_mappings[:object_classes].to_s.chomp.split(/,\s*/)
404
+ anyall = @user_group_mappings[:map_object_class_to_any_or_all]
405
+ oc_filter = Net::LDAP::Filter.eq("objectclass", ocs.shift)
406
+ ocs.each do |oc|
407
+ if anyall == "any"
408
+ oc_filter = oc_filter | Net::LDAP::Filter.eq("objectclass", oc)
409
+ else
410
+ oc_filter = oc_filter & Net::LDAP::Filter.eq("objectclass", oc)
411
+ end
412
+ end
413
+
414
+ full_filter = oc_filter & group_filter
415
+ full_filter = full_filter & additional_filter if additional_filter
416
+ treebase = @user_group_mappings[:search_base]
417
+ ldap_attribs = @user_group_attrs_to_get.values
418
+
419
+ # should we grab membership from the group?
420
+ if @user_group_membership_mappings[:user_group_membership_stored_in] == "group object" and \
421
+ @user_group_membership_mappings[:map_user_membership_to_group_field]
422
+ get_members = true
423
+ ldap_attribs << @user_group_membership_mappings[:map_user_membership_to_group_field]
424
+ end
425
+
426
+ results = []
427
+ @connection.search(:base => treebase, :filter => full_filter, :attributes => ldap_attribs ) do |entry|
428
+ hash = {:dn => entry.dn}
429
+ @user_group_attrs_to_get.each do |k,attr|
430
+ hash[k] = entry[attr][0]
431
+ end
432
+ hash[:members] = entry[@user_group_membership_mappings[:map_user_membership_to_group_field]] if get_members
433
+ # to do, if the members are dns, convert to usernames
434
+ results << hash
435
+ end
436
+ results
437
+ end
438
+
439
+
440
+ ###
441
+ ### @param user[String] the username to check for memebership in the group
442
+ ###
443
+ ### @param group[String] the group name to see if the user is a member
444
+ ###
445
+ ### @return [Boolean, nil] is the user a member? Nil if unable to check
446
+ ###
447
+ ### @todo Implement checking groups membership in 'other' ldap area
448
+ ###
449
+ def check_membership(user, group)
450
+
451
+ raise JSS::InvalidConnectionError, "Not connected to LDAP server '#{@name}'. Please use #connect first." unless @connected
452
+
453
+ found_user = find_user(user, :exact)[0]
454
+ found_group = find_group(group, :exact)[0]
455
+
456
+ raise JSS::NoSuchItemError, "No user '#{user}' in LDAP." unless found_user
457
+ raise JSS::NoSuchItemError, "No group '#{group}' in LDAP." unless found_group
458
+
459
+ if @user_group_membership_mappings[:user_group_membership_stored_in] == "group object"
460
+ if @user_group_membership_mappings[:map_user_membership_use_dn]
461
+ return found_group[:members].include? found_user[:dn]
462
+ else
463
+ return found_group[:members].include? user
464
+ end
465
+
466
+
467
+ elsif @user_group_membership_mappings[:user_group_membership_stored_in] == "user object"
468
+ if @user_group_membership_mappings[:use_dn]
469
+ return found_user[:groups].include? found_group[:dn]
470
+ else
471
+ return found_user[:groups].include? group
472
+ end
473
+
474
+
475
+ else
476
+ ### To do!!
477
+ return nil
478
+ # implement a search based on the "other" settings
479
+ # This will be 3 searchs
480
+ # - one for the username mapping in users
481
+ # - one for the gid in groups
482
+ # - one for a record linking them in the "other" search base
483
+ end
484
+ end
485
+
486
+
487
+ ###
488
+ ### The connect to this LDAP server for subsequent use of the {#find_user}, {#find_group}
489
+ ### and {#check_membership} methods
490
+ ###
491
+ ### @param pw[String,Symbol] the LDAP connection password for this server. Can be nil if
492
+ ### authentication type is 'none'.
493
+ ### If :prompt, the user is promted on the commandline to enter the password for the :user.
494
+ ### If :stdin#, the password is read from a line of std in represented by the digit at #,
495
+ ### so :stdin3 reads the passwd from the third line of standard input. defaults to line 2,
496
+ ### if no digit is supplied. see {JSS.stdin}
497
+ ###
498
+ ###
499
+ ### @return [Boolean] did we connect to the LDAP server with the defined credentials
500
+ ###
501
+ def connect(pw = nil)
502
+
503
+ unless @authentication_type == :anonymous
504
+ # how do we get the password?
505
+ password = if pw == :prompt
506
+ JSS.prompt_for_password "Enter the password for the LDAP connection account '#{@lookup_dn}':"
507
+ elsif pw.is_a?(Symbol) and pw.to_s.start_with?('stdin')
508
+ pw.to_s =~ /^stdin(\d+)$/
509
+ line = $1
510
+ line ||= 2
511
+ JSS.stdin line
512
+ else
513
+ pw
514
+ end
515
+
516
+
517
+ raise JSS::InvalidDataError, "Incorrect password for LDAP connection account '#{@lookup_dn}'" unless @lookup_pw_sha256 == Digest::SHA2.new(256).update(password.to_s).to_s
518
+ end # unless
519
+
520
+ @connection = Net::LDAP.new :host => @hostname, :port => @port, :auth => {:method => @authentication_type, :username => @lookup_dn, :password => password }
521
+
522
+ @connected = true
523
+ end # connect
524
+
525
+
526
+
527
+ ###
528
+ ### Aliases
529
+ ###
530
+
531
+ alias connected? connected
532
+
533
+ end # class ldap server
534
+
535
+ end # module