Dovetailed Technologies

Enabling SAF Security

This document describes how to configure your Tomcat installation to use SAF for J2EE user Authentication and Authorization.

These instructions require modifications to the Tomcat server.xml file. Make a backup copy before making any changes. Note: All tomcat configuration files, including server.xml are in codepage ISO8859-1 (ASCII). See editing ASCII files on the mainframe for more details.

Configuring Tomcat to use SAF for user authentication and authorization is different than running Tomcat under a Java security manager. For instructions on how to do this, see: Tomcat and the Java SecurityManager

Note: These instructions make a distinction between CATALINA_HOME and CATALINA_BASE. The steps will also work if CATALINA_HOME == CATALINA_BASE.

  1. set the program controlled extended attribute on the JZOS shared libraries:
    extattr +p libjzos*.so

    Note: Your userid must be authorized to set this attribute. If you are not authorized, your system programmer will either need to set the attribute, or grant you the authority to do it. See the troubleshooting section below for more details.

  2. Program control the PDSE library that contains the JZOSVMxx modules:
    RALTER PROGRAM * ADDMEM ('<JZOS_PDSE_LOADLIB>'//NOPADCHK) UACC(READ)
    SETROPTS WHEN(PROGRAM) REFRESH

    Also at this time, you may want to confirm that the c/c++ runtime libraries are also program controlled. They should be, but if they were missed during installation, the SAF calls will not work properly. See the troubleshooting section below for more details on how to do this.

  3. Make a backup copy of the file <CATALINA_BASE>/conf/server.xml.
  4. Edit server.xml and add the following listener element:
    <Listener className="com.dovetail.zos.tomcat.SafLifecycleListener" />
    Before this element:
    <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
  5. Just below the listener element, change the UserDatabase element to look like this:

    For Tomcat 5.5.X and 6.0.X

    <Resource name="UserDatabase"
      auth="Container"
      type="org.apache.catalina.UserDatabase"
      description="z/OS Role database"
      factory="com.dovetail.zos.tomcat.SafRoleDatabaseFactory"
      pathname="conf/saf-roles.xml" />

    For Tomcat 5.0.X

    <Resource name="UserDatabase"
      auth="Container"
      type="org.apache.catalina.UserDatabase"
      description="z/OS Role database.">
    </Resource>
    <ResourceParams name="UserDatabase">
      <parameter>
        <name>factory</name>
        <value>com.dovetail.zos.tomcat.SafRoleDatabaseFactory</value>
      </parameter>
      <parameter>
        <name>pathname</name>
        <value>conf/saf-roles.xml</value>
      </parameter>
    </ResourceParams>
    The resource name must remain UserDatabase in order for the Tomcat JMX admin page to work properly - don't change it.
  6. Edit server.xml and comment out the active Realm element (usually UserDatabaseRealm):
    <!--
    <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
      debug="0" resourceName="UserDatabase"/>
    -->
    Then insert the following Realm:
    <Realm className="com.dovetail.zos.tomcat.SafRealm" resourceName="UserDatabase" />
  7. Download the latest saf_realm.zip file for the version of Tomcat you are using from the downloads page.
  8. FTP this file (in binary) to z/OS and extract its contents to a temporary directory:

    jar -xvf saf_realm_5.5_1.2.4.zip OR jar -xvf saf_realm_5.0_1.2.4.zip

  9. Copy the extracted saf_realm.jar to the Tomcat installation:

    For Tomcat 6.0.X

    cp saf_realm.jar <CATALINA_HOME>/lib

    For Tomcat 5.0.X and 5.5.X

    cp saf_realm.jar <CATALINA_HOME>/server/lib
  10. Copy the extracted saf-roles.xml file to the Tomcat configuration directory:
    cp saf-roles.xml <CATALINA_BASE>/conf/saf-roles.xml
  11. Add desired role/saf mappings to the newly copied file <TOMCAT_HOME>/conf/saf-roles.xml. This file initially has two mappings; the "admin" and "manager" role.  In order to operate the Administration and Manager pages under tomcat, the authenticated user must have the SAF authority described by this entry.
    <?xml version='1.0' encoding='utf-8'?>
    <saf-roles>
      <role rolename="admin" safclass="FACILITY" safentity="BPX.SERVER" saflevel="READ"/>
      <role rolename="manager" safclass="FACILITY" safentity="BPX.SERVER" saflevel="READ"/>
    <saf-roles>

    Tomcat 6.0.x Note: The admin webapp is no longer supplied with Tomcat, so the admin role is not defined in the 6.0 version of saf-roles.xml.

    The following table describes the role element attributes:
    attribute
    Description
    Required
    Default
    rolename
    The J2EE role to be mapped
    Yes
    n/a
    safclass
    The SAF class, e.g FACILITY, DATASET, etc...
    No
    EJBROLE
    safentity
    The SAF entity within the safclass, e.g BPX.SERVER, 'dsn', etc...
    Yes
    n/a
    saflevel
    The SAF authority level.  One of ALTER, CONTROL. READ, UPDATE
    No
    READ

    This file can be directly edited prior to starting Tomcat.

  12. SUBMIT the TOMCAT JCL and when started, bring up the Tomcat manager page:
    http://your.domain:8080/manager/html
  13. Supply the desired SAF userid and password as credentials.

    If everything is setup and configured correctly, the Tomcat manager page will display. If not, check the STDOUT and STDERR
    DDs for more information. The SafRealm classes will dump diagnostic info if authorization fails.

  14. Once Tomcat is running, roles can be added, deleted and modified via the admin interface. To specify a mapping using the admin interface, supply the saf attributes in the role's description field using the following format:
    {safclass}/{safentity}/{saflevel} - Note that all three components are required when using the admin page
    Changes are immediately written to the saf-roles.xml ile.

    Tomcat 6.0.x Note: The admin webapp is no longer supplied with Tomcat, so changes to the saf-roles.xml file should be made manually

Troubleshooting SAF security problems with SafTest

Getting Tomcat configured properly to work with SAF can be tricky. This section contains some diagnostic information and tests that can be run to help determine where the problem(s) exist.

SafTest

This C program performs simple SAF authentication and authorization
testing.

Usage:
SafTest userid password safClass safEntity
Description:
The program first attempts to authenticate userid with the supplied password, then attempts to test READ level access of the safEntity in the supplied safClass. In order for the authentication portion to succeed, the executable itself must be program controlled. To turn on program control, the extattr command should be run:
extattr +p SafTest
Check that the program control bit was properly set by running:
ls -E SafTest
If the bit is properly set, a "p" will appear in the second position of the extended attributes list for the program:
-rwxr-xr-x -ps- 1 GOETZE1 TEST 155648 Jul 16 13:00 SafTest

If an error occured running extattr, the current needs to be authorized to set this bit.
Have a system programmer grant this authority:

RDEFINE FACILITY BPX.FILEATTR.PROGCTL UACC(NONE)
PERMIT BPX.FILEATTR.PROGCTL CLASS(FACILITY) ID(<user_id>) ACCESS(READ)
SETROPTS RACLIST(FACILITY) REFRESH

Java version of SafTest

There is also a java version of this program which tests the java libraries as well the C runtimes.
The class name is com.dovetail.jzos.testing.SafTest and it should be invoked with the same arguments as the C version. It's probably best to start with the C version, as fewer libraries are involved. Once the C version runs successfully, try invoking the Java version from the z/OS shell. Finally, invoke the Java version from the JZOS batch environment by modifying and submitting the RUN13 or RUN14 JCL:

...
//JAVA EXEC PROC=EXJZOSVM,
// JAVACLS='com.dovetail.jzos.testing.SafTest',
// ARGS='GOETZE1 mypass FACILITY BPX.DAEMON'
//STDENV DD *
...
Check, STDOUT, STDERR and the system log for details in case of a failure. The system log may contain the name of the library that failed.

Examples:

SafTest GOETZE1 mypass FACILITY BPX.DAEMON
This will try to authenticate the userid GOETZE1 with "mypass", then attempt to check READ authority of the BPX.DAEMON entity in the SAF class FACILITY.

The program will display results according to the authority of the current user's capabilities in combination with the userid supplied to the program. The test must run successfully. If it doesn't, the current user probably doesn't have the proper authority to run JZOS within SAF.

In the results that follow, ERRNO and ERRNO2 codes are displayed. For more information about the ERRNO and ERRNO2 (errnojr) codes, see the following IBM publication:
z/OS V1R1.0 UNIX System Services Messages and Codes - SA22-7807-00 (PDF)

In this document, ERRNO is a ReturnCode and the last 4 digits of ERRNO2 is the ReasonCode

Successful execution:

Attempting to authenticate: GOETZE1
Authenticated!
Attempting to authorize: GOETZE1 for FACILITY entity= BPX.DAEMON
Authorization Check succeeded!

The program controlled bit was not properly set:

Attempting to authenticate: GOETZE2
Authentication failed. ERRNO= 157 ERRNO2= 90c02af
Attempting to authorize: GOETZE2 for FACILITY entity= BPX.DAEMON
Authorization Check failed. ERRNO= 139 ERRNO2= 93802af

Here, the 02af low order word of ERRNO2 indicates:

JREnvDirty The specified function is not supported in an address space where a load was done that is not program controlled.

Action: Make sure that programs being loaded from this address space are defined as program controlled.

All of the required libraries, including the C/C++ runtime libs need to be program controlled. Have system programmer program control the runtime libraries (The TSO command RLIST PROGRAM * all can be used to check the status of these libraries):

RALTER PROGRAM * ADDMEM ('<JZOS_PDSE_LOADLIB>'//NOPADCHK) UACC(READ)
RALTER PROGRAM * ADDMEM ('SYS1.LINKLIB'//NOPADCHK) UACC(READ)
RALTER PROGRAM * ADDMEM ('SYS1.CSSLIB'//NOPADCHK) UACC(READ)
RALTER PROGRAM * ADDMEM ('CEE.SCEERUN'//NOPADCHK) UACC(READ)
RALTER PROGRAM * ADDMEM ('CEE.SCEERUN2'//NOPADCHK) UACC(READ)
RALTER PROGRAM * ADDMEM ('CBC.SCLBDLL'//NOPADCHK) UACC(READ)
RALTER PROGRAM * ADDMEM ('SYS1.SEZALINK'//NOPADCHK) UACC(READ)
RALTER PROGRAM * ADDMEM ('DSN710.SDSNEXIT'//NOPADCHK) UACC(READ)
RALTER PROGRAM * ADDMEM ('DSN710.SDSNLOAD'//NOPADCHK) UACC(READ)
RALTER PROGRAM * ADDMEM ('DSN710.SDSNLOD2'//NOPADCHK) UACC(READ)
SETROPTS WHEN(PROGRAM) REFRESH

The userid being checked does not have READ level access:

Attempting to authenticate: GOETZE2
Authenticated!
Attempting to authorize: GOETZE2 for FACILITY entity= BPX.DAEMON
Authorization Check failed. ERRNO= 139 ERRNO2= 93800d9

Here, the 00d9 low order word of ERRNO2 indicates:

JRNoResourceAccess The user specified by the caller does not have the access specified to the resource.

Action: If the user requires access to the resource, have an authorized user grant the user access permission.

The current userid does not have BPX.SERVER READ authority:

Attempting to authenticate: GOETZE1
Authenticated!
Attempting to authorize: GOETZE1 for FACILITY entity= BPX.DAEMON
Authorization Check failed. ERRNO= 139 ERRNO2= 93800d8

Here, the 00d8 low order word of ERRNO2 indicates:

JRNotServerAuthorized
The calling address space is not permitted to the BPX.SERVER Facility class or the BPX.SERVER Facility class is undefined and caller not a superuser (UID=0).

Action: Permit the caller's process to the BPX.SERVER Facility class or make the caller a superuser (UID=0).

Have a system programmer grant the current user this access:

RDEFINE FACILITY BPX.SERVER UACC(NONE)
PERMIT BPX.SERVER CLASS(FACILITY) ID(<user_id>) ACC(read)
SETROPTS RACLIST(FACILITY) REFRESH

The SAF entity is not defined, or SAF class is not active:

Attempting to authenticate: GOETZE1
Authenticated!
Attempting to authorize: GOETZE1 for EJBROLE entity= WEBAPP.USER
Authorization Check failed. ERRNO= 143 ERRNO2= 93800cf

Here, the 00cf low order word of ERRNO2 indicates:

JRSAFResourceUndefined
The resource specified by the caller is not defined to RACF.

Action: Define the specified resource to RACF or correct the resource name and retry.

Have a system programmer activate as follows:

RDEFINE EJBROLE WEBAPP.USER UACC(NONE)
SETROPTS CLASSACT(EJBROLE)
SETROPTS WHEN(EJBROLE) REFRESH