JAX-WS webservice and @rolesAllowed

17,285

Maybe this is a pretty dumb question, but are your webservices EJBs? As noted in Security Annotations and Authorization in GlassFish and the Java EE 5 SDK

The annotations @PermitAll, @DenyAll and @RolesAllowed are defined for specifying permissions of EJB business method

I use those annotations with bottom-up WS from stateless EJBs and they work like a charm in JBoss.


EDIT 1 @TPete I'll add some code to show you more or less what I'm doing.

@Stateless
@WebService()
@WebContext(contextRoot = WSContextRoot.CTX_ROOT, 
    authMethod = "BASIC")
@EndpointConfig(configName = "Standard WSSecurity Endpoint")
@SecurityDomain(value = "myDeclaredDomain")
@RolesAllowed({ "AUTHORISED" })
@SOAPBinding(style = SOAPBinding.Style.DOCUMENT)
public class MyWS implements MyInterface {
    @Override
    public void doSomething(){
        //impl
    }
}

And as for the interface

@Remote
@WebService
public interface MyInterface {

    @WebMethod(operationName="doSomething")
    public void doSomething(); 
}

WebContext, EndpointConfig and SecurityDomain are JBoss annotation, but I suppose there is something similar for GlassFish, or an equivalent way of doing it. The security domain is included in a deployment descriptor for jboss, and defined in the login-config.xml from the configuration files of JBoss.


EDIT 2 @TPete

I suppose you need to add some EJB deployment descriptors from Glassfish, a sun-ejb-jar.xml file package inside your EAR. Again, from the same article as posted in the answer, there is a Using Deployment Descriptors chapter that states

For EJB web service endpoints with @RolesAllowed, you need to specify the type of authentication to use by specifying the and elements in sun-ejb-jar.xml. For username-password authentication, set the element to BASIC, as shown in the following example. This step is required only for EJB web service endpoints, and is not required for EJBs.

Since you are defining an EJB web service endpoint, I think you should put this descriptor in you EAR. Have a quick look at that article, it describes quite well the process you are following :-)

Share:
17,285
TPete
Author by

TPete

Updated on June 04, 2022

Comments

  • TPete
    TPete almost 2 years

    Is it possible to use @RolesAllowed annotation on a JAX-WS webservice and if so how?

    I have a webservice on glassfish 3.1.1 using Basic Authentication but restrictions expressed using @RolesAllowed are ignored. The role information should be available, as I can access it like this:

    @Resource
    WebServiceContext wsContext;
    
    if (wsContext.isUserInRole("READ"))
    log.info("Role: READ");
    

    I get the expected role but still all methods are accessible, even if @RolesAllowed is set to different role. @DenyAll is not working as well.

    If these annotations are not supported, is it possible to use deployment descriptors to manage access to webservice methods based on user roles?

    Edit: This part of the JAVA EE 6 tutorial describes the usage of @RolesAllowed annotation. It reads

    For Java EE components, you define security roles using the @DeclareRoles and @RolesAllowed metadata annotations.

    Web services are not listed as Java EE components in the first part of the tutorial, so it looks like the security annotations are not supported.

    Edit2 Following Izan's post, I gave this another try. Here is what I did:

    @Webservice
    @DeclareRoles(value = {"READ", "UPDATE", "DELETE"})
    public class ServiceImpl implements Service {
      @Override
      @WebMethod(operationName = "helloWorld")
      @RolesAllowed({"NONE"})
      public String helloWorld() throws Exception {
         return "Hello World!";
      }
    }
    

    Using this kind of setup, everybody can access the method, no matter what roles are set. Users get authenticated (can see that in audit.log) but no authorization takes place. As stated above, I can access the role from WebServiceContext (I actually do manual authorization using this info).

    Adding @Stateless annotation, let's me use the security annotations. So @permitAll works as expected. But using roles still does not work, as user don't get authenticated now. They show up as ANONYMOUS in audit log and access is denied to them.

    My web.xml looks like this:

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">
     <display-name>OneMore</display-name>
    
     <security-constraint>  
        <display-name>WebServiceSecurity</display-name>  
    
        <web-resource-collection>  
          <web-resource-name>Authorized users only</web-resource-name>  
          <url-pattern>/service</url-pattern>  
          <http-method>POST</http-method>
        </web-resource-collection>  
    
        <auth-constraint>       
           <role-name>READ</role-name>
           <role-name>UPDATE</role-name>
           <role-name>DELETE</role-name>
        </auth-constraint>  
    
     </security-constraint>  
    
     <login-config>
        <auth-method>BASIC</auth-method>
     </login-config>
    
     <security-role>
        <role-name>READ</role-name>
     </security-role>
    
     <security-role>
        <role-name>UPDATE</role-name>
     </security-role>
    
     <security-role>
        <role-name>DELETE</role-name>
     </security-role>
    </web-app>
    

    Glassfish-web.xml just maps role names to group names, like this:

    <security-role-mapping>
       <role-name>READ</role-name>
       <group-name>READ</group-name>
    </security-role-mapping>
    

    Edit 3 Thanks to Izan and countless tries later I finally got it working.

    As said before, the main point was switching from a plain web service to an EJB web service by adding @Stateless annotation. This allows for using the security annotations.

    This change required to change the deployment descriptors as well. While the original web service required a glassfish-web.xml for setting up the roles, a glassfish-ejb-jar.xml is required afterwards.

  • igracia
    igracia about 12 years
    Sorry, maybe could have posted this as an edit instead of an answer.
  • Flexo
    Flexo about 12 years
    I think posting it as a comment would be most appropriate, although until you've got 50 rep that's not possible
  • TPete
    TPete about 12 years
    @Izan I guess not, though this is my first Java EE project and I'm not that familiar with the terminology. Perhaps posting an example might clarify the issue. I only use the @Webservice annotation right now. I tried to combine it with @Stateless but I wasn`t able to access the web service using Https afterwards.
  • igracia
    igracia about 12 years
    @awoodland Thanks for the info! I thought so too, because it is not really an answer, but as you said I couldn't. I've expanded the answer, but I don't know if I should have done it in a comment also...
  • Flexo
    Flexo about 12 years
    Expanding into an answer is definitely the way to go. Looks like it solved it for the open too.
  • TPete
    TPete about 12 years
    @Izan Thanks for the effort! Adding @stateless indeed let's me use the security annotations. But now, users don't get authenticated. Users are now reported as ANONYMOUS, ignoring the user's credentials. Without @stateless, correct credentials are sent, but security annotations are not working. Furthermore, I can't connect using Https, if @stateless is present. Please see my updated question for more details.
  • igracia
    igracia about 12 years
    @TPete Could it be that the principal is not propagated? You might need to enable the SSO valve in Glassfish, or something in the policy so the role gets propagated to the EJBs. I'm no expert in Glassfish, so I can't help you there. Do you see any errors in the server logs? Can you set the logging level of security appenders to debug or trace and see where the roles of the authenticated principal are lost? What are you using to consume your webservices?
  • igracia
    igracia about 12 years
    @TPete Copuple of subtleties I don't understand the purpose of @RolesAllowed({"NONE"}). Maybe you wanted to use the @DenyAll annotation? I would put the @WebMethod annotation in the interface, not in the implementation
  • TPete
    TPete about 12 years
    @Izan Well, the "None" was to demonstrate, that no authorization is enforced in this setup. I do have @WebMethod annotation in both interface and implementation, but I guess you are right.
  • TPete
    TPete about 12 years
    @Izan I suppose when switching to an EJB by adding @Stateless the role-to-principal mapping in my glassfish-web.xml is no longer used because this is specific to the usage as a web service. I tried adding a glassfish-ejb-jar.xml with this mapping and while playing around with the settings it worked a single time! Unfortunately I wasn`t able to reproduce this setting. Will give it another try tomorrow.
  • TPete
    TPete about 12 years
    @Izan Didn't see your update when writing my last comment, was a long day :-) So we had the same idea, and finally it worked out! That article was helpful, but it is not up to date. Will post my solution in the question. Thanks again.