Install Workspace ONE UEM SCIM Adapter on Photon OS

Joe Rainone & Matt Williams have created an awesome piece of work called Workspace ONE SCIM Adapter, it has been released as a fling, read more about here:
In a nutshell, it provides capability to do SCIM provisioning into Workspace ONE UEM.
This blog post is about installing this component on VMware Photon OS, it is meant to be educational so no script here :).

What is Photon OS

If you missed the news, VMware photon OS is a lightweight container ready Linux distribution. Created by VMware, in 2015, it help having a quick Linux base for deploying container anywhere. For example, vCenter appliance 6.5+ run on Photon OS.
More info:

How to deploy Photon OS

Photon OS can be deployed on multiple type of layer, Azure, Amazon, vSphere, Google Cloud, you name it (yes, Raspberry is in the list).
This blog post assume that you already have deployed Photon OS, meaning network is up, you have either root or sudo permission and you can either type command in the console or SSH to it.
You can follow the documentation from here :

Preparation for the installation

Workspace ONE UEM SCIM Adapter have some prerequisites, detailed here :

Software Installation

The adapter requires NodeJS to run. To install it, run

tdnf install nodejs

The adapter is packed as a tar.gz archive. Photon don’t include tar by default, so you need to install it.

tdnf install tar


Photon OS use iptables and block any port from the outside.
The adapter can run on any port, the default port is 9000.

Open Port

iptables -A INPUT -p tcp --dport 9000 -j ACCEPT

Save IPtables configuration

This will save the configuration for IPv4

iptables-save > /etc/systemd/scripts/ip4save

This will save the configuration for IPv6

iptables-save > /etc/systemd/scripts/ip6save

If you want to enable the port on both IPv4 and IPv6, you need to execute both commands.

Service Account

We are going to run the adapter with a service account, to create it:

useradd --system --no-create-home --shell /bin/bash --user-group ws1scimadapter


Create the directory, which will contain the SCIM adapter. In this blog, I’m going to use /opt/ws1scim but you can use anything else.

mkdir --parents --mode=755 /opt/ws1scim

We now need to change /opt permission to allow other user to read and execute, mkdir only add 755 from the above command on the final directory.

chmod 755 /opt

As we are using a service account, the log folder need to be created and owner changed as the service account can’t write in the /var/log folder

mkdir --mode=755 /var/log/ws1scim/
chown ws1scimadapter:ws1scimadapter /var/log/ws1scim/


You will need to upload the archive onto the server. My favorite way is curl from a web server as curl is by default on Photon OS and don’t require any SSH/SFTP.

curl http://mywebserver.domain.tld/files/WS1SCIMAdapter/ws1_uem_scim_adapter.tar.gz -o /root/ws1_uem_scim_adapter.tar.gz

Adapter Installation

The installation is straight forward. Extract the archive content in the folder previously created.
Change archivelocation and installationfolder accordingly.

tar -xzvf <archivelocation>/ws1_uem_scim_adapter.tar.gz -C <installationfolder>


tar -xzvf /root/ws1_uem_scim_adapter.tar.gz -C /opt/ws1scim

Adapter Configuration

Now the adapter have been installed, we need to configure it.
Edit the file plugin-airwatch.json in installationfolder

vi /opt/ws1scim/config/plugin-airwatch.json


  • port to change the network port, this should the same port as defined in the iptables rule created earlier.
  • localhostonly to false, if you plan to use an external reverse proxy
  • baseUrl to the API server url defined in “Sites URL” in UEM
  • tenantCode to the dedicated API Key generated at the customer OG
    "scimgateway": {
      "scimversion": "2.0",
      "loglevel": "info",
      "localhostonly": false,
      "port": 9000,
      "auth": {
    "endpoint": {
      "entity": {
        "undefined": {
          "baseUrl": "https://{APIServerURL}/api",
          "username": null,
          "password": null,
          "tenantCode": "{RESTAPIKey}"

Persistent runtime

Photon OS use SystemD as the daemon system, we are going to use it to start and stop NodeJS.
We are going to create a daemon file:

vi /etc/systemd/system/ws1scimadapter.service

With the following content:
Change installationfolder to the folder created previously.

Description=Workspace ONE UEM SCIM Adapter

ExecStart=/usr/bin/node <installationfolder>/index.js


Once we have created the daemon file, we need to enable it to start at boot time.

systemctl enable ws1scimadapter

And finally, we can start it

systemctl start ws1scimadapter


To validate that the adapter is up and running, do a curl on localhost first.

curl -vv http://localhost:9000/ping

You should have hello response

[email protected] [ ~ ]# curl -vv http://localhost:9000/ping
*   Trying
* Connected to localhost ( port 9000 (#0)
> GET /ping HTTP/1.1
> Host: localhost:9000
> User-Agent: curl/7.61.1
> Accept: */*
< HTTP/1.1 200 OK
< Content-Type: text/plain; charset=utf-8
< Content-Length: 5
< Date: Mon, 10 Jun 2019 12:11:58 GMT
< Connection: keep-alive
* Connection #0 to host localhost left intact
[email protected] [ ~ ]#

The second test is to access from a another machine to validate that the service is not blocked by iptables, this test only works if localhostonly is set to false in the plugin-airwatch.json file.


curl -vv http://<ipaddess>:9000/ping


Invoke-WebRequest -Uri http://<ipaddess>:9000/ping


If the service doesn’t start, you need to have a look with the following command.

journalctl --unit=ws1scimadapter

If the error state it can’t access a file make sure the ws1scimadapter user can access the folders, you can use the following command to logon as the service account and navigate the folders

su -l ws1scimadapter

What’s next ?

Secure the Adapter

We have now the service up and running on Photon OS.
This service need now to be exposed to the internet, however has the adapter don’t take care of certificate, it’s a HTTP service, we need to secure it with a reverse proxy, either on the machine itself or an external one.
As directory synchronization can be long, the reverse proxy should have a 60 minutes timeout as a best practice.

Directory Configuration

We also need to configure the directory (i.e: Azure AD, Okta, etc.) to point to the adapter.

For the configuration of Azure AD, follow Matt’s post here:

Comment, Feedback, Bug

For anything related to the fling, comment, bug, feedback, go to

Finally, if you have any comment on this blog post, feel free to comment here.