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

Scott Cantor cantor.2 at osu.edu
Fri Aug 18 19:38:00 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=b0c54741891b9784e77e2186c044f2749a68f863

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

commit b0c54741891b9784e77e2186c044f2749a68f863
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Fri Aug 18 19:37:56 2017 -0400

    IDP-1170 - REST DataConnector
    
    https://issues.shibboleth.net/jira/browse/IDP-1170
    
    Extend schema to support POST variant.
---
 .../dc/http/impl/HTTPDataConnectorParser.java      | 105 +++++++++++++++++++--
 .../dc/http/HTTPDataConnectorParserTest.java       |  28 ++++++
 .../dc/http/http-attribute-resolver-v2-body.xml    |  20 ++++
 .../schema/shibboleth-attribute-resolver.xsd       |  29 ++++++
 4 files changed, 175 insertions(+), 7 deletions(-)

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 55cc330..6ff04a8 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
@@ -26,6 +26,7 @@ import javax.xml.namespace.QName;
 import net.shibboleth.ext.spring.util.SpringSupport;
 import net.shibboleth.idp.attribute.resolver.dc.http.impl.HTTPDataConnector;
 import net.shibboleth.idp.attribute.resolver.dc.http.impl.ScriptedResponseMappingStrategy;
+import net.shibboleth.idp.attribute.resolver.dc.http.impl.TemplatedBodyBuilder;
 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;
@@ -94,9 +95,14 @@ public class HTTPDataConnectorParser extends AbstractDataConnectorParser {
         if (searchBuilderID != null) {
             builder.addPropertyReference("executableSearchBuilder", searchBuilderID);
         } else {
-            final BeanDefinition def = v2Parser.createTemplateBuilder(httpClientSecurityBean);
+            BeanDefinition def = v2Parser.createBodyTemplateBuilder(httpClientSecurityBean);
             if (def != null) {
                 builder.addPropertyValue("executableSearchBuilder", def);
+            } else {
+                def = v2Parser.createURLTemplateBuilder(httpClientSecurityBean);
+                if (def != null) {
+                    builder.addPropertyValue("executableSearchBuilder", def);
+                }
             }
         }
 
@@ -174,12 +180,21 @@ public class HTTPDataConnectorParser extends AbstractDataConnectorParser {
         }
         
         /**
-         * Create the definition of the template driven search builder.
+         * Create the definition of the GET search builder.
          * 
          * @param httpClientSecurityParams instance of {@link HttpClientSecurityParameters} to inject
-         * @return the bean definition for the template search builder.
+         * 
+         * @return the bean definition for the search builder
          */
-        @Nonnull public BeanDefinition createTemplateBuilder(@Nullable final BeanDefinition httpClientSecurityParams) {
+        @Nullable public BeanDefinition createURLTemplateBuilder(
+                @Nullable final BeanDefinition httpClientSecurityParams) {
+            
+            final List<Element> urlTemplates = ElementSupport.getChildElements(configElement, 
+                    new QName(AttributeResolverNamespaceHandler.NAMESPACE, "URLTemplate"));
+            if (urlTemplates.size() == 0) {
+                return null;
+            }
+            
             final BeanDefinitionBuilder templateBuilder =
                     BeanDefinitionBuilder.genericBeanDefinition(TemplatedURLBuilder.class);
             templateBuilder.setInitMethodName("initialize");
@@ -202,9 +217,6 @@ public class HTTPDataConnectorParser extends AbstractDataConnectorParser {
                 }
             }
             
-            final List<Element> urlTemplates = ElementSupport.getChildElements(configElement, 
-                            new QName(AttributeResolverNamespaceHandler.NAMESPACE, "URLTemplate"));
-            
             if (urlTemplates.size() > 1) {
                 log.warn("{} A maximum of 1 <URLTemplate> should be specified; the first one has been used",
                         getLogPrefix());
@@ -215,11 +227,90 @@ public class HTTPDataConnectorParser extends AbstractDataConnectorParser {
                 url = urlTemplates.get(0).getTextContent();
             }
             templateBuilder.addPropertyValue("templateText", url);
+            
+            final String headerMapRef = StringSupport.trimOrNull(configElement.getAttributeNS(null, "headerMapRef"));
+            if (headerMapRef != null) {
+                templateBuilder.addPropertyReference("headers", headerMapRef);
+            }
 
+            return templateBuilder.getBeanDefinition();
+        }
+
+// Checkstyle: CyclomaticComplexity OFF
+        /**
+         * Create the definition of the POST search builder.
+         * 
+         * @param httpClientSecurityParams instance of {@link HttpClientSecurityParameters} to inject
+         * 
+         * @return the bean definition for the search builder, or null
+         */
+        @Nullable public BeanDefinition createBodyTemplateBuilder(
+                @Nullable final BeanDefinition httpClientSecurityParams) {
+            
+            final List<Element> urlTemplates = ElementSupport.getChildElements(configElement, 
+                    new QName(AttributeResolverNamespaceHandler.NAMESPACE, "URLTemplate"));
+            final List<Element> bodyTemplates = ElementSupport.getChildElements(configElement, 
+                    new QName(AttributeResolverNamespaceHandler.NAMESPACE, "BodyTemplate"));
+            if (urlTemplates.size() == 0 || bodyTemplates.size() == 0) {
+                return null;
+            }
+            final List<Element> cacheKeyTemplates = ElementSupport.getChildElements(configElement, 
+                    new QName(AttributeResolverNamespaceHandler.NAMESPACE, "CacheKeyTemplate"));
+            
+            final BeanDefinitionBuilder templateBuilder =
+                    BeanDefinitionBuilder.genericBeanDefinition(TemplatedBodyBuilder.class);
             templateBuilder.setInitMethodName("initialize");
             templateBuilder.setDestroyMethodName("destroy");
+
+            String velocityEngineRef = StringSupport.trimOrNull(configElement.getAttributeNS(null, "templateEngine"));
+            if (null == velocityEngineRef) {
+                velocityEngineRef = "shibboleth.VelocityEngine";
+            }
+            templateBuilder.addPropertyReference("velocityEngine", velocityEngineRef);
+
+            // This is duplication but allows the built-in builder to access the parameters if desired.
+            if (httpClientSecurityParams != null) {
+                templateBuilder.addPropertyValue("httpClientSecurityParameters", httpClientSecurityParams);
+            } else {
+                final String securityParamsRef =
+                        StringSupport.trimOrNull(configElement.getAttributeNS(null, "httpClientSecurityParametersRef"));
+                if (securityParamsRef != null) {
+                    templateBuilder.addPropertyReference("httpClientSecurityParameters", securityParamsRef);
+                }
+            }
+            
+            if (urlTemplates.size() > 1) {
+                log.warn("{} A maximum of 1 <URLTemplate> should be specified; the first one has been used",
+                        getLogPrefix());
+            } else if (bodyTemplates.size() > 1) {
+                log.warn("{} A maximum of 1 <BodyTemplate> should be specified; the first one has been used",
+                        getLogPrefix());
+            } else if (cacheKeyTemplates.size() > 1) {
+                log.warn("{} A maximum of 1 <CacheKeyTemplate> should be specified; the first one has been used",
+                        getLogPrefix());
+            }
+            
+            templateBuilder.addPropertyValue("uRLTemplateText", urlTemplates.get(0).getTextContent());
+            final Element bodyTemplate = bodyTemplates.get(0);
+            templateBuilder.addPropertyValue("bodyTemplateText", bodyTemplate.getTextContent());
+            if (bodyTemplate.hasAttributeNS(null, "MIMEType")) {
+                templateBuilder.addPropertyValue("mIMEType", bodyTemplate.getAttributeNS(null, "MIMEType"));
+            }
+            if (bodyTemplate.hasAttributeNS(null, "charset")) {
+                templateBuilder.addPropertyValue("characterSet", bodyTemplate.getAttributeNS(null, "charset"));
+            }
+            if (cacheKeyTemplates.size() > 0) {
+                templateBuilder.addPropertyValue("cacheKeyTemplateText", cacheKeyTemplates.get(0).getTextContent());
+            }
+            
+            final String headerMapRef = StringSupport.trimOrNull(configElement.getAttributeNS(null, "headerMapRef"));
+            if (headerMapRef != null) {
+                templateBuilder.addPropertyReference("headers", headerMapRef);
+            }
+
             return templateBuilder.getBeanDefinition();
         }
+// Checkstyle: CyclomaticComplexity OFF
         
         /**
          * Get the bean ID of an externally defined mapping strategy.
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 c2fac3e..790d605 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
@@ -321,6 +321,34 @@ public class HTTPDataConnectorParserTest {
         Assert.assertTrue(connector.getResultsCache().size() == 1);    
     }
 
+    @Test(enabled=false) public void v2ConfigPOST() throws Exception {
+        
+        final MockPropertySource propSource = singletonPropertySource("serviceURL", "https://shibboleth.net/cgi-bin/_frobnitz.cgi");
+        propSource.setProperty("serviceBody",
+                "[{\"name\" : \"foo\",\"values\" : [ \"foo1\" ]},{\"name\" : \"bar\",\"values\" : [ \"bar1\", \"bar2\" ]}]");
+        propSource.setProperty("scriptPath", (isV8() ? SCRIPT_PATH_V8 : SCRIPT_PATH) + "test.js");
+        
+        final HTTPDataConnector connector =
+                getDataConnector(propSource,
+                        "net/shibboleth/idp/attribute/resolver/spring/dc/http/http-attribute-resolver-v2-body.xml");
+        Assert.assertNotNull(connector);
+        
+        final AttributeResolutionContext context =
+                TestSources.createResolutionContext(TestSources.PRINCIPAL_ID, TestSources.IDP_ENTITY_ID,
+                        TestSources.SP_ENTITY_ID);
+        
+        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");
+    }
+    
     private HTTPDataConnector getDataConnector(final PropertySource propSource, final String... beanDefinitions)
             throws IOException {
         final GenericApplicationContext context = new GenericApplicationContext();
diff --git a/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/http/http-attribute-resolver-v2-body.xml b/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/http/http-attribute-resolver-v2-body.xml
new file mode 100644
index 0000000..3d60179
--- /dev/null
+++ b/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/http/http-attribute-resolver-v2-body.xml
@@ -0,0 +1,20 @@
+<?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="NoTrustEngineHttpClient"
+            acceptStatuses="200 201"
+            acceptTypes="application/json">
+            
+        <URLTemplate>%{serviceURL}</URLTemplate>
+        <BodyTemplate MIMEType="application/json">%{serviceBody}</BodyTemplate>
+        
+        <ResponseMapping>
+            <ScriptFile>%{scriptPath}</ScriptFile>
+        </ResponseMapping>
+        
+    </DataConnector>
+    
+</AttributeResolver>
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 9f26b12..ed0e360 100644
--- a/idp-schema/src/main/resources/schema/shibboleth-attribute-resolver.xsd
+++ b/idp-schema/src/main/resources/schema/shibboleth-attribute-resolver.xsd
@@ -1247,6 +1247,28 @@
                             </documentation>
                         </annotation>
                     </element>
+                    <element name="BodyTemplate">
+                        <annotation>
+                            <documentation>
+                                A template that will be used to create a body to POST.
+                            </documentation>
+                        </annotation>
+                        <complexType>
+                            <simpleContent>
+                                <extension base="string">
+                                    <attribute name="MIMEType" type="string" />
+                                    <attribute name="charset" type="string" />
+                                </extension>
+                            </simpleContent>
+                        </complexType>
+                    </element>
+                    <element name="CacheKeyTemplate" type="string">
+                        <annotation>
+                            <documentation>
+                                A template that will be used to create a key to the caching of the results.
+                            </documentation>
+                        </annotation>
+                    </element>
                     <element name="ResponseMapping" type="resolver:ScriptType">
                         <annotation>
                             <documentation>Maps the response into attributes by means of scripting.</documentation>
@@ -1331,6 +1353,13 @@
                         <list itemType="string"/>
                     </simpleType>
                 </attribute>
+                <attribute name="headerMapRef" type="string">
+                    <annotation>
+                        <documentation>
+                            Reference to a Spring bean providing a Map<String,String> of request headers to set.
+                        </documentation>
+                    </annotation>
+                </attribute>
                 <attribute name="executableSearchBuilderRef" 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