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