Author: mrdon Date: Thu Oct 12 15:14:48 2006 New Revision: 463463 URL: http://svn.apache.org/viewvc?view=rev&rev=463463 Log: Adding a roles interceptor that lets you restrict access to actions via role WW-1469
Added: struts/struts2/trunk/core/src/main/java/org/apache/struts2/interceptor/RolesInterceptor.java struts/struts2/trunk/core/src/test/java/org/apache/struts2/interceptor/RolesInterceptorTest.java Modified: struts/struts2/trunk/core/src/main/resources/struts-default.xml Added: struts/struts2/trunk/core/src/main/java/org/apache/struts2/interceptor/RolesInterceptor.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/java/org/apache/struts2/interceptor/RolesInterceptor.java?view=auto&rev=463463 ============================================================================== --- struts/struts2/trunk/core/src/main/java/org/apache/struts2/interceptor/RolesInterceptor.java (added) +++ struts/struts2/trunk/core/src/main/java/org/apache/struts2/interceptor/RolesInterceptor.java Thu Oct 12 15:14:48 2006 @@ -0,0 +1,151 @@ +/* + * $Id: ScopeInterceptor.java 451544 2006-09-30 05:38:02Z mrdon $ + * + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.struts2.interceptor; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import com.opensymphony.xwork2.ActionInvocation; +import com.opensymphony.xwork2.interceptor.AbstractInterceptor; + +import org.apache.struts2.ServletActionContext; + +/** + * <!-- START SNIPPET: description --> This interceptor ensures that the action + * will only be executed if the user has the correct role. <!-- + * END SNIPPET: description --> + * + * <p/> <u>Interceptor parameters:</u> + * + * <!-- START SNIPPET: parameters --> + * + * <ul> + * + * <li>allowedRoles - a comma-separated list of roles to allow</li> + * + * <li>disallowedRoles - a comma-separated list of roles to disallow</li> + * + * </ul> + * + * <!-- END SNIPPET: parameters --> + * + * <!-- START SNIPPET: extending --> There are two extensions to the + * existing interceptor: + * <ul> + * <li>isAllowed(HttpServletRequest,Object) - whether or not to allow + * the passed action execution with this request</li> + * <li>handleRejection(ActionInvocation) - handles an unauthorized + * request.</li> + * </ul> + * <!-- END SNIPPET: extending --> + * + * <pre> + * <!-- START SNIPPET: example --> + * <!-- only allows the admin and member roles --> + * <action name="someAction" class="com.examples.SomeAction"> + * <interceptor-ref name="completeStack"/> + * <interceptor-ref name="roles"> + * <param name="allowedRoles">admin,member</param> + * </interceptor-ref> + * <result name="success">good_result.ftl</result> + * </action> + * <!-- END SNIPPET: example --> + * </pre> + */ +public class RolesInterceptor extends AbstractInterceptor { + + private List<String> allowedRoles = new ArrayList<String>(); + private List<String> disallowedRoles = new ArrayList<String>(); + + public void setAllowedRoles(String roles) { + this.allowedRoles = stringToList(roles); + } + + public void setDisallowedRoles(String roles) { + this.disallowedRoles = stringToList(roles); + } + + public String intercept(ActionInvocation invocation) throws Exception { + HttpServletRequest request = ServletActionContext.getRequest(); + HttpServletResponse response = ServletActionContext.getResponse(); + String result = null; + if (!isAllowed(request, invocation.getAction())) { + result = handleRejection(invocation, response); + } else { + result = invocation.invoke(); + } + return result; + } + + /** + * Splits a string into a List + */ + protected List<String> stringToList(String val) { + if (val != null) { + String[] list = val.split("[ ]*,[ ]*"); + return Arrays.asList(list); + } else { + return Collections.EMPTY_LIST; + } + } + + /** + * Determines if the request should be allowed for the action + * + * @param request The request + * @param action The action object + * @return True if allowed, false otherwise + */ + protected boolean isAllowed(HttpServletRequest request, Object action) { + if (allowedRoles.size() > 0) { + boolean result = false; + for (String role : allowedRoles) { + if (request.isUserInRole(role)) { + result = true; + } + } + return result; + } else if (disallowedRoles.size() > 0) { + for (String role : disallowedRoles) { + if (request.isUserInRole(role)) { + return false; + } + } + } + return true; + } + + /** + * Handles a rejection by sending a 403 HTTP error + * + * @param invocation The invocation + * @return The result code + * @throws Exception + */ + protected String handleRejection(ActionInvocation invocation, + HttpServletResponse response) + throws Exception { + response.sendError(HttpServletResponse.SC_FORBIDDEN); + return null; + } +} Modified: struts/struts2/trunk/core/src/main/resources/struts-default.xml URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/resources/struts-default.xml?view=diff&rev=463463&r1=463462&r2=463463 ============================================================================== --- struts/struts2/trunk/core/src/main/resources/struts-default.xml (original) +++ struts/struts2/trunk/core/src/main/resources/struts-default.xml Thu Oct 12 15:14:48 2006 @@ -48,6 +48,7 @@ <interceptor name="store" class="org.apache.struts2.interceptor.MessageStoreInterceptor" /> <interceptor name="checkbox" class="org.apache.struts2.interceptor.CheckboxInterceptor" /> <interceptor name="profiling" class="org.apache.struts2.interceptor.ProfilingActivationInterceptor" /> + <interceptor name="roles" class="org.apache.struts2.interceptor.RolesInterceptor" /> <!-- Basic stack --> <interceptor-stack name="basicStack"> Added: struts/struts2/trunk/core/src/test/java/org/apache/struts2/interceptor/RolesInterceptorTest.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/test/java/org/apache/struts2/interceptor/RolesInterceptorTest.java?view=auto&rev=463463 ============================================================================== --- struts/struts2/trunk/core/src/test/java/org/apache/struts2/interceptor/RolesInterceptorTest.java (added) +++ struts/struts2/trunk/core/src/test/java/org/apache/struts2/interceptor/RolesInterceptorTest.java Thu Oct 12 15:14:48 2006 @@ -0,0 +1,83 @@ +/* + * $Id: FileUploadInterceptorTest.java 441909 2006-09-10 05:28:16Z mrdon $ + * + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.struts2.interceptor; + +import java.util.List; + +import org.apache.struts2.StrutsTestCase; + +import com.mockobjects.servlet.MockHttpServletRequest; +import com.mockobjects.servlet.MockHttpServletResponse; + +public class RolesInterceptorTest extends StrutsTestCase { + + private RolesInterceptor interceptor = new RolesInterceptor(); + + public void setUp() throws Exception { + super.setUp(); + interceptor = new RolesInterceptor(); + } + + public void testStringToList() { + List list = interceptor.stringToList("foo"); + assertNotNull(list); + assertEquals(1, list.size()); + + list = interceptor.stringToList("foo,bar"); + assertEquals(2, list.size()); + assertEquals("foo", (String)list.get(0)); + + list = interceptor.stringToList("foo, bar"); + assertEquals(2, list.size()); + assertEquals("bar", (String)list.get(1)); + + list = interceptor.stringToList("foo , bar"); + assertEquals(2, list.size()); + assertEquals("bar", (String)list.get(1)); + } + + public void testIsAllowed() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest() { + public boolean isUserInRole(String role) { + return "admin".equals(role); + } + }; + interceptor.setAllowedRoles("admin"); + assertTrue(interceptor.isAllowed(request, null)); + + interceptor.setAllowedRoles("bar, admin"); + assertTrue(interceptor.isAllowed(request, null)); + + interceptor.setAllowedRoles(null); + assertTrue(interceptor.isAllowed(request, null)); + + interceptor.setDisallowedRoles("bar"); + assertTrue(interceptor.isAllowed(request, null)); + + interceptor.setDisallowedRoles("bar, admin"); + assertTrue(!interceptor.isAllowed(request, null)); + + } + + public void testHandleRejection() throws Exception { + MockHttpServletResponse response = new MockHttpServletResponse(); + response.setExpectedError(response.SC_FORBIDDEN); + interceptor.handleRejection(null, response); + response.verify(); + } +}