[z/OS]

Módulos de Mapeamento Customizado do System Authorization Facility

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

Nota: Se estiver usando o recurso de mapeamento de identidade distribuída SAF, não será necessário configurar um módulo de mapeamento.

O módulo WebSphere Application Server ltpaLoginModule e o módulo AuthenLoginModule usam o estado compartilhado para salvar informações de estado com a capacidade de permitir que LoginModules possa modificar informações de estado. O ltpaLoginModule inicializa a matriz de retorno de chamada no método login() utilizando o seguinte código. A matriz de retorno de chamada é criada pelo ltpaLoginModule apenas se uma matriz não estiver definida na área de estado compartilhado.

No exemplo de código a seguir, a confiança é estabelecida sobre a disponibilidade de uma identidade Java Platform, Enterprise Edition (Java EE) para controlar o mapeamento para uma identidade SAF (System Authorization Facility). Esse código utiliza o valor Constants.WSPRINCIPAL_KEY no estado compartilhado. O valor é colocado no código por um módulo de login do WebSphere Application Server 1. É possível inserir um LoginModule personalizado após o módulo ltpaLoginModule e antes do módulo MapPlatformSubject. Se você fizer isso, utilize uma matriz de retorno de chamada ou outros valores de estado compartilhado para obter um valor utilizado para controlar o mapeamento para o ID do usuário do z/OS.

A seguir está um SAFMappingModule de amostra:
//
// Este programa pode ser utilizado, 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;

/**
 * 
 * SampleSAFMappingModule demonstra um módulo de login personalizado
 * que mapeia o WSPrincipal existente do estado compartilhado para um
 * id de usuário do z/OS.
 * 
 *
 * 
 * Os valores a seguir serão definidos para o estado compartilhado se a autenticação
 * for bem-sucedida.  Se a autenticação falhar, esse módulo de login ainda indicará
 * sucesso, mas nenhum valor será definido para o estado compartilhado.
 * 
 *   AttributeNameConstants.ZOS_USERID
 *   AttributeNameConstants.ZOS_AUDIT_STRING
 *   AttributeNameConstants.CALLER_PRINCIPAL_CLASS
 *
 * Esse módulo de login não utiliza retornos de chamada ou modifica o Subject
 * de forma alguma.
 *
 * @author IBM Corporation
 * @version 1.0
 * @since 1.0
 */
public class SampleSAFMappingModule 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.SampleSAFMappingModule";

    /*
     * Constante que representa o comprimento máximo de ZOS_USERID.  Restrições atuais de
     * nomenclatura do MVS limitam esse valor para oito caracteres.
     *
     * Quando a opção para useWSPrincipalName é escolhida, o nome do WSPrincipal é
     * reduzido para essa quantidade de caracteres.
     */
    private final static int MAXIMUM_NAME_LENGTH = 8;

    /*
     * Especifica se o comportamento de mapeamento padrão do módulo deve ou não ser utilizado, que é
     * utilizar o nome WSPrincipal para gerar o ZOS_USERID.  Isso depende do
     * valor da opção "useWSPrincipalName" transmitida pelo LoginContext.
      */
    private boolean useWSPrincipalName = true;

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

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

    /**
     * Construa um objeto de módulo de mapeamento não-inicializado.
     */
    public SampleSAFMappingModule()
    {
    }

    /**
     * Inicialize esse 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 comunicação com o usuário final 
     *                para coletar informações de login (ex:, nome do 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");
        }

        // 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 (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 mapear WSPrincipal para um ZOS_USERID
     *
     * Esse método deriva um ZOS_USERID e o armazena no Estado Compartilhado para ser utilizado por um
     * Módulo de Login posterior.
     *
     * @retornar verdadeiro se a autenticação for bem-sucedida, ou falso
     *         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");
        }

        if (sharedState.containsKey(AttributeNameConstants.ZOS_USERID))
        {
            // não queremos substituir esse valor se, por qualquer motivo, outro Módulo de Login
            // já tiver o colocado no estado compartilhado, mas ainda o consideramos um sucesso
            // porque os critérios de saída desse módulo foram atendidos
            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))
        {
            // se não houver um Proprietário ou uma Credencial no estado compartilhado, nada pode ser
            // feito, portanto retornaremos false para informar ao LoginContext para ignorar esse módulo
            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;

            // extrair o WSPrincipal e o WSCredential do estado compartilhado
            WSPrincipal principal = (WSPrincipal) sharedState.get(Constants.WSPRINCIPAL_KEY);
            WSCredential credential = (WSCredential) sharedState.get(Constants.WSCREDENTIAL_KEY);

            if (useWSPrincipalName)
            {
                // esse módulo de amostra de mapeamento oferece um método para obter o ZOS_USERID diretamente
                // do nome WSPrincipal se a propriedade "useWSPrincipalName" for definida para true
                if (debugEnabled)
                {
                    debug("Using name from WSPrincipal to obtain ZOS_USERID");
                }

                name = createName(principal);

                String realm = getRealm(credential);

                // nesse exemplo, uma amostra de token de auditoria será criada, combinando o ZOS_USERID,
                // a região e o nome desse módulo de mapeamento
                //
                // um token de auditoria personalizado pode ser criado utilizando quaisquer dados disponíveis ao invés
                // dessa amostra de token
                audit = realm + "/" + name + " MappingModule:" + MAPPING_MODULE_NAME;

                // Um Subject pode conter mais de um Proprietário.  Esse valor especifica a
                // classe do Proprietário a ser retornada quando o Subject é solicitado pelo
                // Proprietário Responsável pela Chamada.  Se uma classe de Proprietário personalizada tiver sido colocada no
                // Subject, esse nome de classe pode ser especificado aqui.
                //
                // Dois valores pré-definidos para a Classe de Proprietário do Responsável pela Chamada são fornecidos:
                //
                // - AttributeNameConstants.ZOS_CALLER_PRINCIPAL_CLASS
                //   a classe do Proprietário do z/OS
                //
                // - AttributeNameConstants.DEFAULT_CALLER_PRINCIPAL_CLASS
                //   a classe de Proprietário padrão
                principalClass = AttributeNameConstants.DEFAULT_CALLER_PRINCIPAL_CLASS;
                succeeded = true;
            }
            else
            {
                if (debugEnabled)
                {
                    debug("Using Custom logic to obtain ZOS_USERID");
                }
                // se o comportamento fornecido por esse módulo de mapeamento para obter ZOS_USERID do
                // nome do WSPrincipal não for suficiente, lógica de mapeamento personalizada pode ser fornecida aqui
                //
                // para utilizar essa lógica de mapeamento personalizada, a propriedade "useWSPrincipalName" deve ser definida
                // para false

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

                // por padrão, nenhum mapeamento personalizado é fornecido, portanto o sucesso desse caminho de código
                // é falso; se mapeamento personalizado for fornecido, a variável a seguir deve ser
                // modificada para representar o sucesso ou falha do mapeamento personalizado
                succeeded = false;
            }

            if (succeeded)
            {
                // agora que temos valores para name, audit, e principalClass, precisamos apenas defini-los
                // para o estado compartilhado
                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[] { "Os valores foram armazenados no estado compartilhado", name, 
                          audit, principalClass });
                }
            }
        }

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

    /**
     * Método para consolidar o resultado da autenticação.
     *
     * Esse Módulo de Login não precisa consolidar dados, portanto simplesmente retornaremos.
     *
     * @retornar verdadeiro se o login original foi bem-sucedido, ou falso
     *         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 interromper 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 verdadeiro se o login original foi bem-sucedido, ou falso
     *         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 efetua 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 verdadeiro 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);
            }
        }
    }

    /*
     * Método privado para obter o nome da região da Credencial e retorná-lo.  Este
     * mantém a manipulação da exceção envolvida com a obtenção do nome da região da
     * lógica login() principal.
     */
    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 emite CredentialExpiredException e CredentialDestroyedException
             if (debugEnabled)
             {
                 debug(new Object[] { "Exceção obtida em getRealm: ", e });
             }
             realm = "UNKNOWN_REALM";
        }

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

    /*
     * Método particular para gerar o ZOS_USERID do nome WSPrincipal.
     */
    private String createName(WSPrincipal principal)
    {
        if (debugEnabled)
        {
            debug("createName() entry");
        }

        String name = principal.getName();

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

        // WSPrincipal.getName() pode retornar REALM/NAME, portanto analise a Cadeia para obter apenas o nome
        int index = name.indexOf("/") + 1; // índice do primeiro caractere após o primeiro /
        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 WSPrincipal 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);
        }

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

        // ids MVS são todos em letras maiúsculas
        name = name.toUpperCase();

        if (debugEnabled)
        {
            debug("createName() exit");
        }
        return name;
    }
}
O módulo de mapeamento de amostra cria um mapeamento entre a identidade do LDAP (Lightweight Directory Access Protocol) e a identidade do z/OS. A identidade do LDAP é utilizada como o ID do usuário do z/OS. Se for requerido um mapeamento diferente, este módulo poderá ser personalizado (conforme mostrado na cláusula else) para executar o mapeamento. Então:
  1. Compile o código Java. Certifique-se de que o código seja confiável e tratado com a mesma atenção que um módulo autorizado por APF. A configuração de login do sistema JAAS (Java Authorization and Authentication Service) padrão é acessada no controlador do z/OS.
  2. Se você especificar uma classe de mapeamento diferente do padrão fornecido pela IBM®, será necessário instalar a classe no diretório de classes do Servidor de Aplicativos e dos Gerenciadores de Implementação. Coloque o arquivo Java archive (JAR) no diretório WAS_HOME/classes para cada nó na célula, incluindo o nó do gerenciador de implementação em uma célula do WebSphere Application Server, Network Deployment.

Í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_writesafmapmods
Nome do arquivo: csec_writesafmapmods.html