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();
+ }
+}