It’s not the first time, and sadly it won’t be the last, that I’ve had to work behind a paranoid firewall. I can understand an enterprise concern with regular employees surfing the web unrestrained (I’ve seen computers rendered almost useless from large infestations of virus, malware and other things I’d rather not mention). But developers? Please...
At my last gig there was no access to any cloud storage service. None? Really? That’s what they thought, any geek could find a way to export data, even with USB ports disabled! But restricting cloud storage makes sense, you limit potentially dangerous traffic which you must monitor.
But restricting access to social networks, blogs, etc? What year is this? Don’t these people know we live in an ever-changing environment? What are they trying to accomplish with these restrictions? Maybe this? Or this? I’m confused...
In order to keep our knowledge sharp we need to access developer communities, blogs, forums, custom libraries, etc... We need to interact with other developers so that we can learn from them. That includes chatting with them, sending them emails with code snippets, hearing their issues and trying to resolve them...
My last blog post is a perfect example, I finished it with a question: “How do you mock all dependencies of a unit under test without dependency injection?” I thought there was no answer but, after no more than 3 hours of being published, +Maarten Seghers gave me a great solution to my problem.
Had I been able to reach the hive-mind before, my productivity would have skyrocketed. But no, I was behind a paranoid firewall. Let me finish with another question: If an employer doesn’t trust their IT experts, why did it hire them in the first place?
Class Found Exception
A Spaniard computer engineer talking about his work
2013/03/11
2013/02/28
The importance of SOLID principles
I don't know why it’s not a common practice in my country to apply engineering principles to software development. It's shocking that practically every project manager and programmer I've met thinks that engineering principles are merely an academic matter and, in real life, it’s more important to sprint to deadlines than to waste resources designing the product and applying good development practices. What baffles me is that all those projects I've found where the team didn't follow such principles had a lot of trouble meeting deadlines because adding features became increasingly harder without having to break something already built in. And those involved never even realized why this was. It’s really simple, big projects are more like a marathon than a 100-metre dash, so you can’t be sprinting all the time without losing your breath and failing to keep the required pace in order to arrive on time.
For example, on my most recent project, the team lost their way and eventually dropped almost every good development practice they had started with. When I arrived during the third year of the project, I tried, as always, to produce quality code despite the project manager’s lack of interest on that matter. I managed to DRY the code, introduce test-driven development, create integration tests and came close to applying every single one of the SOLID principles to all my work... all except the last letter (yes, my code was only SOLI). Due the design of the factories that we used I wasn't able to comply with the dependency injection principle. Ok, it didn't matter... Actually it was a pretty good achievement to have improved the product quality, even when that wasn’t my boss’ primary concern, while all my deadlines were being met... Attaboy!
Everything was going smoothly, but when the number of my automatic tests started to grow I started foreseeing some problems: a good portion of my tests overlapped, so the execution time was not optimal for their code coverage; and almost all of them modified the database’s content which caused a deterioration of performance and readability because I had to insert data for the tests and clean up after their execution.
Solution? Mock all DAOs and other dependencies in order to improve the tests’ readability and performance. But how do you mock all dependencies of a unit under test without dependency injection?
Attaboy! :(
For example, on my most recent project, the team lost their way and eventually dropped almost every good development practice they had started with. When I arrived during the third year of the project, I tried, as always, to produce quality code despite the project manager’s lack of interest on that matter. I managed to DRY the code, introduce test-driven development, create integration tests and came close to applying every single one of the SOLID principles to all my work... all except the last letter (yes, my code was only SOLI). Due the design of the factories that we used I wasn't able to comply with the dependency injection principle. Ok, it didn't matter... Actually it was a pretty good achievement to have improved the product quality, even when that wasn’t my boss’ primary concern, while all my deadlines were being met... Attaboy!
Everything was going smoothly, but when the number of my automatic tests started to grow I started foreseeing some problems: a good portion of my tests overlapped, so the execution time was not optimal for their code coverage; and almost all of them modified the database’s content which caused a deterioration of performance and readability because I had to insert data for the tests and clean up after their execution.
Solution? Mock all DAOs and other dependencies in order to improve the tests’ readability and performance. But how do you mock all dependencies of a unit under test without dependency injection?
Attaboy! :(
2012/04/20
How to secure a Struts 1.3 application
Welcome to my first tutorial!
In this tutorial I will show you how to secure a Struts 1.3.8 web application with servlet filters. Basic knowledge of Struts is required to fully understand this article. Numerous HelloWorld tutorials are available using search engines, such Google, and any of them should be completely understood before starting this manual.
Why using servlet filters? Because is the only way of implementing access restrictions to methods, actions, and jsp files without changing the code of those methods, actions or jsp. This way we can centralize all the security aspect of our application on a few resources (filters and web.xml). Another alternatives that centralize the security aspect of our web application are provided combining Struts with other frameworks such as Spring Security.
In this example, we want to separate our users in two main categories: administrators and normal users. Normal users will, obviously, access to the user panel while administrators will have access also to the administration panel. It is because of this that administrator users will have two roles: “admin” and “user”.
The plan is to allow any anonymous user to access only to the login action (or login jsp). Any other request has to be performed by an user with the correct rights to do so. In order to accomplish this we will separate the administrator’s actions and resources and place all of them in the “admin” directory. Same thing with the user’s action and resources that will live in the “user” directory. We will place a filter for each directory that will intercept all the request on these resources and check for the security credentials of the user making the request.
Let’s take a look into the User class:
As we can see, each user has a collection of roles and a method to check if a specific role is owned by the user. When a user logs in, the User object will be stored in the session object:
Now we can create an filter with the mission of intercepting all the requests to a private area of our application and check if the user logged has the permission to perform the request.
Because AuthorizationFilter is a child of javax.servlet.Filter it has to implement the init(), doFilter() and destroy() methods. Inside init() we will process the initial parameters (defined at web.xml) and prepare them for future use. Two parameters are used by this filter: roles and onError. The roles parameter stores a list of role names separated by one space. The onError parameter stores a path to the jsp file to redirect the client browser in case of the user doing the the request has not the right credentials.
As you can see, doFilter() will take an object User from the session, if it can’t find an User, doFilter() will deny the petition. If an user has logged in the application, doFilter() will check if he has the right role to access the resource (or one of them). If not it will deny the petition with a specific answer.
Let’s see how the filter is set up in web.xml.
We’ve set up two different AuthorizationFilters, one will protect all files under the directory /admin/ and restrict their access to users who have the role admin. The other will do the same for all the files placed under /user/ requiring the user role to access them. If the authentication fails, user will be redirected to /login.jsp.
One alternative of implementing the role restriction is to add to the userAccessFilter another role as follows:
That way we won’t need to add various roles to an administrator user, who previously had both user and admin roles. Both approaches are valid, you should implement whichever is more appropriate to your project.
But how we display error information? As you can see, if AuthorizationFilter fails it will redirect the user to /login.jsp (as seen in web.xml) adding the errors to the request object (as seen in AuthorizationFilter.java). Errors will be displayed using a message resource bundle through a key.
The key “error.authentication.required” is a reference to a message located in a properties file:
As you can see there is a collection of keys (errors.header, errors.footer, errors.prefix, errors.suffix) which allows to change the way the errors will be displayed.
This application.properties is set in struts-config.xml including its path:
As you can see, struts-config.xml maps all the actions of users and administrators under the protected directories.
Finally, login.jsp will have to display the errors using the struts html tag “errors” as follows:
You can find an example of this tutorial here.
References:
In this tutorial I will show you how to secure a Struts 1.3.8 web application with servlet filters. Basic knowledge of Struts is required to fully understand this article. Numerous HelloWorld tutorials are available using search engines, such Google, and any of them should be completely understood before starting this manual.
Why using servlet filters? Because is the only way of implementing access restrictions to methods, actions, and jsp files without changing the code of those methods, actions or jsp. This way we can centralize all the security aspect of our application on a few resources (filters and web.xml). Another alternatives that centralize the security aspect of our web application are provided combining Struts with other frameworks such as Spring Security.
In this example, we want to separate our users in two main categories: administrators and normal users. Normal users will, obviously, access to the user panel while administrators will have access also to the administration panel. It is because of this that administrator users will have two roles: “admin” and “user”.
The plan is to allow any anonymous user to access only to the login action (or login jsp). Any other request has to be performed by an user with the correct rights to do so. In order to accomplish this we will separate the administrator’s actions and resources and place all of them in the “admin” directory. Same thing with the user’s action and resources that will live in the “user” directory. We will place a filter for each directory that will intercept all the request on these resources and check for the security credentials of the user making the request.
Let’s take a look into the User class:
User.java |
package com.jml.tutorial.secure.model;
import java.util.Arrays; import java.util.Collection; public class User { private String username; private Collection<String> roles; public User(String username, String[] roles) { super(); this.username = username; this.roles = Arrays.asList(roles); } public boolean hasRole(String role) { return roles.contains(role); } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String[] getRoles() { return (String[]) roles.toArray(); } public void setRoles(String[] roles) { this.roles = Arrays.asList(roles); } } |
As we can see, each user has a collection of roles and a method to check if a specific role is owned by the user. When a user logs in, the User object will be stored in the session object:
LoginAction.java |
package com.jml.tutorial.secure.action;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.struts.Globals; import org.apache.struts.action.ActionErrors; import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionForward; import org.apache.struts.action.ActionMapping; import org.apache.struts.action.ActionMessage; import com.jml.tutorial.secure.bussiness.LoginBO; import com.jml.tutorial.secure.form.LoginForm; import com.jml.tutorial.secure.model.User; public class LoginAction extends BaseAction { public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { LoginForm loginForm = (LoginForm) form; LoginBO loginBO = new LoginBO(); String username = loginForm.getUsername(); if (loginBO.checkLogin(username, loginForm.getPassword())) { User user = loginBO.getUser(username); request.getSession().setAttribute("user", user); if (user.hasRole("admin")) return findForwardAdminSuccess(mapping); else return findForwardUserSuccess(mapping); } ActionErrors errors = new ActionErrors(); errors.add(ActionErrors.GLOBAL_MESSAGE, new ActionMessage( "error.authorization.invalid")); request.setAttribute(Globals.ERROR_KEY, errors); return findForwardFailure(mapping); } } |
Now we can create an filter with the mission of intercepting all the requests to a private area of our application and check if the user logged has the permission to perform the request.
AuthorizationFilter.java |
package com.jml.tutorial.secure.security;
import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.apache.struts.Globals; import org.apache.struts.action.ActionErrors; import org.apache.struts.action.ActionMessage; import com.jml.tutorial.secure.model.User; public class AuthorizationFilter implements Filter { private String[] roleNames; private String onErrorUrl; public void init(FilterConfig arg0) throws ServletException { String roles = arg0.getInitParameter("roles"); if (roles == null || "".equals(roles)) roleNames = new String[0]; else { roles.trim(); roleNames = roles.split(" "); } onErrorUrl = arg0.getInitParameter("onError"); if (onErrorUrl == null || "".equals(onErrorUrl)) onErrorUrl = "/index.jsp"; } public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) arg0; HttpServletResponse res = (HttpServletResponse) arg1; HttpSession session = req.getSession(); User user = (User) session.getAttribute("user"); ActionErrors errors = new ActionErrors(); if (user == null) errors.add(ActionErrors.GLOBAL_MESSAGE, new ActionMessage("error.authentication.required")); else { boolean hasRole = false; for (int i=0; i < roleNames.length; i++) { if (user.hasRole(roleNames[i])) { hasRole = true; break; } } if (!hasRole) errors.add(ActionErrors.GLOBAL_MESSAGE, new ActionMessage( "error.authorization.nopermission", user.getUsername())); } if (errors.isEmpty()) arg2.doFilter(arg0, arg1); else { req.setAttribute(Globals.ERROR_KEY, errors); req.getRequestDispatcher(onErrorUrl).forward(req, res); } } public void destroy() { } } |
Because AuthorizationFilter is a child of javax.servlet.Filter it has to implement the init(), doFilter() and destroy() methods. Inside init() we will process the initial parameters (defined at web.xml) and prepare them for future use. Two parameters are used by this filter: roles and onError. The roles parameter stores a list of role names separated by one space. The onError parameter stores a path to the jsp file to redirect the client browser in case of the user doing the the request has not the right credentials.
As you can see, doFilter() will take an object User from the session, if it can’t find an User, doFilter() will deny the petition. If an user has logged in the application, doFilter() will check if he has the right role to access the resource (or one of them). If not it will deny the petition with a specific answer.
Let’s see how the filter is set up in web.xml.
web.xml |
<?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_2_5.xsd" id="WebApp_ID" version="2.5"> <display-name>HowTo Security</display-name> <filter> <filter-name>userAccessFilter</filter-name> <filter-class> com.jml.tutorial.secure.security.AuthorizationFilter </filter-class> <init-param> <param-name>roles</param-name> <param-value>user</param-value> </init-param> <init-param> <param-name>onError</param-name> <param-value>/login.jsp</param-value> </init-param> </filter> <filter> <filter-name>adminAccessFilter</filter-name> <filter-class> com.jml.tutorial.secure.security.AuthorizationFilter </filter-class> <init-param> <param-name>roles</param-name> <param-value>admin</param-value> </init-param> <init-param> <param-name>onError</param-name> <param-value>/login.jsp</param-value> </init-param> </filter> <filter-mapping> <filter-name>userAccessFilter</filter-name> <url-pattern>/user/*</url-pattern> </filter-mapping> <filter-mapping> <filter-name>adminAccessFilter</filter-name> <url-pattern>/admin/*</url-pattern> </filter-mapping> <servlet> <servlet-name>action</servlet-name> <servlet-class> org.apache.struts.action.ActionServlet </servlet-class> <init-param> <param-name>config</param-name> <param-value> /WEB-INF/struts/struts-config.xml </param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>action</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app> |
We’ve set up two different AuthorizationFilters, one will protect all files under the directory /admin/ and restrict their access to users who have the role admin. The other will do the same for all the files placed under /user/ requiring the user role to access them. If the authentication fails, user will be redirected to /login.jsp.
One alternative of implementing the role restriction is to add to the userAccessFilter another role as follows:
web.xml |
...
<filter> <filter-name>userAccessFilter</filter-name> <filter-class> com.hgro.beta.security.AuthorizationFilter </filter-class> <init-param> <param-name>roles</param-name> <param-value>user admin</param-value> </init-param> ... |
That way we won’t need to add various roles to an administrator user, who previously had both user and admin roles. Both approaches are valid, you should implement whichever is more appropriate to your project.
But how we display error information? As you can see, if AuthorizationFilter fails it will redirect the user to /login.jsp (as seen in web.xml) adding the errors to the request object (as seen in AuthorizationFilter.java). Errors will be displayed using a message resource bundle through a key.
AuthorizationFilter.java |
...
errors.add(ActionErrors.GLOBAL_MESSAGE, new ActionMessage("error.authentication.required")); ... |
The key “error.authentication.required” is a reference to a message located in a properties file:
application.properties |
################# ERRORS ###########################
#STYLE errors.header = <div style="color:red;"><ul> errors.footer = </ul></div> errors.prefix = <li> errors.suffix = </li> #SECURITY error.authentication.required = You have no permission to access this resource. error.authorization.nopermission = You ({0}) have no permission to access this resource. |
As you can see there is a collection of keys (errors.header, errors.footer, errors.prefix, errors.suffix) which allows to change the way the errors will be displayed.
This application.properties is set in struts-config.xml including its path:
struts-config.xml |
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.3//EN" "http://jakarta.apache.org/struts/dtds/struts-config_1_3.dtd"> <struts-config> <form-beans> <form-bean name="loginForm" type="com.hgro.beta.form.LoginForm"/> </form-beans> <action-mappings> <action path="/login" type="com.hgro.beta.action.LoginAction" name="loginForm" input="/login.jsp" scope="request" validate="true"> <forward name="adminsuccess" path="/admin/menu.jsp"/> <forward name="usersuccess" path="/user/menu.jsp"/> <forward name="failure" path="/login.jsp"/> </action> <action path="/welcome" forward="/login.jsp" /> <action path="/user/menu" forward="/user/menu.jsp" /> <action path="/admin/menu" forward="/admin/menu.jsp" /> </action-mappings> <message-resources parameter="com.jml.tutorial.application" /> </struts-config> |
As you can see, struts-config.xml maps all the actions of users and administrators under the protected directories.
Finally, login.jsp will have to display the errors using the struts html tag “errors” as follows:
login.jsp |
You can find an example of this tutorial here.
References:
Subscribe to:
Posts (Atom)