You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@wookie.apache.org by sc...@apache.org on 2011/11/18 18:38:54 UTC
svn commit: r1203763 - in /incubator/wookie/trunk:
src-tests/org/apache/wookie/tests/proxy/ src/
src/org/apache/wookie/controller/ src/org/apache/wookie/proxy/
Author: scottbw
Date: Fri Nov 18 17:38:53 2011
New Revision: 1203763
URL: http://svn.apache.org/viewvc?rev=1203763&view=rev
Log:
First part of committing update to policy management; See WOOKIE-292. This commit adds the new policy framework.
Added:
incubator/wookie/trunk/src-tests/org/apache/wookie/tests/proxy/
incubator/wookie/trunk/src-tests/org/apache/wookie/tests/proxy/PoliciesTest.java
incubator/wookie/trunk/src-tests/org/apache/wookie/tests/proxy/PolicyTest.java
incubator/wookie/trunk/src/org/apache/wookie/controller/PoliciesController.java
incubator/wookie/trunk/src/org/apache/wookie/proxy/Policies.java
incubator/wookie/trunk/src/org/apache/wookie/proxy/Policy.java
incubator/wookie/trunk/src/org/apache/wookie/proxy/PolicyFormatException.java
incubator/wookie/trunk/src/policies
Removed:
incubator/wookie/trunk/src/org/apache/wookie/controller/WhiteListController.java
incubator/wookie/trunk/src/org/apache/wookie/controller/WidgetAccessRequestPolicyController.java
Modified:
incubator/wookie/trunk/src/org/apache/wookie/proxy/ProxyServlet.java
Added: incubator/wookie/trunk/src-tests/org/apache/wookie/tests/proxy/PoliciesTest.java
URL: http://svn.apache.org/viewvc/incubator/wookie/trunk/src-tests/org/apache/wookie/tests/proxy/PoliciesTest.java?rev=1203763&view=auto
==============================================================================
--- incubator/wookie/trunk/src-tests/org/apache/wookie/tests/proxy/PoliciesTest.java (added)
+++ incubator/wookie/trunk/src-tests/org/apache/wookie/tests/proxy/PoliciesTest.java Fri Nov 18 17:38:53 2011
@@ -0,0 +1,170 @@
+/*
+ *
+ * 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.wookie.tests.proxy;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.net.URISyntaxException;
+
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.wookie.proxy.Policies;
+import org.apache.wookie.proxy.PolicyFormatException;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * Tests Policies
+ */
+public class PoliciesTest {
+
+ @BeforeClass
+ public static void setUp() throws ConfigurationException, PolicyFormatException{
+ //
+ // Clear existing
+ //
+ Policies.getInstance().clear();
+ assertEquals(0, Policies.getInstance().getPolicies().length);
+
+ //
+ // Add a couple of other policies to test with
+ //
+ Policies.getInstance().addPolicy("http://incubator.apache.org/wookie/widgets/test2 http://allowed.com DENY");
+ Policies.getInstance().addPolicy("http://incubator.apache.org/wookie/widgets/test http://*.apache.org ALLOW");
+ Policies.getInstance().addPolicy("http://incubator.apache.org/wookie/widgets/test2 http://test.com:9000 ALLOW");
+ Policies.getInstance().addPolicy("http://incubator.apache.org/wookie/widgets/test2 http://test2.com DENY");
+ Policies.getInstance().addPolicy("http://incubator.apache.org/wookie/widgets/test2 http://*.test3.com DENY");
+ Policies.getInstance().addPolicy("* http://allowed.com ALLOW");
+ Policies.getInstance().addPolicy("* http://notallowed.com DENY");
+ Policies.getInstance().addPolicy("http://www.getwookie.org/widgets/weather http://newsrss.bbc.co.uk:80 ALLOW");
+
+ assertEquals(8, Policies.getInstance().getPolicies().length);
+ }
+
+ @Test
+ public void validUrl() throws URISyntaxException, ConfigurationException{
+ assertTrue(Policies.getInstance().validate("http://abc.apache.org", "http://incubator.apache.org/wookie/widgets/test"));
+ }
+
+ @Test
+ public void invalidUrl() throws URISyntaxException, ConfigurationException{
+ assertFalse(Policies.getInstance().validate("http://abc.invalid.org", "http://incubator.apache.org/wookie/widgets/test"));
+ }
+
+ @Test
+ public void invalidPort() throws URISyntaxException, ConfigurationException{
+ assertFalse(Policies.getInstance().validate("http://test.com:9001", "http://incubator.apache.org/wookie/widgets/test2"));
+ }
+
+ @Test
+ public void validPort() throws URISyntaxException, ConfigurationException{
+ assertTrue(Policies.getInstance().validate("http://test.com:9000", "http://incubator.apache.org/wookie/widgets/test2"));
+ }
+
+ @Test
+ public void globals() throws URISyntaxException, ConfigurationException{
+ assertTrue(Policies.getInstance().validate("http://allowed.com", "http://incubator.apache.org/wookie/widgets/test"));
+ }
+
+ @Test
+ public void globals2() throws URISyntaxException, ConfigurationException{
+ assertFalse(Policies.getInstance().validate("http://notallowed.com", "http://incubator.apache.org/wookie/widgets/test"));
+ }
+
+ @Test
+ public void override() throws URISyntaxException, ConfigurationException{
+ assertFalse(Policies.getInstance().validate("http://allowed.com", "http://incubator.apache.org/wookie/widgets/test2"));
+ }
+
+ @Test
+ public void validSubdomain() throws URISyntaxException, ConfigurationException{
+ assertTrue(Policies.getInstance().validate("http://zzz.apache.org", "http://incubator.apache.org/wookie/widgets/test"));
+ }
+
+ @Test
+ public void invalidSubdomain() throws URISyntaxException, ConfigurationException{
+ assertFalse(Policies.getInstance().validate("http://zzz.allowed.com", "http://incubator.apache.org/wookie/widgets/test"));
+ }
+
+
+ @Test
+ public void invalidSubdomain2() throws URISyntaxException, ConfigurationException{
+ assertFalse(Policies.getInstance().validate("http://abc.test3.com", "http://incubator.apache.org/wookie/widgets/test2"));
+ }
+
+ @Test(expected = URISyntaxException.class)
+ public void badURI() throws URISyntaxException, ConfigurationException{
+ Policies.getInstance().validate("zzzzz", "http://incubator.apache.org/wookie/widgets/test");
+ }
+ @Test(expected = URISyntaxException.class)
+ public void badURI2() throws URISyntaxException, ConfigurationException{
+ Policies.getInstance().validate("test:", "http://incubator.apache.org/wookie/widgets/test");
+ }
+ @Test(expected = URISyntaxException.class)
+ public void badURI3() throws URISyntaxException, ConfigurationException{
+ Policies.getInstance().validate("not:really:valid", "http://incubator.apache.org/wookie/widgets/test");
+ }
+ @Test(expected = URISyntaxException.class)
+ public void badURI4() throws URISyntaxException, ConfigurationException{
+ Policies.getInstance().validate("/test", "http://incubator.apache.org/wookie/widgets/test");
+ }
+
+ @Test
+ public void addAndDeletePolicy() throws ConfigurationException, URISyntaxException, PolicyFormatException{
+ //
+ // Add a new policy and test
+ //
+ Policies.getInstance().addPolicy("* http://temp.org ALLOW");
+ assertTrue(Policies.getInstance().validate("http://temp.org", "http://incubator.apache.org/wookie/widgets/test"));
+ //
+ // Delete the policy and test again
+ //
+ Policies.getInstance().removePolicy("* http://temp.org ALLOW");
+ assertFalse(Policies.getInstance().validate("http://temp.org", "http://incubator.apache.org/wookie/widgets/test"));
+ }
+
+ @Test
+ public void addWildcardPolicy() throws ConfigurationException, URISyntaxException, PolicyFormatException{
+ Policies.getInstance().addPolicy("http://incubator.apache.org/wookie/widgets/test3 * ALLOW");
+ assertTrue(Policies.getInstance().validate("http://xxx.yyy.zzz", "http://incubator.apache.org/wookie/widgets/test3"));
+
+ }
+
+ @Test
+ public void clearPolicies() throws URISyntaxException, ConfigurationException, PolicyFormatException{
+ assertTrue(Policies.getInstance().validate("http://zzz.apache.org", "http://incubator.apache.org/wookie/widgets/test"));
+ Policies.getInstance().clearPolicies("http://incubator.apache.org/wookie/widgets/test");
+ assertFalse(Policies.getInstance().validate("http://zzz.apache.org", "http://incubator.apache.org/wookie/widgets/test"));
+ Policies.getInstance().addPolicy("http://incubator.apache.org/wookie/widgets/test http://*.apache.org ALLOW");
+ }
+
+ @Test
+ public void weather() throws ConfigurationException, URISyntaxException{
+ assertTrue(Policies.getInstance().validate("http://newsrss.bbc.co.uk/weather/forecast/9/Next3DaysRSS.xml", "http://www.getwookie.org/widgets/weather"));
+ }
+
+ @Test
+ public void duplicates() throws ConfigurationException, PolicyFormatException{
+ Policies.getInstance().addPolicy("http://temp.org http://temp.org ALLOW");
+ Policies.getInstance().addPolicy("http://temp.org http://temp.org ALLOW");
+ assertEquals(1, Policies.getInstance().getPolicies("http://temp.org").length);
+ Policies.getInstance().clearPolicies("http://temp.org");
+ }
+
+}
Added: incubator/wookie/trunk/src-tests/org/apache/wookie/tests/proxy/PolicyTest.java
URL: http://svn.apache.org/viewvc/incubator/wookie/trunk/src-tests/org/apache/wookie/tests/proxy/PolicyTest.java?rev=1203763&view=auto
==============================================================================
--- incubator/wookie/trunk/src-tests/org/apache/wookie/tests/proxy/PolicyTest.java (added)
+++ incubator/wookie/trunk/src-tests/org/apache/wookie/tests/proxy/PolicyTest.java Fri Nov 18 17:38:53 2011
@@ -0,0 +1,109 @@
+/*
+ *
+ * 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.wookie.tests.proxy;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import org.apache.wookie.proxy.Policy;
+import org.apache.wookie.proxy.PolicyFormatException;
+import org.junit.Test;
+
+/**
+ * Tests Policy
+ */
+public class PolicyTest {
+
+
+ @Test
+ public void createPolicy() throws PolicyFormatException{
+ Policy policy = new Policy();
+ policy.setScope("*");
+ policy.setOrigin("*");
+ policy.setDirective("ALLOW");
+ }
+
+ @Test
+ public void createPolicyFromString() throws PolicyFormatException{
+ Policy policy = new Policy("* http://localhost ALLOW");
+ }
+
+ @Test(expected = PolicyFormatException.class)
+ public void createPolicyFromInvalidString() throws PolicyFormatException{
+ Policy policy = new Policy("http://localhost ALLOW");
+ }
+
+ @Test
+ public void policyToString() throws PolicyFormatException{
+ Policy policy = new Policy("* http://localhost ALLOW");
+ assertEquals("* http://localhost ALLOW",policy.toString());
+ }
+
+ @Test(expected = PolicyFormatException.class)
+ public void createPolicyFromInvalidUriString() throws PolicyFormatException{
+ Policy policy = new Policy("* isnotauri! ALLOW");
+ }
+
+ @Test(expected = PolicyFormatException.class)
+ public void createPolicyFromInvalidUriString2() throws PolicyFormatException{
+ Policy policy = new Policy("* nohost: ALLOW");
+ }
+
+ @Test(expected = PolicyFormatException.class)
+ public void createPolicyFromInvalidUriString3() throws PolicyFormatException{
+ Policy policy = new Policy("* test:test@http://x.y.z ALLOW");
+ }
+
+ @Test(expected = PolicyFormatException.class)
+ public void createPolicyFromInvalidUriString4() throws PolicyFormatException{
+ Policy policy = new Policy("* http://test@www.apache.org ALLOW");
+ }
+
+ @Test
+ public void checkInvalid() throws URISyntaxException{
+ Policy policy = new Policy();
+ assertEquals(0,policy.allows(new URI("http://test.apache.org")));
+ }
+
+ @Test
+ public void checkInvalid2() throws URISyntaxException, PolicyFormatException{
+ Policy policy = new Policy("* http://test.apache.org ALLOW");
+ assertEquals(0,policy.allows(new URI("ftp://test.apache.org")));
+ }
+
+ @Test
+ public void equalsTest() throws PolicyFormatException{
+ Policy policy = new Policy("* http://test.apache.org ALLOW");
+ Policy policy2 = new Policy("* http://test.apache.org ALLOW");
+ assertEquals(policy,policy2);
+ assertTrue(policy.equals(policy2));
+
+ }
+
+ @Test
+ public void unequalTest() throws PolicyFormatException{
+ Policy policy = new Policy("* http://test.apache.org ALLOW");
+ Object policy2 = new String("* http://test.apache.org ALLOW");
+ assertFalse(policy.equals(policy2));
+ }
+}
+
Added: incubator/wookie/trunk/src/org/apache/wookie/controller/PoliciesController.java
URL: http://svn.apache.org/viewvc/incubator/wookie/trunk/src/org/apache/wookie/controller/PoliciesController.java?rev=1203763&view=auto
==============================================================================
--- incubator/wookie/trunk/src/org/apache/wookie/controller/PoliciesController.java (added)
+++ incubator/wookie/trunk/src/org/apache/wookie/controller/PoliciesController.java Fri Nov 18 17:38:53 2011
@@ -0,0 +1,177 @@
+/*
+ *
+ * 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.wookie.controller;
+
+import java.io.IOException;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.commons.lang.StringUtils;
+import org.apache.log4j.Logger;
+import org.apache.wookie.exceptions.InvalidParametersException;
+import org.apache.wookie.exceptions.ResourceDuplicationException;
+import org.apache.wookie.exceptions.ResourceNotFoundException;
+import org.apache.wookie.exceptions.UnauthorizedAccessException;
+import org.apache.wookie.helpers.PoliciesHelper;
+import org.apache.wookie.proxy.Policies;
+import org.apache.wookie.proxy.Policy;
+import org.apache.wookie.proxy.PolicyFormatException;
+
+/**
+ *
+ */
+public class PoliciesController extends Controller {
+
+ private static final long serialVersionUID = -5779464009961150201L;
+ static Logger _logger = Logger.getLogger(PoliciesController.class.getName());
+
+ /* (non-Javadoc)
+ * @see org.apache.wookie.controller.Controller#show(java.lang.String, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
+ */
+ @Override
+ protected void show(String resourceId, HttpServletRequest request,
+ HttpServletResponse response) throws ResourceNotFoundException,
+ UnauthorizedAccessException, IOException {
+
+ Policy[] policies;
+
+ //
+ // The resource id is the policy scope. E.g., calling
+ // policies/* would get the global policies
+ //
+ try {
+ policies = Policies.getInstance().getPolicies(resourceId);
+ } catch (ConfigurationException e) {
+ _logger.error("Problem with policies configuration", e);
+ throw new IOException();
+ }
+
+ switch (format(request)) {
+ case XML: returnXml(PoliciesHelper.toXml(policies),response);break;
+ case HTML: returnHtml(PoliciesHelper.toHtml(policies),response);break;
+ case JSON: returnJson(PoliciesHelper.toJson(policies),response);break;
+ }
+
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.wookie.controller.Controller#index(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
+ */
+ @Override
+ protected void index(HttpServletRequest request, HttpServletResponse response)
+ throws UnauthorizedAccessException, IOException {
+ Policy[] policies;
+ try {
+ policies = Policies.getInstance().getPolicies();
+ } catch (ConfigurationException e) {
+ _logger.error("Problem with policies configuration", e);
+ throw new IOException();
+ }
+
+ switch (format(request)) {
+ case XML: returnXml(PoliciesHelper.toXml(policies),response);break;
+ case HTML: returnHtml(PoliciesHelper.toHtml(policies),response);break;
+ case JSON: returnJson(PoliciesHelper.toJson(policies),response);break;
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.wookie.controller.Controller#create(java.lang.String, javax.servlet.http.HttpServletRequest)
+ */
+ @Override
+ protected boolean create(String resourceId, HttpServletRequest request)
+ throws ResourceDuplicationException, InvalidParametersException,
+ UnauthorizedAccessException {
+ try {
+
+ //
+ // Check the request body
+ //
+ String policy = request.getReader().readLine();
+ return Policies.getInstance().addPolicy(policy);
+
+ } catch (ConfigurationException e) {
+
+ //
+ // Problem with the configuration
+ //
+ _logger.error("Problem with policies configuration", e);
+ throw new InvalidParametersException();
+
+ } catch (PolicyFormatException e) {
+
+ //
+ // Format of the policy is incorrect
+ //
+ throw new InvalidParametersException();
+
+ } catch (IOException e) {
+
+ //
+ // No body
+ //
+ throw new InvalidParametersException();
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.wookie.controller.Controller#remove(java.lang.String, javax.servlet.http.HttpServletRequest)
+ */
+ @Override
+ protected boolean remove(String resourceId, HttpServletRequest request)
+ throws ResourceNotFoundException, UnauthorizedAccessException,
+ InvalidParametersException {
+
+ //
+ // For some reason the main controller resourceId method isn't parsing
+ // the resource part correctly
+ //
+ resourceId = request.getPathInfo().trim();
+ if (resourceId != null) resourceId = StringUtils.stripStart(resourceId, "/");
+
+ try {
+
+ //
+ // Obtain a policy from the resource identifier
+ //
+ Policy policy;
+ policy = new Policy(resourceId);
+ Policies.getInstance().removePolicy(policy);
+ return true;
+
+ } catch (PolicyFormatException e) {
+
+ //
+ // The resource isn't formatted correctly
+ //
+ throw new InvalidParametersException();
+
+ } catch (ConfigurationException e) {
+
+ //
+ // Problem with the configuration
+ //
+ _logger.error("Problem with policies configuration", e);
+ throw new InvalidParametersException();
+ }
+
+ }
+
+}
Added: incubator/wookie/trunk/src/org/apache/wookie/proxy/Policies.java
URL: http://svn.apache.org/viewvc/incubator/wookie/trunk/src/org/apache/wookie/proxy/Policies.java?rev=1203763&view=auto
==============================================================================
--- incubator/wookie/trunk/src/org/apache/wookie/proxy/Policies.java (added)
+++ incubator/wookie/trunk/src/org/apache/wookie/proxy/Policies.java Fri Nov 18 17:38:53 2011
@@ -0,0 +1,303 @@
+/*
+ *
+ * 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.wookie.proxy;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+
+import org.apache.commons.collections.map.MultiValueMap;
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.commons.configuration.PropertiesConfiguration;
+import org.apache.commons.configuration.reloading.FileChangedReloadingStrategy;
+import org.apache.commons.lang.ArrayUtils;
+
+/**
+ * Policies management class
+ *
+ * <p>This class provides access to policies for the proxy service,
+ * including both global "whitelist" policies and widget-specific
+ * policies derived from the <access> element in config.xml</p>
+ *
+ * <p>The Policies class is a singleton and maps directly onto the
+ * <code>policies</code> configuration file in the server.</p>
+ *
+ * <p>Note that policies are loaded dynamically from the <code>
+ * policies</code> file whenever it changes on the file system</p>
+ */
+public class Policies {
+
+ private MultiValueMap policies;
+ private PropertiesConfiguration properties;
+ private FileChangedReloadingStrategy reloader = new FileChangedReloadingStrategy();
+
+ private static Policies instance;
+
+ private Policies() throws ConfigurationException{
+ policies = new MultiValueMap();
+ properties = new PropertiesConfiguration("policies");
+ properties.setReloadingStrategy(reloader);
+ properties.getLayout().setGlobalSeparator(" ");
+ loadPolicies();
+ }
+
+ public static Policies getInstance() throws ConfigurationException{
+ if (instance == null)
+ instance = new Policies();
+ return instance;
+ }
+
+ /**
+ * Refresh policies, loading from file if the file
+ * has been modified since it was last reloaded.
+ * @throws ConfigurationException
+ */
+ private void refresh() throws ConfigurationException{
+ if (reloader.reloadingRequired()){
+ policies.clear();
+ loadPolicies();
+ reloader.reloadingPerformed();
+ }
+ }
+
+ /**
+ * Load policies from the policies file
+ * @throws ConfigurationException
+ */
+ private void loadPolicies() throws ConfigurationException{
+ properties.clear();
+ properties.load();
+
+ @SuppressWarnings("rawtypes")
+ Iterator keys = properties.getKeys();
+ while(keys.hasNext()){
+ String key = (String)keys.next();
+ String[] entries = properties.getStringArray(key);
+ for(int i=0;i<entries.length;i++){
+ try {
+ addPolicyToCollection(key+" "+entries[i]);
+ } catch (Exception e) {
+ // TODO LOG AN ERROR
+ }
+ }
+ }
+ }
+
+ /**
+ * Validate a request for a resource with a particular scope
+ * @param location the location requested
+ * @param scope the scope of the request
+ * @return true if the location is allowed in the scope, otherwise false
+ * @throws URISyntaxException if the request is not a valid URI
+ * @throws ConfigurationException
+ */
+ public boolean validate(String location, String scope) throws URISyntaxException, ConfigurationException{
+ URI uri = new URI(location);
+ return validate(uri, scope);
+ }
+
+ /**
+ * Validate a request for a resource with a particular scope
+ * @param uri the URI requested
+ * @param scope the scope of the request
+ * @return true if the location is allowed in the scope, otherwise false
+ * @throws URISyntaxException if the request is not a valid URI
+ * @throws ConfigurationException
+ */
+ public boolean validate(URI uri, String scope) throws URISyntaxException, ConfigurationException{
+
+ refresh();
+
+ //
+ // Obtain matching policies
+ //
+ Policy[] matching = getPolicies(scope);
+
+ //
+ // Mix in globals
+ //
+ if (!scope.equals("*")){
+ matching = (Policy[]) ArrayUtils.addAll(getPolicies("*"), matching);
+ }
+
+ //
+ // Check if allowed
+ //
+ boolean allowed = false;
+ boolean denied = false;
+ for (Policy policy:matching){
+ if (policy.allows(uri) == 1) allowed = true;
+ if (policy.allows(uri) == -1) denied = true;
+ }
+ if (allowed && !denied) return true;
+ return false;
+ }
+
+ /**
+ * Add a new policy formatted using a policy string
+ * @param policyString
+ * @throws PolicyFormatException
+ * @throws ConfigurationException
+ * @throws Exception
+ */
+ public boolean addPolicy(String policyString) throws PolicyFormatException, ConfigurationException{
+ Policy policy = new Policy(policyString);
+ return addPolicy(policy);
+ }
+
+ /**
+ * Add a new policy object
+ * @param policy
+ * @throws ConfigurationException
+ */
+ public boolean addPolicy(Policy policy) throws ConfigurationException{
+ boolean added = addPolicyToCollection(policy);
+ if(added){
+ properties.addProperty(policy.getScope(), policy.getOrigin()+" "+policy.getDirective());
+ properties.save();
+ }
+ return added;
+ }
+
+ /**
+ * Private method for adding a policy to the internal policy collection
+ * @param policyString
+ * @throws PolicyFormatException
+ * @throws Exception
+ */
+ private void addPolicyToCollection(String policyString) throws ConfigurationException, PolicyFormatException{
+ Policy policy = new Policy(policyString);
+ addPolicyToCollection(policy);
+ }
+
+ /**
+ * Private method for adding a policy to the internal policy collection
+ * @param policy
+ */
+ private boolean addPolicyToCollection(Policy policy){
+ @SuppressWarnings("unchecked")
+ Collection<Policy> existingPolicies = (Collection<Policy>) policies.get(policy.getScope());
+ if (existingPolicies == null || !existingPolicies.contains(policy)){
+
+ //
+ // Add the policy
+ //
+ policies.put(policy.getScope(), policy);
+ return true;
+
+ } else {
+
+ //
+ // Duplicate of existing policy, so don't add it
+ //
+ return false;
+ }
+ }
+
+ /**
+ * Remove a policy
+ * @param policyString
+ * @throws PolicyFormatException
+ * @throws Exception
+ */
+ public void removePolicy(String policyString) throws ConfigurationException, PolicyFormatException{
+ Policy policy = new Policy(policyString);
+ removePolicy(policy);
+ }
+
+ /**
+ * Remove a policy
+ * @param policy
+ * @throws ConfigurationException
+ */
+ public void removePolicy(Policy policy) throws ConfigurationException{
+
+ //
+ // Remove from local collection
+ //
+ @SuppressWarnings("unchecked")
+ Collection<Policy> matchingPolicies = (Collection<Policy>) policies.get(policy.getScope());
+ matchingPolicies.remove(policy);
+ policies.remove(policy.getScope());
+ for (Policy match: matchingPolicies) policies.put(match.getScope(), match);
+
+ //
+ // Remove from properties file
+ //
+ properties.clearProperty(policy.getScope());
+ for (Policy match: getPolicies(policy.getScope())){
+ properties.addProperty(match.getScope(), match.getOrigin()+" "+match.getDirective());
+ }
+ properties.save();
+
+ }
+
+ /**
+ * Clear all policies relating to the scope provided (typically a widget uri)
+ * @param scope
+ * @throws ConfigurationException
+ */
+ public void clearPolicies(String scope) throws ConfigurationException{
+ refresh();
+ policies.remove(scope);
+ properties.clearProperty(scope);
+ properties.save();
+ }
+
+ /**
+ * Clear all policies
+ * @throws ConfigurationException
+ */
+ public void clear() throws ConfigurationException{
+ refresh();
+ policies.clear();
+ properties.clear();
+ properties.save();
+ }
+
+ /**
+ * Get all policies within a specific scope
+ * @param scope
+ * @return an array of Policy objects
+ * @throws ConfigurationException
+ */
+ public Policy[] getPolicies(String scope) throws ConfigurationException{
+ refresh();
+ @SuppressWarnings("unchecked")
+ Collection<Policy> matchedPolicies = (Collection<Policy>) policies.get(scope);
+ if (matchedPolicies == null) return new Policy[0];
+ return matchedPolicies.toArray(new Policy[matchedPolicies.size()]);
+ }
+
+ /**
+ * Get all policies
+ * @return an array of Policy objects
+ * @throws ConfigurationException
+ */
+ @SuppressWarnings("unchecked")
+ public Policy[] getPolicies() throws ConfigurationException{
+ refresh();
+ ArrayList<Policy> allPolicies = new ArrayList<Policy>();
+ for (Object key:policies.keySet()){
+ allPolicies.addAll(policies.getCollection(key));
+ }
+ return allPolicies.toArray(new Policy[allPolicies.size()]);
+ }
+}
Added: incubator/wookie/trunk/src/org/apache/wookie/proxy/Policy.java
URL: http://svn.apache.org/viewvc/incubator/wookie/trunk/src/org/apache/wookie/proxy/Policy.java?rev=1203763&view=auto
==============================================================================
--- incubator/wookie/trunk/src/org/apache/wookie/proxy/Policy.java (added)
+++ incubator/wookie/trunk/src/org/apache/wookie/proxy/Policy.java Fri Nov 18 17:38:53 2011
@@ -0,0 +1,230 @@
+/*
+ *
+ * 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.wookie.proxy;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import org.apache.wookie.w3c.util.IRIValidator;
+
+/**
+ * A class representing a single Policy, equivalent to a single
+ * entry in the <code>policies</code> configuration file
+ */
+public class Policy {
+
+ private String scope;
+ private String origin;
+ private String directive;
+
+ public Policy(){
+
+ }
+
+ /**
+ * Construct a Policy instance from a policy string comprising
+ * the scope, origin and directive separated by spaces
+ * @param policy
+ * @throws Exception
+ */
+ public Policy(String policy) throws PolicyFormatException{
+ String[] elements = policy.split(" ");
+ if (elements.length == 3){
+ setScope(elements[0]);
+ setOrigin(elements[1]);
+ setDirective(elements[2]);
+ } else {
+ throw new PolicyFormatException("Policy incorrectly formatted");
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#toString()
+ */
+ public String toString(){
+ String policy = scope + " " + origin + " " + directive;
+ return policy;
+ }
+
+ /**
+ * @return the scope
+ */
+ public String getScope() {
+ return scope;
+ }
+ /**
+ * @param scope the scope to set
+ */
+ public void setScope(String scope) {
+ this.scope = scope;
+ }
+ /**
+ * @return the origin
+ */
+ public String getOrigin() {
+ return origin;
+ }
+ /**
+ * @param origin the origin to set
+ * @throws Exception
+ */
+ public void setOrigin(String origin) throws PolicyFormatException {
+ this.origin = this.checkOrigin(origin);
+ }
+ /**
+ * @return the directive
+ */
+ public String getDirective() {
+ return directive;
+ }
+ /**
+ * @param directive the directive to set
+ */
+ public void setDirective(String directive) {
+ this.directive = directive;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (!obj.getClass().equals(this.getClass())) return false;
+
+ Policy otherPolicy = (Policy)obj;
+
+ if(otherPolicy.getScope().equalsIgnoreCase(getScope()) && (otherPolicy.getDirective().equalsIgnoreCase(getDirective())) && (otherPolicy.getOrigin().equalsIgnoreCase(getOrigin()))){
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Checks whether the policy grants or denies access to a given URI.
+ * @param uri
+ * @return returns 1 if the policy grants access to the URI, -1 if it denies access, and 0 if it doesn't match
+ * @throws URISyntaxException
+ */
+ public int allows(URI uri) throws URISyntaxException{
+
+ //
+ // Policy is being checked which has no origin set
+ //
+ if(this.getOrigin() == null) return 0;
+
+ //
+ // Check valid URI
+ //
+ if(uri.getScheme() == null) throw new URISyntaxException(uri.toString(), "no valid scheme");
+ if(uri.getAuthority() == null) throw new URISyntaxException(uri.toString(), "no valid authority");
+
+ //
+ // Wildcard match
+ //
+ if (getOrigin().equals("*")) return 1;
+
+ //
+ // Get the match origin, and check they match
+ //
+ URI match = new URI(getOrigin());
+
+ //
+ // Check schemes match
+ //
+ if(!uri.getScheme().equalsIgnoreCase(match.getScheme())) return 0;
+
+ //
+ // Check ports match
+ // Note that where the Policy has no port specified, we treat
+ // this as being "any port"
+ //
+ int requestedPort = uri.getPort();
+ if (requestedPort == -1) requestedPort = 80;
+ if( match.getPort() != -1 && requestedPort != match.getPort()) return 0;
+
+
+ if(match.getAuthority().startsWith(("*"))){
+
+ //
+ // Subdomain match
+ //
+ String subdomain = uri.getAuthority().split("\\.")[0];
+ if (subdomain != null){
+ String matchHost = match.getAuthority().replace("*", subdomain);
+ if(uri.getHost().equalsIgnoreCase(matchHost))
+ if (getDirective().equalsIgnoreCase("ALLOW")){
+ return 1;
+ } else {
+ return -1;
+ }
+ }
+ } else {
+
+ //
+ // Simple hosts match
+ //
+ if(uri.getHost().equalsIgnoreCase(match.getHost()))
+ if (getDirective().equalsIgnoreCase("ALLOW")){
+ return 1;
+ } else {
+ return -1;
+ }
+ }
+ return 0;
+ }
+
+ /**
+ * Checks whether a supplied origin parameter is valid, and returns the processed result
+ * @param origin
+ * @return a processed origin with extraneous elements removed
+ * @throws PolicyFormatException if the origin is not valid
+ */
+ private String checkOrigin(String origin) throws PolicyFormatException{
+ origin = origin.trim();
+ if (origin.equals("*")) return origin;
+
+ if (!IRIValidator.isValidIRI(origin)) throw new PolicyFormatException("origin is not a valid IRI");
+
+
+ URI uri;
+ try {
+ uri = new URI(origin);
+ if ((uri.getHost() == null && (uri.getAuthority() == null || !uri.getAuthority().startsWith("*.")))) throw new PolicyFormatException("origin has no host");
+ if (uri.getUserInfo()!=null) throw new PolicyFormatException("origin has userinfo");
+
+ URI processedURI;
+ //
+ // If the origin contains a *, we construct it using an authority
+ //
+ if (uri.getAuthority().startsWith("*.")){
+ processedURI = new URI(uri.getScheme(),uri.getAuthority(),null,null,null);
+ } else {
+ //
+ // Remove query and path
+ //
+ processedURI = new URI(uri.getScheme(),null,uri.getHost(),uri.getPort(),null,null,null);
+ }
+
+ return processedURI.toString();
+ } catch (URISyntaxException e1) {
+ throw new PolicyFormatException("origin is not a valid URI");
+ }
+ }
+
+}
Added: incubator/wookie/trunk/src/org/apache/wookie/proxy/PolicyFormatException.java
URL: http://svn.apache.org/viewvc/incubator/wookie/trunk/src/org/apache/wookie/proxy/PolicyFormatException.java?rev=1203763&view=auto
==============================================================================
--- incubator/wookie/trunk/src/org/apache/wookie/proxy/PolicyFormatException.java (added)
+++ incubator/wookie/trunk/src/org/apache/wookie/proxy/PolicyFormatException.java Fri Nov 18 17:38:53 2011
@@ -0,0 +1,31 @@
+/*
+ *
+ * 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.wookie.proxy;
+
+/**
+ * An Exception thrown when a Policy is incorrectly formatted
+ */
+public class PolicyFormatException extends Exception {
+
+ private static final long serialVersionUID = 1273238260784592379L;
+
+ public PolicyFormatException(String reason){
+ super(reason);
+ }
+
+}
Modified: incubator/wookie/trunk/src/org/apache/wookie/proxy/ProxyServlet.java
URL: http://svn.apache.org/viewvc/incubator/wookie/trunk/src/org/apache/wookie/proxy/ProxyServlet.java?rev=1203763&r1=1203762&r2=1203763&view=diff
==============================================================================
--- incubator/wookie/trunk/src/org/apache/wookie/proxy/ProxyServlet.java (original)
+++ incubator/wookie/trunk/src/org/apache/wookie/proxy/ProxyServlet.java Fri Nov 18 17:38:53 2011
@@ -18,6 +18,7 @@ import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URI;
+import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLDecoder;
@@ -28,13 +29,11 @@ import javax.servlet.http.HttpServletReq
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.auth.AuthenticationException;
import org.apache.log4j.Logger;
-import org.apache.wookie.beans.IAccessRequest;
import org.apache.wookie.beans.IWidgetInstance;
-import org.apache.wookie.beans.IWhitelist;
-import org.apache.wookie.beans.IWidget;
import org.apache.wookie.beans.util.IPersistenceManager;
import org.apache.wookie.beans.util.PersistenceManagerFactory;
@@ -102,7 +101,7 @@ public class ProxyServlet extends HttpSe
//
if (properties.getBoolean("widget.proxy.usewhitelist") && !isAllowed(bean.getNewUrl().toURI(), instance)){
response.sendError(HttpServletResponse.SC_FORBIDDEN,"<error>URL Blocked</error>");
- fLogger.warn("URL " + bean.getNewUrl().toExternalForm() + " Blocked");
+ fLogger.warn("URL " + bean.getNewUrl().toExternalForm() + " Blocked for scope "+instance.getWidget().getGuid());
return;
}
@@ -186,32 +185,14 @@ public class ProxyServlet extends HttpSe
* @return
*/
public boolean isAllowed(URI requestedUri, IWidgetInstance instance){
- // Check global whitelist
- IPersistenceManager persistenceManager = PersistenceManagerFactory.getPersistenceManager();
- for (IWhitelist whiteList : persistenceManager.findAll(IWhitelist.class)){
- // TODO - make this better then just comparing the beginning...
- if(requestedUri.toString().toLowerCase().startsWith(whiteList.getfUrl().toLowerCase()))
- return true;
- }
-
- // Check widget-specific policies using W3C WARP
- if (instance != null && isAllowedByPolicy(requestedUri, instance.getWidget())) return true;
-
- return false;
- }
-
- /**
- * Check widget-specific policies using W3C WARP
- * @param requestedUri the URI requested
- * @param widget the Widget requesting access to the URI
- * @return true if a policy grants access to the requested URI
- */
- private boolean isAllowedByPolicy(URI requestedUri, IWidget widget){
- IPersistenceManager persistenceManager = PersistenceManagerFactory.getPersistenceManager();
- for (IAccessRequest policy: persistenceManager.findApplicableAccessRequests(widget))
- if (policy.isAllowed(requestedUri)) return true;
- fLogger.warn("No policy grants widget "+widget.getWidgetTitle("en")+" access to: "+requestedUri.toString());
- return false;
+ try {
+ return Policies.getInstance().validate(requestedUri, instance.getWidget().getGuid());
+ } catch (ConfigurationException e) {
+ fLogger.error("Problem with policies configuration", e);
+ return false;
+ } catch (URISyntaxException e) {
+ return false;
+ }
}
/**
Added: incubator/wookie/trunk/src/policies
URL: http://svn.apache.org/viewvc/incubator/wookie/trunk/src/policies?rev=1203763&view=auto
==============================================================================
--- incubator/wookie/trunk/src/policies (added)
+++ incubator/wookie/trunk/src/policies Fri Nov 18 17:38:53 2011
@@ -0,0 +1,36 @@
+##
+## Access Policies File
+##
+## This file is dynamically loaded by Wookie and configures
+## access policies for the proxy service, including both
+## whitelist (global) and widget-specific access policies
+##
+## Note that when new widgets are added to Wookie their
+## access policy requests are automatically added to this
+## file.
+##
+##
+## The format of entries is widget-uri origin directive
+## The widget-uri and origin may be a wildcard (*). To enable
+## subdomains, use a wildcard as the first element of the
+## origin host, e.g. http://*.apache.org
+##
+## The default (implicit) policy is to deny all origins for all widgets
+##
+## Example:
+##
+## * http://127.0.0.1 ALLOW
+## http\://www.getwookie.org/widgets/weather http://newsrss.bbc.co.uk ALLOW
+## http\://www.getwookie.org/widgets/rss * ALLOW
+##
+## This set of policies would allow access to 127.0.0.1 for all
+## widgets, while the "weather" widget would be allowed to access
+## URLs from http://newsrss.bbc.co.uk, and the RSS widget could
+## access any URL from any origin.
+##
+## Note that it is necessary to escape the ":" character with a "\"
+##
+
+* http://127.0.0.1 ALLOW
+* http://localhost:8080 ALLOW
+* http://*.apache.org ALLOW
\ No newline at end of file