Log Aggregation

Troubleshooting: Secure infrastructure and events management (SIEM) for HYPR hosted tenants

Collecting HYPR Audit Events

HYPR enables customers to collect Audit Events from the Control Center (CC) through a protected API endpoint:

/cc/api/versioned/audit/search

Read the HYPR API Reference for details on how this API works.

πŸ“˜

Event Descriptions

A full list of all Events and common parameters can be found in the Event Descriptions article. Not every Event is listed in the CC Audit Trail; some only appear in API responses or logs.

HYPR Event JSON Format

HYPR Events are structured in .JSON format as returned from the Event API. The following is a model of the response:

{
  "data": [
    {
      "id": "150764872507840257",
      "version": 4,
      "type": "AUDIT",
      "eventName": "WORKSTATION_AUTH_COMPLETE",
      "message": "Final step in Workstation login. Login confirmation sent to device.   Completed",
      "subName": "device/authorize/ws/complete/{sessionId}",
      "eventLoggedBy": "RELYING_PARTY_SERVER",
      "eventTimeInUTC": 1659972800920,
      "loggedTimeInUTC": 1659972800920,
      "tenantId": "highlandsbank",
      "remoteIP": "72.119.96.213",
      "userAgent": "okhttp/4.9.3",
      "traceId": "bccf2c83f9cbf98b1",
      "additionalDetails": {
        "mobileDevice": null,
        "workstation": null,
        "web": null,
        "smartKey": null,
        "magicLink": null,
        "featureFlag": null,
        "createUser": null,
        "deleteUser": null,
        "fido2Setting": null,
        "metadataCertExpiry": null,
        "deviceSignal": null,
        "desktopSSO": null,
        "deregistration": null,
        "logsSubmission": null,
        "extras": {}
      },
      "isSuccessful": true,
      "errorCode": null,
      "errorSeverity": null,
      "deviceType": null,
      "rpAppId": "HBWorkstationUnlock",
      "deviceId": "DevIda65l1ffgt2ji1ieao6b9dn5e22",
      "machineId": "083c0de3-ca70-478e-81a2-e4e62f196357",
      "sessionId": "3be5ab098f6286a9dc46278ad9ad9b661d74c8d1b2eef80e11a199d2f8982a39",
      "fidoUser": "Userltak05d3hkogfb765unlksgfbo",
      "machineUserName": "HIGHLANDS-315-Grace Hopper",
      "authenticator": null,
      "usageType": null,
      "integrationType": null,
      "integrationProvider": null,
      "wsOS": "NA",
      "deviceOS": "Android",
      "wsOSVersion": "NA",
      "deviceOSVersion": "11",
      "wsRelVersion": "NA",
      "deviceRelVersion": "7.6.0",
      "sdkRelVersion": "NA",
      "serverRelVersion": "7.7.0",
      "wsModel": "NA",
      "deviceModel": "Google - Pixel 3a(sargo)"
    }
}

RP App Separation

At the time of this writing HYPR Events are isolated to each HYPR RP Application. HYPR is configured with a specific set of out-of-the-box RP Applications:

RP ApplicationRP Application NamePurpose
controlCenterAdminControl Center AdminManages the Control Center access and configurations. This application is the application to which HYPR Administrators are logging in.
HYPRDefaultApplicationHYPR Default Web ApplicationA pre-created web-oriented RP Application to leverage quickly within environments.
HYPRDefaultWorkstationApplicationHYPR Default Workstation ApplicationA pre-created workstation-oriented RP Application to leverage common default workstation settings out of the box.

Customers may add additional RP Applications as needed.

Based on the above information, if Event collections are required it is important that the collection process take into account the possibility that additional applications might be created by a HYPR administrator. The following sample Python script showcases how you might collect Events not only from a specific RP Application, but dynamically, based on all RP Applications which exist within the Control Center at the time the collection runs.

#!/usr/bin/env python
import requests
import pprint
import time
import json
import sched

client = requests.session()
client.verify = True

pp = pprint.PrettyPrinter(depth=6)
s = sched.scheduler(time.time, time.sleep)

URL = 'https://hypr.host.com'
#The API Token for this script needs to be generated in the ControlCenterAdmin
apiToken = 'API-TOKEN-FROM-CONTROL-CENTER'


client.get(URL)  # sets cookie
SESSIONToken = client.cookies['SESSION']

tokenHeader = {
   'Authorization': 'Bearer ' + apiToken,
   'content-type': 'application/json; charset=utf-8;',
   'accept': '*/*',
   'sec-fetch-mode': 'cors',
   'accept-encoding': 'gzip, deflate, br',
   'accept-language': 'en-US,en;q=0.9',
}

# Set our time stamps for the search
endTSUTC = int(round(time.time() * 1000))
# print 'End UTC ' + str(endTSUTC)
startTSUTC = int(round(endTSUTC - 60 * 1000))
# print 'Start UTC ' + str(startTSUTC)
eventSearchRequest = {
   'endTSUTC': str(endTSUTC),
   'startTSUTC': str(startTSUTC),
   'orderBy': 'eventTimeInUTC',
   'sortDir': 'desc',
   'pageSize': '1000'
}


def getApplications():
   getrpappids = client.get(URL + '/cc/api/application', headers=tokenHeader)

   if getrpappids.ok:
       new_applist = []
       for item in getrpappids.json():
           if item['appID']:
               new_applist.append(item['appID'])
       return new_applist
   else:
       print("Error: " + getrpappids.status_code)

def empty_result(appid):
   emptyresult = {
       "rpAppId": appid,
       "type": "Event Collection",
       "results": 0
   }
   emptyresult_json = json.dumps(emptyresult)
   pp.pprint(emptyresult_json)

def do_eventSearch(sc, apps):
   for i in apps:
       searchEvents = client.get(URL + '/cc/api/versioned/audit/search?endTSUTC=' +
                                 eventSearchRequest.get('endTSUTC') +
                                 '&startTSUTC=' + eventSearchRequest.get('startTSUTC') +
                                 '&rpAppId=' + str(i) +
                                 '&orderBy=' + eventSearchRequest.get('orderBy') +
                                 '&sortDir=' + eventSearchRequest.get('sortDir') +
                                 '&pageSize=' + eventSearchRequest.get('pageSize'), headers=tokenHeader)
       if searchEvents.ok:
           events = searchEvents.json()
           if events['metadata']['totalRecords'] > 0:
               pp.pprint(searchEvents.json())
           else:
               empty_result(i)

       else:
           pp.pprint(searchEvents.content)

   s.enter(60, 1, do_eventSearch, (sc, apps))


s.enter(60, 1, do_eventSearch, (s, getApplications()))

s.run()