quinta-feira, 30 de julho de 2015

Configurando Spring Security 4 com JSF 2.2 e CDI 1.1

Hoje irei mostrar como configurar o Spring Security 4 em aplicações que utilizam JSF e CDI. Assumirei que o CDI que já está previamente configurado.

Neste projeto estão sendo utilizados:
  • CDI 1.1
  • JSF 2.2
  • Spring Security 4.0.1
  • Maven
  • Primefaces 5.2
Toda a configuração será feita de forma programática, dispensando qualquer arquivo xml.

Vamos ao pom.xml

        
            org.springframework
            spring-framework-bom
            4.0.1.RELEASE
            pom
            compile
         
        
        
          
            org.springframework.security  
            spring-security-web  
            4.0.1.RELEASE  
         
         
        
          
            org.springframework.security  
            spring-security-config  
            4.0.1.RELEASE  
        

                
        
            commons-logging
            commons-logging
            1.2
        
A classe responsável por iniciar o serviço de segurança do Spring:
public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer {

    public SecurityWebApplicationInitializer() {
        super(SecurityConfig.class);
    }
}

Vamos criar a classe que conterá boa parte das implementações de restrições de páginas, a SecurityConfig:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@EnableWebSecurity
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().withUser("zezinho").password("123456").roles("COMUM");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();

        http.exceptionHandling().and().authorizeRequests().and()
                .exceptionHandling().accessDeniedPage("/acesso-negado.jsf").and().authorizeRequests()
                .antMatchers("/javax.faces.resource/**").permitAll()
                .and().authorizeRequests()
                .antMatchers("/cadastro-usuarios.jsf", "/cadastro-empresas.jsf").hasRole("ADMINISTRADOR")
                .anyRequest().authenticated()
                .and().logout().logoutSuccessUrl("/login.jsf?logout").permitAll()
                .and().formLogin() //.loginPage("/login.jsf") Para utilizar a própria página de login
                .failureUrl("/login.jsf?erro").permitAll();
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/resources/**");
    }
}

Pronto ! Agora basta rodar a aplicação que a primeira página a ser exibida será um formulário de login do próprio Spring. Caso você tente acessar as URL's que possuem hasRole("ADMINISTRADOR"), o Spring irá redirecionar para acesso-negado.jsf, e é claro, nenhum usuário pode acessar qualquer página da aplicação sem estar devidamente autenticado.

A linha .antMatchers("/javax.faces.resource/**").permitAll(), se refere a liberar os recursos de tela para usuário, como CSS, JavaScript e imagens. O método public void configure(WebSecurity web), também libera o acesso para endereços /resources/** nos GET's do navegador. Eu particularmente tive alguns problemas em conseguir liberar corretamente, passei por alguns erros muito estranhos que envolviam a pasta resources. Deixarei o Post que criei no GUJ ao final. 

Página de Login Personalizada e Logout

A página de login deve ser da seguinte forma:
      
        
        

           
            
           
           

        
        

         

         
         

         
                
Usuário ou senha inválidos.
Botão para Logout.
Sim
Os inputs do formulário de login devem possuir exatamente os ID's username e password, são por esses campos que o Spring faz associação das informações passadas no momento do login.

Foram usadas classes de CSS do primefaces pois ele é uma dependência do projeto.

A autenticação desta configuração ainda é feita utilizando o método inMemoryAuthentication(), em outro post iremos configurar com autenticação via banco de dados.

Fontes:

Documentação do Spring Security
http://docs.spring.io/spring-security/site/docs/4.0.3.CI-SNAPSHOT/reference/htmlsingle/

Documentação de Setup inicial do SpringSecurity:
http://docs.spring.io/spring-security/site/docs/current/guides/html5//index.html

Documentação de migração do Spring 3x para o 4x:
http://docs.spring.io/spring-security/site/migrate/current/3-to-4/html5/migrate-3-to-4-jc.html

Dez utilidades do Spring Security:
http://imasters.com.br/linguagens/java/dez-coisas-que-voce-pode-fazer-com-o-spring-security/

Minha pergunta no GUJ sobre o erro que tive com o Spring:
http://www.guj.com.br/43567-jsf-2--cdi-11--springsecurity-4-custom-login-form-nao-redireciona-para-pagina-correta

segunda-feira, 20 de julho de 2015

Configurando JavaSE com CDI e DeltaSpike

No último post mostrei como configurar o CDI em projetos JavaSE. Porém, hoje vamos um pouco além e mostrarei como deixar o CDI ainda mais poderoso. Iremos configurar com Maven a extensão mais famosa do CDI, o DeltaSpike.

Não vou entrar em detalhes sobre o que é o DeltaSpike, isso já é possível de achar em diversos sites e blogs sobre programação.Pretendo Apenas trazer de maneira resumida as configurações iniciais.

Entretanto, para os que ainda não tiveram contato, deixarei links no final do post para esclarecimento.

Basicamente o DeltaSpike é um conjunto de módulos opcionais que podem ser adicionados a especificação CDI para contemplar funcionalidades que não foram pensadas. O mesmo é composto por um módulo central e diversos módulos opcionais, que são basicamente:

  • Bean Validation
  • Container Control
  • Data
  • JPA
  • JSF
  • Partial-Bean
  • Scheduler
  • Security
  • Servlet
  • TestControl
Vamos ao código !

Inicialmente precisamos adicionar as dependências. Vou assumir que o CDI já está configurado em seu projeto, caso contrário a configuração não funcionará.
org.apache.deltaspike.core deltaspike-core-api 1.4.1 compile org.apache.deltaspike.core deltaspike-core-impl 1.4.1 runtime org.apache.deltaspike.cdictrl deltaspike-cdictrl-api 1.4.1 compile
Chegou a hora da famosa classe Main. Se você leu o artigo anterior sobre CDI EM JAVASE a classe main deve estar da seguinte forma:
public class Main {
@Inject ClasseParaInjecao classeInjetada; public void main(@Observes ContainerInitialized event, @Parameters List params) { classeInjetada.testarInjecao(); } }
Porém, com a classe Main desta maneira, seria necessário iniciar o Container do CDI e do DeltaSpike. Então vamos deixá-la mais simples.
public class Main {
public static void main(String[] args) { CdiContainer cdiContainer = CdiContainerLoader.getCdiContainer(); cdiContainer.boot(); ClasseParaInjecao classeInjetada = BeanProvider.getContextualReference(ClasseParaInjecao.class, false); classeInjetada.testarInjecao(); cdiContainer.shutdown(); } }
Prontinho. Desse modo voltamos a ter a classe Main tradicional, a única diferença é que ela agora carrega programaticamente o Container do DeltaSpike que já inicia o CDI.

As informações deste post foram tiradas da página oficial do projeto, para mais detalhes você pode consultá-la.

Página oficial do DeltaSpike:
http://deltaspike.apache.org/index.html


sábado, 18 de julho de 2015

Configurando aplicação JavaSE com CDI.

Olá mais uma vez !

É a primeira vez que irei postar algum conteúdo sobre a maravilha que é o CDI. Muitas vezes por não conferirmos a documentação da especificação alguns detalhes passam desapercebidos. Pois é, vocês sabiam que o CDI também pode ser configurado em aplicações JavaSE ? Eu sinceramente não sabia. Enfim, leia até o fim e aprenda como configurá-lo em aplicações Standalone que utilizam Maven para gerir as dependências.


Por preferência pessoal utilizarei o NetBeans, mas nada impede que sejam utilizadas as IDE's de sua preferência.

Mostrarei apenas os pontos importantes das configurações, caso queira ver informações mais completas você pode conferir a própria documentação do CDI. Também deixarei abaixo alguns links que me ajudaram nessa jornada (sim, realmente quebrei a cabeça algumas vezes, e tudo por não olhar a documentação direito). Bem, chega de conversa e mostre o código !

Primeiramente vamos ao famoso pom.xml:
 
        
            org.jboss
            jandex
            1.2.4.Final
        
        
        
        
            org.jboss.weld.se
            weld-se
            2.2.14.Final
        
Agora temos que criar um arquivo chamado beans.xml. Para aplicações SE, será necessário você colocá-lo dentro da pasta META-INF. No meu projeto o diretório ficou da seguinte forma:
D:\NetBeansProjects\JavaSECDI\src\main\resources\META-INF\beans.xml. Criei a pasta resources e META-INF por fora da IDE.



Vamos agora a classe Main. Esta ficou realmente com uma cara estranha, mas analisando um pouco e lendo a documentação, tudo faz sentido:
public class Main {

    public void main(@Observes ContainerInitialized event, @Parameters List params) {

    }

}
Na verdade, esta não será mais a classe principal da sua aplicação. Agora você deve configurar o seu projeto para executar a classe seguinte: org.jboss.weld.environment.se.StartMain No NetBeans encontrei um pouco de dificuldade, pois diferente do Eclipse, quando ele não encontra uma classe java Principal, não é sugerido ao usuário escolher qualquer outra classe da aplicação para iniciar o projeto, o que acontece é que simplesmente ele retorna um erro, dizendo que não há classe principal no projeto. Para configurar isso, vá até seu projeto, e na Janela Projetos, clique com o botão direito sobre ele e vá em Propriedadas > Executar > Classe Principal e cole org.jboss.weld.environment.se.StartMain. Se clicar em procurar ele não irá te informar nada, apenas cole e clique em OK.

Vamos criar uma classe para testar injeção de dependência:
public class ClasseParaInjecao {

    public void testarInjecao() {
        System.out.println("Injeção funcionado !!!");
    }

}
Código para teste na classe main:
public class Main {
    
    @Inject
    ClasseParaInjecao classeInjetada;

    public void main(@Observes ContainerInitialized event, @Parameters List params) {
        classeInjetada.testarInjecao();
    }
}
Agora é só iniciar aplicação. Se estiver tudo correto será apresentada a mensagem "Injeção funcionando !!!" no console.

Vamos explicar algumas coisas:
beans.xml

É usado para configurar alguns recursos do CDI, como interceptadores, decoradores etc. A tag de configuração bean-discovery-mode="all", determina a maneira como as classes serão encontradas para satisfazer as dependências.

Classe Main:
A anotação @Observes a grosso modo, ficará de olho no evento ContainerInitialized que será disparado assim que a classe org.jboss.weld.environment.se.StartMain for chamada para iniciar a aplicação. 
Já a anotação @Parameters é usada para receber os tradicionais parâmetros por linha do comando do Java, é equivalente ao String [] args.

Abaixo alguns links que me ajudaram muito na configuração e serviram de fonte para este post.

Documentação Weld.
http://weld.cdi-spec.org/documentation/

Como iniciar o CDI em diversas aplicações Java.
http://antoniogoncalves.org/2011/01/12/bootstrapping-cdi-in-several-environments/

Motivos para usar o CDI.
http://blog.caelum.com.br/use-cdi-no-seu-proximo-projeto-java/

Dúvida sobre bean-discovery-mode no StackOverFlow.
http://stackoverflow.com/questions/18310388/meaning-of-bean-discovery-mode-annotated-in-cdi-1-1

Capítulo da documentação sobre o CDI em JavaSE:
https://docs.jboss.org/weld/reference/latest/en-US/html/environments.html#_bootstrapping_cdi_se

Dúvidas nos comentários. Responderei sempre que possível.
Nos próximos posts pretendo trazer mais sobre CDI com JavaSE, o passo inicial já foi dado !

Até a próxima !!!


sexta-feira, 17 de julho de 2015

Diferença entre variáveis de referência e tipos primitivos

O Post de hoje é sobre um assunto básico para qualquer programador que esteja iniciando com
Java e ainda não se aprofundou na estrutura da linguagem. Um exemplo simples para entender o que ocorre internamente quando manipulamos tipos primitivos e classes.

    Em Java, os ponteiros são implícitos, ou seja, a linguagem não cria objetos e faz cópias a cada ação. Quando você passa o valor de um Objeto para o outro utilizando o operador de atribuição (sinal de igual), é criada uma referência para aquele novo objeto, e não uma cópia.Em outras palavras, os dois apontam para o mesmo endereço de memória. Exemplo :
    Classe c1 = new Classe();
    Classe c2 = new Classe();
    c1.setAtributo("atributo");

    c2 = c1; // Caso você altere c1, o valor de c2 também será alterado.
Caso seja necessário fazer cópias de objetos com os mesmo valores, é possível utilizar o seguinte:
Classe c1 = new Classe ();
Classe c2 = new Classe ();
c1.setAtributo("atributo");

c2 = c1.clone(); // c1 e c2 não irão compartilhar o mesmo endereço de memória
Apenas as variáveis primitivas que fazem cópias de seus valores. Exemplo:
int a = 5;
int b = a;
b++;
System.out.Println("Valor de a: " + a); //Aqui o 'a' continua com o mesmo valor.
Espero ter ajudado quem estava com essa dúvida. Obrigado e até a próxima !