Pergunta

Eu estou escrevendo uma aplicação web java que precisa realizar o login através de um webservice. Claro, nenhum dos reinos fornecidos com o servidor de aplicativos que estou usando (glassfish v2) pode fazer o truque. Assim, tive de escrever meu próprio. Parece, no entanto, que a implementação reino que eu escrevi está completamente ligada à Glassfish e não pode ser usada como é em qualquer outro servidor de aplicação.

Existe alguma maneira padrão ou amplamente suportada para implementar um domínio personalizado? É de qualquer maneira possível para implantar esse reino a partir de um .war, ou ele sempre precisa ser carregado a partir próprio classpath do servidor?

Foi útil?

Solução

NOTA: A resposta abaixo é válida somente para Java EE 5. Como foi trazido a minha atenção em uma das outras respostas, Java EE 6 suporta isso. Então, se você estiver usando Java EE 6, não leia esta resposta, mas leia a outra resposta relevante.

De minha própria pesquisa e das respostas a esta pergunta a resposta que encontrei é o seguinte: Embora JAAS é uma interface padrão, não há nenhuma maneira uniforme para escrever, implementar e integrar uma JAAS Realm + LoginModule em vários servidores de aplicativos.

v2 Glassfish exige que você estenda algumas de suas próprias classes internas que implementam LoginModule ou Realm si. Você, contudo, não pode personalizar todo o processo de login, porque muitos métodos da interface LoginModule são marcadas final na superclasse do Glassfish. Os LoginModule e Realm classes personalizadas devem ser colocados no classpath AS (não a aplicação de), eo reino deve ser registrado manualmente (sem implantação do .war possível).

A situação parece ser um pouco melhor para o Tomcat, que vai deixar você codificar seu próprio reino e LoginModule completamente e, em seguida, configurá-los para o servidor de aplicativos utilizando o seu próprio JAASRealm (que irá delegar o trabalho real para suas implementações de Realm e LoginModule). No entanto, mesmo tomcat não permite a implantação de seu domínio personalizado do seu .war.

Note que nenhum dos servidores de aplicativos que apareceram os meus resultados parecem ser capazes de tirar o máximo proveito de todas as JAAS Callbacks. Todos eles parecem apoiar apenas o esquema básico de senha nome de usuário +. Se precisar de algo mais complicado do que isso, então você terá que encontrar uma solução que não é gerido pelo seu container Java EE.

Para referência, e porque foi solicitado nos comentários a minha pergunta, aqui está o código que eu escrevi para GlassfishV2.

Primeiro de tudo, aqui está a implementação Realm:

public class WebserviceRealm extends AppservRealm {

private static final Logger log = Logger.getLogger(WebserviceRealm.class.getName());

private String jaasCtxName;
private String hostName;
private int port;
private String uri;

@Override
protected void init(Properties props) throws BadRealmException, NoSuchRealmException {
    _logger.info("My Webservice Realm : init()");

    // read the configuration properties from the user-supplied properties,
    // use reasonable default values if not present
    this.jaasCtxName = props.getProperty("jaas-context", "myWebserviceRealm");
    this.hostName = props.getProperty("hostName", "localhost");
    this.uri = props.getProperty("uri", "/myws/EPS");

    this.port = 8181;
    String configPort = props.getProperty("port");
    if(configPort != null){
        try{
            this.port = Integer.parseInt(configPort);
        }catch(NumberFormatException nfe){
            log.warning("Illegal port number: " + configPort + ", using default port (8181) instead");
        }
    }
}

@Override
public String getJAASContext() {
    return jaasCtxName;
}

public Enumeration getGroupNames(String string) throws InvalidOperationException, NoSuchUserException {
    List groupNames = new LinkedList();
    return (Enumeration) groupNames;
}

public String getAuthType() {
    return "My Webservice Realm";
}

public String getHostName() {
    return hostName;
}

public int getPort() {
    return port;
}

public String getUri() {
    return uri;
}
}

E, em seguida, a implementação LoginModule:

public class WebserviceLoginModule extends AppservPasswordLoginModule {

// all variables starting with _ are supplied by the superclass, and must be filled
// in appropriately

@Override
protected void authenticateUser() throws LoginException {
    if (_username == null || _password == null) {
        throw new LoginException("username and password cannot be null");
    }

    String[] groups = this.getWebserviceClient().login(_username, _password);

    // must be called as last operation of the login method
    this.commitUserAuthentication(groups);
}

@Override
public boolean commit() throws LoginException {
    if (!_succeeded) {
        return false;
    }

    // fetch some more information through the webservice...

    return super.commit();
}

private WebserviceClient getWebserviceClient(){
    return theWebserviceClient;
}
}

finalmente, no reino tem que ser amarrado ao LoginModule. Isto é feito no nível do arquivo de configuração JAAS, que por mentiras glassfish v2 em yourDomain / config / login.conf. Adicione as seguintes linhas no final do arquivo:

myWebserviceRealm { // use whatever String is returned from you realm's getJAASContext() method
    my.auth.login.WebserviceLoginModule required;
};

Isto é o que tem coisas que trabalham para mim no GlassFish. Mais uma vez, esta solução não é portátil através de servidores de aplicações, mas tanto quanto eu posso dizer, não há nenhuma solução portátil existente.

Outras dicas

Existe alguma maneira padrão ou amplamente suportada para implementar um personalizado Reino? É de qualquer maneira possível para implantar esse reino a partir de um .war, ou que sempre precisa ser carregado a partir próprio classpath do servidor?

Não é absolutamente uma forma padrão para implementar um domínio personalizado, ou em termos mais gerais um módulo de autenticação personalizada. Isto pode ser feito através do JASPIC / JASPI / JSR 196 SPI / API . JASPIC é uma parte normal de qualquer implementação completa Java EE 6, mas, infelizmente, não faz parte do Java EE 6 Web Profile.

No entanto, apesar JASPIC sendo uma parte do Java EE 6, não é ser perfeitamente suportada pelos fornecedores. GlassFish e WebLogic parecem ter muito boas implementações, JBoss AS e Geronimo são um pouco mais problemático. O engenheiro-chefe da JBoss sobre este tema (Anil Saldhana) tem ainda afirmou que ele se recusa a ativar JASPIC por padrão para o momento. Alguns dos mais graves erros no JBoss AS 7.1 ter sido recentemente fixo , mas como não há lançamentos públicos de JBoss 7.1.x agendado mais e JBoss AS 7.2 ainda algum tempo longe isso significa a partir de agora, pelo menos no JBoss JASPIC é problemático.

Outra questão lamentável é que o módulo de autenticação real pode ser padronizado, mas não há nenhuma maneira declarativa (arquivo XML ler) para configurá-lo de que é padronizado.

É de qualquer maneira possível para implantar esse reino a partir de um .war, ou não sempre precisa ser carregado a partir próprio classpath do servidor?

Com JASPIC, o módulo de autenticação ( 'domínio') pode, efectivamente, ser carregado a partir de um .war. Eu não estou 100% de certeza se isso é garantido pela especificação, mas um dos 4 servidores I testados (GlassFish, WebLogic, Geronimo e JBoss AS), todos eles apoiaram esta. Geronimo, infelizmente, tem algum tipo de condição de corrida no seu registro programático, por isso você precisa de uma solução feia fazendo uma implantação quente duas vezes, mas no final, se faz carregar o módulo do .war.

A partir dos mecanismos de propriedade, pelo menos JBoss AS tem sempre apoiado o carregamento do módulo (por exemplo, uma subclasse de org.jboss.security.auth.spi.AbstractServerLoginModule) do .war ou .ear.

escreveu um post no blog sobre este tópico recentemente que tem um pouco mais detalhes.

Você nunca pode implantar um reino de uma guerra, porque o reino não é um artefato de aplicação, é um artefato de Container (assim a "segurança baseada container" frase). Você pode configurar seu aplicativo para usar um domínio específico, tal como previsto pelo contêiner, mas a aplicação não pode fornecer isso em si.

Dito isso, enquanto todos os recipientes são diferentes, e estes reinos não são portáteis, simples senso comum irá reduzir as diferenças para o pouco de código de cola necessária a integração com o recipiente, se você estiver olhando para a portabilidade.

Tendo tem um rápido olhar para a documentação Suns parece que você terá que escrever uma LoginModule personalizado que estende a sua classe específica servidor de aplicações. Este parece um pouco para trás para mim e uma limitação do Glassfish.

Se você quiser fazer isso mais portátil, eu sugiro colocar a maior parte da implementação em um LoginModule personalizado desenvolvido contra a interface JavaEE Norma (s) e depois com uma camada fina de implementação específica para Glassfish que os delegados ao padrão , implementação portátil.

Confira artigo de Sun sobre este assunto .

Eu nunca realmente fez isso mesmo, mas estou bastante confiante de cada AS lhe dá uma opção para registrar novos domínios (domínios de segurança) sobre ele.

Ele provavelmente não será 100% portátil, e para cada um, como você pode precisar de um XML de configuração diferente, mas basicamente, não há nenhuma razão para o código para ser diferente.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top