[java-identity-provider] branch master updated: IDP-1170 - REST DataConnector

Scott Cantor cantor.2 at osu.edu
Thu Aug 10 16:45:14 EDT 2017


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

scantor pushed a commit to branch master
in repository java-identity-provider.

View the commit online:
http://git.shibboleth.net/view/?p=java-identity-provider.git;a=commit;h=fe8a5c8712b65777d508c73de393b6ad90859df6

The following commit(s) were added to refs/heads/master by this push:
       new  fe8a5c8   IDP-1170 - REST DataConnector
fe8a5c8 is described below

commit fe8a5c8712b65777d508c73de393b6ad90859df6
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Thu Aug 10 16:45:13 2017 -0400

    IDP-1170 - REST DataConnector
    
    https://issues.shibboleth.net/jira/browse/IDP-1170
    
    Add certificate and certificateAuthority shortcuts to schema
---
 idp-attribute-resolver-spring/pom.xml              |  7 ++
 .../dc/http/impl/HTTPDataConnectorParser.java      | 70 ++++++++++++++--
 .../dc/http/HTTPDataConnectorParserTest.java       | 94 ++++++++++++++++++++++
 .../dc/http/http-attribute-resolver-v2-ca.xml      | 18 +++++
 .../http-attribute-resolver-v2-certificate.xml     | 18 +++++
 .../resolver/spring/dc/http/spring-beans.xml       |  8 ++
 .../schema/shibboleth-attribute-resolver.xsd       | 14 ++++
 7 files changed, 222 insertions(+), 7 deletions(-)

diff --git a/idp-attribute-resolver-spring/pom.xml b/idp-attribute-resolver-spring/pom.xml
index d809c3d..a47c608 100644
--- a/idp-attribute-resolver-spring/pom.xml
+++ b/idp-attribute-resolver-spring/pom.xml
@@ -132,6 +132,13 @@
         </dependency>
         <dependency>
             <groupId>${opensaml.groupId}</groupId>
+            <artifactId>opensaml-saml-impl</artifactId>
+            <version>${opensaml.version}</version>
+            <type>test-jar</type>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${opensaml.groupId}</groupId>
             <artifactId>opensaml-storage-impl</artifactId>
             <version>${opensaml.version}</version>
             <scope>test</scope>
diff --git a/idp-attribute-resolver-spring/src/main/java/net/shibboleth/idp/attribute/resolver/spring/dc/http/impl/HTTPDataConnectorParser.java b/idp-attribute-resolver-spring/src/main/java/net/shibboleth/idp/attribute/resolver/spring/dc/http/impl/HTTPDataConnectorParser.java
index 2733151..3d49cfc 100644
--- a/idp-attribute-resolver-spring/src/main/java/net/shibboleth/idp/attribute/resolver/spring/dc/http/impl/HTTPDataConnectorParser.java
+++ b/idp-attribute-resolver-spring/src/main/java/net/shibboleth/idp/attribute/resolver/spring/dc/http/impl/HTTPDataConnectorParser.java
@@ -30,6 +30,8 @@ import net.shibboleth.idp.attribute.resolver.dc.http.impl.TemplatedURLBuilder;
 import net.shibboleth.idp.attribute.resolver.spring.dc.AbstractDataConnectorParser;
 import net.shibboleth.idp.attribute.resolver.spring.dc.impl.CacheConfigParser;
 import net.shibboleth.idp.attribute.resolver.spring.impl.AttributeResolverNamespaceHandler;
+import net.shibboleth.idp.profile.spring.factory.StaticExplicitKeyFactoryBean;
+import net.shibboleth.idp.profile.spring.factory.StaticPKIXFactoryBean;
 import net.shibboleth.idp.profile.spring.relyingparty.metadata.ScriptTypeBeanParser;
 import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
 import net.shibboleth.utilities.java.support.logic.Constraint;
@@ -37,6 +39,7 @@ import net.shibboleth.utilities.java.support.primitive.StringSupport;
 import net.shibboleth.utilities.java.support.xml.AttributeSupport;
 import net.shibboleth.utilities.java.support.xml.ElementSupport;
 
+import org.opensaml.security.httpclient.HttpClientSecurityParameters;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.config.BeanDefinition;
@@ -59,6 +62,7 @@ public class HTTPDataConnectorParser extends AbstractDataConnectorParser {
         return HTTPDataConnector.class;
     }
     
+// Checkstyle: CyclomaticComplexity OFF
     /** {@inheritDoc} */
     @Override protected void doV2Parse(@Nonnull final Element config, @Nonnull final ParserContext parserContext,
             @Nonnull final BeanDefinitionBuilder builder) {
@@ -74,7 +78,14 @@ public class HTTPDataConnectorParser extends AbstractDataConnectorParser {
         
         final String securityParams =
                 StringSupport.trimOrNull(config.getAttributeNS(null, "httpClientSecurityParametersRef"));
-        if (securityParams != null) {
+        final BeanDefinition httpClientSecurityBean =
+                v2Parser.buildHttpClientSecurityParams(config.getAttributeNS(null, "id"));
+        if (httpClientSecurityBean != null) {
+            if (securityParams != null) {
+                log.warn("Ignoring httpClientSecurityParametersRef setting in favor of manual settings");
+            }
+            builder.addPropertyValue("httpClientSecurityParameters", httpClientSecurityBean);
+        } else if (securityParams != null) {
             builder.addPropertyReference("httpClientSecurityParameters", securityParams);
         }
 
@@ -82,7 +93,7 @@ public class HTTPDataConnectorParser extends AbstractDataConnectorParser {
         if (searchBuilderID != null) {
             builder.addPropertyReference("executableSearchBuilder", searchBuilderID);
         } else {
-            final BeanDefinition def = v2Parser.createTemplateBuilder();
+            final BeanDefinition def = v2Parser.createTemplateBuilder(httpClientSecurityBean);
             if (def != null) {
                 builder.addPropertyValue("executableSearchBuilder", def);
             }
@@ -114,6 +125,7 @@ public class HTTPDataConnectorParser extends AbstractDataConnectorParser {
         builder.setInitMethodName("initialize");
         builder.setDestroyMethodName("destroy");
     }
+// Checkstyle: CyclomaticComplexity ON
 
     /**
      * Utility class for parsing v2 schema configuration.
@@ -163,9 +175,10 @@ public class HTTPDataConnectorParser extends AbstractDataConnectorParser {
         /**
          * Create the definition of the template driven search builder.
          * 
+         * @param httpClientSecurityParams instance of {@link HttpClientSecurityParameters} to inject
          * @return the bean definition for the template search builder.
          */
-        @Nonnull public BeanDefinition createTemplateBuilder() {
+        @Nonnull public BeanDefinition createTemplateBuilder(@Nullable final BeanDefinition httpClientSecurityParams) {
             final BeanDefinitionBuilder templateBuilder =
                     BeanDefinitionBuilder.genericBeanDefinition(TemplatedURLBuilder.class);
             templateBuilder.setInitMethodName("initialize");
@@ -178,10 +191,14 @@ public class HTTPDataConnectorParser extends AbstractDataConnectorParser {
             templateBuilder.addPropertyReference("velocityEngine", velocityEngineRef);
 
             // This is duplication but allows the built-in builder to access the parameters if desired.
-            final String securityParams =
-                    StringSupport.trimOrNull(configElement.getAttributeNS(null, "httpClientSecurityParametersRef"));
-            if (securityParams != null) {
-                templateBuilder.addPropertyReference("httpClientSecurityParameters", securityParams);
+            if (httpClientSecurityParams != null) {
+                templateBuilder.addPropertyValue("httpClientSecurityParameters", httpClientSecurityParams);
+            } else {
+                final String securityParamsRef =
+                        StringSupport.trimOrNull(configElement.getAttributeNS(null, "httpClientSecurityParametersRef"));
+                if (securityParamsRef != null) {
+                    templateBuilder.addPropertyReference("httpClientSecurityParameters", securityParamsRef);
+                }
             }
             
             final List<Element> urlTemplates = ElementSupport.getChildElements(configElement, 
@@ -276,6 +293,45 @@ public class HTTPDataConnectorParser extends AbstractDataConnectorParser {
             return parser.createCache(parserContext);
         }
         
+        /**
+         * Check for manually supplied settings and build {@link HttpClientSecurityParameters} instance.
+         * 
+         * @param id connector ID
+         * 
+         * @return a bean definition if applicable
+         */
+        @Nullable public BeanDefinition buildHttpClientSecurityParams(@Nullable final String id) {
+            BeanDefinitionBuilder builder = null;
+            final String certificate = StringSupport.trimOrNull(configElement.getAttributeNS(null, "certificate"));
+            if (certificate != null) {
+                log.debug("Auto-configuring connector {} with a server certificate to authenticate", id);
+                builder = BeanDefinitionBuilder.genericBeanDefinition(HttpClientSecurityParameters.class);
+                final BeanDefinitionBuilder explicitTrust =
+                        BeanDefinitionBuilder.genericBeanDefinition(StaticExplicitKeyFactoryBean.class);
+                explicitTrust.addPropertyValue("certificates", certificate);
+                builder.addPropertyValue("tLSTrustEngine", explicitTrust.getBeanDefinition());
+            }
+            
+            final String certificateAuthority =
+                    StringSupport.trimOrNull(configElement.getAttributeNS(null, "certificateAuthority"));
+            if (certificateAuthority != null) {
+                if (builder != null) {
+                    log.warn("Ignoring certificateAuthority set on connector {}, superseded by certificate", id);
+                } else {
+                    log.debug("Auto-configuring connector {} with a certificate authority to authenticate", id);
+                    builder = BeanDefinitionBuilder.genericBeanDefinition(HttpClientSecurityParameters.class);
+                    final BeanDefinitionBuilder pkixTrust =
+                            BeanDefinitionBuilder.genericBeanDefinition(StaticPKIXFactoryBean.class);
+                    // Relies on underlying enhanced TLSSocketFactory hostname verifier to kick in.
+                    pkixTrust.addPropertyValue("checkNames", false);
+                    pkixTrust.addPropertyValue("certificates", certificateAuthority);
+                    builder.addPropertyValue("tLSTrustEngine", pkixTrust.getBeanDefinition());
+                }
+            }
+            
+            return builder != null ? builder.getBeanDefinition() : null;
+        }
+        
         /** The parent parser's log prefix.
          * @return the log prefix.
          */
diff --git a/idp-attribute-resolver-spring/src/test/java/net/shibboleth/idp/attribute/resolver/spring/dc/http/HTTPDataConnectorParserTest.java b/idp-attribute-resolver-spring/src/test/java/net/shibboleth/idp/attribute/resolver/spring/dc/http/HTTPDataConnectorParserTest.java
index c7de646..3422ba0 100644
--- a/idp-attribute-resolver-spring/src/test/java/net/shibboleth/idp/attribute/resolver/spring/dc/http/HTTPDataConnectorParserTest.java
+++ b/idp-attribute-resolver-spring/src/test/java/net/shibboleth/idp/attribute/resolver/spring/dc/http/HTTPDataConnectorParserTest.java
@@ -166,6 +166,100 @@ public class HTTPDataConnectorParserTest {
         Assert.assertTrue(attrs == null || attrs.isEmpty());
     }
 
+    @Test public void v2Certificate() throws Exception {
+        
+        final MockPropertySource propSource = singletonPropertySource("serviceURL", TEST_URL);
+        propSource.setProperty("scriptPath", (isV8() ? SCRIPT_PATH_V8 : SCRIPT_PATH) + "test.js");
+        propSource.setProperty("certificate", "/org/opensaml/saml/metadata/resolver/impl/repo-entity.crt");
+        
+        final HTTPDataConnector connector =
+                getDataConnector(propSource,
+                        "net/shibboleth/idp/attribute/resolver/spring/dc/http/http-attribute-resolver-v2-certificate.xml");
+        Assert.assertNotNull(connector);
+        
+        final AttributeResolutionContext context =
+                TestSources.createResolutionContext(TestSources.PRINCIPAL_ID, TestSources.IDP_ENTITY_ID,
+                        TestSources.SP_ENTITY_ID);
+        
+        connector.resolve(context);
+        
+        final Map<String,IdPAttribute> attrs = connector.resolve(context);
+        
+        Assert.assertEquals(attrs.size(), 2);
+        
+        Assert.assertEquals(attrs.get("foo").getValues().size(), 1);
+        Assert.assertEquals(attrs.get("foo").getValues().get(0).getValue(), "foo1");
+        
+        Assert.assertEquals(attrs.get("bar").getValues().size(), 2);
+        Assert.assertEquals(attrs.get("bar").getValues().get(0).getValue(), "bar1");
+        Assert.assertEquals(attrs.get("bar").getValues().get(1).getValue(), "bar2");
+    }
+
+    @Test(expectedExceptions=ResolutionException.class) public void v2BadCertificate() throws Exception {
+        
+        final MockPropertySource propSource = singletonPropertySource("serviceURL", TEST_URL);
+        propSource.setProperty("scriptPath", (isV8() ? SCRIPT_PATH_V8 : SCRIPT_PATH) + "test.js");
+        propSource.setProperty("certificate", "/org/opensaml/saml/metadata/resolver/impl/badKey.crt");
+        
+        final HTTPDataConnector connector =
+                getDataConnector(propSource,
+                        "net/shibboleth/idp/attribute/resolver/spring/dc/http/http-attribute-resolver-v2-certificate.xml");
+        Assert.assertNotNull(connector);
+        
+        final AttributeResolutionContext context =
+                TestSources.createResolutionContext(TestSources.PRINCIPAL_ID, TestSources.IDP_ENTITY_ID,
+                        TestSources.SP_ENTITY_ID);
+        
+        connector.resolve(context);
+    }
+
+    @Test public void v2CA() throws Exception {
+        
+        final MockPropertySource propSource = singletonPropertySource("serviceURL", TEST_URL);
+        propSource.setProperty("scriptPath", (isV8() ? SCRIPT_PATH_V8 : SCRIPT_PATH) + "test.js");
+        propSource.setProperty("certificateAuthority", "/org/opensaml/saml/metadata/resolver/impl/repo-rootCA.crt");
+        
+        final HTTPDataConnector connector =
+                getDataConnector(propSource,
+                        "net/shibboleth/idp/attribute/resolver/spring/dc/http/http-attribute-resolver-v2-ca.xml");
+        Assert.assertNotNull(connector);
+        
+        final AttributeResolutionContext context =
+                TestSources.createResolutionContext(TestSources.PRINCIPAL_ID, TestSources.IDP_ENTITY_ID,
+                        TestSources.SP_ENTITY_ID);
+        
+        connector.resolve(context);
+        
+        final Map<String,IdPAttribute> attrs = connector.resolve(context);
+        
+        Assert.assertEquals(attrs.size(), 2);
+        
+        Assert.assertEquals(attrs.get("foo").getValues().size(), 1);
+        Assert.assertEquals(attrs.get("foo").getValues().get(0).getValue(), "foo1");
+        
+        Assert.assertEquals(attrs.get("bar").getValues().size(), 2);
+        Assert.assertEquals(attrs.get("bar").getValues().get(0).getValue(), "bar1");
+        Assert.assertEquals(attrs.get("bar").getValues().get(1).getValue(), "bar2");
+    }
+    
+    @Test(expectedExceptions=ResolutionException.class) public void v2BadCA() throws Exception {
+        
+        final MockPropertySource propSource = singletonPropertySource("serviceURL", TEST_URL);
+        propSource.setProperty("scriptPath", (isV8() ? SCRIPT_PATH_V8 : SCRIPT_PATH) + "test.js");
+        propSource.setProperty("certificateAuthority", "/org/opensaml/saml/metadata/resolver/impl/badCA.crt");
+        
+        final HTTPDataConnector connector =
+                getDataConnector(propSource,
+                        "net/shibboleth/idp/attribute/resolver/spring/dc/http/http-attribute-resolver-v2-ca.xml");
+        Assert.assertNotNull(connector);
+        
+        final AttributeResolutionContext context =
+                TestSources.createResolutionContext(TestSources.PRINCIPAL_ID, TestSources.IDP_ENTITY_ID,
+                        TestSources.SP_ENTITY_ID);
+        
+        connector.resolve(context);
+    }
+    
     @Test public void hybridConfig() throws Exception {
         final MockPropertySource propSource = singletonPropertySource("serviceURL", TEST_URL);
         propSource.setProperty("scriptPath", (isV8() ? SCRIPT_PATH_V8 : SCRIPT_PATH) + "test.js");
diff --git a/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/http/http-attribute-resolver-v2-ca.xml b/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/http/http-attribute-resolver-v2-ca.xml
new file mode 100644
index 0000000..5abd7ae
--- /dev/null
+++ b/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/http/http-attribute-resolver-v2-ca.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<AttributeResolver 
+            xmlns="urn:mace:shibboleth:2.0:resolver" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
+            xsi:schemaLocation="urn:mace:shibboleth:2.0:resolver http://shibboleth.net/schema/idp/shibboleth-attribute-resolver.xsd">
+
+    <DataConnector id="myHTTP" xsi:type="HTTP"
+            httpClientRef="TrustEngineHttpClient"
+            certificateAuthority="%{certificateAuthority}">
+            
+        <URLTemplate>%{serviceURL}</URLTemplate>
+        
+        <ResponseMapping>
+            <ScriptFile>%{scriptPath}</ScriptFile>
+        </ResponseMapping>
+        
+    </DataConnector>
+    
+</AttributeResolver>
diff --git a/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/http/http-attribute-resolver-v2-certificate.xml b/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/http/http-attribute-resolver-v2-certificate.xml
new file mode 100644
index 0000000..12f5b53
--- /dev/null
+++ b/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/http/http-attribute-resolver-v2-certificate.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<AttributeResolver 
+            xmlns="urn:mace:shibboleth:2.0:resolver" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
+            xsi:schemaLocation="urn:mace:shibboleth:2.0:resolver http://shibboleth.net/schema/idp/shibboleth-attribute-resolver.xsd">
+
+    <DataConnector id="myHTTP" xsi:type="HTTP"
+            httpClientRef="TrustEngineHttpClient"
+            certificate="%{certificate}">
+            
+        <URLTemplate>%{serviceURL}</URLTemplate>
+        
+        <ResponseMapping>
+            <ScriptFile>%{scriptPath}</ScriptFile>
+        </ResponseMapping>
+        
+    </DataConnector>
+    
+</AttributeResolver>
diff --git a/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/http/spring-beans.xml b/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/http/spring-beans.xml
index 6c2f273..45c4b20 100644
--- a/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/http/spring-beans.xml
+++ b/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/http/spring-beans.xml
@@ -8,6 +8,14 @@
     <bean id="NoTrustEngineHttpClient"
         class="net.shibboleth.idp.profile.spring.relyingparty.metadata.HttpClientFactoryBean" />
 
+    <bean id="SecurityEnhancedTLSSocketFactory" 
+        class="org.opensaml.security.httpclient.impl.SecurityEnhancedHttpClientSupport"
+        factory-method="buildTLSSocketFactory" />
+
+    <bean id="TrustEngineHttpClient"
+        class="net.shibboleth.idp.profile.spring.relyingparty.metadata.HttpClientFactoryBean"
+        p:TLSSocketFactory-ref="SecurityEnhancedTLSSocketFactory" />
+
     <bean id="BadProtocolParameters"
         class="org.opensaml.security.httpclient.HttpClientSecurityParameters"
         p:TLSProtocols="SSLv3" />
diff --git a/idp-schema/src/main/resources/schema/shibboleth-attribute-resolver.xsd b/idp-schema/src/main/resources/schema/shibboleth-attribute-resolver.xsd
index 86de4b7..d7bdbce 100644
--- a/idp-schema/src/main/resources/schema/shibboleth-attribute-resolver.xsd
+++ b/idp-schema/src/main/resources/schema/shibboleth-attribute-resolver.xsd
@@ -1260,6 +1260,20 @@
                         </documentation>
                     </annotation>
                 </attribute>
+                <attribute name="certificate" type="string">
+                    <annotation>
+                        <documentation>
+                            Location of certificate to authenticate HTTP server
+                        </documentation>
+                    </annotation>
+                </attribute>
+                <attribute name="certificateAuthority" type="string">
+                    <annotation>
+                        <documentation>
+                            Location of CA to indirectly authenticate HTTP server
+                        </documentation>
+                    </annotation>
+                </attribute>
                 <attribute name="templateEngine" type="string">
                     <annotation>
                         <documentation>

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


More information about the commits mailing list