[spring-extensions] branch master updated: OSJ-191 - Support for OpenSAML security features in HTTPResource layer

Scott Cantor cantor.2 at osu.edu
Thu Dec 29 19:25:46 EST 2016


This is an automated email from the git hooks/post-receive script.

scantor pushed a commit to branch master
in repository spring-extensions.

View the commit online:
http://git.shibboleth.net/view/?p=spring-extensions.git;a=commit;h=eb429703cebb54dce0bf74ef47802f1589a37748

The following commit(s) were added to refs/heads/master by this push:
       new  eb42970   OSJ-191 - Support for OpenSAML security features in HTTPResource layer
eb42970 is described below

commit eb429703cebb54dce0bf74ef47802f1589a37748
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Thu Dec 29 19:25:44 2016 -0500

    OSJ-191 - Support for OpenSAML security features in HTTPResource layer
    
    https://issues.shibboleth.net/jira/browse/OSJ-191
    
    Add injected handler support to manipulate client context.
---
 .project                                           |  4 +-
 pom.xml                                            |  4 +-
 .../ext/spring/resource/HTTPResource.java          | 89 +++++++++++++++++++---
 .../ext/spring/resource/HTTPResourceTest.java      | 57 ++++++++++++--
 .../ext/spring/resource/TestHTTPResource.java      |  2 +-
 .../ext/spring/resource/FileBackedHTTPBean.xml     |  2 +-
 .../ext/spring/resource/MemBackedHTTPBean.xml      |  2 +-
 7 files changed, 135 insertions(+), 25 deletions(-)

diff --git a/.project b/.project
index 1f4627c..d2e569a 100644
--- a/.project
+++ b/.project
@@ -16,12 +16,12 @@
 			</arguments>
 		</buildCommand>
 		<buildCommand>
-			<name>org.eclipse.m2e.core.maven2Builder</name>
+			<name>org.springframework.ide.eclipse.core.springbuilder</name>
 			<arguments>
 			</arguments>
 		</buildCommand>
 		<buildCommand>
-			<name>org.springframework.ide.eclipse.core.springbuilder</name>
+			<name>org.eclipse.m2e.core.maven2Builder</name>
 			<arguments>
 			</arguments>
 		</buildCommand>
diff --git a/pom.xml b/pom.xml
index 538dc80..dc03572 100644
--- a/pom.xml
+++ b/pom.xml
@@ -12,7 +12,7 @@
 
     <groupId>net.shibboleth.ext</groupId>
     <artifactId>spring-extensions</artifactId>
-    <version>5.3.1-SNAPSHOT</version>
+    <version>5.4.0-SNAPSHOT</version>
 
     <name>Spring Framework Extension</name>
     <description>
@@ -21,7 +21,7 @@
     </description>
 
     <properties>
-        <java-support.version>7.3.1-SNAPSHOT</java-support.version>
+        <java-support.version>7.4.0-SNAPSHOT</java-support.version>
     </properties>
 
     <repositories>
diff --git a/src/main/java/net/shibboleth/ext/spring/resource/HTTPResource.java b/src/main/java/net/shibboleth/ext/spring/resource/HTTPResource.java
index c9e112f..47cade9 100644
--- a/src/main/java/net/shibboleth/ext/spring/resource/HTTPResource.java
+++ b/src/main/java/net/shibboleth/ext/spring/resource/HTTPResource.java
@@ -27,10 +27,12 @@ import java.net.URL;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
+import javax.annotation.concurrent.ThreadSafe;
 
 import net.shibboleth.utilities.java.support.annotation.ParameterName;
 import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
 import net.shibboleth.utilities.java.support.component.AbstractIdentifiedInitializableComponent;
+import net.shibboleth.utilities.java.support.component.ComponentSupport;
 import net.shibboleth.utilities.java.support.logic.Constraint;
 import net.shibboleth.utilities.java.support.primitive.StringSupport;
 
@@ -44,6 +46,7 @@ import org.apache.http.client.cache.HttpCacheContext;
 import org.apache.http.client.methods.CloseableHttpResponse;
 import org.apache.http.client.methods.HttpGet;
 import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.client.protocol.HttpClientContext;
 import org.apache.http.client.utils.DateUtils;
 import org.apache.http.util.EntityUtils;
 import org.slf4j.Logger;
@@ -65,9 +68,12 @@ public class HTTPResource extends AbstractIdentifiedInitializableComponent imple
 
     /** HTTP Client used to pull the resource. */
     @Nonnull private final HttpClient httpClient;
-
+    
     /** URL to the Resource. */
     @Nonnull private final URL resourceURL;
+    
+    /** Optional handler to pre- and post-process context. */
+    @Nullable private HttpClientContextHandler httpClientContextHandler;
 
     /**
      * Constructor.
@@ -78,9 +84,9 @@ public class HTTPResource extends AbstractIdentifiedInitializableComponent imple
      */
     public HTTPResource(@Nonnull @ParameterName(name="client") final HttpClient client,
             @Nonnull @NotEmpty @ParameterName(name="url") final String url) throws IOException {
-        httpClient = Constraint.isNotNull(client, "The Client must not be null");
+        httpClient = Constraint.isNotNull(client, "HttpClient cannot be null");
         final String trimmedAddress =
-                Constraint.isNotNull(StringSupport.trimOrNull(url), "Provided URL must be non empty and non null");
+                Constraint.isNotNull(StringSupport.trimOrNull(url), "Provided URL cannot be null or empty");
         resourceURL = new URL(trimmedAddress);
 
     }
@@ -94,10 +100,21 @@ public class HTTPResource extends AbstractIdentifiedInitializableComponent imple
      */
     public HTTPResource(@Nonnull @ParameterName(name="") final HttpClient client,
             @Nonnull @ParameterName(name="url") final URL url) throws IOException {
-        httpClient = Constraint.isNotNull(client, "The Client must not be null");
-        resourceURL = Constraint.isNotNull(url, "Provided URL must be non empty and non null");
+        httpClient = Constraint.isNotNull(client, "HttpClient cannot be null");
+        resourceURL = Constraint.isNotNull(url, "Provided URL cannot be null or empty");
 
     }
+    
+    /**
+     * Set a handler to manipulate the {@link HttpClientContext}.
+     * 
+     * @param handler the handler to install
+     */
+    public void setHttpClientContextHandler(@Nonnull final HttpClientContextHandler handler) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+        
+        httpClientContextHandler = handler;
+    }
 
     /**
      * Build the {@link HttpCacheContext} instance which will be used to invoke the {@link HttpClient} request.
@@ -143,10 +160,20 @@ public class HTTPResource extends AbstractIdentifiedInitializableComponent imple
     @Override public InputStream getInputStream() throws IOException {
         final HttpGet httpGet = new HttpGet(resourceURL.toExternalForm());
         final HttpCacheContext context = buildHttpClientContext();
-        HttpResponse response = null;
-
+        
+        if (httpClientContextHandler != null) {
+            log.debug("Invoking HttpClientContextHandler prior to execution");
+            httpClientContextHandler.invokeBefore(context, httpGet);
+        }
+        
         log.debug("Attempting to get data from remote resource '{}'", resourceURL);
-        response = httpClient.execute(httpGet, context);
+        final HttpResponse response = httpClient.execute(httpGet, context);
+        
+        if (httpClientContextHandler != null) {
+            log.debug("Invoking HttpClientContextHandler after execution");
+            httpClientContextHandler.invokeAfter(context, httpGet);
+        }
+        
         reportCachingStatus(context);
         final int httpStatusCode = response.getStatusLine().getStatusCode();
 
@@ -230,7 +257,19 @@ public class HTTPResource extends AbstractIdentifiedInitializableComponent imple
         HttpResponse httpResponse = null;
         try {
             final HttpCacheContext context = buildHttpClientContext();
+            
+            if (httpClientContextHandler != null) {
+                log.debug("Invoking HttpClientContextHandler prior to execution");
+                httpClientContextHandler.invokeBefore(context, httpRequest);
+            }
+            
             httpResponse = httpClient.execute(httpRequest, context);
+            
+            if (httpClientContextHandler != null) {
+                log.debug("Invoking HttpClientContextHandler after execution");
+                httpClientContextHandler.invokeAfter(context, httpRequest);
+            }
+            
             reportCachingStatus(context);
             EntityUtils.consume(httpResponse.getEntity());
             return httpResponse;
@@ -345,10 +384,40 @@ public class HTTPResource extends AbstractIdentifiedInitializableComponent imple
     }
     
     /**
+     * Extension that allows the {@link HttpClientContext} to be externally manipulated before use.
+     */
+    @ThreadSafe
+    public static interface HttpClientContextHandler {
+        
+        /**
+         * Perform any desired context modifications before use.
+         * 
+         * @param context the context to operate on
+         * @param request the request that will be executed
+         * 
+         * @throws IOException if the call should be aborted
+         */
+        void invokeBefore(@Nonnull final HttpClientContext context, @Nonnull final HttpUriRequest request)
+            throws IOException;
+        
+        /**
+         * Perform any desired context modifications after use.
+         * 
+         * @param context the context to operate on
+         * @param request the request that was executed
+         * 
+         * @throws IOException if the call should be aborted
+         */
+        void invokeAfter(@Nonnull final HttpClientContext context, @Nonnull final HttpUriRequest request)
+            throws IOException;
+        
+    }
+    
+    /**
      * A wrapper around the entity content {@link InputStream} represented by an {@link HttpResponse}
      * that closes the stream and the HttpResponse when {@link #close()} is invoked.
      */
-    private static class ConnectionClosingInputStream extends InputStream {
+     private static class ConnectionClosingInputStream extends InputStream {
 
         /** HTTP response that is being wrapped. */
         private final HttpResponse response;
@@ -362,7 +431,7 @@ public class HTTPResource extends AbstractIdentifiedInitializableComponent imple
          * @param httpResponse HTTP method that was invoked
          * @throws IOException if there is a problem getting the entity content input stream from the response
          */
-        public ConnectionClosingInputStream(final HttpResponse httpResponse) throws IOException {
+        public ConnectionClosingInputStream(@Nonnull final HttpResponse httpResponse) throws IOException {
             response = httpResponse;
             stream = response.getEntity().getContent();
         }
diff --git a/src/test/java/net/shibboleth/ext/spring/resource/HTTPResourceTest.java b/src/test/java/net/shibboleth/ext/spring/resource/HTTPResourceTest.java
index a9c6b59..405db1b 100644
--- a/src/test/java/net/shibboleth/ext/spring/resource/HTTPResourceTest.java
+++ b/src/test/java/net/shibboleth/ext/spring/resource/HTTPResourceTest.java
@@ -23,12 +23,15 @@ import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.Collection;
 
+import net.shibboleth.ext.spring.resource.HTTPResource.HttpClientContextHandler;
 import net.shibboleth.ext.spring.util.SchemaTypeAwareXMLBeanDefinitionReader;
 import net.shibboleth.utilities.java.support.httpclient.HttpClientBuilder;
 import net.shibboleth.utilities.java.support.httpclient.InMemoryCachingHttpClientBuilder;
 
 import org.apache.http.client.HttpClient;
 import org.apache.http.client.cache.CacheResponseStatus;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.client.protocol.HttpClientContext;
 import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
 import org.joda.time.DateTime;
 import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
@@ -62,6 +65,44 @@ public class HTTPResourceTest {
         Assert.assertTrue(existsResource.exists());
         Assert.assertFalse(notExistsResource.exists());
     }
+    
+    @Test public void contextHandlerNoopTest() throws IOException {
+        final HTTPResource existsResource = new HTTPResource(client, existsURL);
+        existsResource.setHttpClientContextHandler(new HttpClientContextHandler() {
+            public void invokeBefore(HttpClientContext context, HttpUriRequest request) throws IOException {
+            }
+            public void invokeAfter(HttpClientContext context, HttpUriRequest request) throws IOException {
+            }
+        });
+
+        Assert.assertTrue(existsResource.exists());
+    }
+    
+    @Test public void contextHandlerFailBeforeTest() throws IOException {
+        final HTTPResource existsResource = new HTTPResource(client, existsURL);
+        existsResource.setHttpClientContextHandler(new HttpClientContextHandler() {
+            public void invokeBefore(HttpClientContext context, HttpUriRequest request) throws IOException {
+                throw new IOException("Fail");
+            }
+            public void invokeAfter(HttpClientContext context, HttpUriRequest request) throws IOException {
+            }
+        });
+
+        Assert.assertFalse(existsResource.exists());
+    }
+    
+    @Test public void contextHandlerFailAfterTest() throws IOException {
+        final HTTPResource existsResource = new HTTPResource(client, existsURL);
+        existsResource.setHttpClientContextHandler(new HttpClientContextHandler() {
+            public void invokeBefore(HttpClientContext context, HttpUriRequest request) throws IOException {
+            }
+            public void invokeAfter(HttpClientContext context, HttpUriRequest request) throws IOException {
+                throw new IOException("Fail");
+            }
+        });
+
+        Assert.assertFalse(existsResource.exists());
+    }
 
     @Test public void testCompare() throws IOException {
 
@@ -89,9 +130,9 @@ public class HTTPResourceTest {
 
         final TestHTTPResource what = new TestHTTPResource(client, existsURL);
         Assert.assertTrue(what.exists());
-        Assert.assertNull(what.getLasteCacheResponseStatus());
+        Assert.assertNull(what.getLastCacheResponseStatus());
         Assert.assertTrue(ResourceTestHelper.compare(what, new ClassPathResource("net/shibboleth/ext/spring/resource/document.xml")));
-        Assert.assertNull(what.getLasteCacheResponseStatus());
+        Assert.assertNull(what.getLastCacheResponseStatus());
     }
 
     @Test public void testCachedCache() throws Exception {
@@ -100,10 +141,10 @@ public class HTTPResourceTest {
         builder.setMaxCacheEntries(3);
         final TestHTTPResource what = new TestHTTPResource(builder.buildClient(), existsURL);
         Assert.assertTrue(what.exists());
-        Assert.assertNotNull(what.getLasteCacheResponseStatus());
+        Assert.assertNotNull(what.getLastCacheResponseStatus());
         Assert.assertTrue(ResourceTestHelper.compare(what, new ClassPathResource("net/shibboleth/ext/spring/resource/document.xml")));
 
-        Assert.assertEquals(what.getLasteCacheResponseStatus(), CacheResponseStatus.CACHE_HIT);
+        Assert.assertEquals(what.getLastCacheResponseStatus(), CacheResponseStatus.CACHE_HIT);
     }
 
     private GenericApplicationContext getContext(final String fileName, final File theDir) {
@@ -131,10 +172,10 @@ public class HTTPResourceTest {
             final TestHTTPResource what = beans.iterator().next();
 
             Assert.assertTrue(what.exists());
-            Assert.assertNotNull(what.getLasteCacheResponseStatus());
+            Assert.assertNotNull(what.getLastCacheResponseStatus());
             Assert.assertTrue(ResourceTestHelper.compare(what, new ClassPathResource("net/shibboleth/ext/spring/resource/document.xml")));
 
-            Assert.assertEquals(what.getLasteCacheResponseStatus(), CacheResponseStatus.CACHE_HIT);
+            Assert.assertEquals(what.getLastCacheResponseStatus(), CacheResponseStatus.CACHE_HIT);
         } finally {
             ((GenericApplicationContext) context.getParent()).close();
             context.close();
@@ -164,10 +205,10 @@ public class HTTPResourceTest {
             final TestHTTPResource what = beans.iterator().next();
 
             Assert.assertTrue(what.exists());
-            Assert.assertNotNull(what.getLasteCacheResponseStatus());
+            Assert.assertNotNull(what.getLastCacheResponseStatus());
             Assert.assertTrue(ResourceTestHelper.compare(what, new ClassPathResource("net/shibboleth/ext/spring/resource/document.xml")));
 
-            Assert.assertEquals(what.getLasteCacheResponseStatus(), CacheResponseStatus.CACHE_HIT);
+            Assert.assertEquals(what.getLastCacheResponseStatus(), CacheResponseStatus.CACHE_HIT);
         } finally {
             if (null != theDir) {
                 emptyDir(theDir);
diff --git a/src/test/java/net/shibboleth/ext/spring/resource/TestHTTPResource.java b/src/test/java/net/shibboleth/ext/spring/resource/TestHTTPResource.java
index 210c87f..69066ba 100644
--- a/src/test/java/net/shibboleth/ext/spring/resource/TestHTTPResource.java
+++ b/src/test/java/net/shibboleth/ext/spring/resource/TestHTTPResource.java
@@ -38,7 +38,7 @@ class TestHTTPResource extends HTTPResource {
         super.reportCachingStatus(context);
     }
 
-    public CacheResponseStatus getLasteCacheResponseStatus() {
+    public CacheResponseStatus getLastCacheResponseStatus() {
         return responseStatus;
     }
 
diff --git a/src/test/resources/net/shibboleth/ext/spring/resource/FileBackedHTTPBean.xml b/src/test/resources/net/shibboleth/ext/spring/resource/FileBackedHTTPBean.xml
index 57efed2..f0ef12c 100644
--- a/src/test/resources/net/shibboleth/ext/spring/resource/FileBackedHTTPBean.xml
+++ b/src/test/resources/net/shibboleth/ext/spring/resource/FileBackedHTTPBean.xml
@@ -14,7 +14,7 @@
 	<bean id="ShibResource" class="net.shibboleth.ext.spring.resource.HTTPResource"
 		c:client-ref="apacheClient" c:url="https://git.shibboleth.net/view/?p=spring-extensions.git;a=blob_plain;f=src/test/resources/data/document.xml;h=e8ec7c0d20c7a6b8193e1868398cda0c28df45ed;hb=HEAD" />
 
-<!--  for testing we will use out test resource -->
+<!--  for testing we will use our test resource -->
     <bean id="TestResource" class="net.shibboleth.ext.spring.resource.TestHTTPResource"
         c:client-ref="apacheClient" c:url="https://git.shibboleth.net/view/?p=spring-extensions.git;a=blob_plain;f=src/test/resources/data/document.xml;h=e8ec7c0d20c7a6b8193e1868398cda0c28df45ed;hb=HEAD" />
 
diff --git a/src/test/resources/net/shibboleth/ext/spring/resource/MemBackedHTTPBean.xml b/src/test/resources/net/shibboleth/ext/spring/resource/MemBackedHTTPBean.xml
index 5e795cf..25b89a1 100644
--- a/src/test/resources/net/shibboleth/ext/spring/resource/MemBackedHTTPBean.xml
+++ b/src/test/resources/net/shibboleth/ext/spring/resource/MemBackedHTTPBean.xml
@@ -13,7 +13,7 @@
     <bean id="Resource" class="net.shibboleth.ext.spring.resource.HTTPResource"
         c:client-ref="apacheClient" c:url="https://git.shibboleth.net/view/?p=spring-extensions.git;a=blob_plain;f=src/test/resources/data/document.xml;h=e8ec7c0d20c7a6b8193e1868398cda0c28df45ed;hb=HEAD" />
 
-    <!--  for testing we will use out test resource -->
+    <!--  for testing we will use our test resource -->
     <bean id="TestResource" class="net.shibboleth.ext.spring.resource.TestHTTPResource"
         c:client-ref="apacheClient" c:url="https://git.shibboleth.net/view/?p=spring-extensions.git;a=blob_plain;f=src/test/resources/data/document.xml;h=e8ec7c0d20c7a6b8193e1868398cda0c28df45ed;hb=HEAD" />
 

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the commits mailing list