|
Recipe 11.4. Restricting Actions by RoleProblemYou want to allow a user to access an action if that user has a specific role. SolutionUse the roles attribute of the action element to specify the roles that are permitted to use the action: <!-- Display all users --> <action path="/ViewUsers" forward="/view_users.jsp" roles="manager,sysadmin" /> DiscussionStruts actions, configured via the action element in the struts-config.xml file, can be restricted to certain roles using the roles attribute. This attribute accepts a comma-separated list of role names. When a request is received for the action, the RequestProcessor.processRoles( ) method checks that the user has at least one of the roles specified. If the user doesn't have one of the roles, the HTTP 403 error (Forbidden) is sent; otherwise, processing continues normally. Here is the processRoles( ) method from the Struts RequestProcessor: protected boolean processRoles( HttpServletRequest request, HttpServletResponse response, ActionMapping mapping ) throws IOException, ServletException { // Is this action protected by role requirements? String roles[] = mapping.getRoleNames( ); if ((roles == null) || (roles.length < 1)) { return (true); } // Check the current user against the list of required roles for (int i = 0; i < roles.length; i++) { if ( request.isUserInRole(roles[i]) ) { if (log.isDebugEnabled( )) { log.debug(" User '" + request.getRemoteUser( ) + "' has role '" + roles[i] + "', granting access"); } return (true); } } // The current user is not authorized for this action if (log.isDebugEnabled( )) { log.debug(" User '" + request.getRemoteUser( ) + "' does not have any required role, denying access"); } response.sendError( HttpServletResponse.SC_FORBIDDEN, getInternal( ).getMessage("notAuthorized", mapping.getPath( ))); return (false); } The Struts RequestProcessor determines if a user has a role using the HttpServletRequest.isUserInRole( ) method. This method can only be used if you are using container-managed security (or if you use a Solution such as the one in Recipe 11.10). For application-managed security, you can create your own custom RequestProcessor that overrides the processRoles method. In Example 11-7, the processRoles( ) method retrieves a User object from the HTTP session. Then, the hasRole( ) method is called on this object to determine if the user has at least one of the required roles. Example 11-7. Custom role-handling RequestProcessorpackage com.oreilly.strutsckbk.ch11; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.*; import org.apache.struts.action.*; import org.apache.struts.webapp.example.User; public class RoleRequestProcessor extends RequestProcessor { protected boolean processRoles( HttpServletRequest request, HttpServletResponse response, ActionMapping mapping ) throws IOException, ServletException { // Is this action protected by role requirements? If not, return true. String roles[] = mapping.getRoleNames( ); if ((roles == null) || (roles.length < 1)) { return true; } // Check the current user against the list of required roles HttpSession session = request.getSession( ); User user = (User) session.getAttribute("user"); if (user == null) { return false; } for (int i = 0; i < roles.length; i++) { if (user.hasRole(roles[i])) { return (true); } } // The user does not have one of the roles; send an error response.sendError( HttpServletResponse.SC_BAD_REQUEST, getInternal( ).getMessage("notAuthorized", mapping.getPath( ))); return (false); } } This custom request processor is deployed using the controller element in the struts-config.xml file: <controller processor/> The customization, shown in Example 11-7, used to code the processRoles( ) method to perform checks can be as complex as you want. You have complete access to the servlet request and response, servlet context, HTTP session, and the ActionMapping.
See AlsoYou can learn about additional RequestProcessor methods in the Struts User's Guide "Controller" section at http://struts.apache.org/userGuide/building_controller.html. If you want to implement container-managed security for your application, see Recipe 11.9. |
|