To use an OpenEdge database as the source for user account information, you need an object-oriented ABL class that implements the IHybridRealm interface and is registered with the Progress Application Server (PAS) through its configuration file. This requires adding several object-oriented ABL classes to the PROPATH of the PAS for OpenEdge instance. These classes handle OERealm client requests for user account details and perform password validation.

Server activation

The Progress.Security.Realm.IHybridRealm interface is included in the OpenEdge product as part of ABL. It defines the method signatures used by the OERealm security model. You can view these methods by searching for IHybridRealm in the Class Browser panel of Progress Developer Studio for OpenEdge.

The following example shows the list of available methods:

INTERFACE Progress.Security.Realm.IHybridRealm: 

    METHOD PUBLIC INTEGER ValidateUser ( cUserName AS CHARACTER ).

    METHOD PUBLIC CHARACTER GetAttribute ( iUserid   AS INTEGER,
                                           cAttrName AS CHARACTER ).

    METHOD PUBLIC CHARACTER EXTENT GetAttributeNames ( iUserid AS INTEGER ).

    METHOD PUBLIC CHARACTER EXTENT GetUserNames ( ).

    METHOD PUBLIC CHARACTER EXTENT GetUserNamesByQuery ( cQueryString AS CHARACTER ).

    METHOD PUBLIC LOGICAL SetAttribute ( iUserid    AS INTEGER,
                                         cAttrName  AS CHARACTER,
                                         cAttrValue AS CHARACTER ).

    METHOD PUBLIC LOGICAL RemoveAttribute ( iUserid   AS INTEGER,
                                            cAttrName AS CHARACTER ).

    METHOD PUBLIC LOGICAL ValidatePassword ( iUserid   AS INTEGER,
                                             cPassword AS CHARACTER ).

    METHOD PUBLIC LOGICAL ValidatePassword ( iUserid    AS INTEGER,
                                             cDigest    AS CHARACTER,
                                             cNonce     AS CHARACTER,
                                             cTimestamp AS CHARACTER ).

END INTERFACE.

Sample classes

The following files are required for the OERealm ABL service interface. These files should be placed in your Progress Application Server instance within the application PROPATH, following the OpenEdge/Security/Realm folder structure. Refer to each page below for the code and detailed instructions on where to place each file.

Server activation (continued)

To verify that a PAS client carries the expected Client-Principal (CP) token, you can add a session activate procedure that runs on every request. This helps confirm that OERealm security is functioning correctly once fully configured. After validating that the CP token matches the application users, replace this logic with the SECURITY-POLICY:SET-CLIENT() method or the SET-DB-CLIENT() function as needed to assert the user’s identity to the session or database. For more details, see OpenEdge-performed authentication and SSO.

  1. Copy the following content into a file named activate.p and add it to the PROPATH of your PAS for OpenEdge instance:
      DEFINE VARIABLE hCP      AS HANDLE NO-UNDO.
      DEFINE VARIABLE cCCID    AS CHARACTER NO-UNDO.
      DEFINE VARIABLE cReqName AS CHARACTER NO-UNDO.
    
      hCP = SESSION:CURRENT-REQUEST-INFO:GetClientPrincipal().
      cCCID = SESSION:CURRENT-REQUEST-INFO:clientContextID.
      cReqName = SESSION:CURRENT-REQUEST-INFO:procedureName.
    
      run dumpCP.p (hCP, cReqName).
  2. Copy the following content into a file named dumpCP.p and add it to the PROPATH of your PAS for OpenEdge instance:
      define input param p_hCP  as handle no-undo. 
      define input param p_cCtx as character no-undo. 
      
      OUTPUT to value("dumpCP.out").
      
      if (? = p_cCtx) then p_cCtx = "".
      
      if ( NOT valid-handle(p_hCP) ) then
          message p_cCtx "Client-Principal: <invalid-handle>".
      else do:
          define variable cList           as character no-undo. 
          define variable iListSize       as integer initial 0 no-undo. 
          define variable iListPos        as integer no-undo. 
      
      
          message p_cCtx "Client-Principal:".
          message "    ID:         '" + p_hCP:qualified-user-id + "'".
          message "    session-id:" p_hCP:session-id.
          message "    state:     " p_hCP:login-state.
          message "    created:   " p_hCP:seal-timestamp. 
      
          if (? <> p_hCP:login-expiration-timestamp ) then
              message "       expires:" string(p_hCP:login-expiration-timestamp).  
          if ("" <> p_hCP:state-detail ) then
              message "       details:" p_hCP:state-detail.
          if ("" <> p_hCP:roles ) then
              message "         roles:" p_hCP:roles.
          if ("" <> p_hCP:domain-description ) then
              message "   domain desc:" p_hCP:domain-description.
          if ("" <> p_hCP:domain-type ) then
              message "  domanin type:" p_hCP:domain-type.
          if ("" <> p_hCP:login-host ) then
              message "    login host:" p_hCP:login-host.
          if ("" <> p_hCP:audit-event-context ) then
              message "     audit ctx:" p_hCP:audit-event-context.
          if ("" <> p_hCP:client-tty ) then
              message "    client tty:" p_hCP:client-tty.
          if ("" <> p_hCP:client-workstation ) then
              message "    client wrk:" p_hCP:client-workstation.
      
          cList = p_hCP:list-property-names.
          iListSize = num-entries(cList, ",").
          if ( 0 < iListSize ) then do iListPos = 1 to iListSize:
              define variable cProp       as character no-undo. 
              define variable cVal        as character no-undo. 
      
              message "    properties:".
              cProp = entry(iListPos, cList, ",").
              cVal = p_hCP:get-property(cProp).
              message "          property:" cProp ", value:" cVal.
          end.
      
          cList = p_hCP:db-list.
          iListSize = num-entries(cList, ",").
          if ( 0 < iListSize ) then do iListPos = 1 to iListSize:
              define variable cLDB        as character no-undo. 
              define variable cTenant     as character no-undo. 
              define variable cTenantID   as integer no-undo. 
      
              message "    tenant db list:".
              cLDB = entry(iListPos, cList, ",").
              cTenant = p_hCP:tenant-name(?).
              cTenantID = p_hCP:tenant-id(?).
              /*  cTenant = p_hCP:tenant-name(cLDB).
              cTenantID = p_hCP:tenant-id(cLDB). */
              message "          db:" cLDB ", tenant:" cTenant ", tenant-id:" string(cTenantID).
          end. 
      end.
      
      OUTPUT CLOSE.
  3. Open the CATALINA_BASE/conf/openedge.properties file and locate the section AppServer.Agent.ablapp_name, where ablapp_name is the name of the ABL application linked to the ABL web application (webapp) that will use OERealm security.

    For example, if the ABL application name is RealmExample, the section would appear as:

    AppServer.Agent.RealmExample
    Add the activate.p session activation procedure to this section:
    sessionActivateProc=activate.p

Next, proceed to the Integrate OERealm with Spring Security for PAS for OpenEdge.

For more details, see OERealm security considerations.