Evitar log de LoginException quando usuário errra senha

Passamos a conviver com um número excessivo de exceções de login do JAAS no Jboss EAP 6.0.1 quando algum usuário errava a senha. Essas exceções não indicam erros do sistema propriamente ditos, e estavam enchendo o log e tornando difícil a análise de outros problemas de produção.

Login failure: javax.security.auth.login.LoginException: Login Failure: all modules ignored
	at javax.security.auth.login.LoginContext.invoke(LoginContext.java:921) [rt.jar:1.6.0_45]
	at javax.security.auth.login.LoginContext.access$000(LoginContext.java:186) [rt.jar:1.6.0_45]
	at javax.security.auth.login.LoginContext$4.run(LoginContext.java:683) [rt.jar:1.6.0_45]
	at java.security.AccessController.doPrivileged(Native Method) [rt.jar:1.6.0_45]
	at javax.security.auth.login.LoginContext.invokePriv(LoginContext.java:680) [rt.jar:1.6.0_45]
	at javax.security.auth.login.LoginContext.login(LoginContext.java:579) [rt.jar:1.6.0_45]
	...

A opção foi abaixar o nível de log do pacote org.jboss.security para FATAL para todo o Jboss. Isso pode ser feito no standalone.xml seguinte na seção de logging:

<subsystem xmlns="urn:jboss:domain:logging:1.1">
    ...
    <logger category="org.jboss.security">
        <level name="FATAL"/>
    </logger>
    ...
</subsystem>

Forçando o uso de Hibernate 3.x com JPA no Jboss AS 7 / EAP 6

O Jboss AS 7 já provê a biblioteca do Hibernate 4 para os projetos, não sendo necessário incluí-la na lib de seu WAR. No entanto, pode acontecer de você querer usar uma versão mais antiga do Hibernate, como por exemplo a versão 3. Além de incluí-la como lib, você precisa avisar para o Jboss para deixar de prover o Hibernate dele, no caso a versão 4. Para tanto, alguns passos sesão necessários.

Você precisa adicionar ao WAR final o arquivo META-INF/jboss-deploy-structure.xml com o segunte conteúdo:

<jboss-deployment-structure>
	<deployment>
		<exclusions>
			<module name="org.hibernate" />
		</exclusions>		
	</deployment>
</jboss-deployment-structure>

Você também vai precisar adicionar uma propriedade a mais na sua Persistence Unit declarada no persistence.xml:

...
	<property name="jboss.as.jpa.providerModule" value="hibernate3-bundled" />
...

E por fim, certifique-se de fornecer o JAR do hibernate ao compilar o pacote final. Para quem usa Maven, basta adicionar o seguinte:

<dependency>
	<groupId>org.hibernate</groupId>
	<artifactId>hibernate-entitymanager</artifactId>
	<version>3.6.10-Final</version>
</dependency>

Não se esqueça de verificar a árvore de dependências do Maven para saber se alguma dependência indireta está requerendo alguma biblioteca específica do Hiberante também na versão 4. Se houver, o downgrade pode não ser possível ou pelo menos será não-trivial. Boa sorte!

Resolvendo conversão automática para ZERO no JSF 2 com Jboss 7 AS / EAP 6

Tive um problema com JSF 2.0 onde se um campo mapeado para uma propriedade numérica não era preênchido, ao submeter o formulário ele era interpretado como zero. Isso me trouxe transtornos pois o campo era obrigatório, e zero era um valor válido.

Ainda que no meu caso específico fosse possível resolver definindo o campo como required ou mesmo criando um Validator que verificasse seu preenchimento, não fiquei satisfeito com a conversão automática feita pelo JSF, pois ela poderia afetar outros pontos do sistema

Descobri que no Jboss 7 AS / 6 EAP, que utiliza a implementação Mojarra do JSF e que também utiliza internamente o Tomcat como web container, é possível definir uma propriedade de sistema que desabilita essa conversão automática para zero. No entanto, como não teria sempre acesso aos ambientes onde a aplicação iria rodar, quis uma maneira programática de definir essa propriedade. Para tanto, adicionei a linha de código abaixo ServletListener da minha aplicação web. Veja:

@WebListener
public class MeuWebAppListener implements ServletContextListener
    ...
    @Override
    public void contextInitialized(ServletContextEvent event) {
        ...
        System.setProperty("org.apache.el.parser.COERCE_TO_ZERO", "false");
    }
    ...
}

Problema de falta de detalhes no Log / Console do Jboss AS 7 / EAP 6

Durante um bom tempo reparei que estava sem erros e detalhes da aplicação no Log e Console do Jboss AS 7 / EAP 6. O stack das exceções era exibido na tela do navegador mas não era impresso nem no console nem no arquvo de log.

Verificando minhas configurações de Logging do servidor e da aplicação, tudo estava normal. Tentei atacar o nível do Logging no console, mas não resolvia pois para ver os erros era preciso definir um nível muito baixo, praticamente impossível de filtrar o necessário.

Por fim, descobrímos na equipe que bastava adicionar o seguinte argumento na execução do Jboss:

 -Dorg.jboss.as.logging.per-deployment=false

Pra fazer isso via Eclipse com Jboss Tools, clique duas vezes sobre o servidor na aba Server, clique no link Open Launch Configuration e adicione o argumento mencionado no fim da caixa de texto Program Arguments.

Desabilitando um producer de terceiros no CDI

Entrei um problema no Jboss 7 AS / 6 EAP onde o WELD reclamou ainda no deploy da aplicão que existiam ambiguidade em uma injeção, devido a presença de dois produtores capazes de instanciar a mesma classe (no meu caso o FacesContext do JSF). Veja abaixo o erro:

org.jboss.weld.exceptions.DeploymentException: WELD-001409 Ambiguous dependencies for type 
     [FacesContext] with qualifiers [@Default] at injection point...

Para resolver precisei desativar um dos produtores. Isso foi feito criando uma Extension que veta o funcionamento de um produtor, no caso abaixo, do produtor org.apache.myfaces.extensions.cdi.jsf.impl.util.FacesInformationProducer do Apache MyFaces. Veja abaixo:

import javax.enterprise.event.Observes;
import javax.enterprise.inject.spi.Extension;
import javax.enterprise.inject.spi.ProcessAnnotatedType;

import org.apache.myfaces.extensions.cdi.jsf.impl.util.FacesInformationProducer;

public class FacesProducerSolverExtension implements Extension {

	public void observe(@Observes ProcessAnnotatedType p){
		if(p.getAnnotatedType().getJavaClass()
                    .equals(FacesInformationProducer.class)){
			p.veto();			
		}
	}
}

Para que esse extension funcione, ele deve ser registrado no arquivo de texto WEB-INF/classes/META-INF/services/javax.enterprise.inject.spi.Extension no seu WAR que ficará com o seguinte conteúdo:

br.gov.demoiselle.destdemoiselle.cgpolact.cdi.extension.FacesProducerSolverExtension

Resolvendo falta de classes para SSL do JDK no Jboss 7 AS / 6 EAP

No Jboss AS 7 / EAP 6 enfrentei uma situação onde quando a aplicação tentava estabelecer uma conexão segura via HTTPS (no caso era um webservice), acontecia o seguinte erro:

java.lang.NoClassDefFoundError: com/sun/net/ssl/internal/ssl/Provider

Pesquisando, percebí que essa classe fazia parte da própria JRE, mas no entanto, o Jboss não estava dando visibilidade dela para o ClassLoader da aplicação.

Para resolver, basta adicionar os seguintes path no arquivo XML do módulo da JDK localizado em JBOSS_HOME/modules/sun/jdk/main/module.xml:

...   
     <path name="com/sun/net/ssl/internal"/>
     <path name="com/sun/net/ssl/internal/ssl"/>
... 

Resolvendo problemas com caracteres especiais UTF-8 no JSF 2

As aplicações JSF 2 que crio e faço deploy no Jboss 7 AS / 6 EAP sempre apresentam problemas de encoding no envio de campos de formulários. Forçar o encoding do XHTML, do form, e outros truques parece não resolver pois alguém no meio do caminho entrega os caracteres especiais já estragados para o servidor.

Pesquisando, descobri que se trata de uma configuração do Servidor de Aplicações, no meu caso o Jboss. Uma maneira mais garantida de resolver o problema, sem apelar para configurações do próprio servidor, é garantindo que todo request que chega para a aplição está com o encoding correto, no meu caso UTF-8. Para tanto, um bom e velho filtro resolve, como segue:

...
@WebFilter("*.jsf")
public class CharacterEncodingFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
      throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
        chain.doFilter(request, response);
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void destroy() {
    }
}