[z/OS]

Configuración de un módulo de correlación SAF (System Authorization Facility) para repositorios federados

Puede configurar el módulo de correlación SAF (System Authorization Facility) para utilizar repositorios federados con el adaptador de registro de usuarios SAF para la autorización SAF. El módulo de correlación SAF correlaciona la identidad del repositorio federado con una identidad SAF.

Antes de empezar

Como los repositorios federados pueden tener una cadena de registros de usuarios, como por ejemplo, SAF, Lightweight Directory Access Protocol (LDAP) o un repositorio basado en archivos, el módulo de correlación distingue claramente la identidad SAF que debe utilizarse con autorización SAF. Para habilitar la autorización SAF para los registros del sistema operativo u otros registros, por ejemplo LDAP a través del repositorio federado, es necesaria la correlación de identidades SAF. Esta correlación de identidades establece la información de credenciales adicionales que es necesaria para SAF.

Puede personalizar las configuraciones de inicio de sesión JAAS (Java™ Authentication and Authorization) escribiendo un módulo de correlación de inicios de sesión personalizado. El módulo ltpaLoginModule y el módulo AuthenLoginModule de WebSphere Application Server utilizan las variables de estado compartido que se proporcionan en el módulo de correlación para establecer la identidad adecuada para la autorización SAF.

Avoid trouble Avoid trouble:
  • Debe compilar SampleVMMSAFMappingModule si necesita utilizar este módulo de correlación.
  • No es necesario configurar un módulo de correlación si está utilizando la característica de correlación de identidad distribuida SAF.
gotcha

Acerca de esta tarea

En el siguiente ejemplo de código, se confía en la disponibilidad de la identidad de Java Platform, Enterprise Edition (Java EE) para que controle la correlación con la identidad de SAF. Este código utiliza el valor Constants.WSPRINCIPAL_KEY en el estado compartido. El módulo de inicio de sesión de WebSphere Application Server coloca el valor en el código. Puede insertar un módulo de inicio de sesión personalizado después del módulo ltpaLoginModule y justo antes del módulo MapPlatformSubject. Si añade un módulo de inicio de sesión personalizado, utilice una matriz de devolución de llamada u otros valores de estado compartido para obtener un valor que se utiliza para controlar la correlación al ID de usuario z/OS.
//Este programa se puede utilizar, ejecutar, copiar, modificar y
// distribuir sin derechos de copia para fines de desarrollo,
// uso, comercialización o distribución.

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 demuestra un módulo de inicio de sesión personalizado
 * que correlaciona el principal de WS existente del estado compartido con un ID
 * de usuario de z/OS para un repositorio federado
 *
 *
 *
 * Los valores siguientes se establecerán en el estado compartido si la autenticación
 * es satisfactoria.  Si la autenticación falla, este módulo de inicio de sesión aún indicará
 * una ejecución satisfactoria, pero no se establecerán valores en el estado compartido.
 *
 *   AttributeNameConstants.ZOS_USERID
 *   AttributeNameConstants.ZOS_AUDIT_STRING
 *   AttributeNameConstants.CALLER_PRINCIPAL_CLASS
 *
 * Este módulo de inicio de sesión no utiliza llamadas de retorno ni modifica el sujeto
 * de ninguna forma.
 *
 * @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);

    /*
     * Constante que representa el nombre de este módulo de correlación.  Si se utiliza
     * este código de ejemplo para crear una clase con otro nombre, este valor debe cambiarse.
     *
     * De forma predeterminada, este valor se utiliza como parte del símbolo de auditoría de ejemplo y para
     * depuraciones.
     */
    private final static String MAPPING_MODULE_NAME = "com.ibm.websphere.wim.SampleVMMSAFMappingModule";

    /*
     * Constante que representa la longitud máxima de ZOS_USERID.  Las restricciones de denominación de MVS
     * la limitan a ocho caracteres.
     *
     * Cuando se elige la opción useWSPrincipalName, el nombre del principal de WS se
     * abrevia a estos caracteres.
     */
    private final static int MAXIMUM_NAME_LENGTH = 7;

    /*
     * Especifica si debe utilizarse o no el funcionamiento de correlación predeterminada de este módulo, que
     * es utilizar el nombre del principal de WS para generar el ZOS_USERID.  Esto depende del
     * valor de la opción "useWSPrincipalName" pasada desde LoginContext.
     */
    private boolean useWSPrincipalName = true;

    /*
     * Especifica si la depuración está habilitada para este módulo de inicio de sesión.  Esto depende del
     * valor de la opción "debug" pasada desde LoginContext.
     */
    private boolean debugEnabled = false;

    /*
     * Almacena el sujeto pasado desde LoginContext.
     */
    private Subject subject;

    /*
     * Almacena CallbackHandler pasado desde LoginContext.
     */
    private CallbackHandler callbackHandler;

    /*
     * Almacena la correlación de estado compartido pasada desde LoginContext.
     */
    private Map sharedState;

    javax.security.auth.Subject runas_subject, caller_subject;
    /*
     * Almacena la correlación de opciones pasada desde LoginContext.
     */
    private Map options;

    /*
     * Este valor se utiliza para almacenar la ejecución satisfactoria o la anomalía del método login() para que
     * los métodos commit() y abort() puedan actuar de forma distinta en los dos casos, si se desea.
     */
    private boolean succeeded = false;


    /**
     * Construir un objeto de módulo de correlación no inicializado.
     */
    public SampleVMMSAFMappingModule()
    {
    }

    /**
     * Inicializar este módulo de inicio de sesión.
     *
     * LoginContext realiza una llamada a este método después de que se instancie
     * este módulo de inicio de sesión. La información relevante se pasa de LoginContext
     * a este módulo de inicio de sesión. Si el módulo de inicio de sesión no comprende los datos
     * almacenados en los parámetros sharedState y options,
     * se pueden ignorar.
     *
     * @param subject
     *                Sujeto en el que se autentica este LoginContext
     * @param callbackHandler
     *                CallbackHandler para comunicarse con el usuario final
     *                para recopilar información de inicio de sesión (por ejemplo, nombre de usuario y contraseña).
     * @param sharedState
     *                Estado compartido con otros módulos de inicio de sesión configurados.
     * @param options
     *                Opciones especificadas en la configuración de inicio de sesión de este módulo de inicio de sesión concreto.
     */
    public void initialize(Subject newSubject, CallbackHandler newCallbackHandler,
            Map newSharedState, Map newOptions)
    {
        // obtenga el valor de la depuración antes que nada para que se pueda utilizar el rastreo dentro
        // de este método
        if (newOptions.containsKey("debug"))
        {
            String debugEnabledString = (String) newOptions.get("debug");
            if (debugEnabledString != null && debugEnabledString.toLowerCase().equals("true"))
            {
                debugEnabled = true;
            }
        }

        if (debugEnabled)
        {
            debug("initialize() entry");
        }

        // este módulo de inicio de sesión no va a utilizar ninguno de estos objetos excepto para el estado compartido,
        // pero para obtener coherencia con la mayor parte de módulos de inicio de sesión, guardaremos una referencia a todos ellos
        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 });
        }
    }

    /**
     * Método para correlación el principal de WS con un ID_USUARIO_ZOS
     *
     * Este método deriva un ZOS_USERID y lo almacena en el estado compartido para que lo utilice un
     * módulo de inicio de sesión posterior.
     *
     * @return true si la autenticación ha sido satisfactoria o false
     *         si este módulo de inicio de sesión debe ignorarse
     * @exception LoginException
     *         si la autenticación falla, lo cual es imposible para este módulo de inicio de sesión
     */
    public boolean login() throws LoginException
    {
        if (debugEnabled)
        {
            debug("login() entry");
        }

        if (sharedState.containsKey(AttributeNameConstants.ID_USUARIO_ZOS))
        {
            // no deseamos alterar temporalmente este valor si, por algún motivo, otro módulo de inicio de sesión
            // ya lo ha colocado en el estado compartido, pero aún lo considera como una ejecución satisfactoria
            // porque los criterios de salida de este módulo se han cumplido
            if (debugEnabled)
            {
                debug("ID_USUARIO_ZOS ya existe: no se necesita trabajo adicional");
            }
            succeeded = true;
        }
        else if (!sharedState.containsKey(Constants.CLAVE_PRINCIPAL_WS) ||
                !sharedState.containsKey(Constants.CLAVE_CREDENCIAL_WS))
        {
            // si no hay ningún principal ni credencial en el estado compartido, no podemos
            // hacer nada, por lo que devolveremos el valor false para informar a LoginContext de que ignore este módulo
            if (debugEnabled)
            {
                debug("El principal o la credencial no está disponible: ignorando este módulo de inicio de sesión");
            }
            succeeded = false;
        }
        else
        {
            if (debugEnabled)
            {
                debug("El principal y la credencial están disponibles: continúa el inicio de sesión");
            }

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

            // extrae WSPrincipal y WSCredential del estado compartido
            WSPrincipal principal = (WSPrincipal) sharedState.get(Constants.CLAVE_PRINCIPAL_WS);
            WSCredential credential = (WSCredential) sharedState.get(Constants.CLAVE_CREDENCIAL_WS);

            if (useWSPrincipalName)
            {
                // este módulo de correlación de ejemplo proporciona un método para obtener ZOS_USERID
                // del nombre de principal de WS si la propiedad "useWSPrincipalName" se establece en true
                if (debugEnabled)
                {
                    debug("Utilizando el nombre de principal de WS para obtener ZOS_USERID");
                }

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

                // para este ejemplo, se creará un símbolo de auditoría de ejemplo que combine el ZOS_USERID,
                // el reino y el nombre de este módulo de correlación
                //
                // se puede crear un símbolo de auditoría personalizado con los valores disponibles en lugar
de utilizar
                // este símbolo de ejemplo

                // Un sujeto puede contener más de un principal.  Este valor especifica la
                // clase del principal que debe devolverse cuando se solicita al sujeto
                // el principal llamante.  Si una clase de principal personalizado se ha colocado
                // en el sujeto, ese nombre de clase debe especificarse aquí.
                //
                // Se proporcionan dos valores predefinidos para la clase de principal llamante:
                //
                // - AttributeNameConstants.ZOS_CALLER_PRINCIPAL_CLASS
                //   clase de principal de z/OS
                //
                // - AttributeNameConstants.DEFAULT_CALLER_PRINCIPAL_CLASS
                //   clase de principal predeterminada
                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("Utilizando el nombre de lógica personalizada para obtener ZOS_USERID");
                    }
                    // Si el funcionamiento proporcionado por este módulo de correlación para obtener el ZOS_USERID del
                    // nombre de principal de WS no es suficiente, la lógica de correlación personalizada se puede proporcionar aquí.
                    //
                    // Para utilizar esta lógica de correlación personalizada, la propiedad "useWSPrincipalName" debe establecerse
                    // en false.

                    // name = ...lógica personalizada
                    // audit = ...lógica personalizada
                    // principalClass = ...lógica personalizada

                    // De forma predeterminada, no se proporciona ninguna correlación personalizada, por lo que la ejecución satisfactoria
                    // de esta vía de acceso tiene el valor false; si se proporciona la correlación personalizada, la siguiente variable
                    // debe modificarse para representar la ejecución satisfactoria o no de la correlación personalizada
                    succeeded = false;
                }

                if (succeeded)
                {
                    // Ahora que tenemos valores para el nombre, la auditoría y la clase de principal, sólo tenemos
                    // que establecerlos en el estado compartido.
                    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[] { "Los valores se han almacenado en estado compartido", name, audit, principalClass });
                    }
                }
            }

            if (debugEnabled)
            {
                debug("login() exit");
            }
            return succeeded;
        }

        /**
         * Método para comprometer el resultado de la autenticación.
         *
         * Este módulo de inicio de sesión no tiene que comprometer ningún dato, por lo que simplemente se devolverá.
         *
         * @return true si el inicio de sesión original ha sido satisfactorio o false
         *         si el inicio de sesión original ha fallado
         * @exception LoginException
         *         si la acción de comprometer falla, lo que no puede suceder en este módulo de inicio de sesión
         */
        public boolean commit() throws LoginException
        {
            if (debugEnabled)
            {
                debug("commit() entry");
            }

            // el valor de retorno de commit() es el mismo que para la ejecución satisfactoria del inicio de sesión original
            boolean returnVal = succeeded;

            cleanup();

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

        /**
         * Método para terminar anormalmente el proceso de autenticación (fase 2).
         *
         * Independientemente de si el nuevo inicio de sesión original ha sido satisfactorio o no, este método borra
         * nuestro estado y vuelve.
         *
         * @return true si el inicio de sesión original ha sido satisfactorio o false
         *         si el inicio de sesión original ha fallado
         * @exception LoginException
         *         si la acción de finalización anormal falla, lo que no puede suceder en este módulo de inicio de sesión
         */
        public boolean abort() throws LoginException
        {
            if (debugEnabled)
            {
                debug("abort() entry");
            }

            // el valor de retorno de abort() es el mismo que para la ejecución satisfactoria del inicio de sesión original
            boolean returnVal = succeeded;

            cleanup();

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

        /**
         * Método que finaliza la sesión de un sujeto.
         *
         * Puesto que nuestro método de compromiso no ha modificado el sujeto, no tenemos que
         * finalizar sesión ni borrar los datos y sólo se devolverá true.
         *
         * @return true si la finalización de sesión ha sido satisfactoria
         * @exception LoginException
         *         si la acción de finalización de sesión falla, lo que no puede suceder en el módulo de inicio de sesión
         */
        public boolean logout() throws LoginException
        {
            if (debugEnabled)
            {
                debug("logout() entry");
            }

            // nuestras variables locales se borran durante la acción de compromiso, por lo que no se necesita ningún borrado más

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

            // puesto que no hay ningún elemento cuya sesión deba finalizar, la ejecución siempre es satisfactoria
            return true;
        }

        /*
         * Borra nuestras variables locales; el único borrado obligatorio para
         * este módulo de inicio de sesión es establecer la variable success de nuevo en false.
         */
        private void cleanup()
        {
            if (debugEnabled)
            {
                debug("cleanup() entry");
            }

            // no hay ningún método que borrar realmente, por lo que debe restablecer simplemente la variable success
            succeeded = false;

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

        /*
         * Método privado para imprimir la información de rastreo.  Esta implementación utiliza System.out
         * para imprimir la información de rastreo en la salida estándar, pero un sistema de rastreo personalizado puede
         * implementarse aquí también.
         */
        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);
                }
            }
        }

        /*
         * Método privado para obtener el nombre de reino de la credencial y devolverlo.  Este
         * conserva el manejo de excepciones que implica la obtención del nombre de reino de la
         * lógica principal de login().
         */
        private String getRealm(WSCredential credential)
        {
            if (debugEnabled)
            {
                debug("getRealm() entry");
            }

            String realm = null;

            try
            {
                realm = credential.getRealmName();

                if (debugEnabled)
                {
                    debug("Se ha obtenido el reino='" + realm + "' de la credencial");
                }
            }
            catch (Exception e)
            {
                // getRealmName genera CredentialExpiredException y CredentialDestroyedException
                if (debugEnabled)
                {
                    //debug(new Object[] { "Se ha detectado una excepción en getRealm: ", e });
                }
                realm = "UNKNOWN_REALM";
            }

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

        /*
         * Método privado para generar el ZOS_USERID del name/uniqueName de WSPrincipal.
         */
        private String createSAFIdentityName(String name)
        {
            if (debugEnabled)
            {
                debug("createSAFIdentityName() entry "+ name);
            }

            name=stripRealm(name).toUpperCase();
            //Obtenga CN.if uniqueName de formato "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(","));

            //maneje el caso donde el reino ha añadido :<nombre_reino>\\userid
            if(name.indexOf("\\")>0){
            name = name.substring((name.indexOf("\\")+1),name.length());
            }

            // abrevie el nombre si su longitud supera el máximo definido
            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; //devolver un Nombre de identidad de SAF
        }
        /*
         * Método de ayudante privado para eliminar la información de reino.
         */
        private String stripRealm(String name){
            int index = name.indexOf("/") + 1; // índice del primer carácter después de la primera /
            if (index >= name.length())
            {
                // este bloque maneja el caso en el que la primera / es el último carácter de la serie,
                // no debería suceder, pero si sucede, simplemente se puede quitar
                name = name.substring(0, index - 1);

                if (debugEnabled)
                {
                    debug("Quitando la / final del nombre de principal de WS");
                }
            }
            else
            {
                name = name.substring(index);
            }

            return name;

        }


        /**
         * Método de ayudante privado para deducir el ID de z/OS a correlacionar.
         * Puede utilizarlo cuando desee correlacionar usuarios RACF y otros usuarios de repositorio de formas concretas.
         * Se utiliza un método de programa de utilidad de repositorio federado,isRACFUser para identificar si el usuario es del registro RACF.
         */
        private String  doCustomMapUser(String principalName){
            boolean isRACFUser=true;
            String  mapID=null;
            try{
            isRACFUser=PrincipalUtil.isRACFUser(principalName);
            }
            catch(WIMException we){
               debug("Se ha producido una excepción al comprobar isRACFuser"+we);
               //Gestionarlo según sea necesario.
            }
            mapID=isRACFUser==true?createSAFIdentityName(principalName):doMapUser(principalName);

            return mapID;
        }

        /**
         * Método de ayudante privado para deducir el ID de z/OS a correlacionar.
         * Puede utilizarlo directamente si desea correlacionar el ID de z/OS ID con independencia de los usuarios RACF/No RACF.
         *
         */
        private String  doMapUser(String principalName){
            //Si loginUser pertenece a otro registro como LDAP asegúrese de que existe un usuario MVS que coincida con el nombre derivado.
            //O sólo establezca una correlación con cualquier usuario RAFC existente como en la línea comentada siguiente.
            // name="USER237";
            //si el usuario existe en RACF, establezca una correlación con ese usuario.
            String uniqueName=null;
            String mapID=null;
                     try {
                javax.naming.InitialContext ctx = new javax.naming.InitialContext();
                // Recupera el objeto UserRegistry local.
                final com.ibm.websphere.security.UserRegistry reg = (com.ibm.websphere.security.UserRegistry) ctx.lookup("UserRegistry");
                // Recupera el registro uniqueName basado en el principalName
                uniqueName = reg.getUniqueUserId(principalName);
            } catch(Exception e) {
                debug("Exception thrown while getting uniqueID: "+e);
            }
            mapID=createSAFIdentityName(uniqueName);

            return mapID;
        }
    }
El módulo de correlación de ejemplo crea una correlación entre la identidad del registro de usuario para el repositorio federado y la identidad z/OS. La identidad para el registro de usuarios se utiliza como ID de usuario de z/OS. Si necesita una correlación distinta, puede personalizar este módulo, que se muestra en la cláusula else como parte del ejemplo de código anterior, para realizar la correlación.
Nota: Un método de programa de utilidad de repositorios federados, que se denomina PrincipalUtil.isRACFUser, se utiliza para identificar si el usuario es del registro RACF. Este método devuelve true si el usuario es un usuario RACF. Utilice este método sólo si el registro de usuario actual está configurado bajo repositorios federados.

Procedimiento

  1. Compile el código Java.
    1. Asegúrese de que el código sea fiable y de que se trate con el mismo cuidado que un módulo autorizado por APF (Authorized Program Facility). A la configuración de inicio de sesión del sistema JAAS (Java Authorization and Authentication Service) por omisión se accede desde el controlador de z/OS.
    2. Asegúrese de que el valor de vía de acceso de clases incluye los archivos JAR (Java Archive) correctos: Puede utilizar uno de los siguientes conjuntos de archivos de JAR:
      • Cliente_Aplicaciones_WebSphere/plugins/org.eclipse.emf.commonj.sdo.jar, Cliente_Aplicaciones_WebSphere/plugins/com.ibm.ws.emf.jar y Cliente_Aplicaciones_WebSphere/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.jar y WAS_HOME/plugins/com.ibm.ws.runtime.jar
  2. Instale la clase en el directorio classes de WebSphere Application Server y los gestores de aplicaciones si especifica una clase de correlación distinta de la predeterminada proporcionada por IBM®.
  3. Coloque el archivo JAR en el directorio INICIO_WAS/classes para cada nodo de la célula, incluido el nodo del gestor de despliegue en una célula de WebSphere Application Server, Network Deployment.
  4. Reinicie WebSphere Application Server para que los cambios entren en vigor.
  5. Para habilitar el registro cronológico en el módulo SampleSAFMappingModule especifique una propiedad personalizada para el mismo:
    1. En la consola administrativa de WebSphere Application Server, pulse Seguridad > Seguridad global.
    2. En Autenticación, expanda Java Authentication and Authorization Service.
    3. Pulse Inicios de sesión del sistema.
    4. Pulse nombre_módulo_inicio_sesión.
    5. En los módulos de inicio de sesión de JAAS, pulse com.ibm.websphere.wim.SampleVMMSAFMappingModule.
    6. En propiedades personalizadas, pulse Nuevo.
    7. En el campo Nombre, escriba debug y en el campo Valor, escriba true.
    8. Pulse Aplicar y, a continuación, pulse Guardar.

Icon that indicates the type of topic Task topic



Timestamp icon Last updated: last_date
http://www14.software.ibm.com/webapp/wsbroker/redirect?version=cord&product=was-nd-mp&topic=tsec_customsaffedrepos
File name: tsec_customsaffedrepos.html