WebSphere Application Server for z/OS, Version 6.1   
             オペレーティング・システム: z/OS

             目次と検索結果のパーソナライズ化
このトピックは、z/OS オペレーティング・システムにのみ適用されます。

LDAP から System Authorization Facility (SAF) マッピング・モジュールへの 1 対 1 のカスタム・マッピング

カスタマイズされたログイン・マッピング・モジュールを作成することによって、 Java Authentication and Authorization Service (JAAS) ログイン構成をカスタマイズできます。

WebSphere Application Server for z/OS には、LDAP クレデンシャルを持つリモート・メソッド呼び出し (RMI) インバウンド要求から System Authorization Facility (SAF) ID にマッピングを提供する機能があります。ユース・ケースは、LDAP に構成されるすべてのプラットフォームでの WebSphere Application Server であり、RMI/IIOP 要求を SAF ユーザー・レジストリーに構成されている 2 番目のサーバーに送信します。WebSphere Application Server (リリース 5.1 以降) は、LDAP ID を表す LTPA トークンを使用して RMI 要求を、SAF に構成されている WebSphere Application Server for z/OS に送信します。以下の図は、このマッピングを示しています。


図 1. LDAP クレデンシャルを持つ RMI インバウンド要求から SAF ID へのマッピング

以下のサンプルは、LTPA トークンをオープンする JAAS RMI インバウンド・ログイン・モジュールです。 このサンプルでは、LDAP ユーザー ID を抽出し、cn=userID をストリップし、WSCredential を SAF ユーザー ID に設定します。2 番目のサーバーに構成されるサンプルのインバウンド・ログイン・モジュールは、WebSphere Application Server for z/OS リリース 6.1 以降でのみサポートされます。

このサンプルは実際には、com.ibm.wsspi.security.token.AttributeNameConstants.WSCREDENTIAL_UNIQUEID が、必要な z/OS SAF ID に設定されるハッシュ・ログイン・モジュールです。ltpaLoginModule は、渡された com.ibm.wsspi.security.token.AttributeNameConstants.WSCREDENTIAL_UNIQUEID をチェックし、指定された ID を使用して、ユーザーに適切なセキュリティー・コンテキストをビルドします。

このサンプル・モジュールは RMI_INBOUND JAAS ログイン・モジュールとして構成されます。 また、次に ltpaLoginModule がくるリストの先頭で、このモジュールを指定する必要があります。

次のサンプルでは、SAF ID へのマッピングを制御するために、Java 2 Platform、Enterprise Edition (J2EE) ID が使用可能です。サンプルでは、Constants.WSCREDENTIAL 値のハッシュ・ログインを共用状態で使用します。

SampleLTPASAFMappingModule のサンプルを以下に示します。
// This program may be used, executed, copied, modified and
// distributed without royalty for the purpose of developing,
// using, marketing, or distributing.
//
//

package com.ibm.websphere.security;

import com.ibm.websphere.security.auth.CredentialDestroyedException;
import com.ibm.websphere.security.auth.WSPrincipal;
import com.ibm.websphere.security.cred.WSCredential;
import com.ibm.wsspi.security.auth.callback.Constants;
import com.ibm.wsspi.security.token.AttributeNameConstants;
import java.lang.reflect.Array;
import java.util.Map;
import javax.security.auth.Subject;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.login.CredentialExpiredException;
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;
import com.ibm.wsspi.security.token.WSSecurityPropagationHelper;
import com.ibm.websphere.security.auth.callback.WSCredTokenCallbackImpl;
import com.ibm.websphere.security.auth.WSLoginFailedException;

/**
 * **
 * SampleLTPASAFMappingModule demonstrates a custom login module
 * that maps the existing LTPA Token from the shared state to a UNIQUE ID to avoid the Login. Typical use is a inbound LTPA Token generated from a different realm (perhaps a non zOS Realm) into a SAF User Registry. The LTPA Token is used as the trusted identity token. 
 *
 * ***
 *
 * @author IBM Corporation
 * @version 1.0
 * @since 1.0
 */
public class SampleLTPASAFMappingModule implements LoginModule
{
    /*
     * **
     * Constant that represents the name of this mapping module.  Whenever this sample
     * code is used to create a class with a different name, this value should be changed.
     *
     * By default, this value is used as part of the sample audit token, and for debugging
     * purposes.
     * ***
     */
    private final static String MAPPING_MODULE_NAME = "com.ibm.websphere.security.SampleLTPASAFMappingModule";

    private final static int MAXIMUM_NAME_LENGTH = 8;

    /*
     * **
     * Specifies whether debugging is enabled for this Login Module.  This depends on the
     * value of the "debug" option passed in from the LoginContext.
     * ***
     */
    private boolean debugEnabled = false;
 /*
     * **
     * Specifies the inbound realm that this Login Module is to handle.  If there is no incoming 
     * property setting for onlyThisRealm, then this Login module will process all inbound
     * request regardless of the incoming idenity realm within the LTPA token. 
     * ***
     */
    private String onlyThisRealm = null;

    /*
     * **
     * Stores the Subject passed from the LoginContext.
     * ***
     */
    private Subject subject;

    /*
     * **
     * Stores the CallbackHandler passed from the LoginContext.
     * ***
     */
    private CallbackHandler callbackHandler;

    /*
     * **
     * Stores the shared state Map passed from the LoginContext.
     * ***
     */
    private Map sharedState;

    /*
     * **
     * Stores the options Map passed from the LoginContext.
     * ***
     */
    private Map options;

    /*
     * **
     * This value is used to store the success or failure of the login() method so
     * that commit() and abort() can act differently in the two cases if so desired.
     * ***
     */
    private boolean succeeded = false;

    /**
     * **Construct an uninitialized mapping module object.***
     */
    public SampleLTPASAFMappingModule()
    {
    }

    /**
     * **Initialize this login module.***
     *
     * **
     * This is called by the LoginContext after this login module is
     * instantiated. The relevant information is passed from the LoginContext
     * to this login module. If the login module does not understand any of the data
     * stored in the sharedState and options parameters,
     * they can be ignored.
     * ***
     *
     * @param subject
     *                The subject that this LoginContext is authenticating
     * @param callbackHandler
     *                A CallbackHandler for communicating with the end user to gather login information (e.g., username and password).
     * @param sharedState
     *                The state shared with other configured login modules.
     * @param options
     *                The options specified in the login configuration for this particular login module.
     */
    public void initialize(Subject newSubject, CallbackHandler newCallbackHandler, Map newSharedState, Map newOptions)
    {
        // obtain the value for debug before anything else so that tracing can be used within
        // this method
        if (newOptions.containsKey("debug"))
        {
            String debugEnabledString = (String) newOptions.get("debug");
            if (debugEnabledString != null && debugEnabledString.toLowerCase().equals("true"))
            {
                debugEnabled = true;
            }
        }
if (debugEnabled)
        {
            debug("initialize() entry");
        }
	// obtain the value for realm before anything else to see if this login module should 
	// only process a particular inbound realm or if it should process all realm. A null value 
	// singles all realms will be processed. 
	if (newOptions.containsKey("realm"))
        {
            onlyThisRealm = (String) newOptions.get("realm");
	    onlyThisRealm = onlyThisRealm.trim();
	}


        // this login module is not going to use any of these objects except for the sharedState,
        // but for consistency with most login modules, we will save a reference to all of them
        this.subject = newSubject;
        this.callbackHandler = newCallbackHandler;
        this.sharedState = newSharedState;
        this.options = newOptions;

        if (debugEnabled)
        {
            debug(new Object[] { "initialize() exit", subject, callbackHandler, sharedState, options });
        }
    }

    /**
     *
     * @return true if the authentication succeeded, or false
     *         if this Login Module should be ignored
     * @exception LoginException
     *         if the authentication fails, which is impossible for this Login Module
     */
    public boolean login() throws LoginException
    {
        if (debugEnabled)
        {
            debug("login() entry");
        }

	// Handle the callback 
	javax.security.auth.callback.Callback callbacks[] = 
            new javax.security.auth.callback.Callback[1];
	callbacks[0] = new com.ibm.websphere.security.auth.callback.WSCredTokenCallbackImpl("");

	try
	{
                callbackHandler.handle(callbacks);
	} 
catch (Exception e)
	{
if (debugEnabled)
             {
                 debug(new Object[] { "Caught exception in callbackhandler: ", e });
             }
             return false;
	} 
	
	byte[] credToken = ((WSCredTokenCallbackImpl) callbacks[0]).getCredToken();
        String uid = null;
String realm = null;
	String uniqueID = null;

	//This routine will only process a LTPA token. If there is no inbound token, 
	//then this routine will return true and allow the other LM should handle
	//this request
	if (credToken != null)
	{
		try {
			uniqueID = WSSecurityPropagationHelper.validateLTPAToken(credToken);
			realm = WSSecurityPropagationHelper.getRealmFromUniqueID (uniqueID);
                        uid = createSAFIdenityName (uniqueID);
if (debugEnabled)
                        {
                            debug("using uniqueID: "+ uniqueID+ " inbound realm: "+ realm +
				  "uid: " + uid );
                        }
		}
catch (Exception e)
		{
if (debugEnabled)
                   {
                       debug(new Object[] { "Caught exception in callbackhandler: ", e });
                   }
                   return false;
		}	
	}
	else return true; // let the other LM handle this request. 
	

	//onlyThisRealm is a input property setting to see if we want this login module
	//to handle only 1 inputed realm request. If onlyThisRealm is null, 
	//then we will process all request and continue on. If the onlyThisRealm does
	//not match the inbound request extracted from LTPA, then we will let the other
	//LM handle this request. 
	//
	if ((onlyThisRealm != null) && (!realm.trim().equals(onlyThisRealm))) {
            if (debugEnabled)
            {
                debug("inbound realm of "+realm+" does not match option realm of "+onlyThisRealm);
            }
            return true;
	}

	try {
		// Retrieves the default InitialContext for this server.
javax.naming.InitialContext ctx = new javax.naming.InitialContext();

		// Retrieves the local UserRegistry object.
		com.ibm.websphere.security.UserRegistry reg = 
(com.ibm.websphere.security.UserRegistry) ctx.lookup("UserRegistry");				

	
  		// Retrieves the registry uniqueID based on the uid that is specified 
           // in the NameCallback.
		String uniqueid = reg.getUniqueUserId(uid);
if (debugEnabled)
            {
                debug("uniqueid "+uniqueid);
            }
		// Retrieves the display name from the user registry based on the uniqueID.
		String securityName = reg.getUserSecurityName(uid);
if (debugEnabled)
            {
                debug("securityName "+securityName);
            }
	
		// Retrieves the groups associated with this uniqueID.
		java.util.List groupList = reg.getUniqueGroupIds(uid);

   		// Creates the java.util.Hashtable with the information that you gathered 
           // from the UserRegistry.
	   // By setting this hashtable, the LTPA login module will propertly
	   // setup the SAF Identity. 
   		java.util.Hashtable hashtable = new java.util.Hashtable();
           			hashtable.put(com.ibm.wsspi.security.token.AttributeNameConstants.
              WSCREDENTIAL_UNIQUEID, uniqueid);
           			hashtable.put(com.ibm.wsspi.security.token.AttributeNameConstants.
              WSCREDENTIAL_SECURITYNAME, securityName);
			hashtable.put(com.ibm.wsspi.security.token.AttributeNameConstants.
              WSCREDENTIAL_GROUPS, groupList);

		// Adds the hashtable to the shared state of the Subject.
	   sharedState.put(com.ibm.wsspi.security.token.AttributeNameConstants.
              WSCREDENTIAL_PROPERTIES_KEY,hashtable);
        }
catch (Exception e)
	{
if (debugEnabled)
           {
               debug(new Object[] { "Caught exception in callbackhandler: ", e });
           }
	   WSLoginFailedException e2 = new WSLoginFailedException("SampleLTPASAFMappingModule detected an error. "+e);
           throw e2;
        }		
        if (debugEnabled)
        {
            debug("login() exit");
        }
        		return succeeded;
    }

    /**
     * **Method to commit the authentication result.***
     *
     * **
     * This Login Module does not need to commit any data, so we will simply return.
     * ***
     *
     * @return true if the original login succeeded, or false
     *         if the original login failed
     * @exception LoginException
     *         if the commit fails, which cannot happen in this Login Module
     */
    public boolean commit() throws LoginException
    {
        if (debugEnabled)
        {
            debug("commit() entry");
        }

        // the return value of commit() is the same as the success of the original login
        boolean returnVal = succeeded;

        cleanup();

        if (debugEnabled)
        {
            debug("commit() exit");
        }
        return returnVal;
    }

    /**
     * **Method to abort the authentication process (Phase 2).***
     *
     * **
     * No matter whether our original login succeeded or failed, this method cleans up
     * our state and returns.
     * ***
     *
     * @return true if the original login succeeded, or false
     *         if the original login failed
     * @exception LoginException
     *         if the abort fails, which cannot happen in this Login Module
     */
    	public boolean abort() throws LoginException
    {
        if (debugEnabled)
        {
            debug("abort() entry");
        }

        // the return value of abort() is the same as the success of the original login
        boolean returnVal = succeeded;

        cleanup();

        if (debugEnabled)
        {
            debug("abort() exit");
        }
        return returnVal;
    }

    /**
     * **Method which logs out a Subject.***
     *
     * **
     * Since our commit method did not modify the Subject, we don't have anything to
     * logout or clean up and can just return true.
     * ***
     *
     * @return true if the logout succeeded
     * @exception LoginException
     *         if the logout fails, which cannot happen in the Login Module
     */
    	public boolean logout() throws LoginException
    {
        if (debugEnabled)
        {
            debug("logout() entry");
        }

        // our local variables were cleanup up during the commit, so no further cleanup is needed

        if (debugEnabled)
        {
            debug("logout() exit");
        }

        // since there is nothing to logout, we always succeed
        return true;
    }

    /*
     * **
     * Cleans up our local variables; the only cleanup required for
     * this Login Module is to set our success variable back to false.
     * ***
     */
    private void cleanup()
    {
        if (debugEnabled)
        {
            debug("cleanup() entry");
        }

        // there's nothing to cleanup, really, so just reset our success variable
        succeeded = false;

        if (debugEnabled)
        {
            debug("cleanup() exit");
        }
    }

    /*
     * **
     * Private method to print trace information.  This implementation uses System.out
     * to print trace information to standard output, but a custom tracing system can
     * be implemented here as well.
     * ***
     */
    private void debug(Object o)
    {
        System.out.println("Debug: " + MAPPING_MODULE_NAME);
        if (o != null)
        {
            if (o.getClass().isArray())
            {
                int length = Array.getLength(o);
                for (int i = 0; i < length; i++)
                {
                    System.out.println("¥t" + Array.get(o, i));
                }
            }
            else
            {
                System.out.println("¥t" + o);
            }
        }
    }
    /*
     * **
     * TODO
     * Private method to generate the SAF Idenity from the LDAP identity. This routine may
     * need to be modify by your installation standards to extract the SAF Idenity from
     * the LDAP IDentity. OR this routine could be written to map the LDAP to SAF identity.
     * ***
     */
    private String createSAFIdenityName(String name)
    {
        if (debugEnabled)
        {
            debug("createSAFIdenityName() entry");
        }

        if (debugEnabled)
        {
            debug("Using name='" + name + "' from principal");
        }

        name = name.toUpperCase();
        int index = name.indexOf("/") + 1; // index of the first character after the first /
        System.out.println(index);
        System.out.println(name);
        if (index >= name.length())
        {
            // this block handles the case where the first / is the last character in the String,
            // it really shouldn't happen, but if it does we can just strip it off
            name = name.substring(0, index - 1);

            if (debugEnabled)
            {
                debug("Stripping trailing / from name");
            }
        }
        else
        {
            // index is either 0 (if no / exists in the name), or it is the position
            // after the first / in the name
            //
            // either way, we will take the substring from that point until the end of the string
            name = name.substring(index);
        }
        System.out.println(name);
        
        if (name.indexOf("CN=") >= 0) 
        	name = name.substring((name.indexOf("CN=")+3),name.length());
        
        
        if (name.indexOf(",") > 0)
            name = name.substring(0,name.indexOf(","));
        
        // shorten the name if its length exceeds the defined maximum
        if (name.length() > MAXIMUM_NAME_LENGTH)
        {
            name = name.substring(0, MAXIMUM_NAME_LENGTH);

            if (debugEnabled)
            {
                debug("WSPrincipal name shortened to " + name);
            }
        }

        if (debugEnabled)
        {
            debug("createSAFIdenityName() exit");
        }
        return name; //return a SAF Idenity Name
    }
}

サンプルのマッピング・モジュールは、LDAP クレデンシャルを持つ RMI インバウンド要求から SAF ID へのマッピングを作成します。マッピングの実行のためにこのモジュールをカスタマイズすることができます。




関連タスク
ローカルでないオペレーティング・システムによるカスタム System Authorization Facility マッピング・モジュールの書き込み
WebSphere Application Server 用のカスタム System Authorization Facility マッピング・モジュールのインストールおよび構成
Java Authentication and Authorization Service によるプログラマチック・ログインの開発
関連資料
システム・ログイン構成用のカスタム・ログイン・モジュール開発
概念トピック    

ご利用条件 | フィードバック

最終更新: Jan 21, 2008 9:12:22 PM EST
http://publib.boulder.ibm.com/infocenter/wasinfo/v6r1/index.jsp?topic=/com.ibm.websphere.zseries.doc/info/zseries/ae/csec_LDAP_SAF_loginmods.html