Enterprise Directory REST API

Middleware provides a read-write interface to the Enterprise Directory via a REST API located at https://api.middleware.vt.edu/v1.

REST API Client Example

The following code sample in Python provides a simple but complete usage overview that covers authentication and reading/writing data:

import jwt
import json
import requests
import time

# Base URL to Enterprise Directory Web services
base_url = 'https://api.middleware.vt.edu/v1'

# Read ED service private key used to sign authentication tokens
with open('/path/to/ed-id-private-key.pem', 'r') as f:
  key = f.read()

# Create authentication token that is valid for ten minutes
# It may be reused several times in that period
now = time.time();
claims = {
  'iss': 'uusid=your-edid-service,ou=services,dc=vt,dc=edu',
  'iat': int(now),
  'exp': int(now) + 10 * 60
}
token = jwt.encode(claims, key, algorithm='RS256')

# Set up HTTP headers to pass the authentication token
# MUST pass these headers with all requests
headers = {'Authorization': 'Bearer ' + token}

# Query for some groups you own
response = requests.get(base_url + '/groups?uugid=chemistry.*', headers=headers)
groups = json.loads(response.text)
for group in groups:
  print group.uugid

# Set up request headers for POST requests
headers['Content-Type'] = 'application/x-www-form-urlencoded'

# Create a new group that will be nested within an existing group
requests.post(
  base_url + '/groups',
  headers=headers,
  data={'uugid': 'chemistry.chromatographers.experts', 'contact': 'alice', 'administrator': 'bob'})

# Set up request headers for PATCH requests
headers['Content-Type'] = 'application/json'

# Set group expiration date to midnight (UTC) January 1, 2020
# Syntax is described in RFC 6902 JSON Patch
patches = [
  {
    'operation': 'replace',
    'path': '/expirationDate',
    'value': 1514764800
  }
]
requests.patch(base_url + '/groups/chemistry.chromatographers', headers=headers, data=patches)

# Set up request headers for POST requests
headers['Content-Type'] = 'application/x-www-form-urlencoded'

# Add roles one at a time, but multiple requests can be pipelined easily
requests.post(
  base_url + '/groups/chemistry.chromatographers/administrators',
  headers=headers,
  data={'kind': 'person', 'id': 'alice'})
requests.post(
  base_url + '/groups/chemistry.chromatographers/managers',
  headers=headers,
  data={'kind': 'person', 'id': 'mandy'})
requests.post(
  base_url + '/groups/chemistry.chromatographers/managers',
  headers=headers,
  data={'kind': 'service', 'id': 'cos-automation'})
requests.post(
  base_url + '/groups/chemistry.chromatographers/members',
  headers=headers,
  data={'kind': 'person', 'id': 'carl'})
requests.post(
  base_url + '/groups/chemistry.chromatographers/members',
  headers=headers,
  data={'kind': 'person', 'id': 'evelyn', 'expiration', 1514764800})
requests.post(
  base_url + '/groups/chemistry.chromatographers/members',
  headers=headers,
  data={'kind': 'group', 'id': 'chemistry.chromatographers.experts'})

# Set up request headers for DELETE requests
del headers['Content-Type']

# Delete roles one at time, but mulitple requests can be pipelined easily
requests.delete(
  base_url + '/groups/chemistry.chromatographers/administrators/albert',
  headers=headers)

# Delete a group
requests.delete(base_url + '/groups/chemistry.chem101', headers=headers)

REST API Operations Reference

Please see the following reference for a complete list of REST API operations:

Operations Reference

Front Matter

The following sections describe usage requirements and conventions that govern all REST API operations.

Prequisites

There are a couple prerequisites that prospective clients need to consider before attempting to consume the REST API.

Enterprise Directory Service

An ED Service provides the security principal and credential to invoke REST API operations. An ED service is typically credentialed with an X.509 certificate issued by the Middleware CA, but may also have a password credential issued under approved circumstances (see below).

Request an ED Service.

Authorization to Invoke REST API

An ED Service must be entitled to invoke various REST API operations. The entitlements required to invoke various operations are listed in the link:rest-api-operations[Operation Reference]; please make note of what operations you want to invoke and document them by endpoint URI on your ED Service request.

Conventions

The following conventions are intended to facilitate using the API. We recommend committing these conventions, which we have found improves users’ ability to anticipate URIs and JSON document field names.

URI Naming Conventions

  1. Resource URIs are named with a plural resource collection and end in a unique identifier, for example, /v1/persons/[uid], /v1/groups/[uugid].
  2. Action URIs have singular path parts and end in a verb, for example, /v1/replication/banner/consume, /v1/password/validate.

URIs Are Case Sensitive and Lower Case

All URIs are case sensitive and canonically lower case in terms of paths and parameter names that appear in the querystring. Parameter values that appear in the querystring may of course be upper case to support searching for case-sensitive fields like person names, but many data elements are canonically lower case as well, such as uupids and uugids and these are searched in a case-insensitive fashion.

JSON Data Is Case Sensitive and Mixed Case

The fields in JSON documents are named using the mixed-case convention of the Enterprise Directory LDAP schema in order to provide consistency between data elements regardless of what interface is used (LDAP vs HTTP).

Authentication

Three authentication methods are supported and are listed in order of recommended practice:

  1. HTTP Bearer token authentication via signed JWT
  2. Client TLS
  3. HTTP Basic authentication using an ED service password

Password-based authentication is discouraged; consequently ED services do not have passwords unless specifically requested and authorized by the IT Security Office.

HTTP Bearer Auth

The HTTP Bearer token authentication method provides the best balance of security and usability to clients:

  1. Strong security via digital signatures
  2. Excellent cross-platform support
  3. Precise control over token validity period
  4. Suitability for use with Javascript-based Web applications

A signed JSON Web Token (JWT) provides most of the advantages above and is simply a JSON document that is prepended with a digital signature algorithm header and to which a digital signature is appended; all parts are base-64 encoded.

# Line breaks added for readability
# Parts separated by "." character
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ2dC1zZXJ2aWNlIiwiaWF0IjoxNDc2MTgwMTU5LCJleHAiOjE0NzYxODE5NTl9.
QQD51aFptIc9u66iqgxJYyXl8dYP8kPanLtlVOPfeXSk5u_BeZ__QBjEKlCW2TjfFeF8SNHsC6zFMiY-
QJIowaYXaYscJQJhl8FSiOUv0M46DJYYGxlHzdbGS9mUmLw25K1bMlUjSG6phNTxlNogCfUyCrIJ92TlLrpYNegQ78DDLvbxkbTTGdj_6Doe_Q-
oVQ3k2tse6aZaMcGa99JY2imO06RCXt7y9n7gUYFliCwKdhemrPApe-6Sgb-jnxNAIAVzOd42_GHJl9DrFOsRCeNO2hbwQGRszSankj8ZFZEVh-
cy0AFcCxGAdRC9jM3jmfXy32g844CWsevHV2OJCw

The token above contains the following JSON document, which you can see by pasting the token (with line breaks removed) into the jwt.io debugger:

{
  "iss": "uusid=vt-service,ou=services,dc=vt,dc=edu",
  "iat": 1476180159,
  "exp": 1476181959
}

The fields of the JSON document follow an established vocabulary called claims, of which four are recognized for Enterprise Directory Web services:

  1. iss - REQUIRED DN of the ED-ID service that issued (signed) the token, e.g. uusid=vt-service,ou=services,dc=vt,dc=edu
  2. iat - REQUIRED creation (Issued At) date of token
  3. exp - REQUIRED expiration date of token
  4. sub - OPTIONAL DN of the person to impersonate when invoking the service, e.g. uid=12345,ou=people,dc=vt,dc=edu

The presence of a sub claim indicates an impersonation token. The token may contain other claims but they will be ignored.

The validity period of the token is defined as the period of time between the iat and exp claims. There are some important policy controls on validity periods that are enforced at authentication time:

  1. Normal tokens MAY define a validity period of no more than 365 days.
  2. Impersonation tokens MAY define a validity period of no more than 30 days.
  3. The iat claim MAY be up to 30 seconds in the future to account for clock drift between client and server.

Tokens that violate the above policy constraints will be rejected when presented for authentication.

The token MUST be signed with the private key corresponding to a valid (e.g. not expired) ED service certificate and whose service exists and is active in the Enterprise Directory. The signature MUST be produced using the RS256 algorithm.

In general JWT bearer tokens MUST NOT be shared since a bearer token is by nature a self-contained authentication token; whoever bears the token may authenticate and access services as the principal identified in the token.

The exception to this strict requirement is an impersonation token that bears the sub claim. An impersonation token is signed by the private key of the issuer and identifies a person principal named in the sub claim. Thus the service that issued and signed the token is impersonating the named principal.

Impersonation tokens MAY be shared, but care must be taken to share the impersonation token exclusively with the principal named in the sub claim; it MUST NOT be shared with other parties due to its bearer nature.

Despite the need for care, impersonation tokens when used correctly are quite powerful. They can be shared with browser clients such that the bearer token can be passed via Authorization header in script-driven HTTP requests, allowing browser clients to directly interact with the Middleware REST API instead of through a facade or proxy that handles authentication. In the future the Middleware REST API may support OAuth for a more complete and standards-compliant security framework that satisfies the same need.

Sample Shell Script to Generate JWT

export TOKEN=$(gen-bearer-token.py your-service /path/to/your-service.key)
curl -v -XGET -H"Authorization: Bearer $TOKEN" https://api.middleware.vt.edu/v1/groups/your.group

The example code above demonstrates how to construct a valid JWT for use with Enterprise Directory Web services. A python script is available to facilitate generating tokens.

Client TLS Auth

The Enterprise Directory Web services support client TLS authentication with an ED service certificate issued by the Middleware CA, which is chained to the Virginia Tech Root CA. There are two primary configuration points for client TLS authentication:

  1. Client authentication credentials (private key + X.509 certificate containing public key)
  2. Server trusted certificates (one or more root certificates)

The authentication credentials MUST be the ED service certificate (issued by the Middleware CA) and corresponding private key. Middleware CA certificates have a 2-year validity period and must be renewed periodically. Only a single trusted CA certificate is required to communicate with the RESTful Web services.

Issuer: C=US, ST=New Jersey, L=Jersey City, O=The USERTRUST Network, CN=USERTrust RSA Certification Authority
Subject: C=US, ST=New Jersey, L=Jersey City, O=The USERTRUST Network, CN=USERTrust RSA Certification Authority
Serial Number:
    01:fd:6d:30:fc:a3:ca:51:a8:1b:bc:64:0e:35:03:2d
Validity
    Not Before: Feb  1 00:00:00 2010 GMT
    Not After : Jan 18 23:59:59 2038 GMT

-----BEGIN CERTIFICATE-----
MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB
iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl
cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV
BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAw
MjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNV
BAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU
aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2Vy
dGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK
AoICAQCAEmUXNg7D2wiz0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B
3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2jY0K2dvKpOyuR+OJv0OwWIJAJPuLodMkY
tJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFnRghRy4YUVD+8M/5+bJz/
Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O+T23LLb2
VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT
79uq/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6
c0Plfg6lZrEpfDKEY1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmT
Yo61Zs8liM2EuLE/pDkP2QKe6xJMlXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97l
c6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8yexDJtC/QV9AqURE9JnnV4ee
UB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+eLf8ZxXhyVeE
Hg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd
BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8G
A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPF
Up/L+M+ZBn8b2kMVn54CVVeWFPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KO
VWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ7l8wXEskEVX/JJpuXior7gtNn3/3
ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQEg9zKC7F4iRO/Fjs
8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM8WcR
iQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYze
Sf7dNXGiFSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZ
XHlKYC6SQK5MNyosycdiyA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/
qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9cJ2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRB
VXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGwsAvgnEzDHNb842m1R0aB
L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG
jjxDah2nGN59PRbxYvnKkKj9
-----END CERTIFICATE-----

The servers hosting Enterprise Directory Web services are configured for optional client authentication. If a valid client certificate is not provided in the TLS handshake, the connection will proceed with an anonymous client authentication context to allow other mechanisms such as HTTP Bearer or HTTP Basic to proceed.

HTTP Basic Auth

Clients may authenticate with a password credential provided by HTTP Basic authentication if and only if the corresponding ED service has been configured with a generated password. The following code snippet demonstrates HTTP Basic authentication.

# HTTP Basic Authentication Example
from requests.auth import HTTPBasicAuth
import json
import requests

response = requests.get(
  'https://api.middleware.vt.edu/v1/group?uugid=chemistry.*',
  auth=HTTPBasicAuth('vt-service', 'fakepass'))
groups = json.loads(response.text)
for group in groups:
  print group.uugid

Enterprise Directory Resources

There are 6 kinds of resources in the Enterprise Directory Web services that correspond to the branches of the Enterprise Directory LDAP schema. A resource is accessible via an HTTP request made to a URI that identifies the kind of resource and its unique identifier; thus URIs follow the convention +/[api_version]/[resource_collection_name]/[unique_id]+.

There are two related URIs for every resource type:

  1. Resource collection URI (create and bulk fetch resources)
  2. Resource URI (fetch, update, delete resource)

The resource URI is defined by appending the unique ID to the resource collection URI.

Resource Branch ID Resource URI Notes
Person ou=people uid /v1/persons/[uid] person demographic data
Account ou=people pid /v2/accounts/[pid] person PID account details
Mailbox ou=people address /v2/mailboxes/[address] person email account details
Service ou=services uusid /v1/services/[uusid] uusid is the service name
Group ou=groups uugid /v1/groups/[uugid] uugid is the group name
Entitlement ou=entitlements uid /v1/entitlements/[uid] uid is a numeric identifier

Optional Fields

All resources contain numerous fields, and in many cases some fields are expensive to fetch and unnecessary for the use at hand. In order to balance breadth and depth cases, many fields are marked optional and must be explicitly requested when a resource is fetched via the optional with querystring parameter included in the GET request. The syntax for requesting optional fields is follows:

/v1/[resource_collection_name]/[unique_id]?with=section1&with=section2&with=section3

where section1, section2, and section3 are sections denoting a field or field set

The names of optional field sections are documented in the resource schemas that follow and in many cases the section name is the field name since the field is naturally lowercase, otherwise a brief lowercase name is used to describe the section. The all section name is shorthand for requesting that all optional fields be included in the fetched resource. Use of this capability is discouraged for bulk queries that may return large result sets.

Person Resource

The person resource provides information about the identifying characteristics of a Virginia Tech affiliate: name, birthdate, afffiliations, employment information, and student information. It has the following schema (in YAML to allow for comments).

# Resource URI: /v1/person/14142135
{
  "uid": 14142135,
  "displayName": "Alexander Hamsandwich",
  "type": "VT",

  # Use the Account resource for full account details
  "pid": "hammy",

  "mailPreferredAddress": "hammy@vt.edu",
  "dateOfBirth": 876215266,
  "gender": "M",
  "virginiaTechId": "987654321",

  # Optional: with=affiliations
  "affiliations": [
    "VT-ACTIVE-MEMBER",
    "VT-STUDENT",
    "VT-STUDENT-ACTIVE",
    "VT-EMPLOYEE",
    "VT-EMPLOYEE-WAGE"
  ],

  # Optional: with=mailboxes
  # Use the Mailbox resource for full email account details
  "mailboxes": [
    "hammy@vt.edu",
    "hambone@vtc.vt.edu"
  ], 

  # Optional: with=suppressions
  "suppressDisplay": false,
  "suppressions": [
    "uupid"
  ],
  "suppressibleAttributes": [
    "uupid",
    "mailPreferredAddress"
  ],

  # Optional: with=names
  "names": [
    {
      # Allowed types: BANNER, PREFERRED, ALUMNI, SELF_REPORTED
      "type": "BANNER",
      "prefix": "",
      "first": "Alexander",
      "middle": "Mayo",
      "last": "Hamsandwich",
      "suffix": "Jr"
    }
  ],

  # Optional: with=addresses
  "addresses": [
    {
      # Allowed types: HOME, LOCAL, OFFICE, SELF_REPORTED
      "type": "LOCAL",
      "street1": "314 Progress Street",
      "street2": "Apt 5",
      "street3": "",
      "poBox": "",
      "city": "Blacksburg",
      "state": "VA",
      "zip": "24060",
      "country": "US",
      "mailStop": "",
      "phones": [
        {
          # Allowed types: HOME, LOCAL, OFFICE, CELLUAR, FAX, PAGER, SELF_REPORTED
          "type": "LOCAL",
          "number": "5405551212",
          "displayNumber": "540-555-1212"
        }
      ]
    }
  ],

  # Optional: with=social
  "uris": [
    {
      "uid": 27182,
      "label": "Facebook",
      "uri": "https://www.facebook.com/profile.php?id=12345"
    },
    {
      "uid": 27183,
      "label": "Google+",
      "uri": "https://plus.google.com/+AlexanderHamsandwich"
    }
  ],
  "imids": [
    {
      "uid": 31415,
      "label": "VT IM",
      "uri": "hammy@im.vt.edu"
    },
    {
      "uid": 31416,
      "label": "Google Talk",
      "uri": "hammy@google.com"
    }
  ],
  "emails": [
    {
      "type": "DISPLAY_EMAIL",
      "address": "hammy@icloud.com"
    },
    {
      "type": "NOTIFICATION_EMAIL",
      "address": "lexham@hotmail.com"
    }
  ]

  # Optional: with=certificates
  "certificates": [
    {
      "type": "X509",
      "certificate": "MIIDtTCCAp2gAwIBAgIIE...MCiAvnNZvu6HYU="
    }
  ],

  # Optional: with=employee
  "employeeData": {
    "title": "Lab Technician",
    "departments": [
      {
        "name": "Chemistry",
        "number": "000111"
      }
    ]
  },

  # Optional: with=student
  "studentData": {
    "academicLevel": "SENIOR",
    "campus": "Blacksburg",
    "college": "College of Science",
    "major": "Chemistry",
    "lastEnrollmentTerm": "Spring Semester 2000",
    "nextEnrollmentTerm": ""
  }
}

Account Resource

The account resource provides details on the person’s PID account. The account resource is intended primarily for viewing account state and managing credentials.

# Resource URI: /v2/accounts/hammy
{
  "pid": "hammy",
  "personName": "Alexander Brandon Hamsandwich",

  # Use Person resource to get person demographic data
  "personUid": 123456789,

  "creationDate": "2001-09-01:10:00-05:00",
  "expirationDate": null,

  # Optional: with=state
  # Valid states:
  #  1. ACTIVE - Most common state for active members
  #  2. LOCKED - Commonly due to password expiration; cannot authenticate
  #  3. SHELVED - First step to deprovision; easily recoverable
  #  4. TO_BE_RELEASED - Last step to deprovision; not recoverable
  #  5. UNCREDENTIALED - Uncommon state where account is provisioned ahead of time
  "accountState": {
    "state": "ACTIVE",
    "reason": "Userid Assigned"
  },
  "nextStateChangeDate": null,
  "passwordState": "ACTIVE",
  "passwordChangeDate": "2016-09-02:10:00-05:00",
  "passwordExpirationDate": "2017-09-01:10:00-05:00",

  # Optional: with=recovery
  "call4Help": false,
  "checkupDate": "2016-09-02:10:01-05:00",
  "recoveryOptions": [
    {
      # Send an OTP via SMS
      "type": "OTP2SMS",
      "endpoint": "5405551212"
    },
    {
      # Send an OTP via voice call
      "type": "OTP2VOICE",
      "endpoint": "5405551212"
    },
    {
      # OAuth2 authentication via Google
      "type": "GOOGLE",
      "endpoint": "123456789987654321"
    },
    {
      # OAuth2 authentication via Yahoo!
      "type": "YAHOO",
      "endpoint": "123456789987654321"
    }
  ]
}

Mailbox Resource

There is one mailbox resource for each type of ED email account but all share the same fields. Email accounts support aliases such that a single account may receive mail sent to multiple addresses. Additionally, forwarding addresses are supported for FE accounts such that mail sent to the account is not stored but forwarded to another address.

There are several types of ED email accounts based on the purpose and backing system:

Type Provider Description
GE Google (vt.edu) Virginia Tech email account
CE Google (vtc.vt.edu) Carilion email account
GAE Google (vt.edu) Virginia Tech auxiliary email account
CAE Google (vtc.vt.edu) Carilion auxilary email account
FE Virginia Tech (vt.edu) Virginia Tech forward-only email account

Auxiliary accounts are supplemental accounts that may be requested and granted for special circumstances. Forward only accounts are special purpose accounts that expose a specific Virgnia Tech email address for mail to be forwarded to another account, often a Virginia Tech Exchange account. Most users have only a single GE account. Carilion affiliates may have both CE and GE accounts.

# Resource URI: /v2/mailboxes/hammy@vt.edu
{
  # Every mailbox has an address that is its unique identifier. This is the
  # primary address of the email account.
  "address": "hammy@vt.edu",
  # Valid mailbox types:
  # 1. AUXILIARY - A supplementary Google account
  # 2. FORWARDING - Virtual mailbox that forward mail to another address
  # 3. PERSONAL - Primary Google account for an individual at the University

  "accountType": "PERSONAL",
  "personName": "Alexander Brandon Hamsandwidh",
  "personUid": 123456789,
  "creationDate": "2016-01-01T00:00:00-05:00",
  "expirationDate": null,

  # Email system routing control allowed values:
  #  1. GOOGLE
  #  2. EXCHANGE
  #  3. NONE
  "routeType": "GOOGLE",

  # Optional: with=state
  # Valid states:
  #  1. ACTIVE - Most common state for active members
  #  2. LOCKED - Commonly due to password expiration; cannot authenticate
  #  3. SHELVED - First step to deprovision; easily recoverable
  #  4. TO_BE_RELEASED - Last step to deprovision; not recoverable
  "accountState": {
    "state": "ACTIVE",
    "reason": "Email Account Added"
  },
  "nextStateChangeDate": null,
  "passwordState": "ACTIVE",
  "passwordChangeDate": "2017-01-01T00:00:00-05:00",

  # Optional: with=addresses
  # In addition to its primary address, every email account has a preferred address.
  "preferredAddress": "hammy.alias1@vt.edu",
  # Mailboxes may have up to 5 aliases by default but MAY be configured for more..
  "aliases": [ "hammy.alias1@vt.edu", "hammy.alias2@vt.edu" ],
  # Mailboxes may have 1 forwarding address by default but MAY be configured for more.
  "forwards": [ "hammy@yahoo.com", "hammy.alias1@aol.com" ],

  # The following field is write-only for purposes of password changes.
  "password": {
    "current": "thecurrentpass",
    "newpass": "thenewpassword"
  }  
}

Service Resource

An Enterprise Directory service is a credentialed account not associated with a person that is intended to be used to access and manage Enterprise Directory resources by an application, service, or system. Services have strong public key credentials by default, though they may also have complex passwords if requested and authorized by the IT Security Office. Services are explicitly authorized to view and modify data via Enterprise Directory Web services; they have the following structure.

# Resource URI: /v1/services/vt-service
{
  "uusid": "vt-service",
  "creationDate": 1476365450,
  "expirationDate": 0,
  "modificationDate": "2016-11-18T18:23:16-05:00",
  # Valid states:
  #  1. ACTIVE - Most common state for active members
  #  2. LOCKED - Commonly due to password expiration; cannot authenticate
  #  3. SHELVED - First step to deprovision; easily recoverable
  #  4. TO_BE_RELEASED - Last step to deprovision; not recoverable
  "accountState": "ACTIVE",
  "serviceDns": [
    "C=US, DC=edu, DC=vt, ST=Virginia, L=Blacksburg, O=Virginia Polytechnic Institute and State University, OU=Middleware-Client, OU=Middleware Services, SERIALNUMBER=1458240372130, CN=middleware"
  ],
  "viewablePersonAttributes": [
    "nextEnrollmentTerm",
    "mailExternalAddress",
    "accountExpirationDate",
    "personType",
    "localPager",
    "classLevelCode",
    "authId",
    "lastEnrollmentTerm",
  ],
  "webServiceAuthorizations": [
    "ed/rest/groups",
  ],
  "certificates": [                                                                                    
    "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"
  ],

  # Optional: with=contacts
  contacts: [
    {
      "kind": "person",
      "uid": 111,
      "pid": "alice",
      "displayName": "Alice Alyssonian"
    },
    {
      "kind": "person",
      "uid": 222,
      "pid": "bob",
      "displayName": "Bob Bobberann"
    }
  ],

  # Optional: with=administrators
  administrators: [
    {
      "kind": "person",
      "uid": 333,
      "pid": "alice",
      "displayName": "Alice Alyssonian"
    },
    {
      "kind": "person",
      "uid": 444,
      "pid": "bob",
      "displayName": "Bob Bobberann"
    }
  ],

  # Optional: with=endpoints
  "endpoints": [
    {
      "protocol": "OAuth2",
      "location": "https://alpha.example.org/oauth"
    },
    {
      "protocol": "SAML",
      "location": "https://alpha.example.org/saml",
      "binding": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
    }
  ],

  # Optional: with=assurance
  "authorizedPersonaTypes": [
    "MEDIUM",
    "HIGH"
  ]
}

Group Resource

An Enterprise Directory group is a container for people, services, and groups that may be used by its members for communication, collaboration, and/or authorization. Groups have a controlled namespace where each namespace part is separated by a dot. The first namespace part is called the stem and must be created via service request; groups are subsequently self-service with respect to creation and membership management. Groups have 5 roles associated with them:

Role View Members Manage Members Create Groups Designate Managers Email Notifications
Member          
Administrator X X X X X
Manager X X      
Contact         X
Viewer X        

All roles except viewer may be fulfilled by either an account (i.e. person) or a service (i.e. machine) to allow both human users and software agents to communicate, collaborate, and participate in authorization. Only services may fulfill the viewer role, which is intended to permit a software agent to see the group when its suppression flags are enabled. Groups are private by default but may be made public by toggling suppression flags, suppressDisplay and suppressMembers. If these flags are enabled, the group and its members are hidden from anonymous LDAP queries against the ou=groups branch of the Enterprise Directory. Suppressed groups can be made visible by setting a service viewer and using that service principal to bind and query the directory.

Groups have expiration dates by default to encourage active maintenance; email notifications include periodic email expiration notifications at a minimum. Group members (in any of the roles above) MAY have expiration dates. A common use case for member expiration is to enforce temporary authorization policy on a party whose affiliation has a known end-date; for example, end of term for a student participating in a research project.

# Resource URI: /v1/groups/chemistry.chromatographers
{
  "uugid": "chemistry.example",
  "displayName": "Gas Chromatograph Operators",
  "creationDate": 1476365450,
  "expirationDate": 1507901499,

  # Optional: with=replication
  # Provides information on the subordinate systems the group is replicated to
  # May grow or change as subordinate systems are added, removed, or modified
  "targets": [
    "banner.vt.edu",
    "code.vt.edu",
    "google.com:a:vt.edu",
    "urn:amazon:webservices:$TARGET_AWS_ACCOUNT_ID",
    "w2k.vt.edu"
  ],

  # Optional: with=suppression
  "suppressDisplay": false,
  "suppressMembers": false,

  # Optional: with=social
  "emailAddress": "chromatographers@vt.edu",
  "labeledUris": [
    "Home Page:http://www.chem.vt.edu/chromatography"
  ],

  # Optional: with=contacts
  contacts: [
    {
      "kind": "person",
      "uid": 111,
      "pid": "mallory",
      "displayName": "Mallory Noe-Payne Nogaine",
      "creationDate": 1476365450,
      "expirationDate": 0
    }
  ],

  # Optional: with=administrators
  administrators: [
    {
      "kind": "person",
      "uid": 222,
      "pid": "alice",
      "displayName": "Alice Alyssonian",
      "creationDate": 1476365450
    },
    {
      "kind": "person",
      "uid": 333,
      "pid": "bob",
      "displayName": "Bob Bobberann"
      "creationDate": 1476377549
    },
    {
      "kind": "service",
      "uusid": "chem-automation",
      "creationDate": 1476377549,
      "expirationDate": 1507913549
    }
  ]

  # Optional: with=managers
  managers: [
    {
      "kind": "person",
      "uid": 444,
      "pid": "carla",
      "displayName": "Carla Carlottington",
      "creationDate": 1476365450,
      "expirationDate": 1507901499
    }
  ],

  # Optional: with=viewers
  # Typically these are services
  viewers: [
    {
      "kind": "service",
      "uusid": "cos-toolkit",
      "creationDate": 1476377549,
      "expirationDate": 1507913549
    }
  ],

  # Optional: with=members
  # Members may be any of the following: account, person, or service
  members: [
    {
      "kind": "person",
      "uid": 555,
      "pid": "david",
      "displayName": "David Davidian",
      "creationDate": 1476377549,
      "expirationDate": 1507913549
    },
    {
      "kind": "person",
      "uid": 666,
      "pid": "eloise",
      "displayName": "Eloise Elysian",
      "creationDate": 1476377549,
      "expirationDate": 1507913549
    },
    {
      "kind": "group",
      "uugid": "chemistry.chromatographers.experts",
      "displayName": "Chromatography Experts Group",
      "creationDate": 1476377549,
      "expirationDate": 1507913549
    }
  ],

  # Optional: with=membership
  # These are the IDs of groups of which this one is a member
  # This field is read-only
  membership: [
    "chemistry"
  ]
}

Entitlement Resource

An Enterprise Directory entitlement is an authorization granted to an account or service to access data or perform an action. An ED service belonging to an application, service, or system grants the entitlement to an account or service and interprets its meaning when the grantor presents its. Entitlements have 4 associated roles:

  1. Manager - the service that created the entitlement
  2. Member - the account or service to which the entitlement was granted
  3. Sponsor - optional account (owned by a person) that sponsored granting the entitlement
  4. Viewer - one or more arbitary third party services that may view the entitlement

Entitlements are naturally sensitive and may be viewed only by the parties involved; third parties may view entitlements only when explicitly permitted via the viewers field.

Entitlements have an open namespace, but are encouraged to following the URN specification. A URI, which is a specialization of a URN, has a good balance of structure and flexibility to accommodate most cases. Consider the following example:

factory/widgets/activate?field=value

The entitlement above belongs to the factory application and entitles the grantor to perform the activate action of the widgets section with data field=value. It’s a contrived example, but explains how entitlements can cover both actions and data.

# Resource URI: /v1/entitlement/factory%2Fwidgets%2Factivate%3Ffield%3Dvalue
# The entitlement name MUST be URL encoded when it appears in the resource URI.
{
  "name": "factory/widgets/activate?field=value",
  "creationDate": 1476365450,
  "expirationDate": 1507901499,

  # Member may be either an account or a service
  # An account is demonstrated here.
  "member": {
    "kind": "person",
    "uid": 111,
    "pid": "bob",
    "displayName": "Bob Bobberann"
  },

  "manager": {
    "kind": "service",
    "uusid": "vt-service"
  },

  # Optional: with=sponsor
  "sponsor": {
    "kind": "person",
    "uid": 222,
    "pid": "alice",
    "displayName": "Alice Alyssonian"
  },

  # Optional: with=viewers
  "viewers": [
    {
      "kind": "service",
      "uusid": "some-other-service"
    }
  ]
}

Entitlements are immutable except for the following fields that may be modified:

  1. expirationDate
  2. viewers

The entitlement should be removed and recreated if other fields require modification.