Overview

Skill Level: Any Skill Level

Developers and Websphere specialists

Ingredients

z/OS LPAR with Liberty Profile, Customer Information Control System (CICS) and Rational Application Developer for z (RDZ)

Step-by-step

  1. Introduction

    WOLA enables local and bidirectional communication between a WAS server (Liberty or Full Profile) and processes in z/OS, which can be batch jobs, IMS or CICS servers. A WAS Java Enterprise (JEE) application can access a z/OS native application, or be accessed by it, provided that both run on the same partition (LPAR). This article is about identity assertion and propagation in “outbound” applications, that is, originating from WAS and accessing a program in CICS. The outbound access from Java EE applications follows the JCA standard.

    It is worth mentioning alternative JCA adapters for remote or local CICS access like CICS Transaction Gateway (CTG).

  2. The user’s identity problem

    Back end system access from JEE applications is usually made by using a service (or generic) user whose ID and password are configured in the “connection factory” object and passed by the software when establishing the connection, as we can see below:

    When Elisa or Carlos use the Java application in WAS, they are required to authenticate. In this example the WAS is configured to perform authentication on a LDAP server (lightweight Directory Access Protocol). Then, the Java application calls a CICS program but, the user’s identity the CICS application runs under is the generic user (GENUSER in the illustration), no matter who is the actual user. Proceed in this way is simple and efficient, the same connection can be utilized in successive transactions by different users without having to authenticate again. On the other hand, we lost tracking. Database updates, messages sent, log messages or any other actions taken by the CICS program will not carry the identities of real users. We have also some additional problems:

    In a Liberty Profile server using WOLA, this setting would be like the example below, extracted from the server.xml file:

    <connectionFactory jndiName=”eis/legacy” containerAuthDataRef=”olaauth”>
    <properties.ola RegisterName=”OLASERVER/>
    </connectionFactory>
    <authData id=”olaauth” user=”genuser” password=”{xor}Lz4sLCgwLTtt” />

    • “genuser” is a user id on the z/OS security system authorized to access business logic in CICS, a COBOL program for example.
    • “genuser’s” password is encoded just to avoid accidental exposure. It is not a cryptographic protection and can be easily reversed.
    • “OLASERVER” represents the CICS server.

    The configuration file must be protected, from reading and writing. Its exposure opens the door to several transactions in CICS environment. Even protected, the infrastructure personnel will always have access to this information.

  3. What is identity assertion?

    To avoid those problems, application servers such as WebSphere support identity assertion, what consists in telling the partner system which identity is to be used without any password checking. For remote systems this requires secure communication and certificate authentication. As WOLA is local, no communication security concerns apply. Conceptually we have three different ways of identity assertion:

    • Scenario 1
      A fixed service user on the target system, such as “genuser”. The only advantage is not to use a password for authentication. Still no traceability. This option is supported on calls between JEE servers (Java X Java), but not by WOLA.
    • Scenario 2
      Passing the identity of the actual user. This is the best option but the user has to be “known” to the CICS system, That is, the authentication mechanism should be the same. We will test the option in this tutorial. The next figure shows the situation:

    Now, WAS Liberty still authenticates Elisa and Carlos when they access the application for the first time but now the z/OS security system (RACF) is used. Elisa and Carlos are registered in RACF and have permission to run the necessary programs in CICS. All components of the transaction are executed under the authority of the real user (Elisa / Carlos), including the database SQL instructions performed by the program. We have total traceability.

    • Scenario 3
      The third option is “identity propagation”, a combination of the other two. In this case the user is authenticated in a distributed system, typically LDAP, and the identity is mapped to a service user on the server system. The service user is used for authorization checks and both the service and remote user information are maintained to provide traceability, as shown next:

    This option is currently supported only by Liberty JVMSEREVR which is part of CICS TS 5.3 or by Full Profile using the CICS Transaction Gateway. We will not test that scenario here.

  4. Java application

    In order to test identity assertion we have built an application with a servlet and an EJB. The EJB makes a standard JCA call to a CICS/COBOL program using WOLA. The COBOL retrieves control information from z/OS through CICS calls and returns this information to the EJB. Finally, the authenticated user in the WAS and the information extracted by the COBOL program are shown in the browsed for comparison.

    The servlet is associated with LegacyUser shortcut, and called in the test machine as: https://172.24.200.46:9443/COBCliWeb/LegacyUser

    The relevant application parts follow:

    WebServlet("/LegacyUser")
    // @HttpConstraint(rolesAllowed="authservlet", transportGuarantee=TransportGuarantee.CONFIDENTIAL) //Does not work
    public class LegacyUserServlet extends HttpServlet {
    ...
    @EJB(beanName="COBCliBean")
    COBCliBeanLocal lbean;

    The security annotation (HttpConstraint) for the servlet did not work and was commented. Since it is necessary to protect the application from unauthorized access, you can use the deployment descriptor (web.xml) in spite of annotations. The configuration shown below, only allows HTTP GET and POST methods from users in role “authsetvlet”:

     <security-constraint>
    <web-resource-collection>
    <web-resource-name />
    <url-pattern>/*</url-pattern>
    <http-method-omission>GET</http-method-omission>
    <http-method-omission>POST</http-method-omission>
    </web-resource-collection>
    </security-constraint>
    <security-constraint>
    <web-resource-collection>
    <web-resource-name />
    <url-pattern>/*</url-pattern>
    <http-method>GET</http-method>
    <http-method>POST</http-method>
    </web-resource-collection>
    <auth-constraint>
    <role-name>authservlet</role-name>
    </auth-constraint>
    <user-data-constraint>
    <transport-guarantee>CONFIDENTIAL</...>
    </user-data-constraint>
    </security-constraint>

    We also configured the type of authentication in web.xml. As basic authentication (browse collects userid/password) is not secure, we used form authentication:

     <login-config>
    <auth-method>FORM</auth-method>
    <form-login-config>
    <form-login-page>/logon.html</form-login-page>
    <form-error-page>/logonError.html</form-error-page>
    </form-login-config>
    </login-config>

    The JEE specification does not define another way to configure the login page, only the web.xml. No annotation exists. The logon.html page is very simple. For a test, there is no need for embellishment. The HTML code follows:

    <!DOCTYPE HTML>
    <html>
    <head>
    <title>logon</title>
    <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
    </head>
    <body>
    <form action="j_security_check" method=post>
    <p><strong>Please Enter Your User Name: </strong>
    <input type="text" name="j_username" size="25">
    <p><p><strong>Please Enter Your Password: </strong>
    <input type="password" size="15" name="j_password">
    <p><p>
    <input type="submit" value="Submit">
    <input type="reset" value="Reset">
    </form>
    </body>
    </html>

    When accessing the application for the first time, the login page appears. The authentication will be done by WebSphere. This is indicated by j_security_check standard action. The screen is displayed below:

    The servlet runs once the user is authenticated. The answer is thrown directly into the browser with no special formatting:

     protected void doPost ... {
    try {
    response.getWriter().println(request.getRemoteUser() + "/" + lbean.getUser());
    } catch (Exception e) {...
    } finally {
    response.setHeader("Cache-Control", "no-cache");
    response.setHeader("Pragma", "no-cache");
    response.setHeader("Expires", "0");
    response.getWriter().flush();

    The answer is the concatenation of “request.getRemoteUser”, which identifies the user as authenticated by the application server and the result of calling the EJB method “getUser”, which access a CICS program:

     public String getUser() throws ResourceException {
    Connection conn = cf.getConnection();
    CICSUserCommarea input = new CICSUserCommarea();
    ...
    CICSUserCommarea output = new CICSUserCommarea();
    Interaction inter = conn.createInteraction();
    try {
    inter.execute(is, input, output);
    return output.getCics__user();
    } finally {
    inter.close();
    conn.close();
    }
    }

    The variable cf contains the “connection factory” and is is an object of type “interaction spec.” Both instantiated at startup EJB.

    The parameters for the CICS program are passed through a CICSUserCommarea type object that translates the parameters exchanged with the CICS program. Although the program uses a single parameter area for input and output, the JCA standard specifies separate areas. The program returns the identity of the executing user on CICS and this information is passed back to the servlet.

    The CICSUserCommarea Java class corresponds to the CICS program parameter area and does the conversion work between Java and COBOL. The class can be created from the COBOL code in two ways: with JZOS, a Java z/OS component and using RAD in a developer station. The COBOL parameter area to be translated is as follows:

    01 DFHCOMMAREA.
    03 CICS-USER PIC X(8).
    03 RACF-RREALM PIC X(256).
    03 RACF-RUSER PIC X(256).

    The RACF-RREALM and RACF-Ruser information identifies the remote user mapped to the generic user in scenario 3 (identity propagation). Although we do not consider this scenario here, the COBOL program is prepared to it. Here we have the EJB construction and how variables cf and is are initialized:

    @Stateless
    @TransactionManagement(value=TransactionManagementType.CONTAINER)
    @TransactionAttribute(value=TransactionAttributeType.NOT_SUPPORTED)
    @RolesAllowed("authejb")
    @Local(COBCliBeanLocal.class)
    @Remote(COBCliBeanRemote.class)
    @LocalBean
    public class COBCliBean implements COBCliBeanRemote, COBCliBeanLocal {
    @Resource(lookup="eis/legacy")
    private ConnectionFactory cf;
    @Resource
    private SessionContext ctx;
    private InteractionSpec is = null;

    The EJB is protected by @RolesAllowed(“authejb”) annotation. The “connection factory” is injected. The “interaction spec” variable “is”, is a type of object whose definition depends on the implementation, that is, their properties are defined by the supplier. For WOLA, this object contains the information “service name”, which is the program name to be called in CICS. To fill the value, we would have to do something like:

    ((com.ibm.websphere.ola.InteractionSpecImpl) is).setServiceName(“CICSUSER”);

    This makes the code attached to the implementation class. The application cannot transparently access CICS in other ways, as using CTG. The JCA specification allows the vendor to externalize their proprietary classes so that we can pass the parameters by configuration. Unfortunately, WOLA developers have not done it. To improve the application, we create a file with the name of the implementation class and the property:

    isclass = com.ibm.WebSphere.ola.InteractionSpecImpl
    serviceName = CICSUSER

    The variable is then initialized in the EJB constructor, with the help of BeanUtils class:

      public COBCliBean() {
    InputStream input = null;
    try {
    input = this.getClass().getClassLoader().getResourceAsStream("COBCli.properties");
    if(input != null) {
    Properties props = new Properties();
    props.load(input);
    is = (InteractionSpec) Class.forName(props.getProperty("isclass")).newInstance();
    BeanUtils.populate(is, new HashMap(props));
  5. COBOL program

    The COBOL test code is very simple:

            ID DIVISION.
    PROGRAM-ID. CICSUSER.
    ENVIRONMENT DIVISION.
    DATA DIVISION.
    WORKING-STORAGE SECTION.
    01 WRK.
    03 W-RREALM PIC N(256) USAGE NATIONAL.
    03 W-RUSER PIC N(256) USAGE NATIONAL.
    LINKAGE SECTION.
    01 DFHCOMMAREA.
    03 CICS-USER PIC X(8).
    03 RACF-RREALM PIC X(256).
    03 RACF-RUSER PIC X(256).
    PROCEDURE DIVISION.
    1. EXEC CICS ASSIGN USERID(CICS-USER) END-EXEC.
    * EXEC CICS INQUIRE ASSOCIATION(EIBTASKN) DNAME(W-RUSER)
    * REALM(W-RREALM) END-EXEC.
    * MOVE FUNCTION DISPLAY-OF (W-RUSER, 1208) TO RACF-RUSER.
    * MOVE FUNCTION DISPLAY-OF (W-RREALM, 1208) TO RACF-RREALM.
    EXEC CICS RETURN END-EXEC.

    The first statement retrieves the user ID while the second gets remote user data mapped in the case of scenario 3. The realm identifies how the remote user has been authenticated and may contain a domain name or an LDAP server ID. The information is maintained in its original UTF-8 form so, there is an EBCDIC conversion. For scenario 2 test these statements were commented.

  6. Liberty configuration

    Follow the relevant details in server.xml configuration. The “features were:

     <featureManager>
    <feature>zosSecurity-1.0</feature>
    <feature>zosTransaction-1.0</feature>
    <feature>zosLocalAdapters-1.0</feature>
    <feature>ssl-1.0</feature>
    <feature>restConnector-1.0</feature>
    <feature>appSecurity-2.0</feature>
    <feature>jsp-2.3</feature>
    <feature>cdi-1.2</feature>
    <feature>jca-1.7</feature>
    <feature>jndi-1.0</feature>
    <feature>localConnector-1.0</feature>
    <feature>ejbLite-3.2</feature>
    </featureManager>

    z/OS Security enables z/OS (RACF) authentication and z/OS Local Adapters is WOLA. We need to define a key store, the user registry and activate administrative security, as follows:

     <keyStore id="defaultKeyStore" password="passw0rd" />
    <safRegistry id="saf" />
    <administrator-role>
    <group>was</group>
    </administrator-role>

    The “keystore” is required to maintain digital certificates, since we require access protection (“<transport-guarantee> CONFIDENTIAL </ …>”) in the application web.xml. The “safRegistry indicates we authenticate users on z/OS. SAF (System Authorization Facility) refers to the interface. the implementation is IBM’s RACF, present in the test machine. the tag “<administrator-role>” determines that administrator users for this server must belong to group “WAS” in SAF (RACF).

    The server will be accessed through the ports 9080 (HTTP) and 9443 (HTTPS):

     <httpEndpoint id="defaultHttpEndpoint" host="*" httpPort="9080" httpsPort="9443" />

    This is the adapter and “connection factory” definition:

     <zosLocalAdapters wolaGroup="Liberty" wolaName2="WOLA" wolaName3="SERVER1" useCicsTaskUserId="true" />
    <connectionFactory id="wolaCF" jndiName="eis/legacy">
    <properties.ola RegisterName="CICSAOR2" />
    </connectionFactory>

    Unlike other adapters, WOLA requires the partner process to register before you can perform calls. As there could be different WAS servers in the LPAR, each WAS instance is identified by a 3-part name. In the case of Full Profile, this name is composed of the cell name, node, and server and can not be modified. For Liberty Profile, names are of free choice, provided that the combination is unique in the LPAR. When CICS register, it will also provide a unique name, referenced in the connection factory as the “register name” (CICSAOR2). What happens can be read as follows: An instance of CICS is registered with the name “CICSAOR2” to an instance of WAS, named as “Liberty/WOLA/ SERVER1”.

    There is no userid/password in connection factory. the useCicsTaskUserId=”true” parameter causes the authenticated user in WAS to be forwarded to CICS.

    We created a “shared library” to accommodate the Apache Bean Utils and properties file:

     <library id="lib">
    <fileset dir="/usr/lpp/zWebSphere/Liberty/V8R5/usr/servers/server1/lib" includes="*.jar" />
    <folder dir="/usr/lpp/zWebSphere/Liberty/V8R5/usr/servers/server1/lib" />
    </library>

    Here is the application definition. We can see the association of roles to authorize access to both the servlet and EJB with the WAS group (in RACF). We also have an application classloader for the “shared library” and adapter classes:

     <application location="COBCliApp.ear">
    <classloader commonLibraryRef="lib" classProviderRef="ola" />
    <application-bnd>
    <security-role name="authservlet">
    <group name="was" />
    </security-role>
    <security-role name="authejb">
    <group name="was" />
    </security-role>
    </application-bnd>
    </application>
  7. CICS

    To allow identity assertion CICS have to start with XUSER and XTRAN parameters set. These parameters are specified in the SYSIN card of CICS execution JCL. The output (SYSOUT) will show the parameters used:

    13.19.09 STC06455 IEF695I START CICSAOR2 WITH JOBNAME CICSAOR2 IS ASSIGNED TO USER SYSSTC , GROUP SYSPROC
    13.19.09 STC06455 $HASP373 CICSAOR2 STARTED
    13.19.09 STC06455 IEF403I CICSAOR2 – STARTED – TIME=13.19.09

    13.19.09 STC06455 DFHPA1927 CICSACB2 XTRAN=YES, 00370062

    13.19.09 STC06455 DFHPA1927 CICSACB2 XAPPC=NO, 00450038
    13.19.09 STC06455 DFHPA1927 CICSACB2 XUSER=YES, 00460061

    To start WOLA you must first activate a provided communication exit routine, the Task Related User Exit (TRUE). Such activation is done through the WOLA control transaction (BBOC), started from a CICS terminal:

    BBOC START_TRUE

    Since TRUE is enabled, we should start WOLA itself using the same control transaction, also from a CICS terminal:

    BBOC START_SRVR RGN=CICSAOR2 DGN=Liberty NDN=WOLA SVN=SERVER1 SVC=* MNC=1 MXC=10 TXN=Y SEC=Y REU=N TRC=2

    Communication is established as follows: CICS identifies the WAS by DGN + NDN + SVN (Liberty + WOLA + SERVER1) and register with the RGN name (CICSAOR2). Then, to call this CICS, just use the register name (RegisterName=”CICSAOR2″) on a connection factory in WAS, as previously shown.

    Note: In a real environment, the implementation of the two activation transactions above should be automated as a part of CICS startup.

    WOLA uses “Link Server” (BBO$) and “Link Invocation” (BBO#) transactions to run programs in CICS. When identity assertion is configured, BBO$ starts BBO# changing user identity. However, BBO$ runs under the credentials of the user who performed the registration process (BBOC START_SRVR). Figure below depicts the execution:

    The above diagram can be read as: WAS and CICS are z/OS started tasks. An application running on WAS by the user ID accesses CICS. The end user identity is passed to the transaction BBO$, which runs under the user who issued the command START_SRVR (LNKSRVID). The transaction BBO$ starts a new transaction BBO# asserting the user’s identity to the identity forwarded by WAS. The BBO# transaction in turn runs the desired program. No password is passed or checked during all process.

    The operator who initiated WOLA (LNKSRVID) must have a special “surrogate” authorization in RACF. The necessary commands are:

    RDEFINE SURROGAT * .DFHSTART UACC (NONE)
    SETROPTS CLASSACT (SURROGAT) RACLIST (SURROGAT)
    * PERMIT CLASS .DFHSTART (SURROGAT) ID (LNKSRVID)
    SETROPTS RACLIST (SURROGAT) REFRESH

    Additionally, the user whose identity is ID must be authorized in CICS to run the transaction BBO# and to link the program.

  8. Testing the application

    Calling the application from the browser with the correspondent URL makes the authentication form appear. Once authenticated, we have the response containing the concatenation of the remote and CICS userids and can confirm they are the same. Notice that because of the default configuration, z/OS user ids are converted to uppercase:

  9. Next steps

    Scenario 2 requires user authentication on z/OS what limits it to internal users: employees and collaborators. In general, customers and suppliers have no direct access to z/OS.

    In CICS version 5.3, scenario 3 can be implemented by setting the appropriate features in a Liberty JVMSERVER (a Liberty Profile which is part of CICS), along with LDAP authentication. It is also possible to implement scenario 3 with WAS Full Profile accessing CICS on z/OS via CTG. In this case, WAS can run remotely, in a distributed environment.

  10. Resources

    Source code and configuration: https://github.com/jtitop/IAWOLACICSZ

    Liberty Profile information in Developerworks from the basics. It includes downloads and product development tools:

    https://developer.ibm.com/wasdev/WebSphere-Liberty/

    How to Configure Liberty Profile and WOLA on z/OS (set of “techdocs” and videos with all information):

    https://www-03.ibm.com/support/techdocs/atsmastr.nsf/WebIndex/WP101490/

    An introduction to WOLA, including its use with WAS Full Profile:

    WOLA Architectural Considensratios

    Tutorials about J2C code generation:

    How to configure scenario 3 with Liberty JVMSERVER in CICS TS 5.3:
    https://www.ibm.com/support/knowledgecenter/en/SSGMCP_5.3.0/com.ibm.cics.ts.java.doc/topics/dist_identity.html?view=embed#distributed_identity

1 comment on"Identity Assertion with Liberty and WOLA on z/OS and CICS"

  1. […] Paiva recently published a tutorial on the developerWorks Recipes site. The tutorial shows how to provide the identity of the end-user of Java EE applications that are […]

Join The Discussion