ruby-jss 0.7.0 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGES.md +29 -22
- data/README.md +66 -86
- data/bin/jamfHelperBackgrounder +148 -0
- data/bin/netseg-update +0 -1
- data/lib/jss.rb +20 -9
- data/lib/jss/api_connection.rb +369 -295
- data/lib/jss/api_object.rb +651 -418
- data/lib/jss/api_object/account.rb +69 -77
- data/lib/jss/api_object/advanced_search.rb +201 -236
- data/lib/jss/api_object/advanced_search/advanced_computer_search.rb +42 -42
- data/lib/jss/api_object/advanced_search/advanced_mobile_device_search.rb +33 -43
- data/lib/jss/api_object/advanced_search/advanced_user_search.rb +33 -43
- data/lib/jss/api_object/building.rb +39 -52
- data/lib/jss/api_object/categorizable.rb +221 -0
- data/lib/jss/api_object/category.rb +81 -89
- data/lib/jss/api_object/computer.rb +486 -525
- data/lib/jss/api_object/computer_invitation.rb +73 -86
- data/lib/jss/api_object/criteriable.rb +6 -7
- data/lib/jss/api_object/ebook.rb +21 -0
- data/lib/jss/api_object/extendable.rb +6 -8
- data/lib/jss/api_object/group.rb +0 -3
- data/lib/jss/api_object/locatable.rb +19 -20
- data/lib/jss/api_object/mac_application.rb +21 -0
- data/lib/jss/api_object/mobile_device.rb +30 -21
- data/lib/jss/api_object/mobile_device_application.rb +447 -0
- data/lib/jss/api_object/mobile_device_configuration_profile.rb +21 -0
- data/lib/jss/api_object/osx_configuration_profile.rb +0 -3
- data/lib/jss/api_object/package.rb +21 -34
- data/lib/jss/api_object/peripheral.rb +16 -18
- data/lib/jss/api_object/policy.rb +5 -83
- data/lib/jss/api_object/purchasable.rb +11 -13
- data/lib/jss/api_object/scopable.rb +11 -12
- data/lib/jss/api_object/script.rb +3 -17
- data/lib/jss/api_object/self_servable.rb +419 -205
- data/lib/jss/api_object/self_servable/icon.rb +179 -0
- data/lib/jss/api_object/updatable.rb +35 -34
- data/lib/jss/api_object/uploadable.rb +72 -70
- data/lib/jss/api_object/user.rb +6 -7
- data/lib/jss/api_object/vppable.rb +117 -0
- data/lib/jss/client.rb +264 -225
- data/lib/jss/db_connection.rb +7 -5
- data/lib/jss/exceptions.rb +50 -42
- data/lib/jss/ruby_extensions.rb +8 -7
- data/lib/jss/ruby_extensions/object.rb +19 -0
- data/lib/jss/utility.rb +82 -40
- data/lib/jss/version.rb +1 -1
- metadata +37 -68
- data/bin/jss-webhook-server +0 -3
- data/lib/jss/webhooks.rb +0 -53
- data/lib/jss/webhooks/README.md +0 -269
- data/lib/jss/webhooks/configuration.rb +0 -213
- data/lib/jss/webhooks/data/sample_handlers/RestAPIOperation-executable +0 -91
- data/lib/jss/webhooks/data/sample_handlers/RestAPIOperation.rb +0 -45
- data/lib/jss/webhooks/data/sample_jsons/ComputerAdded.json +0 -27
- data/lib/jss/webhooks/data/sample_jsons/ComputerCheckIn.json +0 -27
- data/lib/jss/webhooks/data/sample_jsons/ComputerInventoryCompleted.json +0 -27
- data/lib/jss/webhooks/data/sample_jsons/ComputerPolicyFinished.json +0 -27
- data/lib/jss/webhooks/data/sample_jsons/ComputerPushCapabilityChanged.json +0 -27
- data/lib/jss/webhooks/data/sample_jsons/JSSShutdown.json +0 -14
- data/lib/jss/webhooks/data/sample_jsons/JSSStartup.json +0 -14
- data/lib/jss/webhooks/data/sample_jsons/MobileDeviceCheckIn.json +0 -26
- data/lib/jss/webhooks/data/sample_jsons/MobileDeviceCommandCompleted.json +0 -26
- data/lib/jss/webhooks/data/sample_jsons/MobileDeviceEnrolled.json +0 -26
- data/lib/jss/webhooks/data/sample_jsons/MobileDevicePushSent.json +0 -26
- data/lib/jss/webhooks/data/sample_jsons/MobileDeviceUnEnrolled.json +0 -26
- data/lib/jss/webhooks/data/sample_jsons/PatchSoftwareTitleUpdated.json +0 -14
- data/lib/jss/webhooks/data/sample_jsons/PushSent.json +0 -11
- data/lib/jss/webhooks/data/sample_jsons/RestAPIOperation.json +0 -15
- data/lib/jss/webhooks/data/sample_jsons/SCEPChallenge.json +0 -10
- data/lib/jss/webhooks/data/sample_jsons/SmartGroupComputerMembershipChange.json +0 -13
- data/lib/jss/webhooks/data/sample_jsons/SmartGroupMobileDeviceMembershipChange.json +0 -13
- data/lib/jss/webhooks/event.rb +0 -139
- data/lib/jss/webhooks/event/computer_added.rb +0 -38
- data/lib/jss/webhooks/event/computer_check_in.rb +0 -38
- data/lib/jss/webhooks/event/computer_inventory_completed.rb +0 -38
- data/lib/jss/webhooks/event/computer_policy_finished.rb +0 -38
- data/lib/jss/webhooks/event/computer_push_capability_changed.rb +0 -38
- data/lib/jss/webhooks/event/handlers.rb +0 -192
- data/lib/jss/webhooks/event/jss_shutdown.rb +0 -38
- data/lib/jss/webhooks/event/jss_startup.rb +0 -38
- data/lib/jss/webhooks/event/mobile_device_check_in.rb +0 -38
- data/lib/jss/webhooks/event/mobile_device_command_completed.rb +0 -38
- data/lib/jss/webhooks/event/mobile_device_enrolled.rb +0 -38
- data/lib/jss/webhooks/event/mobile_device_push_sent.rb +0 -38
- data/lib/jss/webhooks/event/mobile_device_unenrolled.rb +0 -38
- data/lib/jss/webhooks/event/patch_software_title_updated.rb +0 -38
- data/lib/jss/webhooks/event/push_sent.rb +0 -38
- data/lib/jss/webhooks/event/rest_api_operation.rb +0 -38
- data/lib/jss/webhooks/event/scep_challenge.rb +0 -38
- data/lib/jss/webhooks/event/smart_group_computer_membership_change.rb +0 -38
- data/lib/jss/webhooks/event/smart_group_mobile_device_membership_change.rb +0 -38
- data/lib/jss/webhooks/event/webhook.rb +0 -40
- data/lib/jss/webhooks/event_objects.rb +0 -112
- data/lib/jss/webhooks/event_objects/computer.rb +0 -49
- data/lib/jss/webhooks/event_objects/jss.rb +0 -36
- data/lib/jss/webhooks/event_objects/mobile_device.rb +0 -48
- data/lib/jss/webhooks/event_objects/patch_software_title_update.rb +0 -38
- data/lib/jss/webhooks/event_objects/push.rb +0 -33
- data/lib/jss/webhooks/event_objects/rest_api_operation.rb +0 -37
- data/lib/jss/webhooks/event_objects/scep_challenge.rb +0 -32
- data/lib/jss/webhooks/event_objects/smart_group.rb +0 -35
- data/lib/jss/webhooks/server_app.rb +0 -37
- data/lib/jss/webhooks/server_app/routes.rb +0 -27
- data/lib/jss/webhooks/server_app/routes/handle_webhook_event.rb +0 -39
- data/lib/jss/webhooks/server_app/routes/home.rb +0 -37
- data/lib/jss/webhooks/server_app/self_signed_cert.rb +0 -65
- data/lib/jss/webhooks/server_app/server.rb +0 -60
- data/lib/jss/webhooks/version.rb +0 -32
data/bin/netseg-update
CHANGED
data/lib/jss.rb
CHANGED
|
@@ -44,7 +44,7 @@ module JSS
|
|
|
44
44
|
require 'singleton'
|
|
45
45
|
require 'pathname'
|
|
46
46
|
require 'fileutils'
|
|
47
|
-
require 'uri'
|
|
47
|
+
require 'open-uri'
|
|
48
48
|
require 'ipaddr'
|
|
49
49
|
require 'rexml/document'
|
|
50
50
|
require 'base64'
|
|
@@ -52,6 +52,7 @@ module JSS
|
|
|
52
52
|
require 'digest'
|
|
53
53
|
require 'yaml'
|
|
54
54
|
require 'open3'
|
|
55
|
+
require 'english'
|
|
55
56
|
|
|
56
57
|
###################
|
|
57
58
|
### Gems
|
|
@@ -95,15 +96,7 @@ module JSS
|
|
|
95
96
|
|
|
96
97
|
module Composer; end
|
|
97
98
|
|
|
98
|
-
### Mix-in Sub Modules
|
|
99
99
|
|
|
100
|
-
module Creatable; end
|
|
101
|
-
module FileUpload; end
|
|
102
|
-
module Locatable; end
|
|
103
|
-
module Matchable; end
|
|
104
|
-
module Purchasable; end
|
|
105
|
-
module Updatable; end
|
|
106
|
-
module Extendable; end
|
|
107
100
|
|
|
108
101
|
### Mix-in Sub Modules with Classes
|
|
109
102
|
|
|
@@ -123,6 +116,7 @@ module JSS
|
|
|
123
116
|
class Client; end
|
|
124
117
|
class DBConnection; end
|
|
125
118
|
class Server; end
|
|
119
|
+
class Icon; end
|
|
126
120
|
class Preferences; end
|
|
127
121
|
|
|
128
122
|
### SubClasses
|
|
@@ -152,9 +146,13 @@ module JSS
|
|
|
152
146
|
class Category < JSS::APIObject; end
|
|
153
147
|
class Computer < JSS::APIObject; end
|
|
154
148
|
class Department < JSS::APIObject; end
|
|
149
|
+
class EBook < JSS::APIObject; end
|
|
155
150
|
class DistributionPoint < JSS::APIObject; end
|
|
156
151
|
class LDAPServer < JSS::APIObject; end
|
|
152
|
+
class MacApplication < JSS::APIObject; end
|
|
157
153
|
class MobileDevice < JSS::APIObject; end
|
|
154
|
+
class MobileDeviceConfigurationProfile < JSS::APIObject; end
|
|
155
|
+
class MobileDeviceApplication < JSS::APIObject; end
|
|
158
156
|
class NetBootServer < JSS::APIObject; end
|
|
159
157
|
class NetworkSegment < JSS::APIObject; end
|
|
160
158
|
class OSXConfigurationProfile < JSS::APIObject; end
|
|
@@ -170,6 +168,19 @@ module JSS
|
|
|
170
168
|
class User < JSS::APIObject; end
|
|
171
169
|
class WebHook < JSS::APIObject; end
|
|
172
170
|
|
|
171
|
+
### Mix-in Sub Modules
|
|
172
|
+
|
|
173
|
+
module Creatable; end
|
|
174
|
+
module FileUpload; end
|
|
175
|
+
module Locatable; end
|
|
176
|
+
module Matchable; end
|
|
177
|
+
module Purchasable; end
|
|
178
|
+
module Updatable; end
|
|
179
|
+
module Extendable; end
|
|
180
|
+
module SelfServable; end
|
|
181
|
+
module Categorizable; end
|
|
182
|
+
module VPPable; end
|
|
183
|
+
|
|
173
184
|
end # module JSS
|
|
174
185
|
|
|
175
186
|
### Load the rest of the module
|
data/lib/jss/api_connection.rb
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
### Copyright 2017 Pixar
|
|
2
|
-
|
|
3
2
|
###
|
|
4
3
|
### Licensed under the Apache License, Version 2.0 (the "Apache License")
|
|
5
4
|
### with the following modification; you may not use this file except in
|
|
@@ -26,251 +25,192 @@
|
|
|
26
25
|
###
|
|
27
26
|
module JSS
|
|
28
27
|
|
|
29
|
-
|
|
30
|
-
### Constants
|
|
28
|
+
# Constants
|
|
31
29
|
#####################################
|
|
32
30
|
|
|
33
|
-
|
|
34
|
-
### Module Variables
|
|
31
|
+
# Module Variables
|
|
35
32
|
#####################################
|
|
36
33
|
|
|
37
|
-
|
|
38
|
-
### Module Methods
|
|
34
|
+
# Module Methods
|
|
39
35
|
#####################################
|
|
40
36
|
|
|
41
|
-
|
|
42
|
-
### Module Classes
|
|
37
|
+
# Classes
|
|
43
38
|
#####################################
|
|
44
39
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
###
|
|
40
|
+
# An API connection to the JSS.
|
|
41
|
+
#
|
|
42
|
+
# This is a singleton class, only one can exist at a time.
|
|
43
|
+
# Its one instance is created automatically when the module loads, but it
|
|
44
|
+
# isn't connected to anything at that time.
|
|
45
|
+
#
|
|
46
|
+
# Use it via the {JSS::API} constant to call the #connect
|
|
47
|
+
# method, and the {#get_rsrc}, {#put_rsrc}, {#post_rsrc}, & {#delete_rsrc}
|
|
48
|
+
# methods, q.v. below.
|
|
49
|
+
#
|
|
50
|
+
# To access the underlying RestClient::Resource instance,
|
|
51
|
+
# use JSS::API.cnx
|
|
52
|
+
#
|
|
59
53
|
class APIConnection
|
|
60
|
-
include Singleton
|
|
61
54
|
|
|
62
|
-
|
|
63
|
-
### Class Constants
|
|
55
|
+
# Class Constants
|
|
64
56
|
#####################################
|
|
65
57
|
|
|
66
|
-
|
|
67
|
-
RSRC_BASE =
|
|
58
|
+
# The base API path in the jss URL
|
|
59
|
+
RSRC_BASE = 'JSSResource'.freeze
|
|
68
60
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
TEST_PATH = "#{RSRC_BASE}/accounts"
|
|
61
|
+
# A url path to load to see if there's an API available at a host.
|
|
62
|
+
# This just loads the API resource docs page
|
|
63
|
+
TEST_PATH = "#{RSRC_BASE}/accounts".freeze
|
|
72
64
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
TEST_CONTENT =
|
|
65
|
+
# If the test path loads correctly from a casper server, it'll contain
|
|
66
|
+
# this text (this is what we get when we make an unauthenticated
|
|
67
|
+
# API call.)
|
|
68
|
+
TEST_CONTENT = '<p>The request requires user authentication</p>'.freeze
|
|
77
69
|
|
|
78
|
-
|
|
70
|
+
# The Default port
|
|
79
71
|
HTTP_PORT = 9006
|
|
80
72
|
|
|
81
|
-
|
|
73
|
+
# The SSL port
|
|
82
74
|
SSL_PORT = 8443
|
|
83
75
|
|
|
84
|
-
|
|
85
|
-
XML_HEADER = '<?xml version="1.0" encoding="UTF-8" standalone="no"?>'
|
|
76
|
+
# The top line of an XML doc for submitting data via API
|
|
77
|
+
XML_HEADER = '<?xml version="1.0" encoding="UTF-8" standalone="no"?>'.freeze
|
|
86
78
|
|
|
87
|
-
|
|
79
|
+
# Default timeouts in seconds
|
|
88
80
|
DFT_OPEN_TIMEOUT = 60
|
|
89
81
|
DFT_TIMEOUT = 60
|
|
90
82
|
|
|
91
|
-
|
|
92
|
-
|
|
83
|
+
# The Default SSL Version
|
|
84
|
+
# As of Casper 9.61 we can't use SSL, must use TLS, since SSLv3 was susceptible to poodles.
|
|
85
|
+
# NOTE - this requires rest-client v 1.7.0 or higher
|
|
86
|
+
# which requires mime-types 2.0 or higher, which requires ruby 1.9.2 or higher!
|
|
87
|
+
# That means that support for ruby 1.8.7 stops with Casper 9.6
|
|
88
|
+
DFT_SSL_VERSION = 'TLSv1'.freeze
|
|
93
89
|
|
|
94
|
-
|
|
95
|
-
### Attributes
|
|
90
|
+
# Attributes
|
|
96
91
|
#####################################
|
|
97
92
|
|
|
98
|
-
|
|
93
|
+
# @return [String] the username who's connected to the JSS API
|
|
99
94
|
attr_reader :jss_user
|
|
100
95
|
|
|
101
|
-
|
|
96
|
+
# @return [RestClient::Resource] the underlying connection resource
|
|
102
97
|
attr_reader :cnx
|
|
103
98
|
|
|
104
|
-
|
|
99
|
+
# @return [Boolean] are we connected right now?
|
|
105
100
|
attr_reader :connected
|
|
106
101
|
|
|
107
|
-
|
|
102
|
+
# @return [JSS::Server] the details of the JSS to which we're connected.
|
|
108
103
|
attr_reader :server
|
|
109
104
|
|
|
110
|
-
|
|
105
|
+
# @return [String] the hostname of the JSS to which we're connected.
|
|
111
106
|
attr_reader :server_host
|
|
112
107
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
#####################################
|
|
116
|
-
|
|
117
|
-
###
|
|
118
|
-
### To connect, use JSS::APIConnection.instance.connect
|
|
119
|
-
### or a shortcut, JSS::API.connect
|
|
120
|
-
###
|
|
121
|
-
def initialize ()
|
|
122
|
-
@connected = false
|
|
123
|
-
end # init
|
|
124
|
-
|
|
125
|
-
#####################################
|
|
126
|
-
### Class Methods
|
|
127
|
-
#####################################
|
|
128
|
-
|
|
129
|
-
###
|
|
130
|
-
### Connect to the JSS API.
|
|
131
|
-
###
|
|
132
|
-
### @param args[Hash] the keyed arguments for connection.
|
|
133
|
-
###
|
|
134
|
-
### @option args :server[String] the hostname of the JSS API server, required if not defined in JSS::CONFIG
|
|
135
|
-
###
|
|
136
|
-
### @option args :port[Integer] the port number to connect with, defaults to 8443
|
|
137
|
-
###
|
|
138
|
-
### @option args :use_ssl[Boolean] should the connection be made over SSL? Defaults to true.
|
|
139
|
-
###
|
|
140
|
-
### @option args :verify_cert[Boolean] should HTTPS SSL certificates be verified. Defaults to true.
|
|
141
|
-
### If your connection raises RestClient::SSLCertificateNotVerified, and you don't care about the
|
|
142
|
-
### validity of the SSL cert. just set this explicitly to false.
|
|
143
|
-
###
|
|
144
|
-
### @option args :user[String] a JSS user who has API privs, required if not defined in JSS::CONFIG
|
|
145
|
-
###
|
|
146
|
-
### @option args :pw[String,Symbol] Required, the password for that user, or :prompt, or :stdin
|
|
147
|
-
### If :prompt, the user is promted on the commandline to enter the password for the :user.
|
|
148
|
-
### If :stdin#, the password is read from a line of std in represented by the digit at #,
|
|
149
|
-
### so :stdin3 reads the passwd from the third line of standard input. defaults to line 1,
|
|
150
|
-
### if no digit is supplied. see {JSS.stdin}
|
|
151
|
-
###
|
|
152
|
-
### @option args :open_timeout[Integer] the number of seconds to wait for an initial response, defaults to 60
|
|
153
|
-
###
|
|
154
|
-
### @option args :timeout[Integer] the number of seconds before an API call times out, defaults to 60
|
|
155
|
-
###
|
|
156
|
-
### @return [true]
|
|
157
|
-
###
|
|
158
|
-
def connect (args = {})
|
|
159
|
-
|
|
160
|
-
# the server, if not specified, might come from a couple places.
|
|
161
|
-
# see #hostname
|
|
162
|
-
args[:server] ||= hostname
|
|
163
|
-
|
|
164
|
-
# settings from config if they aren't in the args
|
|
165
|
-
args[:server] ||= JSS::CONFIG.api_server_name
|
|
166
|
-
args[:port] ||= JSS::CONFIG.api_server_port
|
|
167
|
-
args[:user] ||= JSS::CONFIG.api_username
|
|
168
|
-
args[:timeout] ||= JSS::CONFIG.api_timeout
|
|
169
|
-
args[:open_timeout] ||= JSS::CONFIG.api_timeout_open
|
|
170
|
-
args[:ssl_version] ||= JSS::CONFIG.api_ssl_version
|
|
171
|
-
|
|
172
|
-
# if verify cert given was NOT in the args....
|
|
173
|
-
if args[:verify_cert].nil?
|
|
174
|
-
# set it from the prefs
|
|
175
|
-
args[:verify_cert] = JSS::CONFIG.api_verify_cert
|
|
176
|
-
end
|
|
108
|
+
# @return [Integer] the port used for the connection
|
|
109
|
+
attr_reader :port
|
|
177
110
|
|
|
178
|
-
|
|
179
|
-
|
|
111
|
+
# @return [String] the protocol being used: http or https
|
|
112
|
+
attr_reader :protocol
|
|
180
113
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
args[:timeout] ||= DFT_TIMEOUT
|
|
184
|
-
args[:open_timeout] ||= DFT_OPEN_TIMEOUT
|
|
114
|
+
# @return [RestClient::Response] The response from the most recent API call
|
|
115
|
+
attr_reader :last_http_response
|
|
185
116
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
# which requires mime-types 2.0 or higher, which requires ruby 1.9.2 or higher!
|
|
189
|
-
# That means that support for ruby 1.8.7 stops with Casper 9.6
|
|
190
|
-
args[:ssl_version] ||= DFT_SSL_VERSION
|
|
117
|
+
# @return [String] The base URL to to the current REST API
|
|
118
|
+
attr_reader :rest_url
|
|
191
119
|
|
|
120
|
+
# Constructor
|
|
121
|
+
#####################################
|
|
192
122
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
123
|
+
# To connect, use JSS::API.connect
|
|
124
|
+
#
|
|
125
|
+
def initialize
|
|
126
|
+
@connected = false
|
|
127
|
+
end # init
|
|
197
128
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
args[:use_ssl] = (not args[:use_ssl] == false) or (args[:port] == SSL_PORT)
|
|
129
|
+
# Instance Methods
|
|
130
|
+
#####################################
|
|
201
131
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
132
|
+
# Connect to the JSS API.
|
|
133
|
+
#
|
|
134
|
+
# @param args[Hash] the keyed arguments for connection.
|
|
135
|
+
#
|
|
136
|
+
# @option args :server[String] the hostname of the JSS API server, required if not defined in JSS::CONFIG
|
|
137
|
+
#
|
|
138
|
+
# @option args :port[Integer] the port number to connect with, defaults to 8443
|
|
139
|
+
#
|
|
140
|
+
# @option args :use_ssl[Boolean] should the connection be made over SSL? Defaults to true.
|
|
141
|
+
#
|
|
142
|
+
# @option args :verify_cert[Boolean] should HTTPS SSL certificates be verified. Defaults to true.
|
|
143
|
+
# If your connection raises RestClient::SSLCertificateNotVerified, and you don't care about the
|
|
144
|
+
# validity of the SSL cert. just set this explicitly to false.
|
|
145
|
+
#
|
|
146
|
+
# @option args :user[String] a JSS user who has API privs, required if not defined in JSS::CONFIG
|
|
147
|
+
#
|
|
148
|
+
# @option args :pw[String,Symbol] Required, the password for that user, or :prompt, or :stdin
|
|
149
|
+
# If :prompt, the user is promted on the commandline to enter the password for the :user.
|
|
150
|
+
# If :stdin#, the password is read from a line of std in represented by the digit at #,
|
|
151
|
+
# so :stdin3 reads the passwd from the third line of standard input. defaults to line 1,
|
|
152
|
+
# if no digit is supplied. see {JSS.stdin}
|
|
153
|
+
#
|
|
154
|
+
# @option args :open_timeout[Integer] the number of seconds to wait for an initial response, defaults to 60
|
|
155
|
+
#
|
|
156
|
+
# @option args :timeout[Integer] the number of seconds before an API call times out, defaults to 60
|
|
157
|
+
#
|
|
158
|
+
# @return [true]
|
|
159
|
+
#
|
|
160
|
+
def connect(args = {})
|
|
161
|
+
args = apply_connection_defaults args
|
|
162
|
+
verify_basic_args args
|
|
163
|
+
@jss_user = args[:user]
|
|
205
164
|
|
|
165
|
+
@rest_url = build_rest_url args
|
|
206
166
|
|
|
207
|
-
#
|
|
208
|
-
|
|
209
|
-
args[:verify_ssl] = (args[:verify_cert] == false) ? OpenSSL::SSL::VERIFY_NONE : OpenSSL::SSL::VERIFY_PEER
|
|
167
|
+
# figure out :verify_ssl from :verify_cert
|
|
168
|
+
args[:verify_ssl] = verify_ssl args
|
|
210
169
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
elsif args[:pw].is_a?(Symbol) and args[:pw].to_s.start_with?('stdin')
|
|
214
|
-
args[:pw].to_s =~ /^stdin(\d+)$/
|
|
215
|
-
line = $1
|
|
216
|
-
line ||= 1
|
|
217
|
-
JSS.stdin line
|
|
218
|
-
else
|
|
219
|
-
args[:pw]
|
|
220
|
-
end
|
|
170
|
+
# figure out :password from :pw
|
|
171
|
+
args[:password] = acquire_password args
|
|
221
172
|
|
|
222
173
|
# heres our connection
|
|
223
|
-
@cnx = RestClient::Resource.new(
|
|
174
|
+
@cnx = RestClient::Resource.new(@rest_url.to_s, args)
|
|
224
175
|
|
|
225
|
-
|
|
226
|
-
@server_host = args[:server]
|
|
227
|
-
@connected = true
|
|
228
|
-
@server = JSS::Server.new
|
|
176
|
+
verify_server_version
|
|
229
177
|
|
|
230
|
-
|
|
231
|
-
raise JSS::UnsupportedError, "Your JSS Server version, #{@server.raw_version}, is to low. Must be #{JSS::MINIMUM_SERVER_VERSION} or higher."
|
|
232
|
-
end
|
|
233
|
-
|
|
234
|
-
return @connected ? @server_host : nil
|
|
178
|
+
@connected ? hostname : nil
|
|
235
179
|
end # connect
|
|
236
180
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
181
|
+
# A useful string about this connection
|
|
182
|
+
#
|
|
183
|
+
# @return [String]
|
|
184
|
+
#
|
|
241
185
|
def to_s
|
|
242
|
-
@connected ? "Using #{@rest_url} as user #{@jss_user}" :
|
|
186
|
+
@connected ? "Using #{@rest_url} as user #{@jss_user}" : 'not connected'
|
|
243
187
|
end
|
|
244
188
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
def timeout= (timeout)
|
|
189
|
+
# Reset the response timeout for the rest connection
|
|
190
|
+
#
|
|
191
|
+
# @param timeout[Integer] the new timeout in seconds
|
|
192
|
+
#
|
|
193
|
+
# @return [void]
|
|
194
|
+
#
|
|
195
|
+
def timeout=(timeout)
|
|
253
196
|
@cnx.options[:timeout] = timeout
|
|
254
197
|
end
|
|
255
198
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
def open_timeout= (timeout)
|
|
199
|
+
# Reset the open-connection timeout for the rest connection
|
|
200
|
+
#
|
|
201
|
+
# @param timeout[Integer] the new timeout in seconds
|
|
202
|
+
#
|
|
203
|
+
# @return [void]
|
|
204
|
+
#
|
|
205
|
+
def open_timeout=(timeout)
|
|
264
206
|
@cnx.options[:open_timeout] = timeout
|
|
265
207
|
end
|
|
266
208
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
### @return [void]
|
|
273
|
-
###
|
|
209
|
+
# With a REST connection, there isn't any real "connection" to disconnect from
|
|
210
|
+
# So to disconnect, we just unset all our credentials.
|
|
211
|
+
#
|
|
212
|
+
# @return [void]
|
|
213
|
+
#
|
|
274
214
|
def disconnect
|
|
275
215
|
@jss_user = nil
|
|
276
216
|
@rest_url = nil
|
|
@@ -279,141 +219,275 @@ module JSS
|
|
|
279
219
|
@connected = false
|
|
280
220
|
end # disconnect
|
|
281
221
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
return JSON.parse(data, :symbolize_names => true) if format == :json
|
|
305
|
-
data
|
|
222
|
+
# Get an arbitrary JSS resource
|
|
223
|
+
#
|
|
224
|
+
# The first argument is the resource to get (the part of the API url
|
|
225
|
+
# after the 'JSSResource/' )
|
|
226
|
+
#
|
|
227
|
+
# By default we get the data in JSON, and parse it
|
|
228
|
+
# into a ruby data structure (arrays, hashes, strings, etc)
|
|
229
|
+
# with symbolized Hash keys.
|
|
230
|
+
#
|
|
231
|
+
# @param rsrc[String] the resource to get
|
|
232
|
+
# (the part of the API url after the 'JSSResource/' )
|
|
233
|
+
#
|
|
234
|
+
# @param format[Symbol] either ;json or :xml
|
|
235
|
+
# If the second argument is :xml, the XML data is returned as a String.
|
|
236
|
+
#
|
|
237
|
+
# @return [Hash,String] the result of the get
|
|
238
|
+
#
|
|
239
|
+
def get_rsrc(rsrc, format = :json)
|
|
240
|
+
raise JSS::InvalidConnectionError, 'Not Connected. Use JSS::API.connect first.' unless @connected
|
|
241
|
+
rsrc = URI.encode rsrc
|
|
242
|
+
@last_http_response = @cnx[rsrc].get(accept: format)
|
|
243
|
+
return JSON.parse(@last_http_response, symbolize_names: true) if format == :json
|
|
306
244
|
end
|
|
307
245
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
### convert CRs & to
|
|
246
|
+
# Change an existing JSS resource
|
|
247
|
+
#
|
|
248
|
+
# @param rsrc[String] the API resource being changed, the URL part after 'JSSResource/'
|
|
249
|
+
#
|
|
250
|
+
# @param xml[String] the xml specifying the changes.
|
|
251
|
+
#
|
|
252
|
+
# @return [String] the xml response from the server.
|
|
253
|
+
#
|
|
254
|
+
def put_rsrc(rsrc, xml)
|
|
255
|
+
raise JSS::InvalidConnectionError, 'Not Connected. Use JSS::API.connect first.' unless @connected
|
|
256
|
+
|
|
257
|
+
# convert CRs & to
|
|
321
258
|
xml.gsub!(/\r/, ' ')
|
|
322
259
|
|
|
323
|
-
|
|
324
|
-
@cnx[rsrc].put(xml, :
|
|
260
|
+
# send the data
|
|
261
|
+
@last_http_response = @cnx[rsrc].put(xml, content_type: 'text/xml')
|
|
262
|
+
rescue RestClient::Conflict => exception
|
|
263
|
+
raise_conflict_error(exception)
|
|
325
264
|
end
|
|
326
265
|
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
### convert CRs & to
|
|
266
|
+
# Create a new JSS resource
|
|
267
|
+
#
|
|
268
|
+
# @param rsrc[String] the API resource being created, the URL part after 'JSSResource/'
|
|
269
|
+
#
|
|
270
|
+
# @param xml[String] the xml specifying the new object.
|
|
271
|
+
#
|
|
272
|
+
# @return [String] the xml response from the server.
|
|
273
|
+
#
|
|
274
|
+
def post_rsrc(rsrc, xml)
|
|
275
|
+
raise JSS::InvalidConnectionError, 'Not Connected. Use JSS::API.connect first.' unless @connected
|
|
276
|
+
|
|
277
|
+
# convert CRs & to
|
|
340
278
|
xml.gsub!(/\r/, ' ')
|
|
341
279
|
|
|
342
|
-
|
|
343
|
-
@cnx[rsrc].post xml, :
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
280
|
+
# send the data
|
|
281
|
+
@last_http_response = @cnx[rsrc].post xml, content_type: 'text/xml', accept: :json
|
|
282
|
+
rescue RestClient::Conflict => exception
|
|
283
|
+
raise_conflict_error(exception)
|
|
284
|
+
end # post_rsrc
|
|
285
|
+
|
|
286
|
+
# Delete a resource from the JSS
|
|
287
|
+
#
|
|
288
|
+
# @param rsrc[String] the resource to create, the URL part after 'JSSResource/'
|
|
289
|
+
#
|
|
290
|
+
# @return [String] the xml response from the server.
|
|
291
|
+
#
|
|
352
292
|
def delete_rsrc(rsrc)
|
|
353
|
-
raise JSS::InvalidConnectionError,
|
|
354
|
-
raise MissingDataError,
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
@cnx[rsrc].delete
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
###
|
|
370
|
-
def valid_server? (server, port = SSL_PORT)
|
|
293
|
+
raise JSS::InvalidConnectionError, 'Not Connected. Use JSS::API.connect first.' unless @connected
|
|
294
|
+
raise MissingDataError, 'Missing :rsrc' if rsrc.nil?
|
|
295
|
+
|
|
296
|
+
# delete the resource
|
|
297
|
+
@last_http_response = @cnx[rsrc].delete
|
|
298
|
+
end # delete_rsrc
|
|
299
|
+
|
|
300
|
+
# Test that a given hostname & port is a JSS API server
|
|
301
|
+
#
|
|
302
|
+
# @param server[String] The hostname to test,
|
|
303
|
+
#
|
|
304
|
+
# @param port[Integer] The port to try connecting on
|
|
305
|
+
#
|
|
306
|
+
# @return [Boolean] does the server host a JSS API?
|
|
307
|
+
#
|
|
308
|
+
def valid_server?(server, port = SSL_PORT)
|
|
371
309
|
# cheating by shelling out to curl, because getting open-uri, or even net/http to use
|
|
372
310
|
# ssl_options like :OP_NO_SSLv2 and :OP_NO_SSLv3 will take time to figure out..
|
|
373
311
|
return true if `/usr/bin/curl -s 'https://#{server}:#{port}/#{TEST_PATH}'`.include? TEST_CONTENT
|
|
374
312
|
return true if `/usr/bin/curl -s 'http://#{server}:#{port}/#{TEST_PATH}'`.include? TEST_CONTENT
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
# try ssl first
|
|
378
|
-
# NOTE: doesn't work if we can't disallow SSLv3 or force TLSv1
|
|
379
|
-
# See cheat above.
|
|
380
|
-
begin
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
rescue
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
end #begin
|
|
392
|
-
# if we're here, no API
|
|
393
|
-
|
|
313
|
+
false
|
|
314
|
+
|
|
315
|
+
# # try ssl first
|
|
316
|
+
# # NOTE: doesn't work if we can't disallow SSLv3 or force TLSv1
|
|
317
|
+
# # See cheat above.
|
|
318
|
+
# begin
|
|
319
|
+
# return true if open("https://#{server}:#{port}/#{TEST_PATH}", ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE).read.include? TEST_CONTENT
|
|
320
|
+
#
|
|
321
|
+
# rescue
|
|
322
|
+
# # then regular http
|
|
323
|
+
# begin
|
|
324
|
+
# return true if open("http://#{server}:#{port}/#{TEST_PATH}").read.include? TEST_CONTENT
|
|
325
|
+
# rescue
|
|
326
|
+
# # any errors = no API
|
|
327
|
+
# return false
|
|
328
|
+
# end # begin
|
|
329
|
+
# end # begin
|
|
330
|
+
# # if we're here, no API
|
|
331
|
+
# false
|
|
394
332
|
end
|
|
395
333
|
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
334
|
+
# The server to which we are connected, or will
|
|
335
|
+
# try connecting to if none is specified with the
|
|
336
|
+
# call to #connect
|
|
337
|
+
#
|
|
338
|
+
# @return [String] the hostname of the server
|
|
339
|
+
#
|
|
402
340
|
def hostname
|
|
403
341
|
return @server_host if @server_host
|
|
404
342
|
srvr = JSS::CONFIG.api_server_name
|
|
405
343
|
srvr ||= JSS::Client.jss_server
|
|
406
|
-
|
|
344
|
+
srvr
|
|
407
345
|
end
|
|
408
346
|
|
|
409
|
-
|
|
347
|
+
# aliases
|
|
410
348
|
alias connected? connected
|
|
349
|
+
alias host hostname
|
|
350
|
+
|
|
351
|
+
# Private Insance Methods
|
|
352
|
+
####################################
|
|
353
|
+
private
|
|
354
|
+
|
|
355
|
+
# Apply defaults from the JSS::CONFIG, the JSS::Client
|
|
356
|
+
# or the module defaults to the args for the #connect method
|
|
357
|
+
#
|
|
358
|
+
# @param args[Hash] The args for #connect
|
|
359
|
+
#
|
|
360
|
+
# @return [Hash] The args with defaults applied
|
|
361
|
+
#
|
|
362
|
+
def apply_connection_defaults(args)
|
|
363
|
+
# settings from config if they aren't in the args
|
|
364
|
+
args[:server] ||= JSS::CONFIG.api_server_name
|
|
365
|
+
args[:port] ||= JSS::CONFIG.api_server_port
|
|
366
|
+
args[:user] ||= JSS::CONFIG.api_username
|
|
367
|
+
args[:timeout] ||= JSS::CONFIG.api_timeout
|
|
368
|
+
args[:open_timeout] ||= JSS::CONFIG.api_timeout_open
|
|
369
|
+
args[:ssl_version] ||= JSS::CONFIG.api_ssl_version
|
|
411
370
|
|
|
371
|
+
# if verify cert was not in the args, get it from the prefs.
|
|
372
|
+
# We can't use ||= because the desired value might be 'false'
|
|
373
|
+
args[:verify_cert] = JSS::CONFIG.api_verify_cert if args[:verify_cert].nil?
|
|
412
374
|
|
|
413
|
-
|
|
375
|
+
# these settings can come from the jamf binary config, if this machine is a JSS client.
|
|
376
|
+
args[:server] ||= JSS::Client.jss_server
|
|
377
|
+
args[:port] ||= JSS::Client.jss_port
|
|
378
|
+
args[:use_ssl] ||= JSS::Client.jss_protocol.end_with? 's'
|
|
379
|
+
|
|
380
|
+
# defaults from the module if needed
|
|
381
|
+
args[:port] ||= args[:use_ssl] ? SSL_PORT : HTTP_PORT
|
|
382
|
+
args[:timeout] ||= DFT_TIMEOUT
|
|
383
|
+
args[:open_timeout] ||= DFT_OPEN_TIMEOUT
|
|
384
|
+
args[:ssl_version] ||= DFT_SSL_VERSION
|
|
385
|
+
args
|
|
386
|
+
end
|
|
387
|
+
|
|
388
|
+
# Raise execeptions if we don't have essential data for the connection
|
|
389
|
+
#
|
|
390
|
+
# @param args[Hash] The args for #connect
|
|
391
|
+
#
|
|
392
|
+
# @return [void]
|
|
393
|
+
#
|
|
394
|
+
def verify_basic_args(args)
|
|
395
|
+
# must have server, user, and pw
|
|
396
|
+
raise JSS::MissingDataError, 'No JSS :server specified, or in configuration.' unless args[:server]
|
|
397
|
+
raise JSS::MissingDataError, 'No JSS :user specified, or in configuration.' unless args[:user]
|
|
398
|
+
raise JSS::MissingDataError, "Missing :pw for user '#{args[:user]}'" unless args[:pw]
|
|
399
|
+
end
|
|
414
400
|
|
|
415
|
-
|
|
416
|
-
|
|
401
|
+
# Verify that we can connect with the args provided, and that
|
|
402
|
+
# the server version is high enough for this version of ruby-jss.
|
|
403
|
+
#
|
|
404
|
+
# This makes the first API GET call and will raise an exception if things
|
|
405
|
+
# are wrong, like failed authentication. Will also raise an exception
|
|
406
|
+
# if the JSS version is too low
|
|
407
|
+
# (see also JSS::Server)
|
|
408
|
+
#
|
|
409
|
+
# @return [void]
|
|
410
|
+
#
|
|
411
|
+
def verify_server_version
|
|
412
|
+
@connected = true
|
|
413
|
+
@server = JSS::Server.new
|
|
414
|
+
min_vers = JSS.parse_jss_version(JSS::MINIMUM_SERVER_VERSION)[:version]
|
|
415
|
+
return unless @server.version < min_vers
|
|
416
|
+
err_msg = "JSS version #{@server.raw_version} to low. Must be >= #{min_vers}"
|
|
417
|
+
@connected = false
|
|
418
|
+
raise JSS::UnsupportedError, err_msg
|
|
419
|
+
end
|
|
420
|
+
|
|
421
|
+
# Build the base URL for the API connection
|
|
422
|
+
#
|
|
423
|
+
# @param args[Hash] The args for #connect
|
|
424
|
+
#
|
|
425
|
+
# @return [String] The URI encoded URL
|
|
426
|
+
#
|
|
427
|
+
def build_rest_url(args)
|
|
428
|
+
# we're using ssl if:
|
|
429
|
+
# 1) args[:use_ssl] is anything but false
|
|
430
|
+
# or
|
|
431
|
+
# 2) the port is the default casper ssl port.
|
|
432
|
+
(args[:use_ssl] = (args[:use_ssl] != false)) || (args[:port] == SSL_PORT)
|
|
433
|
+
|
|
434
|
+
# and here's the URL
|
|
435
|
+
@protocol = 'http'
|
|
436
|
+
@protocol << 's' if args[:use_ssl]
|
|
437
|
+
@server_host = args[:server]
|
|
438
|
+
@port = args[:port].to_i
|
|
439
|
+
URI.encode "#{@protocol}://#{@server_host}:#{@port}/#{RSRC_BASE}"
|
|
440
|
+
end
|
|
441
|
+
|
|
442
|
+
# From whatever was given in args[:pw], figure out the real password
|
|
443
|
+
#
|
|
444
|
+
# @param args[Hash] The args for #connect
|
|
445
|
+
#
|
|
446
|
+
# @return [String] The password for the connection
|
|
447
|
+
#
|
|
448
|
+
def acquire_password(args)
|
|
449
|
+
if args[:pw] == :prompt
|
|
450
|
+
JSS.prompt_for_password "Enter the password for JSS user #{args[:user]}@#{args[:server]}:"
|
|
451
|
+
elsif args[:pw].is_a?(Symbol) && args[:pw].to_s.start_with?('stdin')
|
|
452
|
+
args[:pw].to_s =~ /^stdin(\d+)$/
|
|
453
|
+
line = Regexp.last_match(1)
|
|
454
|
+
line ||= 1
|
|
455
|
+
JSS.stdin line
|
|
456
|
+
else
|
|
457
|
+
args[:pw]
|
|
458
|
+
end
|
|
459
|
+
end
|
|
460
|
+
|
|
461
|
+
# Get the appropriate OpenSSL::SSL constant for
|
|
462
|
+
# certificate verification.
|
|
463
|
+
#
|
|
464
|
+
# @param args[Hash] The args for #connect
|
|
465
|
+
#
|
|
466
|
+
# @return [Type] description_of_returned_object
|
|
467
|
+
#
|
|
468
|
+
def verify_ssl(args)
|
|
469
|
+
# if verify_cert is anything but false, we will verify
|
|
470
|
+
args[:verify_cert] == false ? OpenSSL::SSL::VERIFY_NONE : OpenSSL::SSL::VERIFY_PEER
|
|
471
|
+
end
|
|
472
|
+
|
|
473
|
+
# Parses the HTTP body of a RestClient::Conflict (409 conflict)
|
|
474
|
+
# exception and re-raises a JSS::ConflictError with a more
|
|
475
|
+
# useful error message.
|
|
476
|
+
#
|
|
477
|
+
# @param exception[RestClient::Conflict] the exception to parse
|
|
478
|
+
#
|
|
479
|
+
# @return [void]
|
|
480
|
+
#
|
|
481
|
+
def raise_conflict_error(exception)
|
|
482
|
+
exception.http_body =~ %r{<p>Error:(.*)</p>}
|
|
483
|
+
conflict_reason = Regexp.last_match(1)
|
|
484
|
+
conflict_reason ||= exception.http_body
|
|
485
|
+
raise JSS::ConflictError, conflict_reason
|
|
486
|
+
end
|
|
487
|
+
|
|
488
|
+
end # class JSSAPIConnection
|
|
417
489
|
|
|
490
|
+
# The default APIConnection
|
|
491
|
+
API = APIConnection.new
|
|
418
492
|
|
|
419
493
|
end # module
|