JAX-WS webservice and #rolesAllowed - web-services

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.

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 :-)

The original question is old but I'm still leaving a comment just in case someone like me stumbles across it. Starting with EJB 3.1, EJBs may be packaged in a WAR module but when it comes to securing them, EJB deployment descriptors need to be used. What is not clear in the spec is that EJBs may not be declared as Servlets in web.xml or else the app will fail to start.
Here's an excellent article about packaging EJBs in WAR modules and the differences with packaging in EJB JAR modules:
http://pic.dhe.ibm.com/infocenter/wasinfo/v8r0/index.jsp?topic=%2Fcom.ibm.websphere.nd.multiplatform.doc%2Finfo%2Fae%2Fae%2Fcejb_ejbinwar.html

Related

Need IBM Websphere jax ws webservices.xml and web.xml file

I don't have the sample webservices.xml and web.xml file. Can some one help by providing a complete example? I'm using Web Sphere JAX-WS implementation. WAS 7.x version. JDK 1.6.
I tried setting "UseWSFEP61ScanPolicy: true" in MANIFEST.MF file, for automated annotation scanning (instead of webservices.xml and web.xml file usage), but it is working first time, and after deploying a dynamic patch it doesn' works. The services listed under "services" category of IBM Console is having question mark instead of green arrow. Also some times the services even not listed in "services" category.
I'm using web module version 2.3, so i've to enable automated scanning. I'm not using EJB for web service.
I've decided to use webservices.xml and web.xml due to not much help in annotation scanning. I hope for webservices.xml and web.xml not need to install and reinstall the application EAR in WebSphere. In the case of annotation scanning reinstall is needed.
PLEASE IBM WEB SITE DOESN'T HELP MUCH!!!
Here's a web.xml I've used. Since it's "empty", the default rules for mapping annotated webservice classes to URL's apply, approximately, URL = name of class + "Service".
webservices.xml is not needed.
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.5" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_5.xsd">
<display-name>wsfp_hello_svc</display-name>
</web-app>
Check SystemOut.log to find the URL of your service, look for something like this:
WSWS7037I: The /HelloService URL pattern was configured for the example.HelloDelegate servlet
If you don't like the default mappings, then you can map your webservice class to a different URL in web.xml just like you would do with a servlet.

Implementing ssl on glassfish 4.0 on localhost

I am using a glassfish server and implementing Rest webservices which can be consumed from web or mobile clients.
I now want to secure these webservices using ssl certificates and create a session between client and server. I have not yet purchased any domain name or server space and trying to build it on my local machine.
How do i configure a free ssl certificate for glassfish on my localhost.
Thanks,
Pavan
Hotcoder24,
As far as I understand the problem from your question and comment, you want to communicate with your service via HTTPS. This is a snap when you use an application server. In fact, this is done with configuration in your web.xml file.
Let's start with a simple web application created using maven archetype jersey-quickstart-webapp, described in Jersey tutorial.
mvn archetype:generate -DarchetypeArtifactId=jersey-quickstart-webapp -DarchetypeGroupId=org.glassfish.jersey.archetypes -DinteractiveMode=false -DgroupId=com.example -DartifactId=simple-service-webapp -Dpackage=com.example -DarchetypeVersion=2.14
This creates a web application containing a single resource, which can be deployed to a Glassfish server (a war-file is produced).
#Path("myresource")
public class MyResource {
/**
* Method handling HTTP GET requests. The returned object will be sent
* to the client as "text/plain" media type.
*
* #return String that will be returned as a text/plain response.
*/
#GET
#Produces(MediaType.TEXT_PLAIN)
public String getIt() {
return "Got it!";
}
}
First of all, you should create a user and add it to a group using Glassfish console (http://localhost:4848/). The simplest way to start is to use a file realm. The process is described here. Let's create a user called “user” and group called “users”.
If you deploy the application, the resource will be available in your browser if you enter a URL http://localhost:8080/simple-service-webapp/webapi/myresource. Before we have done any configuration in the project's xml files, the resource is freely available.
Now let's add some elements to your web.xml file.
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<!--Some elements go here-->
<security-constraint>
<web-resource-collection>
<web-resource-name>GetIt</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>users</role-name>
</auth-constraint>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>file</realm-name>
</login-config>
<security-role>
<role-name>users</role-name>
</security-role>
We added tree elements:
security-constraint which describes a URL pattern to protect, lists roles allowed to access it and most important to your question is the user-data-constraint element, which in our case switches on the HTTPS.
login-config element instructs the server to use the simplest authenticated mechanism which means, that when you try to access the resource using a browser, a dialog prompting for login and password is displayed to you; also you realm's name is enshrined here;
the last element defines roles you use.
Now it is necessary that groups are linked to roles. This is done using a container-specific glassfish-web.xml.
<glassfish-web-app error-url="">
<security-role-mapping>
<role-name>users</role-name>
<group-name>users</group-name>
</security-role-mapping>
<!--some elements go here-->
Now if you direct your browser to a http:// URL, you'll be switched to https://, which is not the case without the user-data-constraint element with <transport-guarantee>CONFIDENTIAL</transport-guarantee>.

Add HTTP authentication to embedded Jetty

I'm embedding Jetty 9.1 from within a Java application. I'm configuring everything programmatically; I am not using web.xml or Spring or anything else. I have Wicket mapped to /* and a RestEASY JAX-RS API mapped to /rest/*. That's all working fine.
I wanted to add HTTP authentication, so I added the following (based upon as much Jetty documentation as I find):
HashLoginService loginService = new HashLoginService();
loginService.setName("My Realm");
loginService.setConfig("src/main/resources/realm.properties");
server.addBean(loginService);
I added a user with a role of admin to realm.properties. Then I tried to configure my REST service, putting the following annotation on my main JAX-RS resource:
#RolesAllowed({ "admin" })
Then I added the following annotation to my main Wicket page:
#AuthorizeInstantiation("admin")
None of these changes made any difference; I can still use my browser to navigate to my REST API and Wicket pages.
I'm guessing I need to turn on DIGEST authentication in Jetty. But how do I do that programmatically, without a web.xml file? What else do I need to do?
Another answer to a similar question, providing a link to a sample webapp, helped me immensely and got me up and running.
In Jetty v7, you chain the handlers together:
server.setHandler(securityHandler);
securityHandler.setHandler(resourceHandler);
Works on my machine! (tm)

How can I get access to Servet Context in apache cxf?

How can I get access to Servlet context in my apache cxf web service application?
I am using apache cxf 2.2.7 and Json as the data transfer format.
Have a look at ServletContextAware interface: Spring beans registered in Web context and implementing this interface get the access to ServletContext. More aggressive approach is to request bean with name servletContext from Web Context or use ServletContextParameterFactoryBean.
Otherwise (if you don't use Spring+CXF, which is unusual) you need to implement javax.servlet.ServletContextListener and register this implementation in <web-app> → <listener> → <listener-class>. The implementation should save ServletContext to be later used by your WebService.

Glassfish, EJB3, SOAP web service and basic authentication

I'm setting up a glassfish server with a single EJB3 as a mocked up backend for a POC. Everything was working fine until I went to add some basic authentication. Just plan text userid and password, nothing sophisticated for this job. I added the following annotations to the EJB:
#WebService(name = "Banking", serviceName = "Banking", targetNamespace = BANKING_NAMESPACE)
#DeclareRoles("user")
#Stateless
public class Banking {
...
#RolesAllowed("user")
#SOAPBinding(parameterStyle = ParameterStyle.BARE)
#WebMethod(action = BANKING_NAMESPACE + "/logon", operationName = "logon")
#WebResult(targetNamespace = XmlStrings.BANKING_MODEL_NAMESPACE)
public LogonResponse logon(#WebParam(targetNamespace = XmlStrings.BANKING_MODEL_NAMESPACE) Logon request) throws WebServiceException {
...
}
}
According to what I've read of EJB3 spec, this is pretty common for doing a SOAP web service.
However when I send this xml:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:mod="http://www.dhcbank.com/banking/model">
<soapenv:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:UsernameToken wsu:Id="UsernameToken-79" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsse:Username>fred</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">fred</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</soapenv:Header>
<soapenv:Body>
<mod:logon/>
</soapenv:Body>
</soapenv:Envelope>
I get the following error back as a SOAP fault:
java.lang.Exception: Client not authorized for invocation of public com.dhcbank.www.banking.schema.LogonResponse com.dhcbank.www.banking.Banking.logon(com.dhcbank.www.banking.schema.Logon) throws javax.xml.ws.WebServiceException
And in the glassfish log:
[#|2010-10-10T12:49:27.497+1100|INFO|glassfish3.0.1|javax.enterprise.system.core.security|_ThreadID=41;_ThreadName=http-thread-pool-8080-(2);|JACC Policy Provider: Failed Permission Check, context(BankingEAR/Banking_war_internal)- permission((javax.security.jacc.EJBMethodPermission Banking logon,ServiceEndpoint,com.dhcbank.www.banking.schema.Logon))|#]
In the glassfish admin screens I added a user called fred with a fred password and assigned it to a groups called user. But that didn't work.
I did some more reading which suggested that I create a sun-ejb-jar.xml file and add it to the ear file. So I created it with this content:
<sun-ejb-jar>
<enterprise-beans>
<ejb>
<ejb-name>Banking</ejb-name>
<webservice-endpoint>
<port-component-name>Banking</port-component-name>
<login-config>
<auth-method>BASIC</auth-method>
<realm>file</realm>
</login-config>
</webservice-endpoint>
</ejb>
</enterprise-beans>
</sun-ejb-jar>
This is as near as I can tell, correct. However I could not find anything that told me what the values of the port-component-name element should be. So I don't know if I've got it right.
Security does still not appear to be working and I cannot figure out why. Does anyone have any experience with this and can point me at what I've got wrong or not done?
I'm assuming your declared role "user" is the same role name in your file realm? if not provide this mapping in your descriptor:
<sun-ejb-jar>
<security-role-mapping>
<role-name>user</role-name>
<group-name>filerealm-group-name</group-name>
</security-role-mapping>
...
I don't think that you're currently creating the appropriate HTTP header for Basic Authentication. I'm not sure how you create the SOAP request but if you're using a JAX-WS client, the JAX-WS FAQ documents the following:
Q. How do I do basic authentication in JAX-WS?
You can do the following:
HelloService service = new HelloService();
Hello proxy = (service.getHelloPort());
((BindingProvider)proxy).getRequestContext().put(BindingProvider.USERNAME_PROPERTY, "userfoo");
((BindingProvider)proxy).getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, "passbar");
USERNAME_PROPERTY, PASSWORD_PROPERTY
are used primarily for service
requests. I think when you instantiate
Service, it fetches WSDL and the
server is returning 401. You could try
any one of the following solutions.
Use java.net.Authenticator class in your client application.
Provide a local access to the WSDL using catalog. There is a catalog
sample in the jax-ws distribution.
Configure web.xml to allow GET requests without authentication
And unless I'm wrong, the usernametoken would fit if the webservice expects the authentication in the SOAP header, which is not the case according to your description.
In other words, for me, you're currently not sending the credentials for the BASIC auth.
See also
Example: Basic Authentication with JAX-WS
SSL and HTTP BASIC authentication with Glassfish and JAX-WS (more complex scenario)