users@glassfish.java.net

Re: Simple secure Web service

From: <glassfish_at_javadesktop.org>
Date: Mon, 07 Jul 2008 11:49:54 PDT

Hi,

You may also want to check "Metro" documentation for advanced security, but a quite compatible solution for Glassfish v1 & v2 to restrict access to webservice methods with username + password is using the "sun-ejb-jar.xml" deployment descriptor to define "webservice-endpoint" authentication type/realm, and security role mappings. When it is required SSL, you only have to change "transport-guarantee" tag value to "CONFIDENTIAL" (and it is also useful to change WSDL published location in "webservice-description" to an "https" URL address).

On the implementation code side, you should also define all the roles with the "javax.annotation.security.DeclareRoles" annotation.

For example, if we had implemented the webservice with this EJB:

[code]
package ws;

import javax.annotation.Resource;
import javax.annotation.security.DeclareRoles;
import javax.annotation.security.RolesAllowed;

import javax.ejb.SessionContext;
import javax.ejb.Stateless;

import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;


@WebService()
@Stateless()
@DeclareRoles({"UserRole"})
public class WsEJB
{
    @Resource
    private SessionContext sessionContext;
        

    @WebMethod(operationName = "getPrincipalName")
    @RolesAllowed({"UserRole"})
    public String getPrincipalName() {
        return sessionContext.getCallerPrincipal().getName();
    }
    
}
[code]


Then, you can use the following "sun-ejb-jar.xml" to enable basic username+password authentication on "file" realm (without SSL):

[code]
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sun-ejb-jar PUBLIC "-//Sun Microsystems, Inc.//DTD Application Server 9.0 EJB 3.0//EN" "http://www.sun.com/software/appserver/dtds/sun-ejb-jar_3_0-0.dtd">
<sun-ejb-jar>

  <security-role-mapping>
    <role-name>UserRole</role-name>
    <group-name>users</group-name>
  </security-role-mapping>
  
  <enterprise-beans>
    <ejb>
      <ejb-name>WsEJB</ejb-name>
      <jndi-name>ws.WsEJB</jndi-name>
      <ior-security-config>
        <transport-config>
          <integrity>NONE</integrity>
          <confidentiality>NONE</confidentiality>
          <establish-trust-in-target>NONE</establish-trust-in-target>
          <establish-trust-in-client>NONE</establish-trust-in-client>
        </transport-config>
        <as-context>
          <auth-method>username_password</auth-method>
          <realm>file</realm>
          <required>true</required>
        </as-context>
        <sas-context>
          <caller-propagation>NONE</caller-propagation>
        </sas-context>
      </ior-security-config>
      <webservice-endpoint>
        <port-component-name>WsEJB</port-component-name>
        <login-config>
          <auth-method>BASIC</auth-method>
          <realm>file</realm>
        </login-config>
        <transport-guarantee>NONE</transport-guarantee>
      </webservice-endpoint>
    </ejb>
    <webservice-description>
      <webservice-description-name>WsEJBService</webservice-description-name>
      <wsdl-publish-location>http://localhost:8080/WsEJBService/WsEJB?WSDL</wsdl-publish-location>
    </webservice-description>
  </enterprise-beans>
</sun-ejb-jar>

[code]

Note the "UserRole" mapping to a suposed "users" group in "file" realm.


Finally, to test the previous webservice, you can use the following code:

[code]
package wstest;

import java.util.Map;
import javax.xml.ws.BindingProvider;

// jax-ws stubs:
import ws.WsEJB;
import ws.WsEJBService;


public class Main
{
    public static void main(String[] args)
    {
        WsEJBService service = new WsEJBService();
        WsEJB port = service.getWsEJBPort();

        Map<String,Object> context = ((BindingProvider)port).getRequestContext();
        context.put(BindingProvider.USERNAME_PROPERTY, "username");
        context.put(BindingProvider.PASSWORD_PROPERTY, "secretpassword");
        context.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, "http://localhost:8080/WsEJBService/WsEJB");
        
        System.out.println("Hello " + port.getPrincipalName());
    }

}

[code]

I hope it works for your webservice.
[Message sent by forum member 'jmarine' (jmarine)]

http://forums.java.net/jive/thread.jspa?messageID=284827