The browser settings for Safari, Chrome, and Firefox can be managed on macOS to lock down home pages and other settings.
Safari
With the release of Safari 10, it looks like Apple no longer allows for MCX-style management of Safari’s preferences. In previous versions, you could easily set a homepage using the following command (ran as the current user):
defaults write com.apple.Safari HomePage "http://HOMEPAGE_URL"
MCX preference settings are still supported through configuration profiles. We can create a custom profile with the following attributes:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>PayloadIdentifier</key> <string>com.laurenceschool.profile.safari.20161111</string> <key>PayloadRemovalDisallowed</key> <true/> <key>PayloadScope</key> <string>System</string> <key>PayloadType</key> <string>Configuration</string> <key>PayloadUUID</key> <string>69F2AD5C-A85E-11E6-80F5-76304DEC7EB7</string> <key>PayloadOrganization</key> <string>Laurence School</string> <key>PayloadVersion</key> <integer>1</integer> <key>PayloadDisplayName</key> <string>Safari Home Page</string> <key>PayloadContent</key> <array> <dict> <key>PayloadType</key> <string>com.apple.ManagedClient.preferences</string> <key>PayloadVersion</key> <integer>1</integer> <key>PayloadIdentifier</key> <string>com.laurenceschool.profile.safari.20161113</string> <key>PayloadUUID</key> <string>E276A24C-A85E-11E6-80F5-76304DEC7EB7</string> <key>PayloadEnabled</key> <true/> <key>PayloadDisplayName</key> <string>Sets the Safari HomePage attribute and locks it in place.</string> <key>PayloadContent</key> <dict> <key>com.apple.Safari</key> <dict> <key>Forced</key> <array> <dict> <key>mcx_preference_settings</key> <dict> <key>AlwaysRestoreSessionAtLaunch</key> <false/> <key>NewWindowBehavior</key> <integer>0</integer> <key>NewTabBehavior</key> <integer>0</integer> <key>HomePage</key> <string>http://HOMEPAGE_URL</string> </dict> </dict> </array> </dict> </dict> </dict> </array> </dict> </plist>
The profile can then be installed for a specific user through a script:
/usr/bin/profiles -I -F /path/to/profile.mobileconfig -U $USER
Google Chrome
The same concept applies for Google Chrome:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>PayloadIdentifier</key> <string>com.laurenceschool.profile.chrome.20161113</string> <key>PayloadRemovalDisallowed</key> <true/> <key>PayloadScope</key> <string>System</string> <key>PayloadType</key> <string>Configuration</string> <key>PayloadUUID</key> <string>6A53E33E-A9E8-11E6-80F5-76304DEC7EB7</string> <key>PayloadOrganization</key> <string>Laurence School</string> <key>PayloadVersion</key> <integer>1</integer> <key>PayloadDisplayName</key> <string>Google Chrome Homepage</string> <key>PayloadContent</key> <array> <dict> <key>PayloadType</key> <string>com.apple.ManagedClient.preferences</string> <key>PayloadVersion</key> <integer>1</integer> <key>PayloadIdentifier</key> <string>com.laurenceschool.profile.chrome.20161113</string> <key>PayloadUUID</key> <string>BC8C5630-A9E9-11E6-80F5-76304DEC7EB7</string> <key>PayloadEnabled</key> <true/> <key>PayloadDisplayName</key> <string>Sets the Chrome HomePage attribute and locks it in place.</string> <key>PayloadContent</key> <dict> <key>com.google.Chrome</key> <dict> <key>Forced</key> <array> <dict> <key>mcx_preference_settings</key> <dict> <key>AutoFillEnabled</key> <false/> <key>DefaultBrowserSettingEnabled</key> <false/> <key>BookmarkBarEnabled</key> <true/> <key>HideWebStorePromo</key> <true/> <key>HomepageIsNewTabPage</key> <false/> <key>HomepageLocation</key> <string>http://HOMEPAGE_URL</string> <key>PasswordManagerEnabled</key> <false/> <key>RestoreOnStartup</key> <integer>4</integer> <key>RestoreOnStartupURLs</key> <array> <string>http://HOMEPAGE_URL</string> </array> <key>ShowHomeButton</key> <true/> <key>SyncDisabled</key> <false/> <key>DefaultNotificationsSetting</key> <integer>2</integer> <key>ImportAutofillFormData</key> <false/> <key>ImportBookmarks</key> <false/> <key>ImportHistory</key> <false/> <key>ImportHomepage</key> <false/> <key>ImportSearchEngine</key> <false/> <key>ImportSavedPasswords</key> <false/> </dict> </dict> </array> </dict> </dict> </dict> </array> </dict> </plist>
Firefox
Firefox, however, does not support MCX or Configuration Profile management. There is a third party extension that allows customizing preferences and then exporting them as an add-on package. For our purposes, we will create an override autoconfig.js file inside the app directory itself. The JS file will initially point to a CFG file. This allows us to lock the settings using javascript:
// This file is saved to // Firefox.app/Contents/Resources/defaults/pref/autoconfig.js pref("general.config.filename", "firefox.cfg"); pref("general.config.obscure_value", 0);
// This file is saved to // Firefox.app/Contents/Resources/firefox.cfg // Disable updater lockPref("app.update.enabled", false); // make absolutely sure it is really off lockPref("app.update.auto", false); lockPref("app.update.mode", 0); lockPref("app.update.service.enabled", false); // Disable Add-ons compatibility checking clearPref("extensions.lastAppVersion"); // Don't show 'know your rights' on first run pref("browser.rights.3.shown", true); // Don't show WhatsNew on first run after every update pref("browser.startup.homepage_override.mstone", "ignore"); // Set default homepage lockPref("browser.startup.homepage","http://HOMEPAGE_URL"); // Disable the internal PDF viewer pref("pdfjs.disabled", true); // Disable the flash to javascript converter pref("shumway.disabled", true); // Don't ask to install the Flash plugin pref("plugins.notifyMissingFlash", false); // Plugin checking lockPref("plugins.hide_infobar_for_outdated_plugin", true); clearPref("plugins.update.url"); // Health reporter lockPref("datareporting.healthreport.service.enabled", false); // Telemetry and FHR lockPref("datareporting.policy.dataSubmissionEnabled", false); // Crash reporter lockPref("toolkit.crashreporter.enabled", false); Components.classes["@mozilla.org/toolkit/crash-reporter;1"].getService(Components.interfaces.nsICrashReporter).submitReports = false; // Popup blocker lockPref("dom.disable_open_during_load", true); // Popup whitelist Components.utils.import("resource://gre/modules/Services.jsm"); Components.utils.import("resource://gre/modules/NetUtil.jsm"); Services.perms.add(NetUtil.newURI("http://ALLOWED_URL"), "popup", Services.perms.ALLOW_ACTION); // Set default search engine Components.utils.import("resource://gre/modules/Services.jsm"); var searchService = Services.search; var engine = searchService.getEngineByName("Google"); searchService.currentEngine = engine;
Note: This configuration will reset with each update to the app since Munki will override the actual app. This deployment should be forced to check for the presence of those two files so that it will continue to apply with every Firefox update.
Signing Configuration Profiles
Custom profiles, or profiles created outside of Profile Manager/Apple Configurator, are not signed. We can sign them manually with a trusted certificate from the Apple Developer program.
Sign in to the Developer portal and download a Mac Developer Application cert. After it’s installed to the keychain, verify that it’s available as a code signing identity:
/usr/bin/security find-identity -p codesigning -v
Then use it to sign a profile:
/usr/bin/security cms -S -N "3rd Party Mac Developer Application: NAME (XXXXXX)" -i /path/to/profile.mobileconfig -o /path/to/signedprofile.mobileconfig
The resulting profile will now appear verified to the user.