Running JSPWiki on the Mainframe (z/OS)#

This a summary of hints and tips on running JSPWiki in Tomcat on the mainframe.

What's the big deal ?#

The IBM Mainframe runs a whole series of operating systems:

  • z/OS (formerly called OS/390 and MVS)
  • z/Linux
  • VSE
  • TPF
  • z/VM (Hypervisor that can run all the OS's mentioned above)
  • CF code
  • anymore ?

The "flagship operating system" is z/OS, mainly used by financial institutions and multinationals. z/OS runs on IBM proprietary hardware, the current model is IBM System z10.
You can also run it under a Hercules emulator.

z/OS offers Unix System Services. So basically you can run Unix-type applications on the mainframe, at least that's the theory. In practice, most applications cannot be easily ported.

For Java this is different, Java offers real platform independence, so running Java applications on the mainframe is not a big deal.

The major big difference with other OS's is the default encoding, which is EBCDIC (CP037 or Cp1047). This is also true for Java applications, although you can start a JVM with ' -Dfile.encoding=ISO8859-1' (IBM WebSphere Application Server does so)

For most Systems programmers, running JSPWiki on the mainframe is a natural choice:

  • you know your way around in the environment
  • you can reuse your existing backup procedures
  • reuse your existing disaster recovery procedures
  • reuse your existing system management goodies like WLM and SMF
  • integrate with your existing RACF/ACF2 security package

Installing Tomcat#

  • download Tomcat
  • unzip it
  • binary upload it to the mainframe
  • ascii->ebcdic convert your shell scripts
  • this stuff should go in a read-only mounted HFS, you can then create instances in (for example) /var/tomcatxx (anticipating about 36^2 instances) :

metskem@xat1:/var/tomcat00>l
total 120
lrwxrwxrwx   1 $$BPXRT  FUSPOS        22 Sep 26  2006 bin -> /usr/local/tomcat/bin/
drwxrwx---   3 WIKI00U  USIZOS05    8192 Feb  9 09:25 conf
lrwxrwxrwx   1 $$BPXRT  USIZOS05      21 Jan 28 10:21 lib -> /usr/local/tomcat/lib
drwxrwx---   2 WIKI00U  USIZOS05   28672 Feb 11 06:00 logs
drwxrwx---   2 WIKI00U  USIZOS05    8192 Jan 12 06:58 temp
drwxrwxr-x   5 WIKI00U  USIZOS05    8192 Feb 10 08:50 webapps
drwxrwx---   3 WIKI00U  USIZOS05    8192 Jan 12 07:07 work
metskem@xat1:/var/tomcat00/webapps>cd webapps
metskem@xat1:/var/tomcat00/webapps>l
total 10304
drwxrwxr-x  10 WIKI00U  USIZOS05    8192 Jan 12 13:44 ROOT
lrwxrwxrwx   1 $$BPXRT  USIZOS05      30 Jan 28 10:47 docs -> /usr/local/tomcat/webapps/docs
lrwxrwxrwx   1 $$BPXRT  USIZOS05      38 Jan 28 10:47 host-manager -> /usr/local/tomcat/webapps/host-manager
lrwxrwxrwx   1 $$BPXRT  USIZOS05      33 Jan 28 10:47 manager -> /usr/local/tomcat/webapps/manager

  • run it as a batchjob, or better, run it as a started task (STC)
    an example STC proc:
//TOMCAT PROC ID='00',ACTION='run',JMXPORT='5001'                    
//*----------------------------------------------------------------  
//TOMCAT  EXEC PGM=BPXBATCH,REGION=1000M,TIME=NOLIMIT,MEMLIMIT=2000M,
// PARM='SH /usr/local/sys2/bin/tomcat.sh &ID &ACTION &JMXPORT'      
//STDOUT   DD  SYSOUT=*,RECFM=VB,LRECL=1024,HOLD=YES                 
//STDERR   DD  SYSOUT=*,RECFM=VB,LRECL=1024,HOLD=YES                 
This can be started with the following operator commands :
S tomct,jobname=tomcat00,ID=00,ACTION='run' 
S tomct,jobname=tomcat00,ID=00,ACTION='stop'
With an example startup script:
#!/bin/sh
#
# setup DB2 JDBC stuff:
#
export LIBPATH=/usr/lpp/db2810/jcc/lib:$LIBPATH
#---------------------------------------------
export ID=$1
export ACTION=$2
export JMXPORT=$3
#
export CATALINA_HOME=/var/tomcat$ID
export CATALINA_BASE=$CATALINA_HOME
export JAVA_HOME="/usr/lpp/java/J6.0_64"
#export JAVA_OPTS=" -Xmx256M  -Xshareclasses:name=RaboDefaultCache,verbose,groupAccess -Xscmx100M "
export JAVA_OPTS=" -Xmx256M  "
export CATALINA_OPTS="$CATALINA_OPTS  -Djava.security.auth.login.config=/var/tomcat$ID/conf/jaas.config \
  -Ddb2.jcc.propertiesFile=/var/tomcat$ID/conf/db2.jcc.properties \
  -Dcom.sun.management.jmxremote.port=$JMXPORT \
  -Dcom.sun.management.jmxremote.ssl=false \
  -Dcom.sun.management.jmxremote.authenticate=true \
  -Dcom.sun.management.jmxremote.password.file=/var/tomcat$ID/conf/jmxremote.password \
  -Dcom.sun.management.jmxremote.access.file=/var/tomcat$ID/conf/jmxremote.access"
#
umask 007
echo "Starting tomcat.sh with CATALINA_BASE=$CATALINA_BASE and ACTION=$ACTION"
. $CATALINA_HOME/bin/catalina.sh $ACTION

Installing JSPWiki#

Basically the same procedure

  • download JSPWiki
  • unzip it
  • binary upload to tomcat's webapp directory (do not just drop the warfile !)
  • customize your jspwiki.properties (and optionally web.xml and jspwiki.policy)

Authentication (and authorization) against SAF #

You probably don't want to run production with the default userdatabase.xml / groupdatabase.xml.
So here are some options to use your SAF security system (RACF, ACF2, TopSecret).

Tomcat realm#

Attached you will find a RACFRealm(info) implementation.
This can be used when you have configured Container Managed Authentication.

  • drop this jar file in tomcat's lib directory
  • configure the following (example) in your server.xml:
    <Resource name="RACFDatabase" auth="Container"
	      type="nl.rabobank.hdw.tomcat.realm.RACFRealm"
	      factory="nl.rabobank.hdw.tomcat.realm.RACFRealmFactory"
	      description="RACF database"/>
	      
      <!--Realm className="org.apache.catalina.realm.UserDatabaseRealm"
             resourceName="UserDatabase"/-->

      <Realm className="nl.rabobank.hdw.tomcat.realm.RACFRealm"/>
	      
So ,you should replace the UserDatabaseRealm with the RACFRealm.
  • create an EJBROLE class profile with the name <userid>.<roleName> and permit users/groups.
    So if your tomcat runs with userid TOMCAT75, you need profile TOMCAT75.manager for the manager application.

Recycle tomcat and fire up the tomcat manager application, you should be prompted (Basic Authentication) for your RACF Userid/password.

If you want to use this for JSPWiki, simply enable Container Managed Authentication in the web.xml (see the web.xml for instructions), and create profiles for the roleNames that are mentioned in JSPWiki's web.xml (Admin / Authenticated)

There is one big disadvantage of this way of authentication, and that is that you don't get useful error messages back. In our shop we had complaints from people that could not login because of expired passwords or revoked userids and during their login attempt they were not told so. (the JAAS login module has a solution for this, skip to the next paragraph)

JAAS Login module#

The JAAS login module is just what it says. It's an implementation of the javax.security.auth.spi.LoginModule.

To use it in JSPWiki :

  • drop the attached racfloginmodule(info) in tomcat's lib directory
  • configure this in jspwiki.properties:
jspwiki.loginModule.class = nl.rabobank.hdw.auth.login.RACFLoginModule
  • do not use Container Managed Authentication in this case

That's it, recycle your tomcat and login

As an alternative you can also use IBM's JAAS loginmodule com.ibm.security.auth.module.OS390LoginModule.
You can find more on this in a RedBook SG24-7610: Java Security on z/OS - The Complete View.
This module however does not pass back messages on failed logins.

Pit falls#

Assuming ASCII#

Some Java applications make the false assumption that the default encoding is ASCII, and those don't run correctly on the mainframe.

So when doing IO (files, sockets) think about what the encoding is for the data you are writing/reading :

String encoding = "ISO8859-1";
String fileName = "/tmp/myWonderfulFile";
//
// reading :
BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(new File(fileName)), encoding));
//
// writing :
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new File(fileName)), encoding));

// Specify an encoding when using the getBytes method to convert a String to a ByteArray:

byte myBytes = myString.getBytes("8859_1");

// Also specify an encoding when creating a String from a ByteArray:

String myString = new String(myBytes, "8859_1"); 

Shell script files in DOS format#

If your shell scripts are in DOS format (instead of Unix format) they don't run.
The easiest way to check this is use your favorite Editor (UltraEdit or something else) and convert them to Unix format.
You can also check it with the hexdump command:

metskem@xat1:/usr/local/tomcat/bin>hexdump version.sh | grep '0d 15'
You should not see that many '0d 15' occurrences.

You can strip off these hex'15' chars with (example) :

cat version.sh | tr -d '\r' > versionNew.sh

MVS Program Control#

To validate a userid/password you have to call an MVS authorized function (RACINIT).
For this to succeed, the environment must be "program controlled", see the chapter on the BPX.DAEMON FACILITY in the UNIX System Services Planning guide :

If the BPX.DAEMON resource in the FACILITY class is defined, your system has z/OS UNIX security. 
Your system can exercise more control over your superusers. 

If you have chosen for this security level, the following must be set up in advance :
  • all loadlibraries from which modules get loaded in the address space must be RACF PADS protected
  • all dll's loaded from the file system must have their program control bit on (use shellcmd extattr +p blabla.so)
  • all filesystems that have dll's that are loaded must be mounted with the setuid attibute (mount -s setuid ...), this the default BTW
  • the userid that runs the wiki must have a READ permit on the FACILITY class BPX.DAEMON

If you fail one of these requirements, check the MVS SYSLOG for the following possible symptoms :

ICH420I PROGRAM CELHV003 FROM LIBRARY CEE.SCEERUN2 CAUSED THE ENVIRONMENT TO BECOME UNCONTROLLED.
BPXP014I ENVIRONMENT MUST BE CONTROLLED FOR DAEMON (BPX.DAEMON) PROCESSING. 
BPXP015I HFS PROGRAM /A0/usr/lpp/java/J6.0_64/lib/s390x/libwrappers.so
 IS NOT MARKED PROGRAM CONTROLLED.                                    
BPXP014I ENVIRONMENT MUST BE CONTROLLED FOR DAEMON (BPX.DAEMON)       
PROCESSING.                                                           

You can check with the following :

  • use ls -E , the "p" (program control) must be present in the mode bits
metskem@xat1:/usr/lpp/java/J6.0_64>ls -E ./bin/j9vm/libjvm.so
-rwxr-xr-x  aps-  1 $$BPXRT  OMVS      225280 Nov  8 06:21 ./bin/j9vm/libjvm.so
  • use df -v to check the mount attributes (the second display shows the no SUID):
metskem@xat1:/usr/lpp/java/J6.0_64>df -v .
Mounted on     Filesystem                Avail/Total    Files      Status
/A0/usr/lpp/java/J6.0_64 (SYS8.OMVS.JAVA16.A0)     11216/868320   4294962897 Available
HFS, Read Only, Device:14437, ACLS=Y
File System Owner : XAT1        Automove=Y      Client=N
Filetag : T=off   codeset=0

metskem@xat1:/usr/lpp/java/J6.0_64>df -v /var/tomcat00/
Mounted on     Filesystem                Avail/Total    Files      Status
/XAT1/var/tomcat00 (SYSTEM.XAT1.HFS.VAR.TOMCAT00) 736312/1792800 4294966301 Available
HFS, Read/Write, Device:14533, ACLS=Y, No SUID
File System Owner : XAT1        Automove=U      Client=N
Filetag : T=off   codeset=0

Add new attachment

Only authorized users are allowed to upload new attachments.

List of attachments

Kind Attachment Name Size Version Date Modified Author Change note
jar
racfloginmodule.jar 20.4 kB 1 18-Feb-2009 07:44 Harry Metske properly handle return/reason codes
jar
racfrealm.jar 15.6 kB 1 17-Feb-2009 07:38 Harry Metske a new version that uses JUL instead of commons-logging
« This page (revision-10) was last changed on 06-May-2013 21:54 by Harry Metske