[z/OS]

연합된 저장소를 위해 사용자 정의 SAF(System Authorization Facility) 맵핑 모듈 구성

SAF 권한 부여를 위해 SAF 사용자 레지스트리 어댑터와 함께 연합 저장소를 사용하도록 SAF(System Authorization Facility) 맵핑 모듈을 구성할 수 있습니다. SAF 맵핑 모듈은 연합 저장소에서 ID를 SAF ID에 맵핑합니다.

시작하기 전에

연합 저장소에는 SAF, LDAP(Lightweight Directory Access Protocol) 또는 파일 기반 저장소 등과 같은 사용자 레지스트리의 체인이 있을 수 있으므로 맵핑 모듈은 SAF 권한 부여와 함께 사용해야 하는 SAF ID를 명백하게 구별합니다. 예를 들어, 연합 저장소를 통해 LDAP와 같이 운영 체제 레지스트리 또는 다른 레지스트리에 대해 SAF 권한 부여를 사용 가능으로 설정하려면 SAF ID 맵핑이 필요합니다. 이 ID 맵핑은 SAF에 필요한 추가 신임 정보 정보를 설정합니다.

사용자 정의된 로그인 맵핑 모듈을 작성하여 JAAS(Java™ Authentication and Authorization) 로그인 구성을 사용자 정의할 수 있습니다. WebSphere® Application Server ltpaLoginModule 모듈 및 AuthenLoginModule 모듈은 맵핑 모듈에 제공된 공유 상태 변수를 사용하여 SAF 권한 부여를 위한 적합한 ID를 설정합니다.

문제점 방지 문제점 방지:
  • 이 맵핑 모듈을 사용해야 하는 경우에는 SampleVMMSAFMappingModule을 컴파일해야 합니다.
  • SAF 분배 ID 맵핑 기능을 사용 중이라면 맵핑 모듈을 구성할 필요가 없습니다.
gotcha

이 태스크 정보

다음 코드 예제에서 SAF ID에 대한 맵핑을 제어하기 위해 Java EE(Java Platform, Enterprise Edition) ID의 사용 가능성에 의존합니다. 이 코드는 공유 상태에서 Constants.WSPRINCIPAL_KEY 값을 사용합니다. 값은 WebSphere Application Server 로그인 모듈에 의해 코드에 배치됩니다. ltpaLoginModule 모듈 후와 MapPlatformSubject 모듈 직전에 사용자 정의 로그인 모듈을 삽입할 수 있습니다. 사용자 정의 로그인 모듈을 추가하는 경우에는 콜백 배열 또는 다른 공유 상태 값을 사용하여 z/OS® 사용자 ID에 대한 맵핑을 제어하는 데 사용되는 값을 구하십시오.
//This program may be used, run, copied, modified and
//distributed without royalty for the purpose of developing,
//using, marketing, or distributing.

package com.ibm.websphere.wim;

import com.ibm.websphere.security.auth.WSPrincipal;
import com.ibm.websphere.security.cred.WSCredential;
import com.ibm.websphere.wim.util.PrincipalUtil;
import com.ibm.websphere.wim.exception.WIMException;
import com.ibm.websphere.wim.ras.WIMLogger;
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 java.util.logging.Level;
import java.util.logging.Logger;

import javax.security.auth.Subject;
import javax.security.auth.callback.CallbackHandler;

import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;

/**
 *
 * SampleVMMSAFMappingModule demonstrates a custom login module
 * that maps the existing WSPrincipal from the shared state to a z/OS
 * user id for a Federated Repository.
 *
 *
 *
 * The following values will be set into the shared state if authentication
 * succeeds.  If authentication fails, this login module will still indicate
 * success, but no values are set into the shared state.
 *
 *   AttributeNameConstants.ZOS_USERID
 *   AttributeNameConstants.ZOS_AUDIT_STRING
 *   AttributeNameConstants.CALLER_PRINCIPAL_CLASS
 *
 * This login module does not use any callbacks, nor does it modify the Subject
 * in any way.
 *
 * @author IBM Corporation
 * @version 1.0
 * @since 1.0
 */
public class SampleVMMSAFMappingModule implements LoginModule
{
    public final static String CLASSNAME = SampleVMMSAFMappingModule.class.getName();
    private static final Logger trcLogger = WIMLogger.getTraceLogger(CLASSNAME);
    boolean logEnabled = trcLogger.isLoggable(Level.FINER);

    /*
     * 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.wim.SampleVMMSAFMappingModule";

    /*
     * Constant that represents the maximum length of the ZOS_USERID.  Current MVS naming
     * restrictions limit this to eight characters.
     *
     * When the option to useWSPrincipalName is chosen, the name from the WSPrincipal is
     * shortened to this many characters.
     */
    private final static int MAXIMUM_NAME_LENGTH = 7;

    /*
     * Specifies whether or not to use this module's default mapping behavior, which is
     * to use the WSPrincipal name to generate the ZOS_USERID.  This depends on the
     * value of the "useWSPrincipalName" option passed in from the LoginContext.
     */
    private boolean useWSPrincipalName = true;

    /*
     * 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;

    /*
     * 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;

    javax.security.auth.Subject runas_subject, caller_subject;
    /*
     * 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 SampleVMMSAFMappingModule()
    {
    }

    /**
     * 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");
        }

        // 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 (options.containsKey("useWSPrincipalName"))
        {
            String useWSPrincipalNameString = (String) options.get("useWSPrincipalName");
            if (useWSPrincipalNameString != null && useWSPrincipalNameString.toLowerCase().equals("false"))
            {
                useWSPrincipalName = false;
            }
        }

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

    /**
     * Method to map the WSPrincipal to a ZOS_USERID
     *
     * This method derives a ZOS_USERID and stores it into the Shared State for use by a later
     * Login Module.
     *
     * @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");
        }

        if (sharedState.containsKey(AttributeNameConstants.ZOS_USERID))
        {
            // we don't want to override this value if, for whatever reason, another Login Module
            // has already placed it into the shared state, but we still consider this a success
            // because the exit criteria for this module has been met
            if (debugEnabled)
            {
                debug("ZOS_USERID already exists:  so no additional work is needed");
            }
            succeeded = true;
        }
        else if (!sharedState.containsKey(Constants.WSPRINCIPAL_KEY) ||
                !sharedState.containsKey(Constants.WSCREDENTIAL_KEY))
        {
            // if there isn't a Principal or Credential in the shared state, we can't do
            // anything so we'll return false to inform the LoginContext to ignore this module
            if (debugEnabled)
            {
                debug("Principal or Credential is unavailable:  skipping this Login Module");
            }
            succeeded = false;
        }
        else
        {
            if (debugEnabled)
            {
                debug("Principal and Credential are available:  continue with login");
            }

            String name = null;
            String audit = null;
            String principalClass = null;

            // extract the WSPrincipal and WSCredential from the shared state
            WSPrincipal principal = (WSPrincipal) sharedState.get(Constants.WSPRINCIPAL_KEY);
            WSCredential credential = (WSCredential) sharedState.get(Constants.WSCREDENTIAL_KEY);

            if (useWSPrincipalName)
            {
                // this sample mapping module provides a method to obtain the ZOS_USERID from the uniqueID obtained
                // from the WSPrincipal name if the property "useWSPrincipalName" is set to true
                if (debugEnabled)
                {
                    debug("Using name from WSPrincipal to obtain ZOS_USERID");
                }

                final String principalName=stripRealm(principal.getName());
                String realm = getRealm(credential);

                // for this example, a sample audit token will be created that combines the ZOS_USERID,
                // the realm, and the name of this mapping module
                //
                // a custom audit token can be created using any available data rather than using
                // this sample token

                // A Subject may contain more than one Principal.  This value specifies the
                // class of the Principal to be returned when the Subject is asked for the
                // Caller Principal.  If a custom Principal class has been placed into the
                // Subject, that class name can be specified here.
                //
                // Two predefined values for the Caller Principal Class are provided:
                //
                // - AttributeNameConstants.ZOS_CALLER_PRINCIPAL_CLASS
                //   the z/OS Principal class
                //
                // - AttributeNameConstants.DEFAULT_CALLER_PRINCIPAL_CLASS
                //   the default Principal class
                principalClass = AttributeNameConstants.DEFAULT_CALLER_PRINCIPAL_CLASS;

                //name=doMapUser(principalName);
                name=doCustomMapUser(principalName);

                succeeded = true;
                audit = realm + "/" + name + " MappingModule:" + MAPPING_MODULE_NAME;
                }

                else
                {
                    if (debugEnabled)
                    {
                        debug("Using Custom logic to obtain ZOS_USERID");
                    }
                    // if the behavior provided by this mapping module to obtain the ZOS_USERID from the
                    // WSPrincipal name is not enough, custom mapping logic can be provided here
                    //
                    // to use this custom mapping logic, the property "useWSPrincipalName" must be set
                    // to false

                    // name = ...custom logic
                    // audit = ...custom logic
                    // principalClass = ...custom logic

                    // by default, no custom mapping is provided, so the success of this code path
                    // is false; if custom mapping is provided, the following variable should be
                    // modified to represent the success or failure of the custom mapping
                    succeeded = false;
                }

                if (succeeded)
                {
                    // now that we have values for name, audit, and principalClass, we just need to set
                    // them into the shared state
                    sharedState.put(AttributeNameConstants.ZOS_USERID, name);
                    sharedState.put(AttributeNameConstants.ZOS_AUDIT_STRING, audit);
                    sharedState.put(AttributeNameConstants.CALLER_PRINCIPAL_CLASS, principalClass);
                    if (debugEnabled)
                    {
                        debug(new Object[] { "Values have been stored into the shared state", name, audit, principalClass });
                    }
                }
            }

            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);
                }
            }
        }

        /*
         * Private method to obtain the realm name from the Credential and return it.  This
         * keeps the exception handling involved with obtaining the realm name out of the main
         * login() logic.
         */
        private String getRealm(WSCredential credential)
        {
            if (debugEnabled)
            {
                debug("getRealm() entry");
            }

            String realm = null;

            try 
            {
                realm = credential.getRealmName();

                if (debugEnabled)
                {
                    debug("Got realm='" + realm + "' from credential");
                }
            }
            catch (Exception e)
            {
                // getRealmName throws CredentialExpiredException and CredentialDestroyedException
                if (debugEnabled)
                {
                    //debug(new Object[] { "Caught exception in getRealm: ", e });
                }
                realm = "UNKNOWN_REALM";
            }

            if (debugEnabled)
            {
                debug("getRealm() exit");
            }
            return realm;
        }

        /*
         * Private method to generate the ZOS_USERID from the WSPrincipal name/uniqueName.
         */
        private String createSAFIdentityName(String name)
        {
            if (debugEnabled)
            {
                debug("createSAFIdentityName() entry "+ name);
            }

            name=stripRealm(name).toUpperCase();
            //Get the CN.if uniqueName of format "uid=test,o=com" strip to "test".
            if (name.indexOf("=") >= 0)
                name = name.substring((name.indexOf("=")+1),name.length());

            if (name.indexOf(",") > 0)
                name = name.substring(0,name.indexOf(","));

            //handle case where realm appended :<realmname>\\userid
            if(name.indexOf("\\")>0){
            name = name.substring((name.indexOf("\\")+1),name.length());
            }

            // 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/uniqueName shortened to " + name);
                }
            }

            if (debugEnabled)
            {
                debug("createSAFIdentityName() exit");
            }
            return name; //return a SAF Idenity Name
        }
        /*
         * Private Helper method to Strip realm information if any.
         */
        private String stripRealm(String name){
            int index = name.indexOf("/") + 1; // index of the first character after the first /
            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 WSPrincipal name");
                }
            }
            else
            {
                name = name.substring(index);
            }

            return name;

        }


        /**
         * Private helper method to deduce the z/OS ID to be mapped.
         * You can use this when you want to map RACF users & other repository users in specific ways.
         * This uses a Federated Repository util method, isRACFUser to identify if the user is from RACF registry.
         */
        private String  doCustomMapUser(String principalName){
            boolean isRACFUser=true;
            String  mapID=null;
            try{
            isRACFUser=PrincipalUtil.isRACFUser(principalName);
            }
            catch(WIMException we){
               debug("Exception happened while checking isRACFuser"+we);
               //Handle it as per need.
            }
            mapID=isRACFUser==true?createSAFIdentityName(principalName):doMapUser(principalName);

            return mapID;
        }

        /**
         * Private helper method to deduce the z/OS ID to be mapped.
         * You can use this directly if you want to map z/OS ID irrespective of RACF/Non-RACF users.
         *
         */
        private String  doMapUser(String principalName){
            //If loginUser belongs to other registry like LDAP make sure an MVS user exists to match the derived name.
            //Or just map to any existing RACF user as in the commented line below.
            // name="USER237";
            //if user exists in RACF then Map that user.
            String uniqueName=null;
            String mapID=null;
            try {
                javax.naming.InitialContext ctx = new javax.naming.InitialContext();
                // Retrieves the local UserRegistry object.
                final com.ibm.websphere.security.UserRegistry reg = (com.ibm.websphere.security.UserRegistry) ctx.lookup("UserRegistry");
                // Retrieves the registry uniqueName based on the principalName
                uniqueName = reg.getUniqueUserId(principalName);
            } catch (Exception e) {
                debug("Exception thrown while getting uniqueID: "+e);
            }
            mapID=createSAFIdentityName(uniqueName);

            return mapID;
        }
    }
샘플 맵핑 모듈은 연합 저장소의 사용자 레지스트리의 ID와 z/OS ID 간의 맵핑을 작성합니다. 사용자 레지스트리의 ID는 z/OS 사용자 ID로서 사용됩니다. 다른 맵핑이 필요한 경우에는 맵핑을 수행하려면 이전 코드 샘플의 일부로서 else 절에 표시된 대로 이 모듈을 사용자 정의할 수 있습니다.
참고: PrincipalUtil.isRACFUser라고 불리는 연합 저장소 유틸리티 메소드는 사용자가 RACF® 레지스트리로부터 나왔는지 여부를 식별하는 데 사용됩니다. 이 메소드는 사용자가 RACF 사용자인 경우 true를 리턴합니다. 현재 사용자 레지스트리가 연합 저장소 아래에 구성된 경우에는 이 메소드만을 사용하십시오.

프로시저

  1. Java 코드를 컴파일하십시오.
    1. 코드가 신뢰되고 APF(Authorized Program Facility) 권한 부여된 모듈과 동일하게 취급되는지 확인하십시오. 기본 JAAS(Java Authorization and Authentication Service) 시스템 로그인 구성은 z/OS 제어기로부터 액세스됩니다.
    2. 사용자의 클래스 경로 설정에 올바른 JAR(Java) 파일이 포함되는지 확인하십시오. JAR 파일의 다음 설정 중 하나를 사용할 수 있습니다.
      • WebSphere_Application_Client/plugins/org.eclipse.emf.commonj.sdo.jar, WebSphere_Application_Client/plugins/com.ibm.ws.emf.jarWebSphere_Application_Client/plugins/com.ibm.ws.runtime.client.jar
      • WAS_HOME/plugins/org.eclipse.emf.commonj.sdo.jar, WAS_HOME/plugins/com.ibm.ws.runtime.wim.base.jarWAS_HOME/plugins/com.ibm.ws.runtime.jar
  2. IBM®이 제공한 기본값이 아닌 맵핑 클래스를 지정하는 경우에는 클래스를 WebSphere Application Server 및 배치 관리자의 classes 디렉토리에 설치하십시오.
  3. JAR 파일을 WebSphere Application Server, Network Deployment 셀의 배치 관리자 노드를 포함하여 셀에 있는 각 노드에 대한 WAS_HOME/classes 디렉토리에 두십시오.
  4. 변경사항을 적용하려면 WebSphere Application Server을 다시 시작하십시오.
  5. 이 모듈에 사용자 정의 특성을 지정하여 SampleSAFMappingModule의 로깅을 사용 가능으로 설정하십시오.
    1. WebSphere Application Server 관리 콘솔에서 보안 > 글로벌 보안을 클릭하십시오.
    2. 인증 아래에서 JAAS(Java Authentication and Authorization Service)를 확장하십시오.
    3. 시스템 로그인을 클릭하십시오.
    4. login_module_name을 클릭하십시오.
    5. JAAS 로그인 모듈 아래에서 com.ibm.websphere.wim.SampleVMMSAFMappingModule을 클릭하십시오.
    6. 사용자 정의 특성 아래에서 새로 작성을 클릭하십시오.
    7. 이름 필드에 debug를 입력하고 값 필드에 true를 입력하십시오.
    8. 적용을 클릭한 다음 저장을 클릭하십시오.

주제 유형을 표시하는 아이콘 태스크 주제



시간소인 아이콘 마지막 업데이트 날짜: last_date
http://www14.software.ibm.com/webapp/wsbroker/redirect?version=cord&product=was-nd-mp&topic=tsec_customsaffedrepos
파일 이름:tsec_customsaffedrepos.html