Try OpenEdge Now
skip to main content
Programming Interfaces
Data Management : Application Security : Authenticating and managing user identity in ABL : Establishing and managing identity for multi-tier applications : Initializing a client-principal object for a multi-tier application
 
Initializing a client-principal object for a multi-tier application
The code examples in this section show two approaches to initializing the client-principal object for a multi-tier application. Both examples test for the AppServer operating mode and both add the sealed client principal to a database that stores session context. The examples differ in the way the client-principal object is accessed.
The following code fragment shows the use of the GetClientPrincipal ( ) method to access an unsealed client-principal object. The client-principal object is created in a Progress.Lang.OERequestInfo instance. OERequestInfo is automatically initialized when a CREATE SERVER statement executes on an ABL client and can be referenced using the attributes of the SESSION system handle.
The following code fragment also shows the use of the SetClientPrincipal ( ) method to store a deep copy (clone) of the client principal in the OERequestInfo instance after either the success or failure of authentication.
Client principal initialization using GetClientPrincipal (  ) and SetClientPrincipal ( ) methods
DEFINE VARIABLE hCP AS HANDLE NO-ERROR.

/* Get unsealed Client Principal from client and create a deep copy.*/

hCP:SESSION:CURRENT-REQUEST-INFO:GetClientPrincipal().

IF (SESSION:SERVER-OPERATING-MODE = "State-free" OR
    SESSION:SERVER-OPERATING-MODE = "Stateless") THEN DO:
    hCP:SESSION-ID = SESSION:CURRENT-REQUEST-INFO:ClientContextId.

END. /* ELSE Other session-managed operating modes don't need it */

/* Initialize audit and other context info */
m_hCP:AUDIT-EVENT-CONTEXT = m_hCP:USER-ID + "@" + hCP:DOMAIN-NAME.
m_hCP:CLIENT-TTY = SESSION:CLIENT-TYPE + "." + SESSION:DISPLAY-TYPE.

/* Authenticate and seal client-principal */
IF SECURITY-POLICY:SET-CLIENT(hCP) THEN /* Authn succeeded */
  SESSION:CURRENT-RESPONSE-INFO:SetClientPrincipal(hcp). /* Return sealed Client Principal*/
  IF (SESSION:SERVER-OPERATING-MODE = "State-free" OR
      SESSION:SERVER-OPERATING-MODE = "State-aware") THEN DO:
    /* Add sealed Client Principal to client context store */
    ASSIGN
      ContextDB.ContextID = hCP:SESSION-ID /* Add key to context store */
      ContextDB.ContextC-P = hcp:EXPORT-PRINCIPAL(). /* Add sealed Client Principal as RAW value to context store */
  END.
ELSE DO: /* If authn fails, return failed C-P to client*/
  SESSION:CURRENT-RESPONSE-INFO:SetClientPrincipal(hcp).
END.
DELETE OBJECT hCP.
Note: The GetClientPrincipal ( ) and SetClientPrincipal ( ) methods were implemented in OpenEdge Release 11.2. Therefore, the previous example only applies to 11.2 and later OpenEdge releases. For more information about these methods and other ABL features, see OpenEdge Development: ABL Reference.
The next code fragment shows the use of the IMPORT-PRINCIPAL ( ) and EXPORT-PRINCIPAL ( ) methods for initializing the client-principal object. Using these methods requires that the client-principal object is explicitly created in the code, rather than referenced as an attribute of the SESSION system handle, as in the previous example. Also note, that in this case the client-principal object is passed as a parameter rather than referenced as an attribute.
Client-principal initialization using the IMPORT-PRINCIPAL (  ) and EXPORT-PRINCIPAL ( ) methods
DEFINE INPUT  PARAMETER prCPIn  AS RAW NO-ERROR. /* Unsealed C-P to authn */
DEFINE OUTPUT PARAMETER prCPOut AS RAW NO-ERROR. /* Sealed C-P to return */

DEFINE VARIABLE m_hCP AS HANDLE NO-ERROR.

CREATE CLIENT-PRINCIPAL m_hCP.
m_hCP:IMPORT-PRINCIPAL(prCPIn). /* Import unsealed C-P from client */

IF (SESSION:SERVER-OPERATING-MODE = "State-free" OR
    SESSION:SERVER-OPERATING-MODE = "Stateless") THEN DO:
  m_hCP:SESSION-ID = SESSION:CURRENT-REQUEST-INFO:ClientContextId.

END. /* ELSE Other session-managed operating modes don't need it */

/* Initialize audit and other context info */
m_hCP:AUDIT-EVENT-CONTEXT = m_hCP:USER-ID + "@" + m_hCP:DOMAIN-NAME.
m_hCP:CLIENT-TTY = SESSION:CLIENT-TYPE + "." + SESSION:DISPLAY-TYPE.

/* Authenticate and seal client-principal */
IF SECURITY-POLICY:SET-CLIENT(m_hCP) THEN /* Authn succeeded */
  prCPOut = m_hCP:EXPORT-PRINCIPAL( ). /* Export sealed C-P to client */
  IF (SESSION:SERVER-OPERATING-MODE = "State-free" OR
      SESSION:SERVER-OPERATING-MODE = "State-aware") THEN DO:
    /* Add sealed C-P to client context store */
    ASSIGN
      ContextDB.ContextID = m_hCP:SESSION-ID /* Add key to context store */
      ContextDB.ContextC-P = prCPOut. /* Add exported C-P */
  END.
ELSE DO: /* Authn failed */
  prCPOut = m_hCP:EXPORT-PRINCIPAL( ). /* Export failed C-P to client */
END.

DELETE OBJECT m_hCP.
For the state-free and stateless operating modes, both code fragments set the SESSION-ID attribute to the ClientContextId property value obtained from the OERequestInfo object returned by the CURRENT-REQUEST-INFO attribute on the SESSION system handle. This property is automatically initialized with a GUID value when the client initially creates the server handle to access the authentication server. This ClientContextId property value, as well as the sealed client-principal set on the CURRENT-RESPONSE-INFO handle in the first example, remain unchanged during all subsequent requests from the client to the AppServer (using the same server handle) unless either the client or the AppServer change them.
A stateless application service can also identify each request by the client connection and key a context store using the SERVER-CONNECTION-ID attribute on the SESSION system handle. However, it also needs a unique value to set the SESSION-ID attribute in the client-principal for auditing purposes. Because the same ClientContextId property value is both globally unique and can be easily passed between sessions, the management of stateless context can be simplified by using this one value for both purposes instead of creating a separate unique value for auditing with the ABL GENERATE-UUID function. This one inter-session value ensures that a unique user login session auditing record is recorded across all possible AppServer sessions and can also be used to key a context store for the login session.
Both stateless and state-free application services must manage user context in order to export, store, retrieve, and import different client-principal objects between client requests. In releases prior to OpenEdge 11.0, but they must do it differently according to their respective session-managed and session-free behavior. With Release 11.0, application services running in either operating mode can take advantage of the same ClientContextId property mechanism.
However, the SESSION:SERVER-CONNECTION-ID attribute and GENERATE-UUID function mechanisms continue to work for stateless operating mode. The following sections provide more detail using different examples on how to manage identity for both stateless and state-free application services.