Summary
KeepAPI exposes new endpoints / resources and extensions to the existing data model to facilitate integration with the HID Mobile Access Credentials product, Origo. Currently all access to the is through the API, with future plans to incorporate the Origo integration into the Windows and Web Client user interfaces.
Licensing
Origo Integration is a licensable feature. An example license request would be:
{
"Environment": "DEV",
"InstanceKey": "{{ WorkingInstance.Key }}",
"LicensedBy": {
"CompanyName": "Feenics Inc",
"EmailAddress": "ralph.shillington@feenics.com",
"MailingAddress": {
"Street": "301 - 2310 St. Laurent Blvd",
"City": "Ottawa",
"Province": "ON",
"Country": "CA",
"PostalCode": "K1G 5H9"
},
"PhoneNumber": "613-520-2455"
},
"Licensee": {
"CompanyName": "Feenics Inc - Development",
"EmailAddress": "ralph.shillington@feenics.co",
"MailingAddress": {
"Street": "302 - 2310 St. Laurent Blvd",
"City": "Ottawa",
"Province": "ON",
"Country": "CA",
"PostalCode": "K1C 5J9"
},
"PhoneNumber": "613-520-2426"
},
"PurchaseOrder": "RALPH",
"RequestingComponents": [
{
"PrivateProductCode": "ORIGO",
"ValueAdded": 1
}
]
}
Permissions
Users that will be configuring the Origo integration must have the OrigoAdmin
action attached to the Instance
object type. Of course administrators with *,*
permissions will automatically have this permission.
Configuration
Configuration can be set or updated by with POST method to the endpoint /api/origo/configuration
The currently stored configuration can not be retrieved by the API user since it contains sensitive information. Subsequent POST methods will replace the existing configuration.
Setting the Configuration, will automatically register the instance to receive callback messages.
Response | Condition | Description |
---|---|---|
401 | NotAuthorized | failed to find and operation right for the current user with action of OrigoAdmin on the object type Instance |
409 | Conflict | Missing license for this instance. |
400 | BadRequest | Failed to log into Origo with the supplied credentials |
400 | BadRequest | Failed to register the callback endpoint with Origo |
200 | Ok | Configuration has been saved, and the callback endpoint has been registered with Origo |
Example setting configuration
In this example, the keepcli tool is used to maintain credentials to the KeepApi endpoint. The example configures the default
defined instance. The example posts the contents of the file origoconfig.json
INSTANCE=$(keepcli test -j)
BASEADDRESS=$(echo $INSTANCE | jq -r .BaseAddress)
TOKEN=$(echo $INSTANCE | jq -r .Token)
curl -v -X POST -d @origoconfig.json -H 'Content-Type: application/json' -H 'Accept: application/json' -H "Authorization: Bearer ${TOKEN}" ${BASEADDRESS}/api/origo/configuration
The contents of the configuration information is obtained from HID by the customer’s administrator using the HID Origo portal. It’s important to note that the user may have access to both a pre-production and production HID portal
{
"CustomerId":"1000582",
"ClientId":"1000582-SRV1620440120",
"ClientSecret":"password_goes_here",
"GrantType":"client_credentials",
"DefaultPartNumber":"MID-SUB-CRD_FTPN_30176"
}
Confirm Origo Customer
The Api exposes a new endpoint to get the Origo Customer information for the configured CustomerId: /api/origo/customer
. The following script gets the customer information
INSTANCE=$(keepcli test -j)
BASEADDRESS=$(echo $INSTANCE | jq -r .BaseAddress)
TOKEN=$(echo $INSTANCE | jq -r .Token)
curl -s -H 'Accept: application/json' -H "Authorization: Bearer ${TOKEN}" ${BASEADDRESS}/api/origo/customer | json_pp
{
"Name" : "FEENICS-TP-D_SUB",
"Id" : "1000582",
"SubscriptionMode" : "Full term subscription",
"pendingInvitations" : 0,
"TotalUsers" : 18,
"$type" : "Feenics.Keep.Origo.Customer, Feenics.Keep.WebApi.Model",
"urn:hid:scim:api:ma:2.0:LicenseInfo" : [
{
"ConsumedQty" : 0,
"AvailableQty" : 100,
"StartDate" : "2019-05-27T00:00:00Z",
"PartNumber" : "MID-SUB-T100",
"LicenseState" : "Good Standing",
"StatusMessage" : "Good Standing",
"PeriodState" : "Normal",
"EndDate" : "2020-05-26T00:00:00Z",
"Name" : "T100 Subscription",
"$type" : "Feenics.Keep.Origo.License, Feenics.Keep.WebApi.Model"
}
],
"MobileKeysets" : "MOB0001, MOB0022",
"ActiveUsers" : 0
}
Normal Operation
Once properly configured, the normal operation of the integration is largely ‘behind the scenes’. There is only one additional Origo specific endpoint that has been added to the PersonInfo
resource: /origo/issue
.
To issue a mobile credential a cardholder must already exist in the Keep instance. In the case of a Enterprise instances, the card holder may exist in either the root instance, or the shared instance.
Internally the processing of issuing a mobile credential involves several steps:
1. Confirm the cardholder exists as an Origo user, and if not, then add the user
2. Create an invitation code, send invitation email, and create credential (all one call to Origo)
3. Wait for an ISSUED
status callback for the requested credential
4. Create the CardAssignmentInfo
object and attach it to the PersonInfo
object in Keep
.
The ISSUED
status will be sent from Origo to Keep (via the preconfigured endpoint that was provisioned at the time of setting the Origo Configuration). This call only occurs after the mobile device has successfully downloaded the credential. It is the callback handler that creates the CardAssignmentInfo object attaches it to the PersonInfo and raises the appropriate event, such that the Mercury Service pushes the Mobile Credential card number to the appropriate controllers.
Example of issuing a new mobile credential
In this example keepcli
is being used to provide authentication to the Keep api, using it’s default
configuration. A search by moniker is executed for a specific person, and a POST to /origo/issue
on Person is called, sending the requested activeOn and expiresOn values (UTC).
In a separate window use keepcli
to subscribe to events, to observe the mobile credential being issued.
keepcli subscribe | jq '{d:.PublishedOn."$date"| (. / 1000 | todate),m:.MessageLong,et:.ObjectLinks[] | select(.Relation=="PublishingEventType")|.CommonN
ame,bd:.EventData.BeforeData, ad:.EventData.AfterData}'
With the event subscriber running, issue a new mobile credential.
#!/bin/bash
INSTANCE=$(keepcli test -j)
BASEADDRESS=$(echo $INSTANCE | jq -r .BaseAddress)
TOKEN=$(echo $INSTANCE | jq -r .Token)
BODY='{"activeOn":"2019-09-04T:00:00.0000000+00:00","expiresOn":"2019-09-04T07:00:00.0000000+00:00"}'
PERSON=$(keepcli search -s '{"Monikers":{"$elemMatch":{"Nickname":"ralshi", "Namespace":"feenicsdev.people"}}}' | jq -r .Href)
echo ${BASEADDRESS}${PERSON}/origo/issue
echo ${BODY}
curl -v -X POST -H 'Content-Type: application/json' -H 'Accept: application/json' -H "Authorization: Bearer ${TOKEN}" -d ${BODY} ${BASEADDRESS}${PERSON}/origo/issue
Currently it is possible that the issue
request will fail with an HTTPStatus of 400 and a response body of:
{
"$type": "Feenics.Keep.WebApi.ErrorResponse, WebApi",
"Error": "OrigoOperation",
"Message": "Failed to get send invite. Status=InternalServerError response: {\"schemas\":[\"urn:hid:scim:api:ma:2.0:Error\"],\"detail\":\"We are unable to continue with your request, due to technical difficulty with Subscription Service. Please try again or contact your support.\",\"status\":500}"
}
This is a known issue with HID Origo, and occurs occasionally when issuing both a new user request immediately followed by a new invitation request. In this circumstance it’s OK to retry the request. On the second call the user will exist in Origo and the new invitation email and invitation code will be sent to the user.
When the user accepts the invitation and receives the credential on the mobile device, Origo will send an ISSUED event to the registered Keep endpoint for the instance and a credential will be issued, which can be observed in the window that is subscribing to events.
{
"d": "2019-09-04T23:57:10Z",
"m": "Shillington, Ralph card 24 modified by System Administrator. Action POST",
"et": "Object Modified",
"bd": null,
"ad": {
"_t": [
"Item",
"CardAssignmentInfo"
],
"Href": "/api/f/5d52b8b453b83b0001f25361/people/10436012/cards/5d704f562bc5040001225f80",
"Key": "5d704f562bc5040001225f80",
"EncodedCardNumber": 24,
"DisplayCardNumber": "24",
"ActiveOn": {
"$date": 1567486800000
},
"ExpiresOn": {
"$date": 1567494000000
},
"PinCode": null,
"AntiPassbackExempt": false,
"ExtendedAccess": false,
"PinExempt": false,
"IsDisabled": false,
"ManagerLevel": 0,
"OriginalUseCount": null,
"CurrentUseCount": 0,
"Note": null,
"HexValue": null,
"RecordId": 6,
"LastUsed": null,
"OrigoCredentialId": 10436012
}
}
Note the OrigoCredentialId
property that is available both in the EventData.AfterData property of the EventMessageData
and is also present on the CardAssignment entry for the new mobile credential. This non-zero value is the indicator that the credential is a mobile credential.
Example of revoking a Mobile Credential
In this example, simply setting the expired on value to something less than DateTime.UtcNow on the mobile credential will trigger a call to Origo by the KeepAPI to revoke the credential.
INSTANCE=$(keepcli test -j)
BASEADDRESS=$(echo $INSTANCE | jq -r .BaseAddress)
TOKEN=$(echo $INSTANCE | jq -r .Token)
CARDURL=$(keepcli search -s '{"Monikers":{"$elemMatch":{"Nickname":"ralshi", "Namespace":"feenicsdev.people"}}}' | jq -r .CardAssignments[0].Href)
echo ${BASEADDRESS}${CARDURL}
curl -s -H 'Content-Type: application/json' -H 'Accept: application/json' -H "Authorization: Bearer ${TOKEN}" ${BASEADDRESS}${CARDURL} | jq '.ExpiresOn=.ActiveOn' | \
curl -v -X PUT -H 'Content-Type: application/json' -H 'Accept: application/json' -H "Authorization: Bearer ${TOKEN}" -d @- ${BASEADDRESS}${CARDURL} | jq .
This sample script assumes the first member of the CardAssignments array for the selected person is a mobile credential. Using the card assignment URL, the first cUrl command retrieves the CardAssignmentInfo
details, and uses jq
to set the ExpiresOn field to the same value as the ActiveOn value (effectively making the card revoked.)
Observe in the event subscriber window the updated CardAssignmentInfo object, immediately followed by an Origo Command Sent event, which instructs Origo to revoke the mobile credential.
{
"d": "2019-09-05T00:16:42Z",
"m": "Shillington, Ralph modified by System Administrator. Action PUT",
"et": "Object Modified",
"bd": {
"_t": [
"Item",
"CardAssignmentInfo"
],
"Href": "/api/f/5d6eac48c198dc0001664425/people/5d704ec62bc5040001225f6c/cards/5d704f562bc5040001225f80",
"Key": "5d704f562bc5040001225f80",
"EncodedCardNumber": 24,
"DisplayCardNumber": "24",
"ActiveOn": {
"$date": 1567486800000
},
"ExpiresOn": {
"$date": 1567494000000
},
"PinCode": null,
"AntiPassbackExempt": false,
"ExtendedAccess": false,
"PinExempt": false,
"IsDisabled": false,
"ManagerLevel": 0,
"OriginalUseCount": null,
"CurrentUseCount": 0,
"Note": null,
"HexValue": null,
"RecordId": 6,
"LastUsed": null,
"OrigoCredentialId": 10436012
},
"ad": {
"_t": [
"Item",
"CardAssignmentInfo"
],
"Href": "/api/f/5d6eac48c198dc0001664425/people/5d704ec62bc5040001225f6c/cards/5d704f562bc5040001225f80",
"Key": "5d704f562bc5040001225f80",
"EncodedCardNumber": 24,
"DisplayCardNumber": "24",
"ActiveOn": {
"$date": 1567486800000
},
"ExpiresOn": {
"$date": 1567486800000
},
"PinCode": null,
"AntiPassbackExempt": false,
"ExtendedAccess": false,
"PinExempt": false,
"IsDisabled": false,
"ManagerLevel": 0,
"OriginalUseCount": null,
"CurrentUseCount": 0,
"Note": null,
"HexValue": null,
"RecordId": 6,
"LastUsed": null,
"OrigoCredentialId": 10436012
}
}
{
"d": "2019-09-05T00:16:43Z",
"m": "Origo Command Sent",
"et": "Origo Command Sent",
"bd": null,
"ad": null
}