Implementing ssl on glassfish 4.0 on localhost - web-services

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>.

Related

Getting 403 Forbidden, trying to access secured web service

Has anyone successfully secured a web service using Active Directory credentials instead of an application specific username/password?
I have an application that talks to web services written with Axis2 1.5.1 and deployed on Tomcat 6.0.24, deployed on Linux, FWIW.
I have changed Tomcat from a JDBCRealm, authenticating against a database, to a JAASRealm, configured to access AD with Centrify (the client's preferred solution).
This works with web applications but for web services I get a 403 response.
I have tested using a simple Axis2 service (written with Axis2 1.5.1) and deployed against Tomcat 6.0.24 and 7.0.63. I've also tried with a web service written using Axis2 1.6.2. I get the same result in each case. I'm testing using a browser, BTW. When the service works I get xml; when it doesn't I get the error.
I'm wondering whether I need to change something in axis2.xml since even https://tomcat:8443/HelloWorld (my service is called HelloWorld) generates a 403.
Some configuration details...
I've changed the realm in server.xml to the following
<Realm className="org.apache.catalina.realm.JAASRealm"
appName="CENTRIFYDC"
roleClassName="com.centrify.dc.tomcat.RolesPrincipal"
userClassName="com.centrify.dc.tomcat.LoginPrincipal" />
<Valve className="com.centrify.dc.tomcat.ContextValve" />
In web.xml I have added
<security-constraint>
<display-name>Security Web Service</display-name>
<web-resource-collection>
<web-resource-name>Secured Area</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>USER</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>SPNEGO</auth-method>
<realm-name>CENTRIFYDC</realm-name>
</login-config>
<!-- Security roles referenced by this web application -->
<security-role>
<role-name>USER</role-name>
</security-role>
I've mapped the USER role to one of my AD groups
Any suggestions or guidance or setups that have worked for someone would be very useful, thanks.
The 403 error is indicating the permission problem after authentication. It is because after SSO, the server will check for group membership to see if the user got proper permission. The 403 error is coming from the configuration part of role mapping. SSO to the server is actually working fine.
We would suggest you to try the following(the following example is using 5.5 version tomcat but it will be the same for later version):
Configure tomcat for Centrify
a. Configure tomcat for Centrify by using configure.pl:
cd /usr/share/centrifydc/java
./configure.pl
Enter /opt/apache-tomcat-5.5.25 when prompted for the tomcat directory.
Enter /usr/jdk1.5.0_15 when prompted for the java directory.
Enter y when prompted if you want to configure Tomcat for SSL
Enter n when prompted if you want to configure Tomcat for SSL communication with ADFS server
Take default for everything else.
Configure webdav for Centrify and use kerberos(SPNEGO) for authentication
a. Set the logon realm to CENTRIFYDC:
cd /opt/apache-tomcat-5.5.25/webapps/
mkdir webdav/META-INF
create webdav/META-INF/context.xml as:
<Context path="/webdav">
<Realm className="org.apache.catalina.realm.JAASRealm"
appName="CENTRIFYDC"
roleClassNames="com.centrify.dc.tomcat.RolesPrincipal"
userClassNames="com.centrify.dc.tomcat.LoginPrincipal"/>
<Valve className="com.centrify.dc.tomcat.ContextValve"/> </Context>
b. Configure mapping of AD groups to roles for the jspwiki app.
cp /usr/share/centrifydc/java/templates/centrifydc.xml webdev/WEB-INF/centrifydc.xml
modify RoleMapping section in webdev/WEB-INF/centrifydc.xml as follow:
<RoleMapping separator=";">
<Role name="user" group="*" user="*"/>
<Role name="#ROLE2#" group="#GROUP2#"/>
<Role name="#ROLE3#" user="#USER3#"/>
</RoleMapping>
c. Configure web.xml to use kerberos(SPNEGO) for authentication:
Edit web.xml and add
<login-config>
<auth-method>SPNEGO</auth-method>
<realm-name>Default</realm-name>
</login-config>
<!--
OPTIONAL: Add CentrifyFilter to set the authenticated user's attributes
such as group membership in HTTP headers. You must also configure the
<SetHeaders> element in centrifydc.xml to set user attributes in HTTP
headers.
This filter is not needed if you do not want the authenticated
user's attributes set in HTTP headers.
-->
<filter>
<filter-name>CentrifyFilter</filter-name>
<filter-class>com.centrify.dc.wbase.DCFilter</filter-class>
</filter>
<!--
OPTIONAL: Apply (map) CentrifyFilter to the url patterns in the
<security-constraint> section of this application to set the
authenticated user's attributes in HTTP headers.
This <filter-mapping> is not needed if you do not want the
authenticated user's attributes set in HTTP headers.
-->
<filter-mapping>
<filter-name>CentrifyFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<security-constraint>
<web-resource-collection>
<web-resource-name>ProtectedResource</web-resource-name>
<url-pattern>/index.html</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>user</role-name>
</auth-constraint>
</security-constraint>
<security-role>
<description>
An test role
</description>
<role-name>user</role-name>
</security-role>
You could also refer to the Centrify Java Guide p.135 for the example for role mapping configured as follow:
Extensible Markup Language (XML) files, like the centrifydc.xml file, are structured documents that contain a set of supported elements enclosed in opening and closing angle (< >) brackets. The elements can be required or optional depending on the requirements of the application. The following is an example of how the key elements defined in the centrifydc.xml file:
<Centrifydc>
<enableAuthSchemes>Negotiate,NTLM,Basic</enableAuthSchemes>
<adclientSocket>/var/centrifydc/daemon</adclientSocket>
<RoleMapping>
<Role name=”role1” group=”arcade.com/Users/Sales”/>
</RoleMapping>
</Centrifydc>
Although the template centrifydc.xml file contains some default settings, these default settings should be modified in the copy of the centrifydc.xml file you place in an application’s WEB-INF directory. The following table describes the elements you can set in the centrifydc.xml file.
If you need any further assistance, please feel free to contact Centrify Technical Support directly.
There were a couple of problems. The first was an error was in the server.xml file. JAASRealms can accept several classes for role and user so the properties are roleClassNames and userClassNames as follows
<Realm className="org.apache.catalina.realm.JAASRealm"
appName="CENTRIFYDC"
roleClassNames="com.centrify.dc.tomcat.RolesPrincipal"
userClassNames="com.centrify.dc.tomcat.LoginPrincipal" />
The second issue is around using several applications which use different authorization. The centrifydc.xml file maps roles when the app is first authenticated. However, if org.apache.catalina.authenticator.SingleSignOn is enabled then the roles are set only for the application that performs the authentication. Thereafter, only the roles set in the authenticating application's centrifydc.xml file are set. Other applications will see that the user is already authenticated but does not have the necessary authorization and fail with a 403 error.
In different applications use the roles user, USER and manager then the logging-in application must set up all three roles when it authenticates.

How to identify cxf web service end point

I am trying to creating web service using wsdl first approach and CXF. I am able to generate java file from wsdl and deploy the war file to tomcat server. However, I don't see any soapaction in the generated file. How do I identify the end point url for this web service?
thanks,
Usually in CXF you use Spring configuration to configure endpoint, as described in JAX-WS Configuration. Usually address is relative, e.g.
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
<jaxws:endpoint id="classImpl"
implementor="org.apache.cxf.jaxws.service.Hello"
address="/helloService"/>
</beans>
Address is local to you web app context root.
Assuming that name of you web application is SomeWebApp and the server is available at localhost:8080 then web service should be published at http://localhost:8080/SomeWebApp/helloService. You can test it retrieving WSDL at: http://localhost:8080/SomeWebApp/helloService?wsdl. This URL can be used to create SOAP UI project (the tool that I really recommend for exploring and testing SOAP services).
If you don't use Spring to configure endpoint or you still can't access web service please provide more details about your configuration.

Enable https for java ejb Webservice

i'm developing a webservice with ejb 3 and glassfish 3.1.1. I'm using Netbeans 7.0 and would like to know, how to enable https on port 8181 for this webservice.
I dont need any authentication method, just secure the communication through https!
Thx
Adem
You need to specify a secure connection as explained here. Essentially, in your deployment descriptor web.xml you need to set:
<security-constraint>
...
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
However NetBeans will insert the code for you: open web.xml, click the Security tab along the top of the editor, then click the Add Security Constraint button. Type a name, in URL pattern write /*, set All Http Methods, and specify Confidential as Transport Guarantee.
If you don't have web.xml, because you are deploying just the Enterprise Java Bean, create a New GlassFish Descriptor glassfish-ejb-jar.xml and fill it like this (or see here the file hierarchy):
<glassfish-ejb-jar>
<enterprise-beans>
<ejb>
<ejb-name>Hello</ejb-name>
<webservice-endpoint>
<port-component-name>Hello</port-component-name>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</webservice-endpoint>
</ejb>
</enterprise-beans>/>
</glassfish-ejb-jar>
Your application will use port 8181 from now on.
See here for further information about how to setup security in a Netbeans web application and here for learning about certificates.

JAX-WS webservice and #rolesAllowed

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

Is there a way to restrict access to an ASMX Webservice, i.e. the asmx page and its WSDL?

I have a C# .net webservice that I need to restrict access to. I already require my consumers to use a username and password to call the service. But, is there a way to restrict access to the actual asmx page and the WSDL? I would need to restrict access to the webservice by username/password and IP address. If a user did not have the correct credentials, I would not want them to know what webmethods exist in the webservice.
Can this be done though IIS? I know that I can restrict IP addresses through IIS, but can I also use usernames/passwords?
Is there any other way to do this outside of IIS, maybe using C#.net?
Well, since it's ASMX you have the entire ASP.NET runtime stack at your disposal.
Step #1 - managing the resource through .config
Apply a <location> tag for the resources you want secured. Assuming it's a single ASMX file you can simply do the following in your web.config:
<location path="MyWebService.asmx">
<system.web>
<!-- resource specific options will go here -->
</system.web>
</location>
Step #2 - authenticating your users
You need to decide how you're actually going to authenticate users. There are several ways to do this and several authentication standards you could leverage. You need to pick the approach that's the right fit for you.
If you're on an intranet and are using Windows authentication I would highly suggest leveraging that because it's truly the simplest option to get setup. However, if your services are being accessed over the internet then Windows authenticatio is not really an option and you need to choose from a web standard. The simplest of those is Basic Authentication, but you should only use this over SSL since the username/password are not encrypted (only base64 encoded). The next step up from that is Digest authentication which doesn't require SSL because the username/password are sent using an MD5 hash. For the ultimate you can go with SSL v3 where you issue a specific client certificate to each user of your API.
Now, which option you select for security dictates what else needs to be done. If you choose Windows security, it's as easy as adding the following element to the <system.web> element we started with in Step #1:
<authentication mode="Windows" />
The remainder of the security protocols are going to require a little more work. ASP.NET doesn't provide intrinsic support for Basic, Digest or SSL v3. Technically you can leverage IIS to do this type of authentication for you, but it's always going to map to a Windows user. If that's an option for you, then simply leave the <authentication mode="Windows" /> element and configure IIS accordingly. If, however, that is not an option, either because you simply have no control over IIS/ActiveDirectory or you need to authenticate against a custom user database, then that means that you need to hook up a custom HttpModule to provide support for these security protocols.
Step #3 - securing the resource
The simplest approach to securing the resource is to basically say: "don't let anyone who hasn't successfully authenticated in some way into this resource". This is done using the following authorization configuration:
<authorization>
<deny users="?" />
</authorization>
If you wanted to only allow certain users you could change to do the following instead:
<authorization>
<deny users="*" />
<allow users="jdoe, msmith" />
</authorization>
Another approach is to define roles (groups) and simply lock the resource down to a special role which you put the users who you want to access the resource into.
<authorization>
<deny users="*" />
<allow roles="My Service Users" />
</authorization>
This maps well to Windows authentication because you can just setup a Windows group and let your MIS team manage which users are in that group using ActiveDirectory. However, the feature also works just fine for non-Windows authentication assuming the security implementation you've used exposes roles via its IPrincipal implementation.
I don't know how practical this is for you, but you could consider upgrading to WCF. WCF is fully backward compatible with ASMX web services, and lets you control whether or not the WSDL is exposed by defining a MEX (metadata exchange) endpoint. No MEX endpoint, no WSDL.
You can stop WSDL being shown by removing the Documentation protocol from the element in Machine.config
Update:
Web Services authentication - best practices?
If your users have usernames/passwords you can use HTTP basic authentication via HTTPS.
You can also implement it in a slightly differnt way. The first call to your web service should be the authentication method. Client authenticates and receives an authentication token. This token should be presented to all other methods exposed by your web service.
Two options: Create an entirely different site on a different port with locked down permissions. This has the advantage of providing some amount of "security through obscurity" (half joking...) Or you can add a new Application under your site(same port, different path), on a different app pool and assign permissions that way.
In either case, your web service isn't going to be able to talk with the various ASP.NET "things" like the application object (well it will, but it won't be the same one). Deployment is only slightly harder: deploy the same binaries, but only include the one web service file.
You can authenticate using an HttpModule.
SSL + BasicAuthentication should yield the best interop with other tool chains.
In the HttpModule, you have access to the request and can deny unauthenticated users access to just .asmx requests. And even then you might let them access the WSDL.
Add <add path="*.asmx" verb="*" type="System.Web.HttpForbiddenHandler" validate="True" /> to the <httpHandlers> section of the web.config file