In this topic, you enable the OpenEdge Authentication Gateway to monitor the database for login events, and add ABL code to the Authentication Gateway that records login attempt information to the Authentication Gateway agent log file.

The built-in mechanism for OpenEdge Authentication Gateway is “Events”. Using events, you can write ABL code that is run whenever a specific event is fired. This is done by modifying your domains.json file to set events groups to true, and assigning a class file to be run as the eventProvider.

In this topic, you use an ABL class file to write events to the oeauthserver.agent.log file when a login event occurs.

Add event auditing

Modify your domains.json to use a specific eventsProvider, and fire events on specific groups.

  1. Open the C:\OpenEdge\WRK\oeauthserver\webapps\ROOT\WEB-INF\config\domains.json file in an editor.
  2. Make the following changes to the local domain:
    • Add a login events provider.
    • Change all of the groups from false to true in the events section.
    • Add an eventPolicy of login to the bottom of the local domain definition.
    These edits are shown in bold in the following local domain definition:
    {
        	"name" : "local",
            "enabled" : true,
            "description" : "Replaced default blank domain with local",
            "actions" : {
                "authenticate" : {
                	"enabled" : true,
                	"options" : ""
                },
                "exchange" : {
                	"enabled" : false,
                	"options" : ""
                },
                "sso" : {
                	"enabled" : true,
                	"options" : ""
                },
                "refresh" : {
                	"enabled" : false,
                	"options" : ""
                }
           },
           "options" : "",
           "authProvider" : "_oslocal",
           "policyProvider" : "",
           "events" : {
                "provider" : "login",
                "groups" : {
                    "client" : true,
                    "tokenAuthenticate" : true,
                    "tokenExchange" : true,
                    "tokenRevoke" : true,
                    "tokenValidate" : true,
                    "tokenRefresh" : true,
                    "policy" : true,
                    "sessionLogin" : true,
                    "sessionLogout" : true,
                    "sessionValidate" : true,
                    "sessionRefresh" : true
                }
           },
        },
  3. At the bottom of the domains.json file, edit the eventProviders section to add a login event, as well as information about finding the SampleEventHandler and hash information (which can be blank), for example:
       "eventProviders":{
          "login":{
             "type":"com.progress.sts.SampleEventHandler",
             "hash":""
          }
       }
    Note: For testing purposes, the hash information can be blank or omitted. However, the hash value is a security feature to ensure that the correct code is being run. For more information about setting hash values for events and policies, see Configure event callbacks.
  4. On the Authentication Gateway machine, create the directory path for the SampleEventHandler code so that it is added to the PROPATH:
    proenv>cd %WRKDIR%\oeauthserver\openedge
    proenv>mkdir com\progress\sts
    proenv>cd com\progress\sts
  5. Create the SampleEventHandler.cls file in the newly-created oeauthserver\openedge\com\progress\sts directory using the following code:
    using Progress.Lang.*.
    using OpenEdge.Security.STS.IEventProvider.
    using OpenEdge.Security.Principal.
    using Progress.Json.ObjectModel.JsonObject.
    block-level on error undo, throw.
    
    class com.progress.sts.SampleEventHandler implements IEventProvider:
        method public void RecordEvent( input pcSender as character,
                                    input pcEvent as character,
                                    input poPrincipal as Principal,
                                    input poDomainCtx as JsonObject ):
        message "sender: " pcSender skip
        "event: " pcEvent skip
        "C-P Token: " poPrincipal:Token skip
    	"C-P Domain: " poPrincipal:Token:domain-name skip
    	"C-P Roles: " poPrincipal:Token:roles skip
    	"C-P user id: " poPrincipal:Token:user-id skip
        "context:" poDomainCtx.
    	MESSAGE "       ".
        end method.
    end class.
  6. Stop, clean, and, restart the Authentication Gateway server:
    proenv>cd %WRKDIR%\oeauthserver
    proenv>bin\tcman pasoestart -restart
  7. Use your database machine to connect to the database using an authorized local user, for example:
    proenv>cd %WRKDIR%\db
    proenv>mpro sports2020 -U testuser1@local -P testuser1
  8. Open the C:\OpenEdge\WRK\oeauthserver\logs\oeauthserver.agent.log and view the bottom entries, which look like the following:
    2020-08-01T15:11:11.194-0400 013096 010064 1 AS-15 ?:?:? -- (Procedure: 'RecordEvent com.progress.sts.SampleEventHandler' Line:11) sender:  STS 
    2020-08-01T15:11:11.194-0400 013096 010064 1 AS-15 ?:?:? -- (Procedure: 'RecordEvent com.progress.sts.SampleEventHandler' Line:11) event:  CLIENT-AUTHENTICATING 
    2020-08-01T15:11:11.194-0400 013096 010064 1 AS-15 ?:?:? -- (Procedure: 'RecordEvent com.progress.sts.SampleEventHandler' Line:11) C-P Token:  1251 
    2020-08-01T15:11:11.194-0400 013096 010064 1 AS-15 ?:?:? -- (Procedure: 'RecordEvent com.progress.sts.SampleEventHandler' Line:11) C-P Domain:  local 
    2020-08-01T15:11:11.194-0400 013096 010064 1 AS-15 ?:?:? -- (Procedure: 'RecordEvent com.progress.sts.SampleEventHandler' Line:11) C-P Roles:   
    2020-08-01T15:11:11.194-0400 013096 010064 1 AS-15 ?:?:? -- (Procedure: 'RecordEvent com.progress.sts.SampleEventHandler' Line:11) C-P user id:  testuser1 
    2020-08-01T15:11:11.194-0400 013096 010064 1 AS-15 ?:?:? -- (Procedure: 'RecordEvent com.progress.sts.SampleEventHandler' Line:11) context: Progress.Json.ObjectModel.JsonObject_1253
    2020-08-01T15:11:11.195-0400 013096 010064 1 AS-15 ?:?:? -- (Procedure: 'RecordEvent com.progress.sts.SampleEventHandler' Line:18)        
    2020-08-01T15:11:11.360-0400 013096 011228 1 AS-15 ?:?:? -- (Procedure: 'RecordEvent com.progress.sts.SampleEventHandler' Line:11) sender:  STS 
    2020-08-01T15:11:11.360-0400 013096 011228 1 AS-15 ?:?:? -- (Procedure: 'RecordEvent com.progress.sts.SampleEventHandler' Line:11) event:  CLIENT-AUTHENTICATED 
    2020-08-01T15:11:11.360-0400 013096 011228 1 AS-15 ?:?:? -- (Procedure: 'RecordEvent com.progress.sts.SampleEventHandler' Line:11) C-P Token:  1258 
    2020-08-01T15:11:11.360-0400 013096 011228 1 AS-15 ?:?:? -- (Procedure: 'RecordEvent com.progress.sts.SampleEventHandler' Line:11) C-P Domain:  local 
    2020-08-01T15:11:11.360-0400 013096 011228 1 AS-15 ?:?:? -- (Procedure: 'RecordEvent com.progress.sts.SampleEventHandler' Line:11) C-P Roles:   
    2020-08-01T15:11:11.360-0400 013096 011228 1 AS-15 ?:?:? -- (Procedure: 'RecordEvent com.progress.sts.SampleEventHandler' Line:11) C-P user id:  testuser1 
    2020-08-01T15:11:11.360-0400 013096 011228 1 AS-15 ?:?:? -- (Procedure: 'RecordEvent com.progress.sts.SampleEventHandler' Line:11) context: Progress.Json.ObjectModel.JsonObject_1260
    2020-08-01T15:11:11.360-0400 013096 011228 1 AS-15 ?:?:? -- (Procedure: 'RecordEvent com.progress.sts.SampleEventHandler' Line:18)       

Add audit details

The poDomainCtx parameter can contain additional information related to the event. In the case of an authentication request from a database, this parameter can contain information in an auditDetail string. This string has the following format:

Audit Detail Format for DB connection
  "Initial connection" - constant
  0x06
  RemoteUser - Not always userid from CP
  ProcessID
  OSType
  IP Address
  Client Type
  DB Connection Type
  ruserID
When coming from a Database authentication request, the auditDetail string starts with “Initial connection” followed by an ASCII character 0x06. The values are delimited by colons. Here is an example:
auditDetail = new String(poDomainCtx:GetCharacter("auditDetail")).
details = auditDetail:Split(":").
        
remoteUser = CAST(details:Get(1), String).
auditDetail = CAST(remoteUser:Split(chr(6)):Get(1), String).
remoteUser = CAST(remoteUser:Split(chr(6)):Get(2), String).
            
if auditDetail:CompareTo(new String("Initial connection")) = 0 then do:
  theUserID = new String(poPrincipal:Token:USER-ID).               
  ipAddress = CAST(details:Get(4), String).               
  if pcEventName = "CLIENT-AUTHENTICATING" then do:
    message "Client Authentication attemp from" 
            remoteUser:ToString() "as" theUserID:ToString() 
            "on" ipAddress:ToString().
    end.
    else do:
      if pcEventName = "CLIENT-AUTHENTICATED" then do:
           message theUserID:ToString() "successfully authenticated".
         end.
         else do:
            if pcEventName = "CLIENT-AUTHENTICATION-ERROR" then do:
               message theUserID:ToString()
               "unsuccessful authentication attempt".
            end.
         end.
    end.
end.
This logs the remote user’s ID as well as their IP Address, which may be different than the values in the ClientPrincipal.

Summary

In this topic, we configured events to be recorded in the agent log file. This provides an audit trail for Authentication Gateway administrators to have a view of login events in the server's agent log file.