WS1 UEM SCIM Adapter

Today is an exciting day. It’s my first experience developing a VMware Fling, and it’s is the GA release of what Joe Rainone and I put hours of laborious love into. Identity is not only our day job, but also an area that we are both very passionate about. Our belief is that this Fling, while unsupported, answers a question that many of our customers ask when designing production Workspace ONE deployments. Take a look, play around, and please provide feedback here!

What is the Fling about?

The SCIM protocol is quickly modeling after what SAML brought to identity management almost 15 years ago: a common way to establish resource identity in a service-to-service architecture. Gone are the days where LDAP and Active Directory are the primary systems of record. This concept is particularly enhanced as EUC platforms like Microsoft Azure, VMware Workspace ONE, and others provide native directory services while maintaining a common identity among themselves and their relying parties. Furthermore, the burden of maintaining ‘connector’-like infrastructure for the sole purpose of identity synchronization not only diminishes the value of cloud-based identity stores, but also fosters dependence on secondary technology that isn’t critical to cloud-first initiatives.

The Workspace ONE UEM SCIM Adapter was created by Joe and I to address this very gap in Workspace ONE: AD/LDAP dependence for identity sourcing. In short, the Fling “provides user and group resource management capabilities to Workspace ONE UEM. The middleware translates the System for Cross-Domain Identity Management, SCIM, to a CRUD REST framework that Workspace ONE UEM can interpret. This capability allows Workspace ONE UEM to synchronize cloud-based identity resources (users/groups/entitlements) without the need for an LDAP endpoint (service to service model).” We’ve finished testing with Azure AD, and are far down the path of enabling Okta Universal Directory as a documented source system.

A brief look at the flow from Azure AD to WS1 UEM using this Fling:

Azure AD User SCIM Provisioning Flow

Deploying on Bitnami

The gory details around prerequisites, functionality, and process map are all included here and in the README contained in the tar file. What isn’t included, and the focus of this post, is an example deployment using real-world architecture. Check out Camille’s post on a directions for deploying on Photon OS, or continue reading for step-by-step guidance to deploy on Bitnami Certified Node.js. Side note, VMware recently announced its acquisition of Bitnami. Interesting point of inflection…

Overview of Deployment Procedure

  1. Deploy and Configure Bitnami Certified Node.js Appliance
  2. Upload and extract Fling tarball
  3. Install and Configure SCIM Adapter
  4. Start Apache and ws1scim services
  5. Enable Azure AD provisioning

As mentioned in the prerequisites, I will assume that you have environmental settings in place, such as a working and properly licensed Azure AD tenant, WS1 UEM 1810+ tenant, and the plumbing in between to enable the Azure AD provisioning functions.

Deploy and Configure Bitnami

Bitnami offers several flavors of this appliance. YMMV depending on choice, but the configuration should remain the same regardless. I’m partial to the AWS EC2 offering and will be using it to document the below. Once your appliance is deployed:

1. Install an SSL certificate from LetsEncrypt via SSH:

sudo /opt/bitnami/letsencrypt/scripts/generate-certificate.sh -m {YOUREMAIL} -d {YOURDOMAIN}

2. Configure Apache to step-up all HTTP to HTTPS:

sudo vim /opt/bitnami/apache2/conf/bitnami/bitnami.conf

Replace the <VirtualHost _default_:80> block with the following:

<VirtualHost _default_:80>
  DocumentRoot "/opt/bitnami/apache2/htdocs"
  RewriteEngine On
  RewriteCond %{HTTPS} !=on
  RewriteCond %{HTTP_HOST} !^(localhost|127.0.0.1)
  RewriteRule ^/(.*) https://%{SERVER_NAME}/$1 [R,L]

  # Error Documents
  ErrorDocument 503 /503.html

  # Bitnami applications installed with a prefix URL (default)
  Include "/opt/bitnami/apache2/conf/bitnami/bitnami-apps-prefix.conf"
</VirtualHost>

Then, restart Apache:

sudo /opt/bitnami/ctlscript.sh restart apache

Upload and Extract Fling

1. Download the latest version of the Workspace ONE UEM SCIM Adapter

2. From within your download directory, open an SCP connection and upload to Bitnami:

scp ./ws1_uem_scim_adapter_1906.ga.tar.gz bitnami@scim.virtualprivateer.com:/home/bitnami/

3. Create a new file called ~/install.sh and set the execute permission:

touch ~/install.sh && chmod 755 ~/install.sh

4. Copy the following into ~/install.sh with your favorite text editor (i.e. vim) and save it:

#! /bin/sh

# Install Workspace ONE UEM SCIM Adapter to apps/ws1scim and set configuration parameters

# Declarations
DOWNLOADPATH="/home/bitnami"
INSTALLPATH="/opt/bitnami/apps/ws1scim"
FLINGNAME="ws1_uem_scim_adapter_1906.ga.tar.gz"
CONFIGPATH="config/plugin-airwatch.json"
LOGDIR="/var/log/ws1scim"
APACHEPATH="/opt/bitnami/apache2/conf"
RESTARTCTL="/opt/bitnami/ctlscript.sh"

# Service User
SERVICEACCOUNT="ws1scim"

# Binary locations
TARPATH="/bin/tar"
SEDPATH="/bin/sed"
MKDIRPATH="/bin/mkdir"
CHOWNPATH="/bin/chown"
CHMODPATH="/bin/chmod"
ADDUSERPATH="/usr/sbin/adduser"
NODEPATH="/opt/bitnami/nodejs/bin"
CURLPATH="/opt/bitnami/common/bin/curl"

# Check if being run as root
if [ `id|sed -e s/uid=//g -e s/\(.*//g` -ne 0 ]; then
    echo "You need to be root for this to work"
    exit 1
fi

# Create the service account
$ADDUSERPATH --system --no-create-home --shell /bin/bash --disabled-password --disabled-login --group $SERVICEACCOUNT

# Create install and log directories
echo "Creating directories at ${INSTALLPATH}"
$MKDIRPATH /opt/bitnami/apps
$MKDIRPATH /opt/bitnami/apps/ws1scim
echo "Creating log directory at ${LOGDIR}"
$MKDIRPATH $LOGDIR
$CHOWNPATH $SERVICEACCOUNT:$SERVICEACCOUNT $LOGDIR
$CHMODPATH 750 $LOGDIR

# Unpack files
echo "Unpacking files to ${INSTALLPATH}"
$TARPATH -zxf $DOWNLOADPATH/$FLINGNAME -C $INSTALLPATH

# Set configuration parameters
echo "Configuring Workspace ONE UEM SCIM Adapter"
while [ -n "$1" ]; do

    case "$1" in

    --host)
        APIHOST="$2"
        echo "Setting UEM API baseUrl to ${APIHOST}"
        $SEDPATH -i 's#your_api_server#'$APIHOST'#g' $INSTALLPATH/$CONFIGPATH
        shift
        ;;

    --api-key)
        APIKEY="$2"
        echo "Setting UEM API key"
        $SEDPATH -i 's#your_aw-tenant-code#'$APIKEY'#g' $INSTALLPATH/$CONFIGPATH
        shift
        ;;

    --port)
        SVCPORT="$2"
        echo "Setting listening port to ${SVCPORT}"
        $SEDPATH -i 's#9000#'$SVCPORT'#g' $INSTALLPATH/$CONFIGPATH
        shift
        ;;

    *) echo "Option $1 not recognized" ;;
    esac
    shift
done

# Setup Apache hosting
echo "Updating Apache configuration"

# Create the Apache config directory
$MKDIRPATH $INSTALLPATH/conf

# Create link files
echo "Include \"/opt/bitnami/apps/ws1scim/conf/httpd-app.conf\"" > $INSTALLPATH/conf/httpd-prefix.conf
echo "ProxyPass / http://127.0.0.1:${SVCPORT}/" > $INSTALLPATH/conf/httpd-app.conf
echo "ProxyPassReverse / http://127.0.0.1:${SVCPORT}/" >> $INSTALLPATH/conf/httpd-app.conf
echo "Include \"/opt/bitnami/apps/ws1scim/conf/httpd-prefix.conf\"" >> $APACHEPATH/bitnami/bitnami-apps-prefix.conf

# Restart Apache Server
echo "Configuration applied - restarting Apache server"
$RESTARTCTL restart apache

# Start Fling for testing and verification
echo "Starting up Workspace ONE SCIM Adapter for install verification"
$NODEPATH/forever start $INSTALLPATH/index.js

# Need to wait for services
echo "Pausing for 5 seconds while services initiate"
sleep 5

# Verify that applet is listening
echo "Requesting /ping to confirm service is alive"
TESTRESPONSE=$($CURLPATH -k https://localhost/ping)
echo "${TESTRESPONSE}"
if [ $TESTRESPONSE = "hello" ]; then
        echo "Everything checks out - shutting down temporary thread"
        $NODEPATH/forever stop $INSTALLPATH/index.js
        exit 0
else
        echo "Something went wrong - make sure Apache is up and listening for HTTPS with valid certificate"
        $NODEPATH/forever stop $INSTALLPATH/index.js
        exit 1
fi

Install and Configure SCIM Adapter

1. Install the service and it’s dependencies (include quotes around API key and trailing line break to prevent carriage return):

sudo ~/install.sh --host {uem_api_server} --api-key "{your_customer_og_tenant_code}" --port {port_for_service_to_bind}

For example:

sudo ~/install.sh --host cn000.awmdm.com --api-key "abc123thisisbase64==" --port 9000

After you press ‘Enter’, you should see a series of log lines indicating progress, steps taken, and the result of verification. Lastly, to persist the applet:

2. Create a Systemd target file by pasting the below into /lib/systemd/system/ws1scim.service

[Unit]
Description=index.js - ws1scim wrapper
Documentation=https://labs.vmware.com/flings/workspace-one-uem-scim-adapter
After=network.target

[Service]
Type=simple
User=ws1scim
ExecStart=/opt/bitnami/nodejs/bin/node /opt/bitnami/apps/ws1scim/index.js
Restart=on-failure
StandardOutput=file:/var/log/ws1scim/ws1scim.log
StandardError=file:/var/log/ws1scim/ws1scim.log

[Install]
WantedBy=multi-user.target

Start SCIM Adapter Services

1. Reload the Systemd daemon and start the SCIM Adapter service

sudo systemctl daemon-reload && sudo systemctl start ws1scim

You can run a quick test from your web browser by going to http://{YOURDOMAIN}/ping. A successful test will promote your connection to https with a valid certificate, and display ‘hello’ in the body.

Enabling Azure AD Provisioning

Time to conjure up the magic. Assuming you have met the prerequisites and successfully deployed the Fling, head over to Azure AD and select your WS1 UEM enterprise application configuration. Then, select ‘Provisioning’.

1. Change the Provisioning Mode from Manual to Automatic:

2. Set the ‘Tenant URL’ to https://{YOURDOMAIN}/scim and the ‘Secret Token’ to base64 encode of your WS1 UEM API admin. Press ‘Test Connection’ to confirm the settings, then press ‘Save’ before moving forward:

3. Expand ‘Mappings’, then select “… Groups to customappsso”:

4. Change the ‘objectId’ AAD Attribute mapping to ‘displayName’, press ‘Save’, then close the ‘Attribute Mapping’ blade:

5. In the ‘Mappings’ section, select “… Users to customappsso”:

6. Perform the actions in the following screenshot to map the 7 supported attributes, press ‘Save’, then close the ‘Attribute Mapping’ blade (see second screenshot for changing ‘externalId’ mapping to ‘immutableId’):

7. Select the ‘Users and groups’ blade, then select ‘Add user’ to entitle users and/or groups to the WS1 UEM environment (recommend starting with small subset for testing):

8. Once you have entitled resources, select the ‘Provisioning’ blade once more, then toggle the ‘Provisioning Status’ option to ‘On’, confirm the ‘Scope’ is set to ‘Sync only assigned users and groups’, then press ‘Save’:

After a few moments (depending on sync size), you will notice Azure AD feedback indicate that objects have been created in the target system:

Confirming the resource residence in Workspace ONE UEM Admin Console (first screenshot showing users, second showing group and membership):

In a deprovision event (account disabled, resource entitlement removed, etc), a ‘softDelete’ is transmitted for user resources which disables the account in Workspace ONE UEM. Groups are hard deleted if they’re removed from the enterprise application in Azure AD.

Lastly, testing indicates that Azure AD runs an incremental sync on the last known watermark every 20 minutes or so. This is subject to change, but has been consistent over the recent past.

The World is Your Oyster

Joe and I sincerely hope you enjoy the functionality this Fling has to offer. We are very interested in your feedback, so please provide us with comments and bug requests as they arise.

Tags: , , , , , ,