ENSv2 Database

ENS Database Schema

The ENS system leverages Amazon RDS(SQL Server) instance for its data persistence needs and makes use of 3 main tables.

EnsSubscriptionInfo

Keeps all user records with keys needed for decryption of url callbacks and device tokens to send messages to

APITokens

Keeps all valid API tokens for authenticating with the API

EWSUrlCache

Security

For security, apart from leveraging best practices defaults followed by Amazon on their RDS instances, the following has been enforced to protect customers data and integrity of the system:

  1. Database never contain user’s emails or passwords. All identification is done via the userId that gets matched to a public/private key pair
  2. Database access by ENS machines is limited via a single AWS IAM account with limited role, it has read/write records permission but no database/table level access.

API/Services Client Authentication

Authentication by clients is done via API keys created by us. The API token is sent as a header parameter (key: “ApiToken”) for all outgoing connections and authenticated by ENS server by checking against a table of authorized API keys. The api key is provided to the clients via a configuration pushed down by the console. Each VMware/Airwatch client is provided 1 API key for all their devices.
API Keys can be revoked and invalidated as explained in the API Key Revocal/Refresh section.

Boxer client activation via console

There are some keys that can be configured via console to activate the feature on Boxer iOS. These are described in Managed App Configuration

API/Services Provided by ENS Server to client devices.

Alive: Used to determine if ENS the service is up and running.

Task Endpoint Description Params
REQUEST/GET /alive Check if the system is currently up -

Get Public Key:

Gets a public key from the server.

Task Endpoint Description Params
REQUEST/POST /getpublickey Based on email passed, ENS server creates a record with a public/private key pair and a userId. At this point no devices are added and registered = false userid = sha256Hash( lowercase(email))
RESPONSE { pubKey = <public key value including header/footer>, userid = , responseCode = <response_code> }

Register Device V2:

Register devices so ENS starts monitoring its email Inbox Task: REQUEST/POST Endpoint: /registerdevicev2 Description: Based on credentials passed, ENS should now autodiscover what is the EWS endpoint it needs to subscribe to for push notifications. Upon receiving a success it will update the registered column in the DB to true and the endpoint as well. Any errors should be reported to the client. Note: We can force a registerdevicev2 call to ignore current user status (including Subscribed) and force a resubscription by putting a “force” flag equal to 1 in the payload Params:

userid = sha256Hash( lowercase(email))

email = email address of the user to aid in autodiscovery.

*creds = {
apnsToken: <device apns token>,
ewsUrl: <EWS endpoint url>,
**oauthAccessToken: <oauth access token>,
**userName: <username for account>,
**password: <password for accounts>,

**CBAData: {
certificate: <pkcs12 certificate>
password: <certificate password>
}
}

bundleid = string with application id
exchVersion = integer specifying which exchange version is to be used first on autodiscovery
force = parameter that forces the server to ignore the users current status (subscribed) and redoes the registration completely
defaultSound = string with soundname to be returned back on the notification payload.
ewsDeviceId = Eas device identifier which will be sent to SEG to evaluate the policies, depending on allowed status we will send the notification to device.

*parameter is encrypted with publickey and encoded in base 64. base64(RSAEncryptWithKey(creds))  
**optional values depending on authentication type

Response:

{  
responseCode = <response_code>
}

Unregister:

Tells the server that we want to remove a specific device from using push notifications. Task: REQUEST/POST Endpoint: /unregister Description: Based on userId and device token passed ENS will update corresponding record.

  1. Get record and list of devices
  2. Remove device, and Update Record
  3. If its last device on list unregister from Exchange push subscription, and delete record Params:
userid = sha256Hash( lowercase(email))  
token =  
base64(RSAEncryptWithKey(apnstoken, ensPublicKey))

Response:

{  
responseCode = <response_code>
}

Update Device:

Task: REQUEST/POST Endpoint: /updatedevice Description: Based on userId and device token passed ENS will update corresponding record.

  1. Get record and list of devices
  2. Replace old token for new one
  3. Update Record or delete record Params:
userid = sha256Hash( lowercase(email))  
token =  
base64(RSAEncryptWithKey(apnstoken, ensPublicKey))

Response:

{  
responseCode = <response_code>
}

### Get Subscription Status V1 and V2:
This service let's us "checkin" with ENS to keep our subscription active as well as help clients know if they need to resubscribe. This is also helpful for debugging purposes
Task: REQUEST/POST
Endpoint: /getsubscriptionstatus
Description: Based on userId passed, ENS checks what is the corresponding status for that account
Params:
```json
userid = sha256Hash( lowercase(email))  
lastMessageDate = string date "MM/dd/yyyy HH:mm:ss.SSS"

Endpoint: /getsubscriptionstatusv2 Description: Based on userId-devicetoken passed, ENS checks what is the corresponding status for that account. This was introduced so we could have more granularity and be able to better cleanup “stale” records for users who may not be using device anymore Params:

userid = emailhash string  
*subscriptionPayload = {  
pushToken: <apnsToken>  
lastMessageDate: <string date "MM/dd/yyyy HH:mm:ss.SSS"> ignoreLastMessageDate: <1 or 0>
}

*parameter is encrypted with publickey and encoded in base 64. base64(RSAEncryptWithKey(subscriptionPayload))  
= base64(RSAEncryptWithKey(apnstoken, lastMessageDate)) note: lastMessageDate format = "MM/dd/yyyy HH:mm:ss.SSS"

Update Sync Key:

Register devices so ENS starts monitoring its email Inbox Task: REQUEST/POST Endpoint: /updatesynckey Description: Based on information sent, we update the background sync key and expiration time of the system which is sent down to the device with each push notification. Params:

userid = sha256Hash( lowercase(email))

*info = {
apnsToken: <device apns token>,
backgroundSyncKey: <new background sync key>,
syncKeyExpirationTime: <expiration time of sync key in UTC "MM/dd/yyyy HH:mm:ss.SSS">
}  

*parameter is encrypted with publickey and encoded in base 64. base64(RSAEncryptWithKey(info))

Extra Header parameters:

On each request we can send some extra parameters which influences how ENS handles the subscriptions as well.

  1. badge - Whenever we send this on the header of a request (with value 1) we know that this device needs to be badged and hence ENS will include the badge on every notification that it sends down
  2. development - This header needs to be included (with value 1) to know that this request is coming from a development device/build. This helps in sending the push notification to the correct push notification environment among other things we do server side that are special to development devices.

Response Codes for applicable services:

• UserSubscriptionNotFound
• UserRecordPresentNotSubscribed • UserAlreadySubscribed
• UserUpdated
• UserSubscribed
• DeviceUnregistered • UpdateSuccess • UpdateFail

API Key Revocal/Refresh:

ENS server machines keep a cache of all API keys to speed up the process of validating every single call they receive. They refresh their keys on a schedule so that we can confidently remove api tokens and make them unusable

Encryption:

The ENS system uses asymmetric key encryption to keep all customer data transferred safe and invulnerable to various types of malicious attacks. Specifically, we use RSA Encryption to encrypt any crucial data passed around from client/server (see API/Services section for details).

A public key is created per user and is provided to the client upon authenticated request. Using this key, RSA encryption following PKCS1 standards needs to be performed on the client side for any services requiring it.