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.

Um comentário:

  1. Caiu a ficha que essa solução não funciona por um simples motivo: por ser um EJB Stateless o container EJB poderá instanciar apenas um EJB para toda chamada ao WebService.
    Dessa forma, ao invocar ctx.getCallerPrincipal() você sempre irá obter o mesmo usuário.

    ResponderExcluir