[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