sábado, 11 de julho de 2009

WebService com segurança

Atenção!!! Essa solução não funciona.
Veja o porque nos comentários.
Em breve irei postar um comentário ou um novo post com a solução correta.


Estou começando a estudar WebServices e uma de minhas primeiras necessidades é implementar um WebService que seja acessado apenas por 'pessoas' autorizadas.

Dessa forma, nesse post irei explicar como se implementa e acessa um WebService utilizando segurança na camada HTTP com o JBoss 5 e Axis.

1) Crie um novo EJB Project: File, New, Project, EJB, EJB Project.

2) O segundo passo é codificar uma Interface que extende de java.rmi.Remote:
package br.com.hello;

import java.rmi.Remote;

import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.Style;

@WebService
@SOAPBinding(style = Style.DOCUMENT)
public interface HelloWS extends Remote {

 public String hello();
  
}
3) Codificar uma classe que implementa a Interface:
package br.com.hello;

import javax.annotation.Resource;
import javax.annotation.security.RolesAllowed;
import javax.ejb.Remote;
import javax.ejb.SessionContext;
import javax.ejb.Stateless;
import javax.jws.WebService;

import org.jboss.ejb3.annotation.SecurityDomain;
import org.jboss.wsf.spi.annotation.WebContext;

@Stateless
@WebService(endpointInterface = "br.com.hello.HelloWS")
@Remote(HelloWS.class)
@SecurityDomain("JBossWS")
@RolesAllowed("admin")
@WebContext(contextRoot="/hello", urlPattern="/*", authMethod="BASIC", transportGuarantee="NONE", secureWSDLAccess=false)
public class HelloBean {

 @Resource
 SessionContext ctx;

 public String hello() {
  String user = String.valueOf(ctx.getCallerPrincipal());
  return "Hello " + user + "!";
 }
}
Observações:

@Stateless: Define o EJB sendo sem estado, ou seja, será um EJB que não irá manter o seu estado para cada invocação de um método;

@WebService(endpointInterface = "com.roassunca.hellows.HelloWS"): Especifica a interface que define os métodos do WebService;

@Remote(HelloWS.class);

@SecurityDomain("JBossWS"):Define qual Realm o EJB deve utilizar. Nesse caso estou utilizando um já definido na configuração Default do JBoss (veja o arquivo /server/default/conf/login-config.xml);

@RolesAllowed("admin"):Define quais roles poderão acessar o WebService;

@WebContext(contextRoot="/hello", urlPattern="/*", authMethod="BASIC", transportGuarantee="NONE", secureWSDLAccess=false):Define a segurança do EJB na camada Web, utilizando como autenticação o método BASIC.

@Resource
SessionContext ctx;

Serve para injetar o SessionContext, para que possa ser utilizado para buscar o nome do usuário.

4) Compile e crie um .jar

5) Copie o .jar para jboss-dir/server/default/deploy

6) Inicie o JBoss

7) Copie o ultimo arquivo .wsdl gerado em jboss-dir/server/default/data/wsdl/hello.jar para a pasta do seu projeto no Eclipse

8) Clique com o mouse botão direito sobre o arquivo .wsdl no Eclipse e selecione New, Other, WebServices, Web Service Client, Next

9) Client type: Java Proxy
No lado direito da tela, deixe apenas a opção Develop Client.
Certifique-se de que nas configurações estejam selecionados Server: JBoss, Web service runtime: Apache Axis, Client project: o projeto onde será criado os fontes
Clique em Next

10) Abra o fonte gerado br.com.hello.HelloWSBindingStub

11) No metodo protected org.apache.axis.client.Call createCall(), após a linha onde é chamado super._createCall(); defina o nome de usuário e senha:

            _call.setUsername("admin");
            _call.setPassword("admin");
12) Não se esqueca de definir no arquivo jboss-dir/server/default/conf/props/jbossws-roles.properties o role do usuário admin:

admin=admin

e no arquivo jboss-dir/server/default/conf/props/jbossws-users.properties a senha do usuário admin:

admin=admin

13) Implemente um método main em HelloWSProxy:
 public static void main(String[] args) throws Exception {
  System.out.println( new HelloWSProxy().hello() );
 }
14) Caso o seu projeto (a implementação do WebService) precise incluir alguns arquivos .jar (como bibliotecas), para fazer o deploy, crie um arquivo .ear, contendo o .jar que você acabou de criar e uma pasta lib com todos os outros .jars necessários.

domingo, 1 de março de 2009

Hibernate - Relacionamento one-to-one (com annotation)

Embedded

O relacionamento "embedded one-to-one" trata-se de um relacionamento onde os atributos das entidades relacionadas serão persistidas na mesma tabela.

No exemplo temos uma classe Pessoa que tem um relacionamento um-para-um com a classe Endereco.

O relacionamento é definido da seguinte forma:
package myexample;

import javax.persistence.*;

@Entity
public class Pessoa {

 @Id
 private long id;
 private String nome;
 @Embedded
 private Endereco endereco;

        //get's e set's
}
package myexample;

import javax.persistence.Embeddable;

@Embeddable
public class Endereco {

 private String logradouro;

 //get's e set's
}

Com esses annotations, o hibernate irá criar (pesquise por hbm2ddl do Hibernate Tools no Google) uma tabela Pessoa com os seguintes atributos:

  • id bigint not null
  • logradouro varchar(255)
  • nome varchar(255)
  • Relacionamento convencional one-to-one

    O relacionamento convencional um-para-um trata-se de um relacionamento onde os atributos das entidades relacionadas serão persistidas em tabelas distintas.

    O relacionamento das classes Pessoa e Endereco em um relacionamento convencional um-para-um é declarado da seguinte forma:
    package myexample;
    
    import javax.persistence.*;
    
    @Entity
    public class Pessoa {
    
     @Id
     private long id;
     private String nome;
     @OneToOne(cascade = CascadeType.ALL)
     private Endereco endereco;
    
     //get's e set's
    }
    
    package myexample;
    
    import javax.persistence.*;
    
    @Entity
    public class Endereco {
    
     @Id
     private long id;
     private String logradouro;
     @OneToOne(mappedBy = "endereco")
     private Pessoa pessoa; 
    }
    
    O annotaion @OneToOne(mappedBy = "endereco") serve para indicar um relacionamento bidirecional, informando que Endereco é o final do relacionamento entre Pessoa-Endereco e que é mapeado em Pessoa pelo atributo endereco.
    Ou seja, a tabela Pessoa terá a chave estrangeira para Endereco.

    Com esses annotations, o hibernate irá criar duas tabelas: Pessoa e Endereco com os seguintes atributos:

    Pessoa
  • id bigint not null
  • nome varchar(255)
  • endereco_id bigint


  • Endereco
  • id bigint not null
  • logradouro varchar(255)


  • Devo salientar que não é obrigatório declarar esse relacionamento bidirecional. Ele pode ser unidirecional. Para isso basta não declarar o atributo Pessoa em Endereco:
    package myexample;
    
    import javax.persistence.*;
    
    @Entity
    public class Endereco {
    
     @Id
     private long id;
     private String logradouro;
    }
    

    Hibernate - Tutorial

    Vou começar uma série de posts com um tutorial sobre Hibernate.

    Nesse tutorial, vou focar primeiramente os relacionamentos entre entidades e o mapeamento será feito utilizando annotations.
    Depois de mostrar como se faz todos os tipos de relacionamentos com annotations, irei mostrar como fazer os mesmos relacionamentos com XML.

    Após mostrar o relacionamentos entre entidades, vou mostrar como fazer o mapeamento de hierarquia entre entidades, novamento primeiramente com annotations e depois com XML.

    Boa leitura.

    Relacionamentos com annotations

  • One-to-one
  • sábado, 21 de fevereiro de 2009

    Grails: problema com a tag g:actionSubmit

    Para quem tiver problemas com a tag g:actionSubmit, que deverá estar dentro de uma tag g:form, além de declarar o "action" na tag "g:form", declare tambem em actionSubmit, como no exemplo abaixo:
    
       ...
       
       ...
    
    

    AcegiSecurity Plugin para o Grails com BD Postgresql

    O problema:

    Hoje tive um problema ao utilizar o plugin AcegiSecurity no Grails com o banco de dados Postgresql.
    O AcegiSecurity é o framework de segurança do Spring.

    Seguindo os passos descritos em Basic Tutorial using Requestmap tudo ocorreu bem enquanto eu estava utilizando o banco de dados HSQLDB, mas quando coloquei a aplicação em produção no PostgreSql, meus problemas começaram...

    Ao iniciar a aplicação eu obtinha um erro. Analisando o stacktrace, percebi que o erro era gerado pela linha n. 9 do meu BootStrap. Nessa linha, eu estava criando e salvando no banco de dados um usuário default administrador.

    A primeira coisa que fiz foi abrir o pgAdmin (PostgreSQL admin) para ver a tabela User e para minha surpresa ela não havia sido criada.

    A solução:

    Para ver porque a tabela não estava sendo criada fiz as seguintes alterações:
    • no arquivo conf/Config.groovy:

    alterei a linha: rootLogger="error,stdout" para: rootLogger="error,stacktraceLog" (onde stacktraceLog é meu appender para um arquivo de log)

    configurei codehaus.groovy.grails.orm.hibernate para "debug"

    configurei hibernate="on"
    • no BootStrap comentei a linha que tentava criar um novo usuário para não poluir muito o arquivo de log.

    Rodei a aplicação novamente e procurei por "create table user" no arquivo de log. O erro estava logo abaixo:

    [1953] hbm2ddl.SchemaExport Unsuccessful: create table user.... [1953] hbm2ddl.SchemaExport ERROR: syntax error at or near "user"

    Isso ocorreu pois "user" é uma palavra reservada no PostgreSQL.

    Para resolver o problema no passo "Create the User, Role, and Requestmap domain classes" em Basic Tutorial using Requestmap deixe que ele gere os nomes padrões das classes de domínio, que serão Person, Authority e Requestmap. Para isso use apenas o comando:

    grails create-auth-domains