xolo-server 1.0.0 → 2.0.2
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/README.md +42 -4
- data/bin/xoloserver +3 -0
- data/data/client/xolo +1233 -0
- data/lib/optimist_with_insert_blanks.rb +1216 -0
- data/lib/xolo/core/base_classes/configuration.rb +238 -0
- data/lib/xolo/core/base_classes/server_object.rb +112 -0
- data/lib/xolo/core/base_classes/title.rb +884 -0
- data/lib/xolo/core/base_classes/version.rb +641 -0
- data/lib/xolo/core/constants.rb +85 -0
- data/lib/xolo/core/exceptions.rb +52 -0
- data/lib/xolo/core/json_wrappers.rb +43 -0
- data/lib/xolo/core/loading.rb +59 -0
- data/lib/xolo/core/output.rb +292 -0
- data/lib/xolo/core/security_cmd.rb +128 -0
- data/lib/xolo/core/version.rb +21 -0
- data/lib/xolo/core.rb +47 -0
- data/lib/xolo/server/app.rb +7 -0
- data/lib/xolo/server/configuration.rb +243 -38
- data/lib/xolo/server/constants.rb +10 -0
- data/lib/xolo/server/helpers/auth.rb +19 -2
- data/lib/xolo/server/helpers/autopkg.rb +157 -0
- data/lib/xolo/server/helpers/client_data.rb +90 -60
- data/lib/xolo/server/helpers/file_transfers.rb +412 -82
- data/lib/xolo/server/helpers/jamf_pro.rb +31 -7
- data/lib/xolo/server/helpers/log.rb +2 -0
- data/lib/xolo/server/helpers/maintenance.rb +1 -0
- data/lib/xolo/server/helpers/notification.rb +4 -3
- data/lib/xolo/server/helpers/pkg_signing.rb +16 -12
- data/lib/xolo/server/helpers/progress_streaming.rb +9 -12
- data/lib/xolo/server/helpers/subscriptions.rb +119 -0
- data/lib/xolo/server/helpers/titles.rb +27 -3
- data/lib/xolo/server/helpers/versions.rb +23 -11
- data/lib/xolo/server/mixins/changelog.rb +9 -16
- data/lib/xolo/server/mixins/title_jamf_access.rb +375 -390
- data/lib/xolo/server/mixins/title_ted_access.rb +50 -8
- data/lib/xolo/server/mixins/version_jamf_access.rb +118 -129
- data/lib/xolo/server/mixins/version_ted_access.rb +34 -4
- data/lib/xolo/server/object_locks.rb +2 -1
- data/lib/xolo/server/routes/auth.rb +2 -2
- data/lib/xolo/server/routes/jamf_pro.rb +11 -1
- data/lib/xolo/server/routes/maint.rb +2 -1
- data/lib/xolo/server/routes/subscriptions.rb +126 -0
- data/lib/xolo/server/routes/title_editor.rb +1 -1
- data/lib/xolo/server/routes/titles.rb +26 -11
- data/lib/xolo/server/routes/uploads.rb +0 -14
- data/lib/xolo/server/routes/versions.rb +14 -13
- data/lib/xolo/server/routes.rb +15 -23
- data/lib/xolo/server/title.rb +100 -77
- data/lib/xolo/server/version.rb +178 -18
- data/lib/xolo/server.rb +8 -0
- metadata +20 -11
data/lib/xolo/core.rb
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Copyright 2025 Pixar
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the terms set forth in the LICENSE.txt file available at
|
|
4
|
+
# at the root of this project.
|
|
5
|
+
#
|
|
6
|
+
|
|
7
|
+
# frozen_string_literal: true
|
|
8
|
+
|
|
9
|
+
# Load the core xolo functionality
|
|
10
|
+
#
|
|
11
|
+
# This is done automatically when you `require 'xolo/admin'` or
|
|
12
|
+
# `require 'xolo/server'`
|
|
13
|
+
|
|
14
|
+
# Ruby Standard Libraries
|
|
15
|
+
######
|
|
16
|
+
require 'English'
|
|
17
|
+
require 'date'
|
|
18
|
+
require 'time'
|
|
19
|
+
require 'pathname'
|
|
20
|
+
require 'json'
|
|
21
|
+
|
|
22
|
+
# Other Gems to include at this level
|
|
23
|
+
require 'pixar-ruby-extensions'
|
|
24
|
+
|
|
25
|
+
# Internal requires - order matters
|
|
26
|
+
require 'xolo/core/loading'
|
|
27
|
+
require 'xolo/core/version'
|
|
28
|
+
require 'xolo/core/constants'
|
|
29
|
+
require 'xolo/core/exceptions'
|
|
30
|
+
|
|
31
|
+
# The main module
|
|
32
|
+
module Xolo
|
|
33
|
+
|
|
34
|
+
extend Xolo::Core::Loading
|
|
35
|
+
include Xolo::Core::Version
|
|
36
|
+
include Xolo::Core::Constants
|
|
37
|
+
include Xolo::Core::Exceptions
|
|
38
|
+
|
|
39
|
+
end # module Xolo
|
|
40
|
+
|
|
41
|
+
require 'xolo/core/json_wrappers'
|
|
42
|
+
require 'xolo/core/security_cmd'
|
|
43
|
+
require 'xolo/core/base_classes/configuration'
|
|
44
|
+
require 'xolo/core/base_classes/server_object'
|
|
45
|
+
require 'xolo/core/base_classes/title'
|
|
46
|
+
require 'xolo/core/base_classes/version'
|
|
47
|
+
require 'xolo/core/output'
|
data/lib/xolo/server/app.rb
CHANGED
|
@@ -19,6 +19,7 @@ module Xolo
|
|
|
19
19
|
##############################
|
|
20
20
|
##############################
|
|
21
21
|
|
|
22
|
+
# register Sinatra extensions - this 'extends' the app class with the extension's methods
|
|
22
23
|
register Xolo::Server::Routes
|
|
23
24
|
register Xolo::Server::Routes::Auth
|
|
24
25
|
register Xolo::Server::Routes::Maint
|
|
@@ -27,9 +28,13 @@ module Xolo
|
|
|
27
28
|
register Xolo::Server::Routes::Titles
|
|
28
29
|
register Xolo::Server::Routes::Versions
|
|
29
30
|
register Xolo::Server::Routes::Uploads
|
|
31
|
+
register Xolo::Server::Routes::Subscriptions
|
|
30
32
|
|
|
33
|
+
# include helper modules - this 'includes' the app class with the helper module's methods
|
|
34
|
+
# making them available as instance methods in routes and views
|
|
31
35
|
helpers Xolo::Core::Constants
|
|
32
36
|
helpers Xolo::Core::JSONWrappers
|
|
37
|
+
helpers Xolo::Core::SecurityCmd
|
|
33
38
|
helpers Xolo::Server::Helpers::Log
|
|
34
39
|
helpers Xolo::Server::Helpers::Notification
|
|
35
40
|
helpers Xolo::Server::Helpers::Auth
|
|
@@ -41,7 +46,9 @@ module Xolo
|
|
|
41
46
|
helpers Xolo::Server::Helpers::PkgSigning
|
|
42
47
|
helpers Xolo::Server::Helpers::ProgressStreaming
|
|
43
48
|
helpers Xolo::Server::Helpers::ClientData
|
|
49
|
+
helpers Xolo::Server::Helpers::Subscriptions
|
|
44
50
|
helpers Xolo::Server::Helpers::Maintenance
|
|
51
|
+
helpers Xolo::Server::Helpers::AutoPkg
|
|
45
52
|
|
|
46
53
|
# Sinatra setup
|
|
47
54
|
##############################
|
|
@@ -79,6 +79,18 @@ module Xolo
|
|
|
79
79
|
# The attribute keys we maintain, and their definitions
|
|
80
80
|
KEYS = {
|
|
81
81
|
|
|
82
|
+
# @!attribute test_server
|
|
83
|
+
# @return [Boolean] Is this a development/testing server? If so, Objects in Jamf will have
|
|
84
|
+
# the prefix 'Xolo-Test-' rather than just 'Xolo-' to avoid confusion and collision with production objects,
|
|
85
|
+
# and some other things may be different as well.
|
|
86
|
+
test_server: {
|
|
87
|
+
type: :boolean,
|
|
88
|
+
desc: <<~ENDDESC
|
|
89
|
+
Is this a development/testing server? If so, Objects in Jamf will have the prefix 'xolotest-' rather than just 'xolo-'
|
|
90
|
+
to avoid confusion and collision with production objects, and some other things may be different as well.
|
|
91
|
+
ENDDESC
|
|
92
|
+
},
|
|
93
|
+
|
|
82
94
|
# @!attribute ssl_cert
|
|
83
95
|
# @return [String] A command, path, or value for the SSL Cert.
|
|
84
96
|
ssl_cert: {
|
|
@@ -89,7 +101,8 @@ module Xolo
|
|
|
89
101
|
desc: <<~ENDDESC
|
|
90
102
|
The SSL Certificate for the https server in .pem format. When the server starts, it will be read from here, and securely stored in #{SSL_CERT_FILE}.
|
|
91
103
|
|
|
92
|
-
If you start this value with a vertical bar '|', everything after the bar is a command to be executed by the server at start-time.
|
|
104
|
+
If you start this value with a vertical bar '|', everything after the bar is a command to be executed by the server at start-time.
|
|
105
|
+
The command must return the certificate to standard output. This is useful when using a secret-storage system to manage secrets.
|
|
93
106
|
|
|
94
107
|
If the value is a path to a readable file, the file's contents are used.
|
|
95
108
|
|
|
@@ -109,7 +122,8 @@ module Xolo
|
|
|
109
122
|
desc: <<~ENDDESC
|
|
110
123
|
The private key for the SSL Certificate in .pem format. When the server starts, it will be read from here, and securely stored in #{SSL_KEY_FILE}/
|
|
111
124
|
|
|
112
|
-
If you start this value with a vertical bar '|', everything after the bar is a command to be executed by the server at start-time.
|
|
125
|
+
If you start this value with a vertical bar '|', everything after the bar is a command to be executed by the server at start-time.
|
|
126
|
+
The command must return the certificate to standard output. This is useful when using a secret-storage system to manage secrets.
|
|
113
127
|
|
|
114
128
|
If the value is a path to a readable file, the file's contents are used.
|
|
115
129
|
|
|
@@ -135,7 +149,8 @@ module Xolo
|
|
|
135
149
|
required: true,
|
|
136
150
|
type: :string,
|
|
137
151
|
desc: <<~ENDDESC
|
|
138
|
-
The name of a Jamf account-group (not a User group) that allows the use of 'xadm' to create and maintain titles and versions.
|
|
152
|
+
The name of a Jamf account-group (not a User group) that allows the use of 'xadm' to create and maintain titles and versions.
|
|
153
|
+
Users of xadm must be in this group, and provide their valid Jamf credentials.
|
|
139
154
|
ENDDESC
|
|
140
155
|
},
|
|
141
156
|
|
|
@@ -144,7 +159,9 @@ module Xolo
|
|
|
144
159
|
server_admin_jamf_group: {
|
|
145
160
|
type: :string,
|
|
146
161
|
desc: <<~ENDDESC
|
|
147
|
-
The name of a Jamf account-group (not a User group) that allows the use of the server admin commands of 'xadm', including --run-server-cleanup,
|
|
162
|
+
The name of a Jamf account-group (not a User group) that allows the use of the server admin commands of 'xadm', including --run-server-cleanup,
|
|
163
|
+
--update-client-data, --rotate-server-logs and --set-server-log-level.
|
|
164
|
+
|
|
148
165
|
Members of this group can also use the xadm commands that require the 'admin_jamf_group' group.
|
|
149
166
|
If unset, no one can use the server admin commands.
|
|
150
167
|
ENDDESC
|
|
@@ -156,7 +173,8 @@ module Xolo
|
|
|
156
173
|
default: Xolo::Server::Log::DFT_LOG_DAYS_TO_KEEP,
|
|
157
174
|
type: :integer,
|
|
158
175
|
desc: <<~ENDDESC
|
|
159
|
-
The server log is rotated daily. How many days of log files should be kept? All logs are kept in #{Xolo::Server::LOG_DIR}.
|
|
176
|
+
The server log is rotated daily. How many days of log files should be kept? All logs are kept in #{Xolo::Server::LOG_DIR}.
|
|
177
|
+
The current file is named '#{Xolo::Server::LOG_FILE_NAME}', older files are appended with '.0' for yesterday, '.1' for the previous day, etc.
|
|
160
178
|
ENDDESC
|
|
161
179
|
},
|
|
162
180
|
|
|
@@ -166,7 +184,9 @@ module Xolo
|
|
|
166
184
|
default: Xolo::Server::Log::DFT_LOG_COMPRESS_AFTER_DAYS,
|
|
167
185
|
type: :integer,
|
|
168
186
|
desc: <<~ENDDESC
|
|
169
|
-
Once a log file is rotated, how many days before it is compressed? Compressed logs are named '#{Xolo::Server::LOG_FILE_NAME}.XX.bz2'.
|
|
187
|
+
Once a log file is rotated, how many days before it is compressed? Compressed logs are named '#{Xolo::Server::LOG_FILE_NAME}.XX.bz2'.
|
|
188
|
+
It can be accessed using the various bzip2 tools (bzip2, bunzip2, bzcat, bzgrep, etc). If this number is negative, or larger than log_days_to_keep,
|
|
189
|
+
no logs will be compressed, if it is zero, all older logs will be compressed.
|
|
170
190
|
ENDDESC
|
|
171
191
|
},
|
|
172
192
|
|
|
@@ -177,18 +197,23 @@ module Xolo
|
|
|
177
197
|
alert_tool: {
|
|
178
198
|
type: :string,
|
|
179
199
|
desc: <<~ENDDESC
|
|
180
|
-
Server errors or other events that happen as part of xadm actions are reported to the xadm user. But sometimes such events happen outside of the scope
|
|
200
|
+
Server errors or other events that happen as part of xadm actions are reported to the xadm user. But sometimes such events happen outside of the scope
|
|
201
|
+
of a xadm session. While these events will be logged, you might want them reported to a server administrator in real time.
|
|
181
202
|
|
|
182
203
|
This value is either:
|
|
183
204
|
|
|
184
|
-
- a command (path to executable plus CLI args) on the Xolo server which will accept an error or other alert message on standard input and send it
|
|
205
|
+
- a command (path to executable plus CLI args) on the Xolo server which will accept an error or other alert message on standard input and send it
|
|
206
|
+
somewhere where it'll be seen by an appropriate audiance, be that an email address, a Slack channel - anything you'd like.
|
|
185
207
|
|
|
186
|
-
- or a string "
|
|
208
|
+
- or a string "#{Xolo::Server::Helpers::Notification::ALERT_TOOL_EMAIL_PREFIX}email_address" where email_address is the email address to send alerts to.
|
|
209
|
+
In this case, the server will send an email to that address using the smtp_server and email_from configuration values.
|
|
187
210
|
|
|
188
211
|
Fictional command example:
|
|
189
212
|
/path/to/slackerator --sender xolo-server --channel xolo-alerts --icon dante
|
|
190
213
|
Fictional email example:
|
|
191
|
-
|
|
214
|
+
#{Xolo::Server::Helpers::Notification::ALERT_TOOL_EMAIL_PREFIX}xolo-server-admins@myschool.edu
|
|
215
|
+
|
|
216
|
+
While not required, it is strongly recommended to use this, so that server admins are made aware of issues that need their attention.
|
|
192
217
|
ENDDESC
|
|
193
218
|
},
|
|
194
219
|
|
|
@@ -220,7 +245,8 @@ module Xolo
|
|
|
220
245
|
desc: <<~ENDDESC
|
|
221
246
|
The password to unlock the keychain used for package signing.
|
|
222
247
|
|
|
223
|
-
If you start this value with a vertical bar '|', everything after the bar is a command to be executed by the server at start-time.
|
|
248
|
+
If you start this value with a vertical bar '|', everything after the bar is a command to be executed by the server at start-time.
|
|
249
|
+
The command must return the certificate to standard output. This is useful when using a secret-storage system to manage secrets.
|
|
224
250
|
|
|
225
251
|
If the value is a path to a readable file, the file's contents are used.
|
|
226
252
|
|
|
@@ -235,16 +261,36 @@ module Xolo
|
|
|
235
261
|
sign_pkgs: {
|
|
236
262
|
type: :boolean,
|
|
237
263
|
desc: <<~ENDDESC
|
|
238
|
-
When
|
|
264
|
+
When a .pkg, is received for a version and it isn't signed, should the server sign it before uploading to Jamf's Distribution Point(s)?
|
|
239
265
|
|
|
240
266
|
If you set this to true, it will use the same keychain and identity as the 'pkg_signing_identity' config value to sign the pkg, using the keychain you installed at:
|
|
241
267
|
/Library/Application Support/xoloserver/xolo-pkg-signing.keychain-db
|
|
242
268
|
|
|
269
|
+
Packages must be signed distribution packages to work with the `xadm deploy` command, which uses MDM to push the package to client machines.
|
|
270
|
+
|
|
243
271
|
NOTE: While it may seem insecure to allow the server to sign pkgs, consider:
|
|
244
272
|
- Users of xadm are authenticated and authorized to use the server (see 'admin_jamf_group')
|
|
245
273
|
- You don't need to distribute your signing certificates to a wide group of individual developers.
|
|
246
274
|
- While you need to trust your xadm users not to upload a malicious pkg, this would be true
|
|
247
275
|
even if you deployed the certs to them, so keeping the certs on the server is more secure.
|
|
276
|
+
|
|
277
|
+
See also the 'sign_autopkg_pkgs' abd 'create_distribution_pkgs' config values.
|
|
278
|
+
ENDDESC
|
|
279
|
+
},
|
|
280
|
+
|
|
281
|
+
# @!attribute create_distribution_pkgs
|
|
282
|
+
# @return [Boolean] When processing uploaded pkgs, should we wrap component pkgs in distribution pkgs?
|
|
283
|
+
create_distribution_pkgs: {
|
|
284
|
+
type: :boolean,
|
|
285
|
+
desc: <<~ENDDESC
|
|
286
|
+
When a .pkg, is received for a version and it is a component package, should the server wrap it in a distribution package before uploading to Jamf's Distribution Point(s)?
|
|
287
|
+
|
|
288
|
+
If you set this to true, component packages will be wrapped in a distribution package using the productbuild tool, like so:
|
|
289
|
+
/usr/bin/productbuild –package /path/to/recieved.pkg /path/to/distribution_package.pkg
|
|
290
|
+
|
|
291
|
+
If sign_pkgs is true, the distribution package will be signed, otherwise it will be unsigned.
|
|
292
|
+
|
|
293
|
+
Packages must be signed distribution packages to work with the `xadm deploy` command, which uses MDM to push the package to client machines.
|
|
248
294
|
ENDDESC
|
|
249
295
|
},
|
|
250
296
|
|
|
@@ -256,7 +302,8 @@ module Xolo
|
|
|
256
302
|
desc: <<~ENDDESC
|
|
257
303
|
The name of a Jamf account-group (not a User group) whose members may set a title's release_groups to 'all'.
|
|
258
304
|
|
|
259
|
-
When this is set, and someone not in this group tries to set a title's release_groups to 'all', they will get a message telling
|
|
305
|
+
When this is set, and someone not in this group tries to set a title's release_groups to 'all', they will get a message telling
|
|
306
|
+
them to contact the person or group named in 'release_to_all_contact' to get approval.
|
|
260
307
|
|
|
261
308
|
To approve the request, one of the members of this group must run 'xadm edit-title <title> --release-groups all'.
|
|
262
309
|
|
|
@@ -270,7 +317,8 @@ module Xolo
|
|
|
270
317
|
required: false,
|
|
271
318
|
type: :string,
|
|
272
319
|
desc: <<~ENDDESC
|
|
273
|
-
When release_to_all_jamf_group is set, and someone not in that group tries to set a title's release_groups to 'all', they are
|
|
320
|
+
When release_to_all_jamf_group is set, and someone not in that group tries to set a title's release_groups to 'all', they are
|
|
321
|
+
old to use this contact info to get approval.
|
|
274
322
|
|
|
275
323
|
This string could be an email address, a chat channel, a phone number, etc.
|
|
276
324
|
|
|
@@ -305,11 +353,13 @@ module Xolo
|
|
|
305
353
|
default: Xolo::Server::Helpers::Maintenance::DFT_DEPRECATED_LIFETIME_DAYS,
|
|
306
354
|
type: :integer,
|
|
307
355
|
desc: <<~ENDDESC
|
|
308
|
-
When a version is deprecated, it will be automatically deleted by the nightly cleanup this many days later. If set to 0 or less,
|
|
356
|
+
When a version is deprecated, it will be automatically deleted by the nightly cleanup this many days later. If set to 0 or less,
|
|
357
|
+
deprecated versions will never be deleted.
|
|
309
358
|
|
|
310
359
|
Deprecated versions are those that have been released, but a newer version has been released since then.
|
|
311
360
|
|
|
312
|
-
WARNING: If you set this to 0 or less, you will need to manually delete deprecated versions. Keeping them around can cause confusion
|
|
361
|
+
WARNING: If you set this to 0 or less, you will need to manually delete deprecated versions. Keeping them around can cause confusion
|
|
362
|
+
and clutter in the GUI, and use up disk space.
|
|
313
363
|
ENDDESC
|
|
314
364
|
},
|
|
315
365
|
|
|
@@ -323,7 +373,8 @@ module Xolo
|
|
|
323
373
|
|
|
324
374
|
Skipped versions are those that were never released, but a newer version has been released.
|
|
325
375
|
|
|
326
|
-
WARNING: If you set this to true, you will need to manually delete skipped versions. Keeping them around can cause confusion
|
|
376
|
+
WARNING: If you set this to true, you will need to manually delete skipped versions. Keeping them around can cause confusion
|
|
377
|
+
and clutter in the GUI, and use up disk space.
|
|
327
378
|
ENDDESC
|
|
328
379
|
},
|
|
329
380
|
|
|
@@ -336,9 +387,11 @@ module Xolo
|
|
|
336
387
|
default: Xolo::Server::Helpers::Maintenance::DFT_UNRELEASED_PILOTS_NOTIFICATION_DAYS,
|
|
337
388
|
type: :integer,
|
|
338
389
|
desc: <<~ENDDESC
|
|
339
|
-
If the newest pilot of a title has not been released in this many days, notify someone about it monthly, asking to release it or delete it.
|
|
390
|
+
If the newest pilot of a title has not been released in this many days, notify someone about it monthly, asking to release it or delete it.
|
|
391
|
+
If set to 0 or less, these notifications are disabled.
|
|
340
392
|
|
|
341
|
-
Notifications are sent on the first of the month via email to the title's contact email address, and the alert_tool (if defined).
|
|
393
|
+
Notifications are sent on the first of the month via email to the title's contact email address, and the alert_tool (if defined).
|
|
394
|
+
Default is 180 days (about 6 months).
|
|
342
395
|
|
|
343
396
|
Pilot versions are those that have been added for testing, but not yet released.
|
|
344
397
|
|
|
@@ -353,7 +406,8 @@ module Xolo
|
|
|
353
406
|
smtp_server: {
|
|
354
407
|
type: :string,
|
|
355
408
|
desc: <<~ENDDESC
|
|
356
|
-
The hostname of the SMTP server to use for sending email. This is a server that can recieve email for your organizaion from the xolo server.
|
|
409
|
+
The hostname of the SMTP server to use for sending email. This is a server that can recieve email for your organizaion from the xolo server.
|
|
410
|
+
Used for sending alerts and notifications. If not set, no email notifications will be sent.
|
|
357
411
|
ENDDESC
|
|
358
412
|
},
|
|
359
413
|
|
|
@@ -364,7 +418,8 @@ module Xolo
|
|
|
364
418
|
desc: <<~ENDDESC
|
|
365
419
|
The email address to use as the 'from' address for emails sent by xolo. This should be a valid email address that can recieve replies.
|
|
366
420
|
|
|
367
|
-
Will default to '#{Xolo::Server::Helpers::Notification::DFT_EMAIL_FROM}@<hostname>' if not set. The human-readable part of the address
|
|
421
|
+
Will default to '#{Xolo::Server::Helpers::Notification::DFT_EMAIL_FROM}@<hostname>' if not set. The human-readable part of the address
|
|
422
|
+
will be 'Xolo Server on <hostname>'.
|
|
368
423
|
ENDDESC
|
|
369
424
|
},
|
|
370
425
|
|
|
@@ -395,7 +450,6 @@ module Xolo
|
|
|
395
450
|
# @!attribute jamf_gui_hostname
|
|
396
451
|
# @return [String] The hostname of the Jamf Pro server used for links to the GUI webapp
|
|
397
452
|
jamf_gui_hostname: {
|
|
398
|
-
required: true,
|
|
399
453
|
type: :string,
|
|
400
454
|
desc: <<~ENDDESC
|
|
401
455
|
The hostname of the Jamf Pro server used for links to the GUI webapp, if different from the jamf_hostname.
|
|
@@ -460,11 +514,17 @@ module Xolo
|
|
|
460
514
|
# @return [String] The username to use when connecting to the Jamf Pro API
|
|
461
515
|
jamf_api_user: {
|
|
462
516
|
required: true,
|
|
517
|
+
load_method: :data_from_command_file_or_string,
|
|
463
518
|
type: :string,
|
|
464
519
|
desc: <<~ENDDESC
|
|
465
520
|
The username of the Jamf account for connecting to the Jamf Pro APIs.
|
|
466
|
-
|
|
467
|
-
|
|
521
|
+
|
|
522
|
+
If you start this value with a vertical bar '|', everything after the bar is a shell command to be executed by the server at start-time.
|
|
523
|
+
The command must return the password to standard output. This is useful when using a secret-storage system to manage secrets.
|
|
524
|
+
|
|
525
|
+
If the value is a path to a readable file, the file's contents are used.
|
|
526
|
+
|
|
527
|
+
Otherwise the value is used as the password.
|
|
468
528
|
ENDDESC
|
|
469
529
|
},
|
|
470
530
|
|
|
@@ -478,7 +538,8 @@ module Xolo
|
|
|
478
538
|
desc: <<~ENDDESC
|
|
479
539
|
The password for the username that connects to the Jamf Pro APIs.
|
|
480
540
|
|
|
481
|
-
If you start this value with a vertical bar '|', everything after the bar is a command to be executed by the server at start-time.
|
|
541
|
+
If you start this value with a vertical bar '|', everything after the bar is a shell command to be executed by the server at start-time.
|
|
542
|
+
The command must return the password to standard output. This is useful when using a secret-storage system to manage secrets.
|
|
482
543
|
|
|
483
544
|
If the value is a path to a readable file, the file's contents are used.
|
|
484
545
|
|
|
@@ -488,14 +549,28 @@ module Xolo
|
|
|
488
549
|
ENDDESC
|
|
489
550
|
},
|
|
490
551
|
|
|
552
|
+
# @!attribute jamf_api_client
|
|
553
|
+
# @return [Boolean] The provided jamf_api_user is an API client, not a normal user, and the
|
|
554
|
+
# jamf_api_pw is the API client's secret.
|
|
555
|
+
jamf_use_api_client: {
|
|
556
|
+
type: :boolean,
|
|
557
|
+
desc: <<~ENDDESC
|
|
558
|
+
If true, the provided jamf_api_user is an API client's "client_id", not a normal username, and the jamf_api_pw is the API client's 'client_secret'.
|
|
559
|
+
|
|
560
|
+
If false, the jamf_api_user is a normal user, and the jamf_api_pw is that user's password.
|
|
561
|
+
ENDDESC
|
|
562
|
+
},
|
|
563
|
+
|
|
491
564
|
# @!attribute jamf_auto_accept_xolo_eas
|
|
492
|
-
# @return [Boolean] should we auto-accept the Jamf patch title eas?
|
|
565
|
+
# @return [Boolean] should we auto-accept the Jamf patch title eas for managed titles?
|
|
493
566
|
jamf_auto_accept_xolo_eas: {
|
|
494
567
|
type: :boolean,
|
|
495
568
|
desc: <<~ENDDESC
|
|
496
|
-
For titles
|
|
569
|
+
For titles managed by Xolo, should we auto-accept the Patch Title Extension Attributes that come from the uploaded version_script from xadm?
|
|
497
570
|
|
|
498
571
|
Default is false, meaning all Title EAs must be manually accepted in the Jamf Pro Web UI.
|
|
572
|
+
|
|
573
|
+
EAs must always be manually accepted for subscribed titles, since the code the run is not under the control of Xolo.
|
|
499
574
|
ENDDESC
|
|
500
575
|
},
|
|
501
576
|
|
|
@@ -510,28 +585,28 @@ module Xolo
|
|
|
510
585
|
desc: <<~ENDDESC
|
|
511
586
|
After a .pkg is uploaded to the Xolo server by someone using xadm, it must then be uploaded to the Jamf distribution point(s) to be available for installation.
|
|
512
587
|
|
|
513
|
-
If
|
|
588
|
+
If your principal distribution point is a Cloud Distribution Point and you're using Jamf Pro 11.6 or later, you can set this value to 'api', and xoloserver will use the Jamf Pro API to upload the pkg to the Cloud Distribution Point. This is the simplest option, and is recommended if it works for your environment.
|
|
514
589
|
|
|
515
|
-
If
|
|
590
|
+
If your principal is not a Cloud Distribution Point, xoloserver can use an custom external tool to do the upload.
|
|
591
|
+
|
|
592
|
+
To do so, set this value to a path to an executable on the xolo server machine that will do the upload to the distribution point(s). This tool can be anything you like, as long as it can upload a .pkg to the Jamf distribution point(s) you use.
|
|
516
593
|
|
|
517
594
|
It will be run with two arguments:
|
|
518
|
-
- First, The display name of the Jamf Package
|
|
595
|
+
- First, The display name of the Jamf Package record the .pkg is used with
|
|
519
596
|
- Then the path to the .pkg file on the Xolo server, which will be uploaded
|
|
520
597
|
to the Jamf distribution point(s).
|
|
521
598
|
|
|
522
|
-
So if the executable is '/usr/local/bin/jamf-pkg-uploader' then when
|
|
599
|
+
So if the executable is '/usr/local/bin/jamf-pkg-uploader' then when xoloserver recieves a .pkg to be uploaded to Jamf, it will run something like:
|
|
523
600
|
|
|
524
601
|
/usr/local/bin/jamf-pkg-uploader 'CoolApp' '/Library/Application Support/xoloserver/tmpfiles/CoolApp.pkg'
|
|
525
602
|
|
|
526
603
|
Where 'CoolApp' is the name of the Jamf Package object that will use this .pkg, and '/Library/Application Support/xoloserver/tmpfiles/CoolApp.pkg' is the location where it was stored on the Xolo server when xadm uploaded it.
|
|
527
604
|
|
|
528
|
-
The upload tool can itself run other tools as needed, e.g. one to upload
|
|
529
|
-
to all fileshare distribution points, and another to upload to a Cloud dist. point.
|
|
530
|
-
or it can do all the things itself.
|
|
605
|
+
The upload tool can itself run other tools as needed, e.g. one to upload to all fileshare distribution points, and another to upload to a Cloud dist. point, or it can do all the things itself.
|
|
531
606
|
|
|
532
|
-
After that tool runs, the copy of the .pkg on the server (
|
|
607
|
+
After that tool runs, the copy of the .pkg on the xolo server ('/Library/Application Support/xoloserver/tmpfiles/CoolApp.pkg' in the example above) will be deleted.
|
|
533
608
|
|
|
534
|
-
An external tool is used here because every Jamf Pro customer has different needs for this
|
|
609
|
+
An external tool is used here because every Jamf Pro customer has different needs for this depending on their environment of distribution points.
|
|
535
610
|
ENDDESC
|
|
536
611
|
},
|
|
537
612
|
|
|
@@ -541,7 +616,8 @@ module Xolo
|
|
|
541
616
|
forced_exclusion: {
|
|
542
617
|
type: :string,
|
|
543
618
|
desc: <<~ENDDESC
|
|
544
|
-
If you have any jamf computers who should never even know that xolo exists, and should never have any software installed via xolo, put them
|
|
619
|
+
If you have any jamf computers who should never even know that xolo exists, and should never have any software installed via xolo, put them
|
|
620
|
+
into a group and put that group's name here.
|
|
545
621
|
|
|
546
622
|
An example would be a group of machines that should have a very minimalist management footprint, only enforcing basic security settings and nothing else.
|
|
547
623
|
|
|
@@ -616,7 +692,8 @@ module Xolo
|
|
|
616
692
|
desc: <<~ENDDESC
|
|
617
693
|
The password for the username that connects to the Title Editor API.
|
|
618
694
|
|
|
619
|
-
If you start this value with a vertical bar '|', everything after the bar is a command to be executed by the server at start-time.
|
|
695
|
+
If you start this value with a vertical bar '|', everything after the bar is a command to be executed by the server at start-time.
|
|
696
|
+
The command must return the certificate to standard output. This is useful when using a secret-storage system to manage secrets.
|
|
620
697
|
|
|
621
698
|
If the value is a path to a readable file, the file's contents are used.
|
|
622
699
|
|
|
@@ -624,6 +701,134 @@ module Xolo
|
|
|
624
701
|
|
|
625
702
|
Be careful of security concerns when passwords are stored in files.
|
|
626
703
|
ENDDESC
|
|
704
|
+
},
|
|
705
|
+
|
|
706
|
+
# @!attribute subscription_webhook_token
|
|
707
|
+
# @return [String] A command, path, or value for the authentication token used by Jamf Pro to send
|
|
708
|
+
# PatchSoftwareTitleUpdated webhook events for subscribed titles.
|
|
709
|
+
subscription_webhook_token: {
|
|
710
|
+
load_method: :data_from_command_file_or_string,
|
|
711
|
+
private: true,
|
|
712
|
+
type: :string,
|
|
713
|
+
desc: <<~ENDDESC
|
|
714
|
+
The authentication token used by Jamf Pro to send PatchSoftwareTitleUpdated webhook events for subscribed titles.
|
|
715
|
+
|
|
716
|
+
This value can be string, but should be treated like a password, and should be changed both here and on the Jamf Pro server if it is ever suspected of being compromised.
|
|
717
|
+
|
|
718
|
+
A good way to generate a random token is to use the following command in Terminal:
|
|
719
|
+
|
|
720
|
+
openssl rand -hex 16
|
|
721
|
+
|
|
722
|
+
When configuring the webhook in Jamf Pro, use "Header Authentication" to send this JSON to use as the header:
|
|
723
|
+
|
|
724
|
+
{"Authorization":"Bearer <token>"}
|
|
725
|
+
|
|
726
|
+
Replacing <token> with the value set here.
|
|
727
|
+
|
|
728
|
+
If you start this value with a vertical bar '|', everything after the bar is a command to be executed by the server at start-time.
|
|
729
|
+
The command must return the password to standard output. This is useful when using a secret-storage system to manage secrets.
|
|
730
|
+
|
|
731
|
+
If the value is a path to a readable file, the file's contents are used.
|
|
732
|
+
|
|
733
|
+
Otherwise the value is used as the token.
|
|
734
|
+
|
|
735
|
+
Be careful of security concerns when secrets are stored in files.
|
|
736
|
+
ENDDESC
|
|
737
|
+
},
|
|
738
|
+
|
|
739
|
+
# @!attribute subscription_updated_alert_tool
|
|
740
|
+
# @return [String] A cli tool or an email address to notify when a subscription updated webhook event
|
|
741
|
+
# is received, but the title is not configured to use autopkg to fetch the new version.
|
|
742
|
+
# If unset, the default alert mechanism is used. See 'alert_tool' for details.
|
|
743
|
+
subscription_updated_alert_tool: {
|
|
744
|
+
type: :string,
|
|
745
|
+
desc: <<~ENDDESC
|
|
746
|
+
If a title is a subscription from a Patch Source, but is not configured to use autopkg to fetch new versions, when a PatchSoftwareTitleUpdated webhook
|
|
747
|
+
event is received from Jamf Pro, an alert should be sent to notify someone to add the new version manually.
|
|
748
|
+
|
|
749
|
+
Leave this unset to use the default alert mechanism defined by the 'alert_tool' configuration value.
|
|
750
|
+
|
|
751
|
+
Otherwise, the value is interpreted the same as for 'alert_tool', either a command to run, or an email address prefixed by "#{Xolo::Server::Helpers::Notification::ALERT_TOOL_EMAIL_PREFIX}".
|
|
752
|
+
ENDDESC
|
|
753
|
+
},
|
|
754
|
+
|
|
755
|
+
# @!attribute autopkg_executable
|
|
756
|
+
# @return [String] The path to the autopkg executable. If unset, titles cannot use autopkg to acquire
|
|
757
|
+
# new .pkgs
|
|
758
|
+
autopkg_executable: {
|
|
759
|
+
type: :string,
|
|
760
|
+
desc: <<~ENDDESC
|
|
761
|
+
The path to the autopkg executable on the server host. If unset, titles cannot use autopkg to acquire
|
|
762
|
+
new .pkgs.
|
|
763
|
+
|
|
764
|
+
AutoPkg must be installed, configured, and maintained on the xoloserver host separately from the xoloserver itself.
|
|
765
|
+
|
|
766
|
+
NOTE: AutoPkg recipes are always run with '-k FAIL_RECIPES_WITHOUT_TRUST_INFO=yes', and will fail if you have not 'trusted'
|
|
767
|
+
them by making an override. See the AutoPkg docs for details.
|
|
768
|
+
ENDDESC
|
|
769
|
+
},
|
|
770
|
+
|
|
771
|
+
# @!attribute autopkg_user
|
|
772
|
+
# @return [String] The name of a local, non-root user that will run actually the autopkg executable as needed.
|
|
773
|
+
autopkg_user: {
|
|
774
|
+
type: :string,
|
|
775
|
+
desc: <<~ENDDESC
|
|
776
|
+
The name of a local, non-root user that will run the autopkg executable as needed. AutoPkg should never be run as root.
|
|
777
|
+
|
|
778
|
+
If unset, titles cannot use autopkg to acquire new .pkgs.
|
|
779
|
+
|
|
780
|
+
AutoPkg must be installed, configured, and maintained on the xoloserver host separately from the xoloserver itself.
|
|
781
|
+
|
|
782
|
+
NOTE: AutoPkg recipes are always run with '-k FAIL_RECIPES_WITHOUT_TRUST_INFO=yes', and will fail if you have not 'trusted'
|
|
783
|
+
them by making an override. See the AutoPkg docs for details.
|
|
784
|
+
ENDDESC
|
|
785
|
+
},
|
|
786
|
+
|
|
787
|
+
# @!attribute autopkg_user_keychain_pw
|
|
788
|
+
# @return [String] A command, path, or value for the password to unlock the autopkg_user's login keychain.
|
|
789
|
+
autopkg_user_keychain_pw: {
|
|
790
|
+
required: true,
|
|
791
|
+
load_method: :data_from_command_file_or_string,
|
|
792
|
+
private: true,
|
|
793
|
+
type: :string,
|
|
794
|
+
desc: <<~ENDDESC
|
|
795
|
+
The password for the login keychain of the autopkg_user.
|
|
796
|
+
|
|
797
|
+
Some autopkg recipes may attempt to sign apps or packages, which requires access to the autopkg_user's login keychain.
|
|
798
|
+
|
|
799
|
+
Since the user is not expected to be logged into the macOS GUI on the server (and even if it were, the xoloserver process doesn't have
|
|
800
|
+
access to the GUI context) the keychain will be locked, and must be unlocked by the server before running autopkg recipes that need it.
|
|
801
|
+
|
|
802
|
+
This config value is used to unlock that keychain when running autopkg recipes. The keychain used is the one located at
|
|
803
|
+
/Users/<autopkg_user>/Library/Keychains/login.keychain-db. Be sure the desired signing identities are in that keychain, and that the
|
|
804
|
+
keychain is set to allow various executables to access them without prompting, including the autopkg itself, codesign, productsign,
|
|
805
|
+
pkgbuild, and productbuild.
|
|
806
|
+
|
|
807
|
+
If you start this value with a vertical bar '|', everything after the bar is a command to be executed by the server at start-time.
|
|
808
|
+
The command must return the password to standard output. This is useful when using a secret-storage system to manage secrets.
|
|
809
|
+
|
|
810
|
+
If the value is a path to a readable file, the file's contents are used.
|
|
811
|
+
|
|
812
|
+
Otherwise the value is used as the password.
|
|
813
|
+
|
|
814
|
+
Be careful of security concerns when passwords are stored in files.
|
|
815
|
+
ENDDESC
|
|
816
|
+
},
|
|
817
|
+
|
|
818
|
+
# @!attribute sign_autopkg_pkgs
|
|
819
|
+
# @return [Boolean] Should the server sign any unsigned pkgs acquired via autopkg?
|
|
820
|
+
sign_autopkg_pkgs: {
|
|
821
|
+
type: :boolean,
|
|
822
|
+
desc: <<~ENDDESC
|
|
823
|
+
This is just like sign_pkgs, but only applies to pkgs acquired via autopkg.
|
|
824
|
+
|
|
825
|
+
Be sure you trust your autopkg recipes to only download safe pkgs if you enable this.
|
|
826
|
+
|
|
827
|
+
Packages must be signed distribution packages to work with the `xadm deploy` command, which uses MDM to push the package to client machines.
|
|
828
|
+
|
|
829
|
+
NOTE: AutoPkg recipes are always run with '-k FAIL_RECIPES_WITHOUT_TRUST_INFO=yes', and will fail if you have not 'trusted'
|
|
830
|
+
them by making an override. See the AutoPkg docs for details.
|
|
831
|
+
ENDDESC
|
|
627
832
|
}
|
|
628
833
|
|
|
629
834
|
}.freeze
|
|
@@ -63,6 +63,16 @@ module Xolo
|
|
|
63
63
|
# full object name if appropriate (e.g. Package objects)
|
|
64
64
|
JAMF_OBJECT_NAME_PFX = 'xolo-'
|
|
65
65
|
|
|
66
|
+
# Jamf objects from a test server are named with this prefix followed by <title>-<version>
|
|
67
|
+
# See also: Xolo::Server::Configuration
|
|
68
|
+
JAMF_TEST_OBJECT_NAME_PFX = 'xolotest-'
|
|
69
|
+
|
|
70
|
+
# when processing things via Jamf webhooks, this is the session[:admin]
|
|
71
|
+
WEBHOOK_HANDLER_ADMIN_USERNAME = 'xolo-webhook-handler'
|
|
72
|
+
|
|
73
|
+
# TODO: remove this stuff when ruby-jss supports Patch Titles via JPAPI
|
|
74
|
+
JPAPI_PATCH_TITLE_ENDPOINT = 'v2/patch-software-title-configurations'
|
|
75
|
+
|
|
66
76
|
end # module Constants
|
|
67
77
|
|
|
68
78
|
end # Server
|
|
@@ -53,6 +53,9 @@ module Xolo
|
|
|
53
53
|
'/maint/shutdown-server'
|
|
54
54
|
].freeze
|
|
55
55
|
|
|
56
|
+
# the route used by Jamf Webhooks to notify Xolo of Patch Title updates
|
|
57
|
+
PATCH_TITLE_UPDATED_WEBHOOK_ROUTE = '/subscribed-title-updates'
|
|
58
|
+
|
|
56
59
|
# The loopback address for IPV4, aka 'localhost'
|
|
57
60
|
IPV4_LOOPBACK = '127.0.0.1'
|
|
58
61
|
|
|
@@ -67,7 +70,7 @@ module Xolo
|
|
|
67
70
|
end
|
|
68
71
|
|
|
69
72
|
# If a request comes in from one of our known IP addresses
|
|
70
|
-
# with a valid
|
|
73
|
+
# with a valid internal_auth_token in the headers, then the request is allowed.
|
|
71
74
|
#
|
|
72
75
|
# This allows the xolo server to send requests to itself without needing
|
|
73
76
|
# to authenticate, as is needed for some kinds of maintenance tasks
|
|
@@ -83,6 +86,12 @@ module Xolo
|
|
|
83
86
|
@internal_auth_token_header ||= "Bearer #{SecureRandom.hex(64)}"
|
|
84
87
|
end
|
|
85
88
|
|
|
89
|
+
# @return [String] The auth token to be used in the Authorization header of webhook event requests
|
|
90
|
+
#####################
|
|
91
|
+
def self.jamf_webhook_auth_token_header
|
|
92
|
+
@jamf_webhook_auth_token_header ||= "Bearer #{Xolo::Server.config.subscription_webhook_token}"
|
|
93
|
+
end
|
|
94
|
+
|
|
86
95
|
# Instance methods
|
|
87
96
|
#####################
|
|
88
97
|
#####################
|
|
@@ -128,6 +137,12 @@ module Xolo
|
|
|
128
137
|
Socket.ip_address_list.map(&:ip_address)
|
|
129
138
|
end
|
|
130
139
|
|
|
140
|
+
# @return [Boolean] Is the jamf webhook auth token in the headers of the request?
|
|
141
|
+
#####################
|
|
142
|
+
def jamf_webhook_auth_token_ok?
|
|
143
|
+
request.env['HTTP_AUTHORIZATION'] == Xolo::Server::Helpers::Auth.jamf_webhook_auth_token_header
|
|
144
|
+
end
|
|
145
|
+
|
|
131
146
|
# is the given username a member of the admin_jamf_group?
|
|
132
147
|
# or the server_admin_jamf_group?
|
|
133
148
|
# If not, they are not allowed to talk to the xolo server.
|
|
@@ -212,6 +227,7 @@ module Xolo
|
|
|
212
227
|
log_debug "Checking if '#{username}' is a member of the Jamf AccountGroup '#{groupname}'"
|
|
213
228
|
|
|
214
229
|
# This isn't well implemented in ruby-jss, so use c_get directly
|
|
230
|
+
# TODO: use JP API when ruby-jss supports it
|
|
215
231
|
jgroup = jamf_cnx.c_get("accounts/groupname/#{groupname}")[:group]
|
|
216
232
|
|
|
217
233
|
if jgroup[:ldap_server]
|
|
@@ -223,7 +239,8 @@ module Xolo
|
|
|
223
239
|
false
|
|
224
240
|
end
|
|
225
241
|
|
|
226
|
-
# Try to authenticate the jamf user trying to log in to xolo
|
|
242
|
+
# Try to authenticate the jamf user trying to log in to xolo.
|
|
243
|
+
# This must be a regular Jamf user acct, not an API client.
|
|
227
244
|
#
|
|
228
245
|
# @param admin [String] The jamf acct name of the person seeking access
|
|
229
246
|
#
|