9 How to Create a Custom AppKey Plug-in

The following sections provide information about how to create custom AppKey generator plug-ins:

How to Create a Custom Plug-In

Note:

You cannot customize Oracle Tuxedo AAA tokens.
  1. Create your custom Java plug-in using the AppKey and UserRec interfaces. You can provide any required initialization parameters or a property file using the param parameter of the init method.

  2. Compile your plug-in. Example:

    javac exampleAppKey.java
    
  3. Update your CLASSPATH to include the path to your compiled plug-in. Example:

    export CLASSPATH=$CLASSPATH:/home/mywork
    
  4. Start your server.

  5. Configure your WTC Service to use the Custom Plug-in. For more information, see the "Custom Plug-in" in WebLogic Tuxedo Connector Administration Guide for Oracle WebLogic Server.

Example Custom Plug-in

The exampleAppKey.java file is an example of a custom plug-in. It utilizes a tpusrfile file as the database to store the AppKey.

Example 9-1 exampleAppKey.Java Custom Plug-In

import java.io.*;
import java.lang.*;
import java.util.*;
import java.security.Principal;
import weblogic.wtc.jatmi.AppKey;
import weblogic.wtc.jatmi.UserRec;
import weblogic.wtc.jatmi.DefaultUserRec;
import weblogic.wtc.jatmi.TPException;
import weblogic.security.acl.internal.AuthenticatedSubject;
import weblogic.security.WLSPrincipals;

/**
 * @author Copyright (c) 2002 by BEA Systems, Inc. All Rights Reserved.
 */

/**
 * @exclude
 * Sample AppKey plug-in using TPUSRFILE as the database for APPKEY.
 * It is installed through "Custom" option.
 * The syntax for option custom plug parameter input contains the full
 * pathname to the <tpusrfile> 
 *
 * @author BEA Systems, Inc.
 */
public class exampleAppKey implements AppKey {
  private String  anon_user = null;
  private String  tpusrfile = null;
  private File    myfile;
  private HashMap userMap;
  private long    l_time;
  private int     dfltAppkey;
  private boolean allowAnon;
  private final static int USRIDX = 0;
  private final static int PWDIDX = 1;
  private final static int UIDIDX = 2;
  private final static int GIDIDX = 3;
  private final static int CLTIDX = 4;

  private final static byte[] tpsysadm_string = {
    (byte)'t', (byte)'p', (byte)'s', (byte)'y', (byte)'s',
    (byte)'a', (byte)'d', (byte)'m' };
  private final static byte[] tpsysop_string = {
    (byte)'t', (byte)'p', (byte)'s', (byte)'y', (byte)'s', (byte)'o',
    (byte)'p' };
  
  public void init(String param, boolean anonAllowed, int dfltAppKey) 
    throws TPException {

    if (param == null) {
      System.out.println("Error: tpusrAppKey.init@param == null");
      throw new TPException(TPException.TPESYSTEM,
                            "Invalid input parameter");
    }

    // get the tpusrfile name
    parseParam(param);

    myfile  = new File(tpusrfile);
    if (myfile.exists() != true) {
      System.out.println("Error: exampleAppKey.init@file \"" + param
                         + "\" does not exist");
      throw new TPException(TPException.TPESYSTEM,
                            "Failed to find TPUSR file");
    }
    if (myfile.isFile() != true) {
      System.out.println("Error: exampleAppKey.init@the specified name \"" +
                         param + "\" is not a file");
      throw new TPException(TPException.TPESYSTEM,
                            "Invalid TPUSR file");
    }
    if (myfile.canRead() != true) {
      System.out.println("Error: exampleAppKey.init@file \"" + param +
                         "\" is not readable");
      throw new TPException(TPException.TPESYSTEM,
                            "Bad TPUSR file permission");
    }

    userMap = new HashMap();

    // create the cache
    if (createCache(tpusrfile) == -1) {
      System.out.println("Error: exampleAppkey.init@fail to create user cache");
      throw new TPException(TPException.TPESYSTEM,
                            "fail to create user cache");
    }

    l_time     = myfile.lastModified();
    anon_user  = weblogic.security.WLSPrincipals.getAnonymousUsername();
    allowAnon  = anonAllowed;
    dfltAppkey = dfltAppKey;

    System.out.println("exampleAppKey installed!");

    return;
  }

  public void uninit() throws TPException {
    if (userMap != null) {
      userMap.clear();
    }
    return;
  }

  public UserRec getTuxedoUserRecord(AuthenticatedSubject subj) {
    Object[] obj = subj.getPrincipals().toArray();
    if (obj == null || obj.length == 0) {
      // a subject without principals is an anonymous user
      if (allowAnon) {
        return new DefaultUserRec(anon_user, dfltAppkey);
      }
                System.out.println("Error: exampleAppKey.
                getTuxedoUserRecord@return " +
                         "anonymous user not allowed");
      return null;
    }

    // looping through all Principal names if necessary to get first user
    // name defined in tpuser file
    Principal user;
    String    username;
    int       key;
    UserRec   rec;

    for (int i = 0; i < obj.length; i++) {
      user     = (Principal)obj[i];
      username = user.getName();
      if (username.equals(anon_user)) {
        return new DefaultUserRec(anon_user, dfltAppkey);
      }
      if ((rec = (UserRec)userMap.get(username)) != null) {
        return rec;
      }
    }
    System.out.println("WARN: exampleAppKey.getTuxedoUserRecord@return " +
                       "null UserRec");
    return null;
  } 
      
  private int createCache(String fname) {
    FileInputStream fin;
    byte[]          line;

    try {
      fin = new FileInputStream(fname);

      while ((line = readOneLine(fin)) != null) {
        DefaultUserRec newUser = parseOneLine(line);
        if (newUser != null) {
          userMap.put(newUser.getRemoteUserName(), newUser);
        }
      }
      fin.close();
    }
    catch (FileNotFoundException fnfe) {
      System.out.println("Error: exampleAppKey.createCache@reason: " + fnfe);
      return -1;
    }
    catch (SecurityException se) {
      System.out.println("Error: exampleAppKey.createCache@reason: " + se);
      return -1;
    }
    catch (IOException ioe) {
      System.out.println("Error: exampleAppKey.createCache@reason: " + ioe);
      return -1;
    }
    catch (Exception e) {
      System.out.println("Error: exampleAppKey.createCache@reason: " + e);
      return -1;
    }
    return 0;
  }

  private byte[] readOneLine(FileInputStream fh) {
    int    len  = 80;
    byte[] line = new byte[len];
    int    inp  = -1;
    int    idx  = 0;

    try {
      while ((inp = fh.read()) != -1) {
        if (idx == 0 && (inp == '\n' || inp == '\0')) {
          continue;
        }
        if (inp == '\n') {
          break;
        }
        if (idx == (len - 1)) {
          byte[] tmp = new byte[len + 80];
          System.arraycopy(line, 0, tmp, 0, len);
          line = tmp;
          len += 80;
        }
        line[idx] = (byte)inp;
        idx++;
      }
    }
    catch (Exception e) {
      System.out.println("Error: exampleAppKey.readOneLine@reason: " + e);
      return null;
    }

    if (inp == -1 && idx == 0) {
      return null;
    }

    byte[] tmp = new byte[idx];
    System.arraycopy(line, 0, tmp, 0, idx);

    return tmp;
  }

  private DefaultUserRec parseOneLine(byte[] line) {
    String      name;
    int         key   = 0;
    DefaultUserRec usr;
    int         firstCharacter;
    int         i;
    int         sidx;
    int         fldlen;
    int         fn;
    byte[]      buid  = null;
    byte[]      bgid  = null;
    byte[]      clt   = null;
    byte[]      uname = null;

    firstCharacter = (int)line[0];
    if (firstCharacter == '#' || firstCharacter == '\n' ||
        firstCharacter == '!' || firstCharacter == '\0' ||
        firstCharacter == '\r') {
      return null;
    }
    fldlen = 0;
    sidx   = 0;
    for (i = 0, fn = 0; i < line.length && fn <= CLTIDX; i++) {
      if (line[i] == (byte)':') {
        switch (fn) {
        case USRIDX:
          uname = new byte[fldlen];
          System.arraycopy(line, sidx, uname, 0, fldlen);
          break;
        case UIDIDX:
          buid = new byte[fldlen];
          System.arraycopy(line, sidx, buid, 0, fldlen);
          break;
        case GIDIDX:
          bgid = new byte[fldlen];
          System.arraycopy(line, sidx, bgid, 0, fldlen);
          break;
        case CLTIDX:
                         if (line[sidx  ] == (byte)'T' &&
                                  line[sidx+1] == (byte)'P' &&
                                  line[sidx+2] == (byte)'C' &&
                                  line[sidx+3] == (byte)'L' &&
                                  line[sidx+4] == (byte)'T' &&
                                  line[sidx+5] == (byte)'N' &&
                                  line[sidx+6] == (byte)'M' &&
                                  line[sidx+7] == (byte)',') {
                                sidx   += 8;
                                fldlen -= 8;
                         }
          if (fldlen > 0) {
                                 clt = new byte[fldlen];
                                 System.arraycopy(line, sidx, clt, 0, fldlen);
          }
          break;
        default:
          break;
        }   // end of switch
        fn++;
        fldlen = 0;
        sidx   = i + 1;
      }     // end of if
      else {
        fldlen++;
      }
    }
    
    // try to tolerate incomplete line
    if (fn <= CLTIDX && fldlen > 0) {
                 switch (fn) {
                  case USRIDX:
                         uname = new byte[fldlen];
                         System.arraycopy(line, sidx, uname, 0, fldlen);
                         break;
                  case UIDIDX:
                         buid = new byte[fldlen];
                         System.arraycopy(line, sidx, buid, 0, fldlen);
                         break;
                  case GIDIDX:
                         bgid = new byte[fldlen];
                         System.arraycopy(line, sidx, bgid, 0, fldlen);
                         break;
                  case CLTIDX:
                         if (line[sidx  ] == (byte)'T' &&
                                  line[sidx+1] == (byte)'P' &&
                                  line[sidx+2] == (byte)'C' &&
                                  line[sidx+3] == (byte)'L' &&
                                  line[sidx+4] == (byte)'T' &&
                                  line[sidx+5] == (byte)'N' &&
                                  line[sidx+6] == (byte)'M' &&
                                  line[sidx+7] == (byte)',') {
                                sidx   += 8;
                                fldlen -= 8;
                         }
                         clt = new byte[fldlen];
                         System.arraycopy(line, sidx, clt, 0, fldlen);
                         break;
                 }
    }

    if (uname == null || buid == null || bgid == null) {
      return null;
    }

    name = new String(uname);
    if (clt != null) {
      if (Arrays.equals(tpsysadm_string, clt) == true) {
        key = TPSYSADM_KEY;
      }
      else if (Arrays.equals(tpsysop_string, clt) == true) {
        key = TPSYSOP_KEY;
      }
    }

    if (key == 0) {
      Integer u_val;
      Integer g_val;
      int uid = 0;
      int gid = 0;

      try {
        u_val = new Integer(new String(buid));
        g_val = new Integer(new String(bgid));
        uid   = u_val.intValue();
        gid   = g_val.intValue();
        uid &= UIDMASK;
        gid &= GIDMASK;
        key = uid | (gid << GIDSHIFT);
      }
      catch (NumberFormatException nfe) {
        System.out.println("Error: exampleAppKey.readOneLine@reason: " + nfe);
        return null;
      }
    }

    return new DefaultUserRec(name, key);
  }

  private void parseParam(String param) {
    String str;

    // trim the input
    tpusrfile = param.trim();

    return;
  }
}