Securing our Applications using OpenSSO in GlassFish Security

Exclusive offer: get 50% off this eBook here
GlassFish Security

GlassFish Security — Save 50%

Secure your GlassFish installation, Web applications, EJB applications, Application Client modules, and Web services

$26.99    $13.50
by Masoud Kalali | May 2010 | Open Source

OpenSSO is the answer to many complexities that have emerged during recent years because of the complexity and dynamicity of the security functionality required for software systems. The complexity in software security increases as a result of the increase in complexity of security requirements of the target business that the software should drive and diversity in the integration between different partner's software systems that collaborate to complete a client request.

In this article by Masoud Kalali, author of GlassFish Security, we will discuss how to go about securing our application using OpenSSO.

An example of such system is integration between an online shopping system, the product provider who actually produces the goods, the insurance company that provides insurance on purchases, and finally the shipping company that delivers the goods to the consumers' hand. All of these systems access some parts of the data, which flows into the other software to perform its job in an efficient way. All the employees can benefit from a single sign-on solution, which keeps them free from having to authenticate themselves multiple times during the working day.

Another example can be a travel portal, whose clients need to communicate with many other systems to plan their traveling. Integration between an in-house system and external partners can happen in different levels, from communication protocol and data format to security policies, authentication, and authorization. Because of the variety of communication models, policies, and client types that each partner may use, unifying the security model is almost impossible and the urge for some kind of integration mechanism shows itself bolder and bolder.

SSO as a concept and OpenSSO as a product address this urge for integrating the systems' security together.

OpenSSO provides developers with several client interfaces to interact with OpenSSO to perform authentication, authorization, session and identity management, and audition. These interfaces include Client SDK for different programming languages and using standards including:

  • Liberty Alliance Project and Security Assertion Markup Language (SAML) for authentication and single sign-on (SSO)
  • XML Access Control Markup Language (XACML) for authorization functions
  • Service Provisioning Markup Language (SPML) for identity management functions. Using the client SDKs and standards mentioned above are suitable when we are developing custom solutions or integrating our system with partners, which are already using them in their security infrastructure. For any other scenario these methods are overkill for developers. To make it easier for the developers to interact with OpenSSO core services the Identity Web Services are provided. We discussed IWS briefly in OpenSSO functionalities section. The IWS are included in OpenSSO to perform the tasks included in the following table.



Task

Description

Authentication and Single sign-on

Verifying the user credentials or its authentication token.

Authorization

Checking the authenticated user's permissions for accessing a resource.

Provisioning

Creating, deleting, searching, and editing users.

Logging

Ability to audit and record operations.

IWS are exposed in two models—the first model is the WS-* compliant SOAP-based Web Services and the second model is a very simple but elegant RESTful set of services based on HTTP and REST principles.

Finally, the third way of using OpenSSO is deploying the policy agents to protect the resources available in a container.

In the following section we will use RESTful interface to perform authentication, authorization, and SSO.

Authenticating users by the RESTful interface

Performing authentication using the RESTful Web Services interface is very simple as it is just like performing a pure HTTP communication with an HTTP server. For each type of operation there is one URL, which may have some required parameters and the output is what we can expect from that operation. The URL for authentication operation along with its parameters is as follows:

  • Operation: Authentication
  • Operation URL: http://host:port/OpenSSOContext/identity/authenticate
  • Parameters: username, password, uri
  • Output: subjectid

The Operation URL specifies the address of a Servlet which will receive the required parameters, perform the operation, and write back the result. In the template included above we have the host, port, and OpenSSOContext which are things we already know. After the context we have the path to the RESTful service we want to invoke. The path includes the task type, which can be one of the tasks included in the IWS task lists table and the operation we want to invoke.

All parameters are self-descriptive except the uri. We pass a URL to have our users redirected to it after the authentication is performed. This URL can include information related to the user or the original resource which the user has requested.

In the case of successful authentication we will receive a subjectid, which we can use in any other RESTful operation like authorization, to log in, log out, and so on. If you remember session ID from your web development experience, subjected is the same as session ID. You can view all sessions along with related information from the OpenSSO administration console homepage under the Sessions tab. The following listing shows a sample JSP page which performs a RESTful call over OpenSSO to authenticate a user and obtain a session ID for the user if they get authenticated.

<%
try {
String operationURL =
"http://gfbook.pcname.com:8080/opensso/identity/authenticate";
String username = "james";
String password = "james";
username = java.net.URLEncoder.encode(username, "UTF-8");
password = java.net.URLEncoder.encode(password, "UTF-8");
String operationString = operationURL + "?username=" +
username +"&password=" + password;
java.net.URL Operation = new java.net.URL(operationString);
java.net.HttpURLConnection connection =
(java.net.HttpURLConnection)Operation.openConnection();
int responseCode = connection.getResponseCode();
if (responseCode == java.net.HttpURLConnection.HTTP_OK) {
java.io.BufferedReader reader = new java.io.BufferedReader(
new java.io.InputStreamReader(
(java.io.InputStream) connection.getContent()));
out.println("<h2>Subject ID</h2>");
String line = reader.readLine();
out.println(line);
}
} catch (Exception e) {
e.printStackTrace();
}
%>

REST made straightforward tasks easier than ever. Without using REST we would have dealt with complexity of SOAP and WSDL and so on but with REST you can understand the whole code with the first scan.

Beginning from the top, we define the REST operation URL, which is assembled using the operation URL and appending the required parameters using the parameters name and the parameters value. The URL that we will connect to it will be something like:

http://gfbook.pcname.com:8080/opensso/identity/authenticate?username=james&password=james

After assembling the URL we open a network connection to authenticate it. After opening the connection we can check to see whether we received an HTTP_OK response from the server or not. Receiving the HTTP_OK means that the authentication was successful and we can read the subjectid from the socket. The connection may result in other response codes like HTTP_UNAUTHORIZED (HTTP Error code 401) when the credentials are not valid. A complete list of possible return values can be found at http://java.sun.com/javase/6/docs/api/java/net/HttpURLConnection.html.

Authorizing using REST

If you remember in Configuring OpenSSO for authentication and authorization section we defined a rule that was set to police http://gfbook.pcname.com:8080/ URL for us. And later on we applied the policy rule to a group of users that we created; now we want to check and see how our policy works. In every security system, before any authorization process, an authentication process should compete with a positive result. In our case the result for the authentication is subjectid, which the authorization process will use to check whether the authenticated entity is allowed to perform the action or not. The URL for the authorization operation along with its parameters is as follows:

  • Operation: Authorization
  • Operation URL: http://host:port/OpenSSOContext/identity/authorize
  • Parameters: uri, action, subjectid
  • Output: True or false based on the permission of subject over the entity and given action

The combination of uri, action, and subjectid specifies that we want to check our client, identified by subjectid, permission for performing the specified action on the resource identified by the uri. The output of the service invocation is either true or false.

The following listing shows how we can check whether an authenticated user has access to a certain resource or not. In the sample code we are checking james, identified by his subjectid we acquired by executing the previous code snippet, against the localhost Protector rule we defined earlier.

<%
try {
String operationURL =
"http://gfbook.pcname.com:8080/opensso/identity/authorize";
String protectecUrl = " http://127.0.0.1:38080/Conversion-war/";
String subjectId =
"AQIC5wM2LY4SfcyemVIZX6qBGdyH7b8C5KFJjuuMbw4oj24=@AAJTSQACMDE=#";
String action = "POST";
protectecUrl = java.net.URLEncoder.encode(protectecUrl, "UTF-8");
subjectId = java.net.URLEncoder.encode(subjectId, "UTF-8");
String operationString = operationURL + "?uri=" + protectecUrl +
"&action=" + action + "&subjectid=" + subjectId;
java.net.URL Operation = new java.net.URL(operationString);
java.net.HttpURLConnection connection =
(java.net.HttpURLConnection) Operation.openConnection();
int responseCode = connection.getResponseCode();
if (responseCode == java.net.HttpURLConnection.HTTP_OK) {
java.io.BufferedReader reader = new java.io.BufferedReader(
new java.io.InputStreamReader(
(java.io.InputStream) connection.getContent()));
out.println("<h2>authorization Result</h2>");
String line = reader.readLine();
out.println(line);
}
} catch (Exception e) {
e.printStackTrace();
}
%>

For this listing everything is the same as the authentication process in terms of initializing objects and calling methods, except that in the beginning we define the protected URL string, then we include the subjectid, which is result of our previous authentication. Later on we define the action that we need to check the permission of our authenticated user over it and finally we read the result of authorization. The complete operation after including all parameters is similar to the following snippet:

http://gfbook.pcname.com:8080/opensso/identity/authorize?uri=http://127.0.0.1:38080/Conversion-war/&action=POST&subjectid=subjectId

Pay attention that two subjectid elements cannot be similar even for the same user on the same machine and same OpenSSO installation. So, before running this code, make sure that you perform the authentication process and include the subjectid resulted from your authentication with the subjectid we specified previously.

GlassFish Security Secure your GlassFish installation, Web applications, EJB applications, Application Client modules, and Web services
Published: May 2010
eBook Price: $26.99
Book Price: $44.99
See more
Select your format and quantity:

SSO using REST

sually in big enterprise systems there is one single server that performs all types of authentication required in the enterprise, including a simple username-password authentication to authenticate based on OpenID or X.509 digital certificates.

In our simple scenario we have a Servlet filter that checks all incoming requests for valid authentication token. It will either find that the request is already authenticated (presence of the subjectid) or it redirects the user to OpenSSO server for authentication. The filter appends a redirection URL when it forwards the user to OpenSSO for authentication to let OpenSSO redirect the user to that URL after a successful authentication.

In this application, our protected resource is the restricted.jsp file on the same context that the Servlet filter is present, and we just check for the authentication token in our filter and no authorization process will commence. In real world example we may define some policies in OpenSSO and check incoming request both for authenticated token and perform authorization after the authentication is completed to see whether we should allow the request to reach the target or should redirect it to an informative page about the requester's access level and why he cannot access the requested resource. The following listing shows the restricted.jsp file.

<form name="attributes" action="logout.jsp" method="post">
<b>You are logged in so you can access this restricted page</b>
<br>
<input name="logout" value="Logout" type="submit">
</form>

The restricted page just shows a welcome message along with a button, which invokes another JSP page for logout operation. Logout operation can be performed using the REST interface. The operation parameters and URL are as follows:

  • Operation: Logout.
  • Operation URL: http://host:port/OpenSSOContext/identity/logout.
  • Parameters: subjectid.
  • Output: No specific output. We can check whether the operation is performed correctly or not using HTTP response codes.

The following listing shows how we can invoke the logout operation using REST.

<%
try {
String serviceUrl =
"http://gfbook.pcname.com:8080/opensso/identity/logout";
String subjectid = null;
javax.servlet.http.Cookie[] cookies = request.getCookies();
cookies = cookies == null ? new Cookie[0] : cookies;
for (Cookie cookie : cookies) {
String cookieName = cookie.getName();
if ("iPlanetDirectoryPro".equals(cookieName)) {
subjectid = cookie.getValue();
}
}
String url = serviceUrl + "?subjectid=" +
java.net.URLEncoder.encode(subjectid, "UTF-8");
System.out.println("Opening the Connection");
java.net.URL Operation = new java.net.URL(url);
java.net.HttpURLConnection connection =
(java.net.HttpURLConnection)Operation.openConnection();
int responseCode = connection.getResponseCode();
if (responseCode == java.net.HttpURLConnection.HTTP_OK) {
out.println("<h2>Logged out</h2>");
}
} catch (Exception ex) {
ex.printStackTrace();
}
%>

We start by defining the SSO server URL, and then we extract all cookies from the request in order to find the cookie associated with the SSO subjectid. This cookie's name is iPlanetDirectoryPro and we need its value to perform the logout. Then we encode the parameters part of logout operation URL and finally open the URL, which is equal to calling the REST operation. We can check the HTTP response code to ensure that our operation has performed with no error and in case that we get an error code we can redirect the user to the appropriate pages.

Now we need to implement the Servlet filter. The filter should be able to check whether the user is authenticated; if not, redirect him to the authentication server for authentication. The following listing shows the Servlet filter's doFilter method.

public void doFilter(ServletRequest request,
ServletResponse response, FilterChain chain)
throws IOException, ServletException {
if (isAuthenticated((HttpServletRequest) request)) {
//perform the authorization if required.
chain.doFilter(request, response);
} else {
((HttpServletResponse)
response).sendRedirect(ssoServerURL +
"/UI/Login?goto=" +((HttpServletRequest)
request).getRequestURL().toString());
}

The doFilter method is implemented in a very simple manner to shows the basics. In the beginning we check to see whether our user is authenticated or not. Later on we redirect the user to the SSO server for authentication; the SSO server will redirect the user to their destination page after the authentication is successfully completed.

The first unknown method in the previous listing is the isAuthenticated method. To keep it simple this method checks to see whether the presented subjectid in the request is valid or not. The isAuthenticated method uses a REST operation to check the subjectid or so-called token; specification of this operation is as follow:

  • Operation: isAuthenticated
  • Operation URL: http://host:port/OpenSSOContext/identity/isAuthenticated
  • Parameters: subjectid
  • Output: boolean

The following listing shows the isAuthenticated method implementation. We used the method in our Servlet filter.

private boolean isAuthenticated(HttpServletRequest request)
throws IOException {
boolean authenticated = false;
String operationURL = ssoServerURL +
"/identity/isTokenValid";
HttpURLConnection connection =
(HttpURLConnection) (new
URL(operationURL).openConnection());
connection.setDoOutput(true);
connection.setRequestMethod("POST");
forwardCookies(request, connection,
getCookieNamesToForward());
int responseCode = connection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
InputStream in_buf = connection.getInputStream();
StringBuffer inbuf = new StringBuffer();
String line;
BufferedReader reader = new BufferedReader(new
InputStreamReader(in_buf, "UTF-8"));
while ((line = reader.readLine()) != null) {
inbuf.append(line).append("\n");
}
String data = new String(inbuf);
if (data.toLowerCase().indexOf("boolean=true") != -1) {
authenticated = true;
}
}
return authenticated;
}

You should be familiar with how we assemble the operationURL except that this time we passed no parameters while the operation, as mentioned, needs subjectid to be passed as its parameter. OpenSSO is smart enough to find its own cookie in the incoming request if we do not provide it as an explicit query parameter. So this time instead of extracting the subjectid value we are going to let OpenSSO extract the cookie from our request, so we add required cookies to the request that we are sending to OpenSSO Identity Web Services. Later on, we just change the GET method to POST for more security. And finally we are checking to see the result of the isTokenValid operation which as mentioned is Boolean; either the token is correct or not. The first unfamiliar method that we may see is forwardCookies, this method simply extracts the required request cookies and adds them to the given connection. We use it to set cookies instead of sending them as query parameters. The following listing shows the forwardCookies method.

private void forwardCookies(HttpServletRequest request,
HttpURLConnection connection, Set<String> cookieNames) {
StringBuilder sb = new StringBuilder();
Cookie[] cookies = request.getCookies();
cookies = cookies == null ? new Cookie[0] : cookies;
for (Cookie cookie : cookies) {
String cookieName = cookie.getName();
if (cookieNames.contains(cookieName)) {
String cookieValue = cookie.getValue();
sb.append(cookieName);
sb.append("=");
sb.append(cookieValue);
sb.append(";");
}
}
System.out.println(sb.toString());
if (sb.length() > 0) {
connection.setRequestProperty("Cookie", sb.toString());
}
}

This method, as we can see, gets a collection of cookies as input parameter. It tries to extract them from the given request, and include them in the given connection request. But how does it know which cookies it should extract from the request? Which cookies don't belong to OpenSSO so our filter should not touch them?

To get this problem solved we use another method to get the list of cookies that belongs to OpenSSO and then we just extract those cookies from the original request header and include them in the request that we are sending to OpenSSO Identity Web Services. There is a REST operation to get the list of OpenSSO cookie names with the following specification:

  • Operation: getCookieNamesToForward
  • URL: http://host:port/OpenSSOContext/identity/getCookieNamesToForward
  • Parameters: Accepts no parameter
  • Output: List of all OpenSSO cookie names

The following snippet shows how we can use the getCookieNamesToForward operation in our Java code:

private Set getCookieNamesToForward() throws IOException {
Set nameSet = new HashSet();
String url = ssoServerURL +
"/identity/getCookieNamesToForward";
HttpURLConnection connection =
(HttpURLConnection) (new URL(url).openConnection());
BufferedReader br = new BufferedReader(
new InputStreamReader((InputStream)
connection.getContent()));
if (connection.getResponseCode() ==
HttpURLConnection.HTTP_OK) {
String line = null;
while ((line = br.readLine()) != null) {
if (line.startsWith("string=")) {
line = line.replaceFirst("string=", "");
nameSet.add(line);
}
}
}
return nameSet;
}

You should be completely familiar with the purpose of each code line in the above listing. The method gets a list of all OpenSSO cookie names and returns it as a set to let forwardCookies send only the cookies belonging to OpenSSO to the OpenSSO server.

You may ask what is the ssoServerURL variable content. I would say that we need to either use a Servlet initializing parameter or a class-level property to provide our filter with the SSO server URL. We also need to add the filter definition to our web.xml file. In the sample code available at https://www.packtpub.com//sites/default/files/downloads/9386_Code.zip which includes the complete web application for this article, the sample application includes complete source code with configure web.xml file for initialization parameter.

The following table shows a complete list of other REST operations that are provided by OpenSSO Identity Services.



Operation

URL

Parameters

Response content

Perform logging

/identity/log

appid, subjectid

logname, message1

No output

Search for identities

/search

flter, attributes_names1

attribute_values_attributename1

identitydetails Attributes

Getting subject attributes

/attributes

attributes_names1, subjectid

userdetails Read

Reading details of a user

/identity/read

name, attributes_names1, admin

identitydetails Creation

Creating an identity

/identity/create

identity_name, identity_attribute_names

identity_attribute_values_attributename

admin

No output

Updating identity details

/identity/update

identity_name, identity_attribute_names

identity_attribute_values_attributename

admin

No output

Removing an Identity

/identity/delete

identity_name,admin

No output

All of the URLs should be prefixed with OpenSSO server URL, for example http://localhost:8080/opensso or http://gfbook.pcname.com:8080/opensso.

Summary

In this article, we looked at security from an integration point of view. Security, most of the time, is the only subject which developers leave for the later development stages, which is a dire pitfall. Security integration is a very broad topic and this article only introduces the OpenSSO server briefly to give you a broader perspective about security integration in general and OpenSSO security in particular.

GlassFish Security Secure your GlassFish installation, Web applications, EJB applications, Application Client modules, and Web services
Published: May 2010
eBook Price: $26.99
Book Price: $44.99
See more
Select your format and quantity:

About the Author :


Masoud Kalali

Masoud Kalali has been working on software development projects since 1998, which gives him a broad perspective on software development in general and changes in the software development landscape in the past 1.5 decades. Masoud has experience with a variety of technologies (.NET, J2EE, CORBA, and COM+) on diverse platforms (Solaris, Linux, and Windows). He has a masters degree in Information Systems with a bachelor degree in Software Engineering.

Masoud has authored a fair number of articles and other types of material, including several articles at Java.net and Dzone. He is the author of multiple refcardz, published by Dzone, including but not limited to Using XML in Java (http://refcardz.dzone.com/refcardz/using-xml-java) and Security and GlassFish v3 (http://refcardz.dzone.com/refcardz/getting-startedglassfish) refcardz. Masoud is one of the founding members of NetBeans Dream Team (http://wiki.netbeans.org/NetBeansDreamTeam) and a GlassFish community spotlighted developer (https://glassfish.java.net/public/developers.html). Masoud is the author of GlassFish Security (http://www.packtpub.com/glassfish-security/book) that was published in 2010, covering GlassFish v3 security and Java EE 6 security.

Masoud's main area of research and interest includes service-oriented architecture and large-scale systems development and deployment. In his spare time he enjoys photography, mountaineering, and climbing.

Masoud's Twitter handle is @MasoudKalali if you want to know what he is up to.

Books From Packt

Pentaho 3.2 Data Integration: Beginner's Guide
Pentaho 3.2 Data Integration: Beginner's Guide

WordPress and Flash 10x Cookbook
WordPress and Flash 10x Cookbook

Spring Python 1.1
Spring Python 1.1

Drupal E-commerce with Ubercart 2.x
Drupal E-commerce with Ubercart 2.x

Learning jQuery 1.3
Learning jQuery 1.3

OpenStreetMap
OpenStreetMap

Firebug 1.5: Editing, Debugging, and Monitoring Web Pages
Firebug 1.5: Editing, Debugging, and Monitoring Web Pages

Getting started with Audacity 1.3
Getting started with Audacity 1.3

No votes yet

Post new comment

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
i
Z
s
U
y
P
Enter the code without spaces and pay attention to upper/lower case.
Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software