This article will describe how to protect your J2EE application from XSS using ESAPI. As with all of the detail articles in this series, if you need a refresher on OWASP or ESAPI, please see the intro article The OWASP Top Ten and ESAPI.
OK, so on to XSS. Here is a slightly modified definition of XSS from OWASP:
XSS flaws occur whenever an application takes untrusted (typically user supplied) data and sends it to a web browser without first validating or encoding that content. XSS allows attackers to execute script in the victim’s browser which can hijack user sessions, deface web sites, possibly introduce worms, etc.
As you can see, XSS essentially allows an attacker to splash whatever they want on the screen since the application doesn’t do any input validation or output encoding. This is not a big deal when you have benevolent users, but an attacker could, say, input some nasty JavaScript and cause quite a few problems. This is typically what happens – JavaScript is output and generally executes in the background so the user is unaware of what’s occurring.
In general there are 3 types of XSS:
1. Stored – The dangerous data is stored in a permanent data store and shown repeatedly on the site – think online forums. If an attacker were to save a forum comment that had an XSS exploit in it, that comment would then be displayed to anyone who visited the page, without requiring any further interaction from the attacker.
2. Reflected – The dangerous data is sent along with the URL typically, and is not stored in a data store but is displayed (reflected) back to the user, which launches the attack. If an attacker sent a URL in an email, and a user clicked on it b/c the site was “trusted”, say that user’s bank, but the site had an XSS exploit, the attacker could cause many issues up to and including processing transactions on behalf of the user at the bank site (more on this in a follow-on article).
3. DOM – This is the most recently named type of attack, and simply represents an entirely client side issue. While the previous 2 types of XSS have to do with the server outputting data to the browser, this has to do with the browser manipulating the DOM and data being moved in and out of context. This can result in an XSS attack if data is not properly validated or encoded. This type of XSS issue has become more prevalent with web 2.0 and the heavy proliferation of JavaScript frameworks being used to do both serious functionality and DOM manipulation in web pages.
XSS, by some accounts, is the most common vulnerability and definitely is one of the most dangerous in the wild. It is extremely prevalent due to a lack of education for the most part, but it can at times be tricky to solve correctly. There are essentially 2 options for how to deal with XSS. Both could be used individually to solve the problem entirely … in theory … but that would require detailed knowledge of every possible input/output vector both now and in the future. Since this is rarely feasible, it is recommended to use both approaches. These approaches are Input Validation and Output Encoding.
Input Validation
—————-
Input validation is simply that – checking each input for validity. This can mean many things, but in the typical and simplest case, it means to check the type and length of the data. For instance, if you are accepting a standard US zip code from a text box, you would know that the only valid type is a digit (0-9) and that the length should be 5, no more and no less. Not all cases are this simple, but many are similar.
Consider this example for what can go wrong. There is a simple search engine and on the page is the search box. A user types in a query only to find on the results page that his search terms are printed on the screen, something like – You searched for “free stuff”. That’s all well and good, but what happens when the user inputs a bit of JavaScript into the search box? If the application doesn’t handle the input/output properly, the screen will print the JavaScript out in all it’s glory, and it will get put inline in the web page response, and treated just as if the web page developer had put that bit of code in there. That’s where the problems come in – now how do we solve these issues?
Here’s an image from OWASP showing their architecture for input validation. The key here is that everything is validated, all input that doesn’t originate within the application (including user input, request headers, cookies, database data, ldap, really everything …).
So how do we use this validation framework to actually validate our data. There are 2 basic types of methods in the validator interface that can be used. They are listed below:
getValidInput(java.lang.String context, java.lang.String input, java.lang.String type,
int maxLength, boolean allowNull, ValidationErrorList errors)
isValidInput(java.lang.String context, java.lang.String input, java.lang.String type,
int maxLength, boolean allowNull)
The first, getValidInput, returns canonicalized and validated input data along with a list of errors (ValidationErrorList) if any validation issues occurred. The second is similar, but does not return errors, and rather just returns a boolean as to whether or not the input is valid. Here are a couple real examples of these being used.
String validatedFirstName = ESAPI.validator().getValidInput("FirstName",
myForm.getFirstName(), "FirstNameRegex", 255, false, errorList);
boolean isValidFirstName = ESAPI.validator().isValidInput("FirstName",
myForm.getFirstName(), "FirstNameRegex", 255, false);
Both of the samples above deal with the first name field from a typical web form, but this could just as easily be a request header or parameter, or cookie value, or anything else.
In the end, there is great value in general in validating ALL of your application inputs. It will help solve the XSS issue, but will also solve other problems, including some we probably haven’t even thought up yet.
Output Encoding
—————-
On the flip side of input validation is output encoding (also known as “escaping”). Here’s a quick definition from OWASP: “Escaping” is a technique used to ensure that characters are treated as data, not as characters that are relevant to the interpreter’s parser. There are lots of different types of escaping, sometimes confusingly called output “encoding.” Some of these techniques define a special “escape” character, and other techniques have a more sophisticated syntax that involves several characters. Escaping is the primary means to make sure that untrusted data can’t be used to convey an injection attack. There is no harm in escaping data properly – it will still render in the browser properly. Escaping simply lets the interpreter know that the data is not intended to be executed, and therefore prevents attacks from working.
What does all of this mean to the developer? In order to prevent “bad” data from causing XSS issues on the screen when rendered, we can’t just out.println them to the screen – we have to “encode/escape” them. There are many libraries out now that do some form of encoding, most are minimal. c:out and jstl both do encoding – some of the struts tags, jsf, spring. All do some minimal encoding. However, ESAPI takes this to a different, but necessary level.
There are 2 issues with the previously mentioned frameworks when it comes to their encoding schemes. 1 – They don’t encode enough characters – they miss some things. 2 – They only encode for 1 context and miss the other 4. As mentioned in the cheat sheet, there are actually 5 output contexts for the browser:
1. HTML entity (this is the standard HTML output that the above frameworks at least partially handle)
2. HTML Attribute
3. JavaScript
4. CSS
5. URL
This image from OWASP shows their architecture for output validation. The important notion here is that before any data is output in the application, the context for output is considered, and the data is encoded.
All of these contexts have some special handling rules. I suggest you reference the cheat sheet in order to learn those. I’ll give a couple of simple examples here just for reference.
First, a simple example to output to an HTML entity.
//performing input validation
String cleanComment = ESAPI.validator().getValidInput("comment",
request.getParameter("comment"), "CommentRegex", 300, false, errorList);
//check the errorList here ...
...
//performing output encoding for the HTML context
String safeOutput = ESAPI.encoder().encodeForHTML( cleanComment );
Now, an example of creating a URL that is safe for output.
//performing input validation
String cleanUserName = ESAPI.validator().getValidInput("userName",
request.getParameter("userName"), "userNameRegex", 50, false, errorList);
//check the errorList here ...
...
//performing output encoding for the url context
String safeOutput = "/admin/findUser.do?name="
+ ESAPI.encoder().encodeForURL(cleanUserName);
Above, you can see that is it very simple to encode output for a given context, as long as you know the context you’re going to. It does take discipline to use this throughout your application, but it will pay you back many-fold in rewards. Additionally, ESAPI does have tag libraries that wrap each of the output encoding mechanisms available for use.
One final note regarding output encoding: you should always explicitly set the character encoding for all your pages (ISO-8859-1 or UTF8 are popular choices).
As you can see, there is quite a bit to solving XSS. It can become tricky, especially in the instances where multiple contexts are involved, like trying to safely pass a parameter to a javascript function inside an HTML attribute handler event, but it is doable. The big takeaway should be that input validation and output encoding, while they do solve XSS, are in general excellent practices that should be exercised for ALL input to an application.
A final XSS note: A great reference for understanding what is occurring in XSS and how to protect against it is the OWASP XSS Prevention Cheat Sheet. Various references in this article drew from the info on this site.
Other articles in this series:
Part 0: The OWASP Top Ten and ESAPI
Part 1: The OWASP Top Ten and ESAPI – Part 1 – Cross Site Scripting (XSS)
Part 2: The OWASP Top Ten and ESAPI – Part 2 – Injection Flaws
Part 3: The OWASP Top Ten and ESAPI – Part 3 – Malicious File Execution
Part 4: The OWASP Top Ten and ESAPI – Part 4 – Insecure Direct Object Reference
Part 5: The OWASP Top Ten and ESAPI – Part 5 – Cross Site Request Forgery (CSRF)
Part 6: The OWASP Top Ten and ESAPI – Part 6 – Information Leakage and Improper Error Handling
Part 7: The OWASP Top Ten and ESAPI – Part 7 – Broken Authentication and Session Management
Part 8: The OWASP Top Ten and ESAPI – Part 8 – Insecure Cryptographic Storage
Part 9: The OWASP Top Ten and ESAPI – Part 9 – Insecure Communications
Part 10: The OWASP Top Ten and ESAPI – Part 10 – Failure to Restrict URL Access
Note: Article updated on 11/18 per Jim Manico’s catch of improper url output encoding since ESAPI’s url encoding is intended for parameter values, not the entire url. Also added input validation as Jim’s comment pointed out was missing.
This article will be the first in an 11-part series (yes eleven!) about the OWASP Top 10 and ESAPI (Enterprise Security API). This article will be a general introduction to the topic, while the follow-on articles will each cover one of the Top Ten web application security vulnerabilities and the associated usage of ESAPI (or another useful framework) to correct that vulnerability securely.
Before we get into the Top Ten, I should first mention what OWASP is for the unfamiliar. OWASP (http://www.owasp.org) is the Open Web Application Security Project. It is the result of a group of generous web application security folks offering their time and effort to build lots of useful security documentation as well as products. There are a large number of projects that are maintained by the group in varying levels of support, ranging from documentation (Top Ten) to teaching tools (webgoat) to proxies (webscarab) to a secure development library (ESAPI) and so on. This group is doing excellent work, and some of the smartest security folks around are running the show, so it’s a good group to get involved with if you are tasked with doing serious web development, or are involved on the security side of things.
Now, let’s move on to discuss the OWASP Top Ten. The Top Ten project is a list of the 10 most critical web application security issues. The list is updated every few years (most recently 2007) and is compiled with lots of input from the industry. The security issues on the list represent all at once those that are generally very simple, dangerous, well-known and commonly exploited in the wild. Here is a link to the Top Ten project at OWASP. http://www.owasp.org/index.php/Category:OWASP_Top_Ten_Project
As a harsh generalization, web developers are not very well equipped with security knowledge. On the other hand, attackers are. Since the sophistication level of many of the Top Ten attacks is so low in today’s environment, developers need to strengthen themselves quickly on two fronts: education and tools. That’s where OWASP and ESAPI comes in. As for education, there is an abundance of good educational material (see the secure development guide – which offers web application security best practices) on the OWASP site with new information put up frequently. From the tool perspective, ESAPI (Enterprise Security API) is a web application security tool (or rather a set of APIs that can be used as a tool) that is very effective at thwarting attacks when used properly.
ESAPI functions as a framework that developers can utilize to put protections in their applications that will prevent many if not all of the attacks openly used today. Even better, when used properly, it will also prevent “0-day” attack variants of known exploits and will very likely prevent new classes of vulnerabilities to some extent. Here is a link to the ESAPI project at OWASP. http://www.owasp.org/index.php/Category:OWASP_Enterprise_Security_API
The image below shows how ESAPI fits into your application design.
The image below shows how the features of ESAPI match up to the Top Ten vulnerabilities.
One great benefit to getting involved with OWASP and ESAPI is the community support. There is a great group of leaders in OWASP, and an equally great group of volunteer contributors. The level of education and toolsets being produced by the community is excellent, and getting better and more complete every day.
Although this quick introduction just barely skims the surface, hopefully it has been useful to explain what the Top Ten and ESAPI are generally useful for in their given contexts. Future articles in this series will cover each of the Top Ten vulnerabilities and the techniques that can be used to protect against them. Please come back and join me for the remainder of the series.
Other articles in this series:
Part 0: The OWASP Top Ten and ESAPI
Part 1: The OWASP Top Ten and ESAPI – Part 1 – Cross Site Scripting (XSS)
Part 2: The OWASP Top Ten and ESAPI – Part 2 – Injection Flaws
Part 3: The OWASP Top Ten and ESAPI – Part 3 – Malicious File Execution
Part 4: The OWASP Top Ten and ESAPI – Part 4 – Insecure Direct Object Reference
Part 5: The OWASP Top Ten and ESAPI – Part 5 – Cross Site Request Forgery (CSRF)
Part 6: The OWASP Top Ten and ESAPI – Part 6 – Information Leakage and Improper Error Handling
Part 7: The OWASP Top Ten and ESAPI – Part 7 – Broken Authentication and Session Management
Part 8: The OWASP Top Ten and ESAPI – Part 8 – Insecure Cryptographic Storage
Part 9: The OWASP Top Ten and ESAPI – Part 9 – Insecure Communications
Part 10: The OWASP Top Ten and ESAPI – Part 10 – Failure to Restrict URL Access
The Spring framework supports AOP very elegantly. Though it does not offer some of the features that AspectJ offers, it also is typically a simpler configuration to get going. This post is just an example of doing a very simple task (logging), a “cross-cutting concern” in AOP lingo, using the Spring framework.
This example will exist of a class with a main method, a business logic interface / class combo, an Advice (Spring’s way of encoding the AOP logic), and the associated Spring configuration file that ties everything together.
This example does not go into great detail about how Spring’s AOP mechanism works, but there is plenty of information in the Spring documentation about that. It simply uses the Java proxy mechanism. Also, I don’t go into all of the options for how you can configure AOP in Spring, though there are several. I only focus on the most recent recommendations.
Having said all of that … here we go.
First for the business logic interface / class:
package com.jtm.aop;
public interface SomeIntf {
public void updateMe1();
}
package com.jtm.aop;
import org.apache.log4j.Logger;
public class MyClass1 implements SomeIntf {
Logger log = Logger.getLogger(this.getClass());
public void updateMe1() {
log.info("in updateMe1");
}
}
This was obviously a very simple class that just writes a log statement. Now onto the Advice mechanism:
package com.jtm.aop;
import java.lang.reflect.Method;
import org.apache.log4j.Logger;
import org.springframework.aop.AfterReturningAdvice;
import org.springframework.aop.MethodBeforeAdvice;
public class PerformanceLoggingAdvice implements
MethodBeforeAdvice,
AfterReturningAdvice {
/** Time in milliseconds */
long startTime = 0;
/** Time in milliseconds */
long finishTime = 0;
protected static final Logger log =
Logger.getLogger(PerformanceLoggingAdvice.class);
public void before(Method method, Object[] args,
Object target) throws Throwable {
startTime = System.currentTimeMillis();
log.debug("Executing method " + method.getName()
+ " on object " + target.getClass().getName());
}
public void afterReturning(Object returnValue,
Method method, Object[] args, Object target) throws Throwable {
finishTime = System.currentTimeMillis();
double totalDuration = finishTime - startTime;
log.debug("Finished executing method " + method.getName()
+ " on object " + target.getClass().getName() + " in "
+ totalDuration / 1000 + " seconds.");
}
}
This class is doing a bit more. This class implements the Spring framework’s before and after advice interfaces. This allows the Spring framework to call these methods before and after the methods in the application where they are configured to do so by the Spring config file.
Now let’s see the main driver class:
package com.jtm.aop;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class RunAll {
public static void main(String[] args) {
SomeIntf myClass1;
ApplicationContext appContext =
new ClassPathXmlApplicationContext(new String[] {"spring-config.xml"});
myClass1 = (SomeIntf) appContext.getBean("myClass1");
myClass1.updateMe1();
}
}
As you can see, this class simply loads Spring, locates the bean, and calls the update method.
Now on to the magic, the Spring config file:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
">
<bean id="myClass1" class="com.jtm.aop.MyClass1" />
<bean id="performanceLoggingAdvice"
class="com.jtm.aop.PerformanceLoggingAdvice" />
<aop:config>
<!-- Performance logging pointcut -
run for every method in a control or facade class -->
<aop:pointcut id="performanceLoggingPointcut"
expression="execution(* com.jtm..*.update*(..))" />
<aop:advisor
advice-ref="performanceLoggingAdvice"
pointcut-ref="performanceLoggingPointcut"
id="performanceLoggingInterceptorAdvisor" />
</aop:config>
</beans>
As you can see, there is more going on here than in the other sections. Let’s break this down.
1. The business logic and Advice classes are configured as standard beans
2. The aop namespace for Spring 2.5 is loaded at the top of the file
3. All of the AOP configuration is located within an aop:config tag
4. First we configure the pointcut, which is a regular-expression like description of when the performance logging code should be run. In this case, we have configured it to run on any class in any subpackage of the com.jtm package and on any method that starts with “update” and that takes any kind of parameters.
5. Next we configure the advisor, which combines the advice class with the pointcut.
6. Finally Spring looks at the code are runtime and auto-proxies the classes that need to be so that the AOP code can be applied at run-time.
That’s it! This is a quick run-through. If you have any further questions, feel free to post here or search for more tutorials online. Also, check out the Spring documentation for further information.
Hope this helps.
-jtm
This post is to show an example of a simple multi-threaded Java HTTP Proxy Server. This sample is not fully functional for every application. It’s very simple and works fine for HTTP GET requests, but is not coded to properly handle HTTP POST requests (nor any other HTTP methods). This is strictly as an example to show how simple it is to proxy requests. This one simply records the url of all requests that are passed through it. Please let me know if you have any questions, and feel free to steal it and improve on it. Let me know what you come up with.
This first bit of code is the actual multithreaded server. It simply starts up the proxy server on a given port, takes in an HTTP request, and spawns off the request to a new thread passing the socket to the thread, and starts that thread on the request.
package proxy;
import java.net.*;
import java.io.*;
public class ProxyServer {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = null;
boolean listening = true;
int port = 10000; //default
try {
port = Integer.parseInt(args[0]);
} catch (Exception e) {
//ignore me
}
try {
serverSocket = new ServerSocket(port);
System.out.println("Started on: " + port);
} catch (IOException e) {
System.err.println("Could not listen on port: " + args[0]);
System.exit(-1);
}
while (listening) {
new ProxyThread(serverSocket.accept()).start();
}
serverSocket.close();
}
}
This is the real meat of the application. However, it’s still a fairly simple class. It’s a thread that starts up, then receives the incoming request from the client, resends the request to the real server that the client intended to send it to (while logging the request), then receives the response from the real server, and propogates that same response to the client. Fairly simple process.
package proxy;
import java.net.*;
import java.io.*;
import java.util.*;
public class ProxyThread extends Thread {
private Socket socket = null;
private static final int BUFFER_SIZE = 32768;
public ProxyThread(Socket socket) {
super("ProxyThread");
this.socket = socket;
}
public void run() {
//get input from user
//send request to server
//get response from server
//send response to user
try {
DataOutputStream out =
new DataOutputStream(socket.getOutputStream());
BufferedReader in = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
String inputLine, outputLine;
int cnt = 0;
String urlToCall = "";
///////////////////////////////////
//begin get request from client
while ((inputLine = in.readLine()) != null) {
try {
StringTokenizer tok = new StringTokenizer(inputLine);
tok.nextToken();
} catch (Exception e) {
break;
}
//parse the first line of the request to find the url
if (cnt == 0) {
String[] tokens = inputLine.split(" ");
urlToCall = tokens[1];
//can redirect this to output log
System.out.println("Request for : " + urlToCall);
}
cnt++;
}
//end get request from client
///////////////////////////////////
BufferedReader rd = null;
try {
//System.out.println("sending request
//to real server for url: "
// + urlToCall);
///////////////////////////////////
//begin send request to server, get response from server
URL url = new URL(urlToCall);
URLConnection conn = url.openConnection();
conn.setDoInput(true);
//not doing HTTP posts
conn.setDoOutput(false);
//System.out.println("Type is: "
//+ conn.getContentType());
//System.out.println("content length: "
//+ conn.getContentLength());
//System.out.println("allowed user interaction: "
//+ conn.getAllowUserInteraction());
//System.out.println("content encoding: "
//+ conn.getContentEncoding());
//System.out.println("content type: "
//+ conn.getContentType());
// Get the response
InputStream is = null;
HttpURLConnection huc = (HttpURLConnection)conn;
if (conn.getContentLength() > 0) {
try {
is = conn.getInputStream();
rd = new BufferedReader(new InputStreamReader(is));
} catch (IOException ioe) {
System.out.println(
"********* IO EXCEPTION **********: " + ioe);
}
}
//end send request to server, get response from server
///////////////////////////////////
///////////////////////////////////
//begin send response to client
byte by[] = new byte[ BUFFER_SIZE ];
int index = is.read( by, 0, BUFFER_SIZE );
while ( index != -1 )
{
out.write( by, 0, index );
index = is.read( by, 0, BUFFER_SIZE );
}
out.flush();
//end send response to client
///////////////////////////////////
} catch (Exception e) {
//can redirect this to error log
System.err.println("Encountered exception: " + e);
//encountered error - just send nothing back, so
//processing can continue
out.writeBytes("");
}
//close out all resources
if (rd != null) {
rd.close();
}
if (out != null) {
out.close();
}
if (in != null) {
in.close();
}
if (socket != null) {
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Hope you enjoy and learn a little from how simple it is in Java to perform network requests, as well as multi-threading to create a somewhat useful application that can be easily extended to be much more useful. Hope this helps.
This is a quick example of a servlet that will tell you the size of your session. This is helpful if you don’t have the tools built into your development suite to give you this information. I found this laying around that I had written a while back. It essentially is a simple servlet that grabs all the session attributes and writes out each to a ObjectOutputStream object. It then takes the size of the ByteArrayOutputStream object contained in the ObjectOutputStream object and displays that.
public class HttpSessionSizeServlet extends HttpServlet {
private static Logger log = LogFactory.
getLogger(HttpSessionSizeServlet.class);
public void doGet(HttpServletRequest req,
HttpServletResponse resp)
throws ServletException, IOException {
HttpSession session = req.getSession();
if (session != null) {
Enumeration e = session.getAttributeNames();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream s = new ObjectOutputStream(bos);
while (e.hasMoreElements()) {
Object o = session.getAttribute((String) e.nextElement());
s.writeObject(o);
s.flush();
}
log.info("size = " + bos.size());
}
}
public void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
//do nothing
}
}
Hope this helps.
Exception handling in Struts is a very simple concept to grasp, once you know the tool that Struts has put in place to handle it. This tool is the org.apache.struts.action.ExceptionHandler . The ExceptionHandler mechanism allows you to configure it in the struts-config.xml file and then Struts will automagically pass any exception type it’s configured to handle to it at runtime. Here’s a simple example of how easy it is to create one of these classes .
package myapp.exc;
import org.apache.struts.action.ExceptionHandler;
//other struts imports
public class MyExceptionHandler extends ExceptionHandler {
public ActionForward execute( Exception ex,
ExceptionConfig exConfig,
ActionMapping mapping,
ActionForm formInstance,
HttpServletRequest request,
HttpServletResponse response
) throws ServletException {
//send email to support that something happened w/ stack trace included
//print stack trace to logs
ex.printStackTrace();
return mapping.findForward("login");
}
}
This method takes in several parameters (including the request/response objects) and returns the forward to where you want to take the user. After setting your class up, all you’ve got to do now is configure it in the struts-config.xml file. You add it to the global-exceptions section. Here’s an example of how to do that for 2 different handlers for 2 different types of exceptions.
<global-exceptions>
<exception
handler="myapp.exc.MyExceptionHandler"
key="standard.error.message"
path="/genericError.jsp"
scope="request"
type="myapp.exc.MyException"/>
<exception
handler="myapp.exc.AuthorizationExceptionHandler"
key="unauthorized.error.message"
path="/auth.jsp"
scope="request"
type="myapp.exc.AuthorizationException"/>
</global-exceptions>
As you can see, you can easily use what Struts has provided to setup a flexible declarative exception handling model for your application.
Hope this helps.
This article will tell you a fairly simple way to put a custom access control framework in place for your J2EE application that will let you integrate it with the struts framework role based access control protection mechanisms. There are a few pieces to this solution:
1. A storage mechanism for the accesses (roles) per user
2. Writing these accesses into the HttpSession per user (generally in the form of an easily accessible object with helper functions on the session)
3. Override the processRoles method of the struts RequestProcessor class in order to recognize your custom roles
4. Add roles=”…” to your struts actions to protect them based on the configured roles
Ok, in order then, here we go.
For #1 – this is usually done via a relational database – whatever application database you’re using, you’ll generally store the accesses for a given user. However, you could store these in flat files, ldap, or some other mechanism if you wanted to – that’s up to you.
For #2 – here’s an object you can use to hold the roles.
public class UserAccesses {
private String userName;
private String[] roles;
public UserAccesses(String userName, String[] roles) {
this.userName = userName;
this.roles = roles;
}
public boolean hasRole(String role) {
if (roles.length > 0) {
for (int i = 0; i < roles.length; i++) {
if (role.equals(roles[i]))
return true;
}
}
return false;
}
public String toString() {
StringBuffer sb = new StringBuffer(1024);
sb.append(userName);
sb.append(" has roles: ");
for(int i=0; i
This object stores a string array of the role names per user. Now here's some code to write this object into the session. This code should be called when the user logs into the application.
List allAccessesList = new ArrayList();
//if the user has the write stories access from the db
allAccessesList.add(Constants.WRITE_STORIES);
//if the user has the read stories access from the db
allAccessesList.add(Constants.READ_STORIES);
//if the user has the delete stories access from the db
allAccessesList.add(Constants.DELETE_STORIES);
String[] allUserAccesses =
(String[])allAccessesList.toArray(new String[0]);
UserAccesses userAccessesObj =
new UserAccesses (userId, allUserAccesses);
HttpSession session = request.getSession();
session.setAttribute(Constants.USER_SESSION_ACCESSES, userAccessesObj);
On to #3 - here you have to write a custom class that overrides the processRoles method of the RequestProcessor class in struts
public class RolesRequestProcessor extends RequestProcessor {
private static final Logger log =
LogFactory.getLog(RolesRequestProcessor.class);
public RolesRequestProcessor() {
super();
}
/**
* @see org.apache.struts.action.RequestProcessor
* #processRoles(javax.servlet.http.HttpServletRequest,
* javax.servlet.http.HttpServletResponse,
* org.apache.struts.action.ActionMapping)
*/
protected boolean processRoles(HttpServletRequest request,
HttpServletResponse response, ActionMapping mapping)
throws IOException, ServletException {
//Obtain the list of roles from action config
String roles[] = mapping.getRoleNames();
if ((roles == null) || (roles.length < 1)) {
log.debug("No role is required for running this operation.");
return (true);
}
//verify user possesses role
StringBuffer sb =
new StringBuffer("Check for required roles ....... n");
//checking in ldap roles
for (int i = 0; i < roles.length; i++) {
sb.append(roles[i]);
sb.append(", ");
if (request.isUserInRole(roles[i])) {
sb.append("Found a matching role in the ldap roles: " + roles[i]);
return (true);
}
}
// checking in custom database roles
// Check the current user against the list of required roles
HttpSession session = request.getSession();
UserAccesses userAccessesObj = (UserAccesses )
session.getAttribute(Constants.USER_SESSION_ACCESSES);
if (userAccessesObj == null) {
return false;
}
for (int i = 0; i < roles.length; i++) {
if (userAccessesObj .hasRole(roles[i])) {
sb.append("Found a matching role in the custom roles: " + roles[i]);
return (true);
}
}
//end custom roles check
//invoke declarative exception handling
sb.append("n");
sb.append("User does not have the required role");
log.debug(sb.toString() + " ");
ActionForward forward = null;
try {
forward = processException(request, response,
new my.application.AuthorizationViolationException(),
null, mapping);
} catch (Throwable e) {
e.printStackTrace();
}
// forward user to the authorization error page...
if (forward != null) {
log.info("Forward to authorization error page");
processForwardConfig(request, response, forward);
}
return (false);
}
}
Finally #4 - here you just add the roles attribute to your struts configuration in order to get struts to check for the specified role(s) (multiple roles, is just a comma-delimeted group) to allow a user to perform a given action.
<action path="/myApplication/deleteStory"
type="my.actions.DeleteStoryAction" roles="DELETE_STORIES,ADMIN">
<forward name="deleteSuccess" path="/myApplication/deleteSuccess.do" />
</action>
This process has worked very well on my projects, and hopefully will on yours as well.
Hope this helps.
This post will show you how to write the code to perform transaction handling in Java using the Spring framework. There are certainly many varied ways to handle this, but this is one that I’ve found works fairly well and tends to lead to a fairly clean code base.
The code below essentially forces the block of code all to occur within a transaction, and either causes the transaction to go through with a commit (assuming everything went well), or rolls it all back if anything failed. In this particular case, there are multiple stored procedures being called that all need to pass for the entire process to be valid. It’s true that this could all be handled in one procedure, but that could make the parameters very ugly. In this situation, I think it’s better to have multiple procedures called within one transaction in the java code.
public boolean saveUser(User user){
boolean success = false;
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
TransactionStatus status = transactionManager.getTransaction(def);
Map results = null;
try{
LinkedHashMap inputTypesMap = new LinkedHashMap();
inputTypesMap.put(Constants.USER_ID,new Integer(Types.INTEGER));
inputTypesMap.put(Constants.FIRST_NAME,new Integer(Types.VARCHAR));
inputTypesMap.put(Constants.LAST_NAME,new Integer(Types.VARCHAR));
inputTypesMap.put(Constants.PHONE_NUMBER,new Integer(Types.VARCHAR));
inputTypesMap.put(Constants.EMAIL_ADDRESS,new Integer(Types.VARCHAR));
LinkedHashMap outputTypesMap = new LinkedHashMap();
AdminStoredProcedure prc =
new AdminStoredProcedure(ds,Constants.USER_SAV_PROCEDURE_NAME,
inputTypesMap,outputTypesMap,null);
LinkedHashMap inputValuesMap = new LinkedHashMap();
inputValuesMap.put(Constants.USER_ID, user.getUserId());
inputValuesMap.put(Constants.FIRST_NAME,contact.getContactFirstName());
inputValuesMap.put(Constants.LAST_NAME,contact.getContactLastName());
inputValuesMap.put(Constants.PHONE_NUMBER,contact.getPhoneNumber());
inputValuesMap.put(Constants.EMAIL_ADDRESS,contact.getEmailAddress());
results = prc.execute(inputValuesMap);
//another procedure call, hence the need for the transaction
userService.deleteUserGroupAssociation(user.getUserId());
int[] contactGroups = user.getContactGroups();
for(int i=0; i
Hope this helps.
Java has a couple of concepts that are used as best practices in web applications that can be very useful even if you don’t intend to use them for their strict purpose. The first is a properties file and the second is internationalization (i18n – 18 letters between the i and the n).
Properties files are simple key=value files. They contain records that are in this format generally:
my.key=My Value
Internationalization is a concept that allows an application to move it’s labels of field names, descriptions, etc. to be encoded in properties files with a specific extension representing the language. These follow the 2-letter ISO 3166 country code extensions. These are very useful in web applications and allow you to extract messages at will using both manual methods as well as tag libraries.
An example of the manual method is shown below:
ResourceBundle messages = ResourceBundle.getBundle("ApplicationResources");
String adminId = messages.getString("adminuserid");
String adminPassword = messages.getString("adminpassword");
This bit of code will extract the value of the adminuserid property from the ApplicationResources.properties file and place it’s value in the adminId field, and the same with the adminPassword field.
An example of using the jstl fmt taglib in order to display a message is shown below:
<fmt:message key="label.userId"/>
This bit of code will extract the value of the label.userId property and render it on the screen.
Hope this helps.
One very useful portion of the Spring Framework is the StoredProcedure wrapper’s and the RowMapper objects. Together these allow you to call a stored procedure and then parse the result set back into a collection of objects with very little pain. Below is an example of how to do just this for a simple query like a user query.
First, we have the StoredProcedure class:
public class MyStoredProcedure extends StoredProcedure {
public MyStoredProcedure (DataSource ds, String spname,
Map map, String sqlOutKey, Integer returnType,
RowMapper rowmapper) {
super();
setDataSource(ds);
/* resultset has to be declared first over other declare parameters */
if (rowmapper != null) {
declareParameter(new SqlReturnResultSet(sqlOutKey, rowmapper));
}
if (map != null) {
Iterator itr = map.keySet().iterator();
while (itr.hasNext()) {
String key = (String) itr.next();
Integer value = (Integer) map.get(key);
declareParameter(new SqlParameter(key, value.intValue()));
}
}
/*
* sql out paramter has to be declared based on the order in stored
* procedures, In all our stored procedures we have it after input
* parameters
*/
if (returnType != null) {
declareParameter(new SqlOutParameter(sqlOutKey, returnType
.intValue()));
}
setSql(spname);
compile();
}
}
Next, we have the Mapper class:
public class UserMapper implements RowMapper {
public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
User user = new User();
user.setUserId(rs.getString(Constants.USER_ID));
user.setFirstName(rs.getString(Constants.FIRST_NAME));
user.setLastName(rs.getString(Constants.LAST_NAME));
user.setOrganizationName(rs.getString(Constants.ORGANIZATION_NAME));
return user;
}
}
Next, we have to query the actual stored procedure from a DAO. Here’s a sample method that would do just such a thing:
public Collection searchUsers(User user) throws Exception {
Map lhm = new LinkedHashMap(4);
lhm.put(Constants.USER_ID, new Integer(Types.VARCHAR));
lhm.put(Constants.FIRST_NAME,new Integer(Types.VARCHAR));
lhm.put(Constants.LAST_NAME,new Integer(Types.VARCHAR));
lhm.put(Constants.ORGANIZATION_NAME,new Integer(Types.VARCHAR));
UserMapper mapper = new UserMapper();
// Call Stored Procedure
EntitlementsStoredProcedure proc = new EntitlementsStoredProcedure(
ds, StoredProcedureConstants.USER_SEL, lhm,
Constants.RESULTSET, null, mapper);
// Collect the criteria for the search
Map map = new LinkedHashMap(4);
map.put(Constants.USER_ID, user.getUserId());
map.put(Constants.FIRST_NAME, user.getFirstName());
map.put(Constants.LAST_NAME, user.getLastName());
map.put(Constants.ORGANIZATION_NAME, user.getOrganizationName());
Map results = proc.execute(map);
List resultList = (LinkedList)results.get(Constants.RESULTSET);
//iterate of results list and print
for (Iterator it=resultList.iterator(); it.hasNext(); ) {
User user1 = (User)it.next();
System.out.println(user1);
}
return resultList;
}
That’s all there is to it! This shows just how simple it is to do queries in an object oriented way, and have generic row mappers. There are full object relational mapping solutions, such as Hibernate, that do a great job of solving the working with relational data in an OO way paradigm, but they take a LOT of configuration and can be daunting if you’re not accustomed to working with them. This solution, however, I feel works very well in simpler scenarios. It also allows someone who is used to looking at code to quickly read through and get an idea of how to use this.
One point to note: this gets even simpler when using generics that are introduced in Java 1.5, but the environment I’m currently in is 1.4, so forgive me. I’ll leave the translation as an exercise for the reader.
Enjoy! Hope this helps!