Approve Or Deny GSuite Access For Devices

The Google Directory integration with GSuite allows you to manage which devices have access to GSuite. This allows you to control access based on a variety of factors.

Below, you’ll find a Google Cloud Function that is meant to respond to a webhook. This function takes an action to set a device into ‘approve’ or ‘deny’ as a state within Google Directory. Before using the function you’ll want to set CustomerID, ResourceID, and EMAIL_ACCOUNT for your GSuite account before using.

Once you have all that, you can upload mobiledevice.py in your Google Cloud Console.

#
# Google Cloud Function meant to respond to a webhook
# Takes an action to set a device into approve or deny state
# Set CustomerID, ResourceID, and EMAIL_ACCOUNT for your GSuite account before using
#

from google.oauth2 import service_account
import googleapiclient.discovery

SCOPES = ['https://www.googleapis.com/auth/admin.directory.device.mobile']
SERVICE_ACCOUNT_FILE = 'auth.json'
EMAIL_ACCOUNT = ''


def get_credential():
credentials = service_account.Credentials.from_service_account_file(SERVICE_ACCOUNT_FILE, scopes=SCOPES)
delegated_credentials = credentials.with_subject(EMAIL_ACCOUNT)
# admin = googleapiclient.discovery.build('admin', 'directory_v1', credentials=credentials)
admin = googleapiclient.discovery.build('admin', 'directory_v1', credentials=delegated_credentials)
return admin


def get_mobiledevice_list(admin, customerId):
results = admin.mobiledevices().list(customerId=customerId).execute()
mobiledevices = results.get('mobiledevices', [])
print('mobile devices name and resourceId')
for mobiledevice in mobiledevices:
print(u'{0} ({1})'.format(mobiledevice['name'], mobiledevice['resourceId']))
return results


def action_mobiledevice(admin, customerId, resourceId, actionName): # actionName: "approve", "block",etc body = dict(action=actionName)
results = admin.mobiledevices().action(customerId=customerId, resourceId=resourceId, body=body).execute()
return results


def main():
admin = get_credential()
customerId = ''
resourceId = ''
action = "approve"
#action = "block"

mobiledevice_list = get_mobiledevice_list(admin, customerId)
print(mobiledevice_list)

action_mobiledevice(admin, customerId, resourceId, action)
print ("Approved successfully")


if __name__ == '__main__':
main()

This is likely to evolve, given that you’ll likely want to migrate your settings into a database as part of your build process, but the general logic is here for now. Happy Googleatinging!

Obtain A List Of Devices or Apps In ZuluDesk Using Bash

The curl command can be used to authenticate to an API using a variety of authentication types such as Bearer, OAuth, Token, and of course Basic. To authenticate to the ZuluDesk API, first create an API token. This is done by logging into ZuluDesk, clicking Organization, then Settings, then API, an then clicking on the Add API Key button.

Once you have your API key, your header will look as follows:

GET /users HTTP/1.1 User-Agent: curl/7.24.0 X-Server-Protocol-Version: 2 Authorization: Basic YOURTOKENHERExxx000111222== Content-Length: 0

The curl command can do this would be as follows, simply converting these into separate values in the -H or header. The URL provided will do a GET against devices, displaying a list of devices in json:

curl -S -i -k -H "Content-Length: 0" "User-Agent: curl/7.24.0" X-Server-Protocol-Version: 2" "Authorization: Basic YOURAPITOKENxx000111222==" https://apiv6.zuludesk.com/devices/

Once you have the “serialNumber” you can programmatically perform a number of other tasks using a POST. Another example would be obtaining a list of apps, done using the /apps/ endpoint.

curl -S -i -k -H "Content-Length: 0" "User-Agent: curl/7.24.0" X-Server-Protocol-Version: 2" "Authorization: Basic YOURAPITOKENxx000111222" https://apiv6.zuludesk.com/apps/

You can also run a POST in the same fashion. In the following we’ll do that, sending a simple delete command to the group 505

curl -X DELETE -S -i -k -H "Content-Length: 0" "User-Agent: curl/7.24.0" X-Server-Protocol-Version: 2" "Authorization: Basic YOURAPITOKENxx000111222" https://apiv6.zuludesk.com/users/groups/:505

Overall, the ZuluDesk API is pretty easy to use and follow with just some basic curl commands.

Register A Webhook In Jamf Pro

A webhook is a small web trigger that when fired can easily send amount of small json to a web listener. Most modern software solutions support webhooks. They provide an easy way to trigger events from a piece of software to happen in another piece of software.

An example of this is when a smart group change happens in Jamf Pro, do something elsewhere. To start, you register a webhook in Jamf Pro by opening an instance of Jamf Pro, clicking on Settings, clicking on Global Management, and then clicking on Webhooks.

Registering Webhooks

From the Webhooks screen, click New.

New Webhook Screen

At the New Webhook screen, you will see a number of fields. Here,

  • Display Name: The name used to identify the webhook in Jamf Pro.
  • Enabled: Check to enable the webhook, uncheck the box to disable the webhook.
  • Webhook URL: The URL that the json or xml will be sent to (note that you’ll need something at this URL to accept your webhook).
  • Authentication Type: None is used for an anonymous webhook and basic can be used to send a username and password to the webhook listener.
  • Connection Timeout: How long the webhook will attempt to open a connection before sending data.
  • Read Timeout: How long the webhook will attempt to send data for before it turns off.
  • Content Type: Choose to send information via xml or json.
  • Webhook Event: The type of event that Jamf Pro can send a hook based on.

The options for webhook events include:

  • ComputerAdded
  • ComputerCheckin
  • ComputerInventoryCompleted
  • ComputerPatchPolicyCompleted
  • ComputerPolicyFinished
  • CoputerPushCapabilityChanged
  • DeviceRateLimited
  • JSSShutdown
  • JSSStartup
  • MobileDeviceCheckin
  • MobileDeviceCommandCompleted
  • MobileDeviceEnrolled
  • PatchSoftwareTitleUpdated
  • PushSent
  • RestAPIOperation
  • SCEPChallenge
  • SmartGroupComputerMembershipChange
  • SmartGroupMobileDeviceMembershipChange

An example of a full workflow would be what we did to trigger a Zapier action, documented at http://krypted.com/mac-os-x/add-jamf-pro-smart-group-google-doc-using-zapier/. Here, we look at sending smart group membership changes to a google sheet so we can analyze it with other tools, a pretty standard use case.

.

Screen Time And Setting Limits For Ourselves And Our Families

Do you know how much time you spend in various apps and on your device? Do you want to gently be reminded of how much time you’re staring at screens and maybe even be limited in how much you can be lost on the screen? 

First, let’s Let’s do this limiting the time you can be on the device in the first place, using a feature of Screen Time called Downtime:

  • Open Settings
  • Tap on Screen Time
  • Tap Downtime

Tap on and then set the start of Downtime and the stop of Downtime. Tap back on Screen Time in the upper left hand corner of the screen. Now, let’s setup an app limit for social apps (because really, most of us are on those wayyyy too much:

  • Open Settings
  • Tap on Screen Time
  • Tap App Limits
  • Tap an app category (e.g. Social Networking)
  • Set the number of hours you can use that type of app (note, if you set 23 hours and 59 minutes you are totally cheating)
  • Tap Add

Should you want to remove those limits you created, just tap Delete Limit. Or better, just configure apps that are allowed to bypass the limits you’ve made by tapping Always Allowed and adding apps that are always allowed to work. This allows you to limit all your apps except, as an example, Maps and Camera. 

Another option in Screen Time is Content and Privacy Restrictions. To configure these:

  • Open Settings
  • Tap on Screen Time
  • Tap on Content & Privacy Restrictions
  • Turn Content & Privacy Restrictions on by tapping the slider
  • Tap on iTunes & App Store Purchases

Here, you can limit installing apps, deleting apps, or making in-app purchases on the device. You can also just force a password in order to make any purchase from iTunes, Book Store purchases, or App Store purchases

  • Tap the back button
  • Tap Allowed Apps
  • Use the indicator light to disable any app you don’t want to be able to access on this profile
  • Once all apps are configured, tap the back button
  • Tap Content Restrictions

There are a lot of restrictions available. Most are mirrored with a profile and so can be controlled by an MDM as well:

  • Country: Start with the country your ratings are set for. 
  • Music, Podcasts, & News: Then, choose what whether or not explicit content is allowed (and by content we really mean music, podcasts, & news). 
  • Music Profiles & Posts: Then choose whether the device is allowed to publish music options and posts about music. 
  • Movies: Then set a maximum AFTRA rating (e.g. PG-13 or R) for content.
  • TV Shows: Select the TV ratings allowed (e.g. TV-G or TV-MA for mature audiences)
  • Books: Luckily, Tipper Gore never got her way so there’s no true rating systems for books. Just select Clean or Explicit.
  • Apps: Choose an age that ratings for apps are most appropriate
  • Web Content: Limit access only to specific websites, limit access to adult websites, or provide unrestricted access to web content
  • Web Search Content: Allow Siri to access the web to search
  • Explicit Language: Allow or restrict Siri from using dirty words
  • Multiplayer Games: Allow or deny access to multiplayer games
  • Adding Friends: Allow or deny access to add friends within the Game Center app
  • Screen Recording: Allow or deny access to screen recordings

Next, go back and in the privacy section, configure what apps are able to access Location Services, Contacts, Calendars, Reminders, Photos, Share My Location, Bluetooth Sharing, Microphone, Speech Recognition, Advertising, Media And Apple Music. 

Finally, under allow changes, configure whether you’ll be able to make changes to Passcode Changes, Account Changes, Cellular Data Changes, Volume Limits, Do Not Disturb While Driving, TV Providers, and Background App Activities. 

Episode 107 of the MacAdmins Podcast: Sweet Rootkits, a Year in Review

It’s been a great year for the MacAdmins Podcast. And a special thank you to Tom, Marcus, Emily, James, and the former co-host Pepijn for continuing to allow me to be a part of something special. The last episode of the year is available at podcast.macadmins.org, using the below embedded link, or wherever you get your podcasts!

New Page Explaining Apple MDM Even Further

Apple has published a new page that goes through all of the settings and commands available via MDM and explains many in much more detail. This is available at http://help.apple.com/deployment/mdm/. The new guide is a great addition to the work @Mosen has done at https://mosen.github.io/profiledocs/ in terms of explaining what each setting, command, and payload do. And let’s not forget the definitive MDM protocol reference guide, available at https://developer.apple.com/library/content/documentation/Miscellaneous/Reference/MobileDeviceManagementProtocolRef/1-Introduction/Introduction.html#//apple_ref/doc/uid/TP40017387-CH1-SW1

Overall, I’m excited to see so much information now available about MDM, including how to develop an MDM properly, what each setting does, and now what you should expect out of an MDM!

Apple Business Manager Documentation Publicly Available

Hey, who knew that the developer documentation for Apple Business Manager would be made publicly available? It’s at https://beta.business.apple.com/static/docs/beta.pdf. Or if it gets taken down, at Apple Business Manager Documentation.

Note: I saw this pop up in like 4 different places. If anyone knows who I can attribute for realizing it was publicly available, please let me know so I can!

Using Managed App Config with Jamf Pro

Hey look, there’s a new category on the Jamf Marketplace, available at https://marketplace.jamf.com/apps/#category=AppConfig,selecting the AppConfig category. The new AppConfig category gives administrators of any MDM that supports AppConfig access to a set of apps that support AppConfig. If you have an app that isn’t listed here, feel free to let me know. 

What does this mean? Well, AppConfig is a way of sending data into an app. App config allows a customer to deploy settings into applications on iOS devices in much the same way that settings can be sent into a Mac app via the defaults command. This means an end user could get an app installed on their device from the iOS App Store, a custom app, or a B2B app and that app would have any settings the user might need to connect to servers or configure the experience.

So what is Managed App Config? At it’s most basic, you identify a label and a value in XML and send it to an iOS device that’s running iOS 7 or later (e.g. via Jamf 9 and up). The vendor who makes the app has to basically define what those settings are. Which brings up an interesting problem never fully addressed with defaults domains: standardization and ease-of-use (although MCX was close). 


AppConfig.org  is a consortium of MDM vendors and software vendors that maintain the emerging AppConfig standards around Managed App Config (within the confines of what Apple gives vendors) and then makes a feed of settings for apps that conform to those standards. Jamf is a founding member of Appconfig.org, along with MobileIron and AirWatch. Examples of what you could put into the AppConfig.org feed include 
  • Enabling certain features of apps
  • Server URLs
  • Logos (if they’re pulled dynamically)
  • Text labels
  • Language packs

To see a list of apps that are available, check out http://www.appconfig.org. 

Managed App Config options are set by vendors at compile time within the code and then the XML sent with the app is parsed by the app at installation time. If you’re a software vendor who wants to get started with AppConfig, check out the Spec Creator from Jamf Research or get in touch with the developer relations team from any MDM vendor.

If you’re a customer of an app and would like to leverage Managed App Config and your vendor isn’t listed on the appconfig.org site, get in touch with them, as this is the future of app management and chances are that you won’t be the only organization looking to unlock this type of feature. 

Let’s look at how this actually works. The Managed App Config options per supported app are available on a feed. The feed is available at http://d2e3kgnhdeg083.cloudfront.net. Here, as follows, you’ll see a list of all of the apps supported.


You can then copy the path for an app, such as com.adobe.Adobe-Reaser/1/appconfig.xml and append it to the end of the URL to get the feed for that specific app. You can test this using http://d2e3kgnhdeg083.cloudfront.net/com.adobe.Adobe-Reader/1/appconfig.xml to see output as follows.


Here, note that most of these fields are key value pairs defined by Adobe (in this example at least). You can enable or disable features of Adobe Reader using these keys. The same is true with a tool like Box that might want a more granular collection of settings than a feature like Managed Open In. 

Once you have the XML, you can then copy it to the clipboard and paste it into the App Configuration tab of an app, as follows. 

Finally, Apple has sample code available at https://developer.apple.com/library/content/samplecode/sc2279/Introduction/Intro.html

Embracing (and managing) tech for your iGen child

I have a new article for Thrive Global (another Arianna Huffington property) available at Thrive Global. This one is on “Tools and best practices on monitoring and teaching your kids responsible mobile device use.” It starts out like this:
My world changed when I awoke one day to find my 4-year-old daughter with a tablet in her hands, watching Transformers. The sight unleashed a handful of worries I hadn’t before experienced. Prior to that morning, I knew her to be fan of Star Wars figures, Legos and stuffed animals. And while I wasn’t displeased by her choice to watch a Michael Bay movie, I did start thinking about what else she could access on the device.
Click here to read more…
Screenshot of "Embracing (and managing) tech for your iGen child"

Get The Title Of An App From Apple App Store URLs

When you’re building and manipulating apps in the Apple App Stores, it helps to be able to pull and parse pieces of data. Here, we’ll look at two strategies that you can use to do so. It’s worth noting that the purpose of this was to use the URL of an app from an MDM and then be able to script updating metadata about the app, given that vendors often change names of the display name of an app (e.g. Yelp is actually called “Yelp: Discover Local Favorites on the App Store”).

First, we’ll grab a URL. This one is for Self Service:

https://itunes.apple.com/us/app/self-service-mobile/id718509958?mt=8

If you don’t know the URL then you can get it based on the ID by parsing the json from:

curl https://itunes.apple.com/lookup?id=718509958

Of course, if you know the id, you can probably just assume that https://itunes.apple.com/us/app/id718509958?mt=8 will work as well, since if you remove the name it has always worked for me (although I’ve never seen that in a spec so I can’t guarantee it will always be true). Then, we can curl it, but the output is a bit not lovely:

curl -s 'https://itunes.apple.com/us/app/self-service-mobile/id718509958?mt=8'

So then we’ll want to just grab the pieces of information we want, which could be done using a variety of scripting techniques. Below, we’ll use grep:

curl -s 'https://itunes.apple.com/us/app/self-service-mobile/id718509958?mt=8' | grep -o "<title>[^<]*" | cut -d'>' -f2-

And here, we’ll use perl:

curl -s 'https://itunes.apple.com/us/app/yelp/id284910350?mt=8' | perl -l -0777 -ne 'print $1 if /<title.*?>\s*(.*?)\s*<\/title/si'

And there you go, you have the title. The title is easy, because it’s a simple title tag. But let’s look at the description:

curl -s 'https://itunes.apple.com/us/app/self-service-mobile/id718509958?mt=8' | awk '/meta name="description"/{;print }'

The output would be similar to the following 

<meta name="description" content="Read reviews, compare customer ratings, see screenshots, and learn more about Self Service Mobile. Download Self Service Mobile and enjoy it on your iPhone, iPad, and iPod touch." id="ember75894226" class="ember-view">

From there it’s pretty simple to extract the exact field you want and the metadata from that field. If you are obtaining names and descriptions for a large number of apps then you’d simply move the path into a variable as follows so you can put it into your loop:

curl -s $appurl | grep -o "<title>[^<]*" | cut -d'>' -f2-

I haven’t covered finding items in the App Store if you don’t know the ID of an app, but there’s a /search endpoint at iTunes.apple.com that will respond to a variety of parameters you can pass:

curl https://itunes.apple.com/search?term=yelp&country=us&entity=software

This wasn’t necessary for my use case. But it’s worth noting. And if you’ll be doing a lot of that, I’d recommend checking out the affiliates portal at https://affiliate.itunes.apple.com/resources/documentation/itunes-store-web-service-search-api/. Additionally, if you’re actually trying to automate the App Store instead, there are a few tools out there to do so, including https://github.com/mas-cli/mas or if you want to extract packages there’s https://github.com/maxschlapfer/MacAdminHelpers/tree/master/AppStoreExtract