[z/OS]

Módulos de Mapeamento de LDAP de Um para UM para o System Authorization Facility (SAF) Customizados

Você pode customizar configurações de login do JAAS (Java™ Authentication and Authorization) gravando um módulo de mapeamento de login customizado.

O WebSphere Application Server for z/OS pode fornecer mapeamento a partir de uma solicitação de entrada do remote method invocation (RMI) com as credenciais LDAP para a Identidade do System Authorization Facility (SAF). O caso de uso é um WebSphere Application Server em qualquer plataforma configurada para o LDAP e envia uma solicitação RMI/IIOP para um segundo servidor configurado para um Registro do Usuário SAF. O WebSphere Application Server (liberação 5.1 ou posterior) envia uma solicitação de RMI usando o Token LTPA, representando a identidade LTPA para o WebSphere Application Server para z/OS que é configurado para o SAF. A figura a seguir ilustra este mapeamento.

Figura 1. Mapeamento do Pedido de Entrada de RMI com Credenciais de LDAP para Identidade de SAFUm WebSphere Application Server em qualquer plataforma que esteja configurada para LDAP e envia um pedido RMI/IIOP para um segundo servidor configurado para um Registro de Usuário SAF. O WebSphere Application Server (release 5.1 e mais recente) envia um pedido RMI usando o token LTPA representando a identidade LDAP para o WebSphere Application Server para z/OS que está configurado para SAF.

A amostra a seguir é um módulo de login de entrada de RMI de JAAS que abre o token de LTPA, extrai o ID do usuário de LDAP, retira o cn=userID e configura WSCredential para o ID do usuário de SAF. O módulo de login de entrada de amostra que é configurado para o segundo servidor é suportado apenas no WebSphere Application Server para z/OS liberação 6.1 ou posterior.

A amostra na verdade é um módulo de login de hash no qual o com.ibm.wsspi.security.token.AttributeNameConstants.WSCREDENTIAL_UNIQUEID é definido como o z/OS SAF Identity desejado. O ltpaLoginModule verifica um com.ibm.wsspi.security.token.AttributeNameConstants.WSCREDENTIAL_UNIQUEID que foi transmitido e usa o ID especificado para criar o contexto de segurança apropriado para o usuário.

Esse módulo de amostra é configurado como um módulo de login RMI_INBOUND JAAS e deve ser especificado no topo da lista seguida pelo ltpaLoginModule.

Na amostra a seguir, uma identidade Java Platform, Enterprise Edition (Java EE) está disponível para controlar o mapeamento para uma identidade do SAF. O modelo usa o login de hash do valor Constants.WSCREDENTIAL no estado compartilhado.

O código a seguir é um programa SampleLTPASAFMappingModule de amostra. Esse programa de amostra pode ser usado "no estado em que se encontra" ou modificado, compilado e instalado no diretório WAS_HOME/classes.
// Este programa pode ser usado, executado, copiado, modificado e
// distribuído sem royalty para a finalidade de desenvolvimento,
// utilização, marketing ou distribuição.
//
//

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 demonstra um módulo de login customizado
 * que mapeia o Token LTPA existente do estado compartilhado para ID EXCLUSIVO para evitar o Login.
 * O uso normal é um Token LTPA de entrada gerado de uma região diferente (talvez uma Região não zOS)
 * para um Registro de Usuário SAF.
 * O Token LTPA é usado como o token de identidade confiável. 
 *
 * ***
 *
 * @author IBM Corporation
 * @version 1.0
 * @since 1.0
 */
public class SampleLTPASAFMappingModule implements LoginModule
{
    /*
     * **
     * Constante que representa o nome desse módulo de mapeamento.  Sempre que essa amostra
     * de código for utilizada para criar uma classe com um nome diferente, esse valor deve ser alterado.
     *
     * Por padrão, esse valor é utilizado como parte da amostra do token de auditoria, e para
     * propósitos de depuração.
     * ***
     */
    private final static String MAPPING_MODULE_NAME = "com.ibm.websphere.security.SampleLTPASAFMappingModule";

    private final static int MAXIMUM_NAME_LENGTH = 8;

    /*
     * **
     * Especifica se a depuração é ativada para esse Módulo de Login.  Isso depende do
     * valor da opção "debug" transmitida pelo LoginContext.
     * ***
     */
    private boolean debugEnabled = false;
 /*
     * **
     * Especifica a região de entrada que este Módulo de Login deve manipular.  Se não houver nenhuma configuração 
     * de propriedade de entrada para onlyThisRealm, o Módulo de Login processará todo o pedido de entrada
     * independentemente da região da identidade de entrada no token de LTPA. 
     * ***
     */
    private String onlyThisRealm = null;

    /*
     * **
     * Armazena o Assunto transmitido a partir do LoginContext.
     * ***
     */
    private Subject subject;

    /*
     * **
     * Armazena o CallbackHandler transmitido pelo LoginContext.
     * ***
     */
    private CallbackHandler callbackHandler;

    /*
     * **
     * Armazena o Mapa de estado compartilhado transmitido pelo LoginContext.
     * ***
     */
    private Map sharedState;

    /*
     * **
     * Armazena o Mapa de opções transmitido pelo LoginContext.
     * ***
     */
    private Map options;

    /*
     * **
     * Esse valor é utilizado para armazenar o sucesso ou falha do método login() para
     * que commit() e abort() possam agir de modo diferente nos dois casos, se desejado.
     * ***
     */
    private boolean succeeded = false;

    /**
     * **construir um objeto do módulo de mapeamento não inicializado.***
     */
    public SampleLTPASAFMappingModule()
    {
    }

    /**
     * **Inicializar este módulo de login.***
     *
     * **
     * Ele é chamado pelo LoginContext depois que esse módulo de login é
     * instanciado. As informações relevantes são transmitidas do LoginContext
     * para esse módulo de login. Se o módulo de login não entender os dados
     * armazenados no sharedState e parâmetros opcionais,
     * eles podem ser ignorados.
     * ***
     *
     * @param subject
     *                O assunto que esse LoginContext está autenticando
     * @param callbackHandler
     *                Um CallbackHandler para se comunicar com o usuário final para reunir informações de login (por exemplo, nome de usuário e senha).
     * @param sharedState
     *                O estado compartilhado com outros módulos de login configurados.
     * @param options
     *                As opções especificadas nas configurações de login desse módulo de login específico.
     */
    public void initialize(Subject newSubject, CallbackHandler newCallbackHandler, Map newSharedState, Map newOptions)
    {
        // obtenha primeiramente o valor para depuração, para que o rastreio possa ser utilizado
        // nesse 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");
        }
	// obtenha o valor para a região antes de tudo para saber se este módulo de login deverá 
	// processar somente uma região de entrada em particular ou se deverá processar toda a região. Um valor nulo 
	// seleciona todas as regiões a serem processadas. 
	if (newOptions.containsKey("realm"))
        {
            onlyThisRealm = (String) newOptions.get("realm");
	    onlyThisRealm = onlyThisRealm.trim();
	}


        // nenhum desses objetos será utilizado por esse módulo de login, com exceção do sharedState,
        // mas para manter consistência com a maioria dos módulos de login, manteremos uma referência a todos eles
        this.subject = newSubject;
        this.callbackHandler = newCallbackHandler;
        this.sharedState = newSharedState;
        this.options = newOptions;

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

    /**
     *
     * @retornar true se a autenticação for bem-sucedida ou false
     *         se esse Módulo de Login deve ser ignorado
     * @exception LoginException
     *         se a autenticação falhar, o que é impossível para esse Módulo de Login
     */
    public boolean login() throws LoginException
    {
        if (debugEnabled)
        {
            debug("login() entry");
        }

	// Manipular o retorno de chamada 
	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;

	//Esta rotina processará apenas um token de LTPA. Se não houver nenhum token de entrada, 
	//essa rotina retornará true e permitirá que outro LM manipule
	//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 é uma configuração de propriedade de entrada para saber se desejamos este módulo de login
	//para manipular somente 1 pedido de região inserido. Se onlyThisRealm for nulo, 
	//processaremos todos os pedidos e continuaremos. Se onlyThisRealm não
	//corresponder ao pedido de entrada extraído de LTPA, deixaremos o outro
	//LM manipular este pedido. 
	//
	if ((onlyThisRealm != null) && (!realm.trim().equals(onlyThisRealm))) {
            if (debugEnabled)
            {
                debug("inbound realm of "+realm+" does not match option realm of "+onlyThisRealm);
            }
            return true;
	}

	try {
	    // Recupera o InitialContext padrão para esse servidor.
	    javax.naming.InitialContext ctx = new javax.naming.InitialContext();

	    // Recupera o objeto UserRegistry local.
	    com.ibm.websphere.security.UserRegistry reg = 
		    (com.ibm.websphere.security.UserRegistry) ctx.lookup("UserRegistry");				

	
  	   // Recupera o uniqueID de registro com base no uid especificado 
           // no NameCallback.
	   String uniqueid = reg.getUniqueUserId(uid);
	   if (debugEnabled)
            {
                debug("uniqueid "+uniqueid);
            }
	   // Recupera o nome de exibição do registro do usuário com base no uniqueID.
	   String securityName = reg.getUserSecurityName(uid);
	   if (debugEnabled)
            {
                debug("securityName "+securityName);
            }
	
	   // Recupera os grupos associados a esse uniqueID.
	   java.util.List groupList = reg.getUniqueGroupIds(uid);

   	   // Cria java.util.Hashtable com as informações reunidas 
           // do UserRegistry.
	   // Ao configurar esta tabela de hash, o módulo de login de LTPA configurará
	   // a Identidade de SAF corretamente. 
   	   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);

	   // Inclui a tabela hash para o estado compartilhado do 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;
    }

    /**
     * **Método para confirmar o resultado de autenticação.***
     *
     * **
     * Esse Módulo de Login não precisa consolidar dados, portanto simplesmente retornaremos.
     * ***
     *
     * @retornar true se o login original for bem-sucedido, ou false
     *         se o login original falhar
     * @exception LoginException
     *         se a consolidação falhar, o que não pode ocorrer nesse Módulo de Login
     */
    public boolean commit() throws LoginException
    {
        if (debugEnabled)
        {
            debug("commit() entry");
        }

        // o valor de retorno de commit() é igual ao sucesso do login original
        boolean returnVal = succeeded;

        cleanup();

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

    /**
     * **Método para abortar o processo de autenticação (Fase 2).***
     *
     * **
     * Independente de nosso login original ter tido sucesso ou falhado, esse método limpa
     * nosso estado e retorna.
     * ***
     *
     * @retornar true se o login original for bem-sucedido, ou false
     *         se o login original falhar
     * @exception LoginException
     *         se a interrupção falhar, o que não pode ocorrer nesse Módulo de Login
     */
    public boolean abort() throws LoginException
    {
        if (debugEnabled)
        {
            debug("abort() entry");
        }

        // o valor de retorno de abort() é igual ao sucesso do login original
        boolean returnVal = succeeded;

        cleanup();

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

    /**
     * **Método que faz logout de um Subject.***
     *
     * **
     * Como nosso método commit não modificou o Subject, não há do que
     * efetuar logout ou limpar e podemos apenas retornar true.
     * ***
     *
     * @retornar true se o logout for bem-sucedido
     * @exception LoginException
     *         se o logout falhar, o que não pode ocorrer no Módulo de Login
     */
    public boolean logout() throws LoginException
    {
        if (debugEnabled)
        {
            debug("logout() entry");
        }

        // nossas variáveis locais foram limpas durante o commit, portanto não há necessidade de limpeza adicional

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

        // como não há do que efetuar logout, sempre obtemos sucesso
        return true;
    }

    /*
     * **
     * Limpa nossas variáveis locais; a única limpeza requerida para
     * esse Módulo de Login é definir nossa variável de sucesso novamente para false.
     * ***
     */
    private void cleanup()
    {
        if (debugEnabled)
        {
            debug("cleanup() entry");
        }

        // não há o que limpar, portanto iremos apenas reconfigurar nossa variável de sucesso
        succeeded = false;

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

    /*
     * **
     * Método privado para imprimir informações de rastreio.  A implementação utiliza System.out
     * para imprimir informações de rastreio de saída padrão, mas um sistema de rastreio personalizado pode
     * ser implementado aqui também.
     * ***
     */
    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
     * Método particular para gerar a Identidade de SAF da identidade de LDAP. Talvez seja necessário
     * modificar essa rotina por seus padrões de instalação para extrair a Identidade de SAF da
     * Identidade de LDAP. Ou essa rotina pode ser escrita para mapear LDAP para a identidade de SAF.
     * ***
     */
    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; // índice do primeiro caractere após o primeiro /
        System.out.println(index);
        System.out.println(name);
        if (index >= name.length())
        {
            // esse bloco manipula o caso em que o primeiro / é o último caractere da Cadeia,
            // isso realmente não deve ocorrer, mas se ocorrer podemos apenas o ignorar
            name = name.substring(0, index - 1);

            if (debugEnabled)
            {
                debug("Stripping trailing / from name");
            }
        }
        else
        {
            // o índice é 0 (se não houver / no nome), ou é a posição
            // após o primeiro / no nome
            //
            // de qualquer forma, iremos tirar a sub-cadeia desse ponto até o final da cadeia
            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(","));
        
        // reduzir o nome se seu comprimento exceder o máximo definido
        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; //retorne um Nome de Identidade SAF
    }
}

O módulo de mapeamento de amostra cria um mapeamento de um pedido de entrada de RMI com credenciais de LDAP para a identidade de SAF. Este módulo pode ser customizado para desempenhar o mapeamento.


Ícone que indica o tipo de tópico Tópico de Conceito



Ícone de registro de data e hora Última atualização: last_date
http://www14.software.ibm.com/webapp/wsbroker/redirect?version=cord&product=was-nd-mp&topic=csec_LDAP_SAF_loginmods
Nome do arquivo: csec_LDAP_SAF_loginmods.html