[java-identity-provider] branch master updated: IDP-1170 - REST DataConnector
Scott Cantor
cantor.2 at osu.edu
Tue Jun 13 15:46:34 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=4e4df06fcd1abbdd2aa66e0b74cb6d4a7de166ee
The following commit(s) were added to refs/heads/master by this push:
new 4e4df06 IDP-1170 - REST DataConnector
4e4df06 is described below
commit 4e4df06fcd1abbdd2aa66e0b74cb6d4a7de166ee
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Tue Jun 13 15:46:04 2017 -0400
IDP-1170 - REST DataConnector
https://issues.shibboleth.net/jira/browse/IDP-1170
Spring parser and schema for configuration.
---
.../dc/http/impl/HTTPDataConnectorParser.java | 280 +++++++++++++++++++++
.../resolver/spring/dc/http/impl/package-info.java | 22 ++
.../impl/AttributeResolverNamespaceHandler.java | 2 +
.../dc/http/HTTPDataConnectorParserTest.java | 239 ++++++++++++++++++
.../http-attribute-resolver-spring-context.xml | 25 ++
.../http-attribute-resolver-v2-badprotocol.xml | 18 ++
.../dc/http/http-attribute-resolver-v2-hybrid.xml | 15 ++
.../http/http-attribute-resolver-v2-missingok.xml | 20 ++
.../spring/dc/http/http-attribute-resolver-v2.xml | 21 ++
.../resolver/spring/dc/http/spring-beans.xml | 33 +++
.../schema/shibboleth-attribute-resolver.xsd | 102 ++++++++
11 files changed, 777 insertions(+)
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
new file mode 100644
index 0000000..b3f40d7
--- /dev/null
+++ b/idp-attribute-resolver-spring/src/main/java/net/shibboleth/idp/attribute/resolver/spring/dc/http/impl/HTTPDataConnectorParser.java
@@ -0,0 +1,280 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You 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 net.shibboleth.idp.attribute.resolver.spring.dc.http.impl;
+
+import java.util.List;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+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.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.relyingparty.metadata.ScriptTypeBeanParser;
+import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.support.BeanDefinitionBuilder;
+import org.springframework.beans.factory.xml.ParserContext;
+import org.w3c.dom.Element;
+
+/** Bean definition Parser for a {@link HTTPDataConnector}. */
+public class HTTPDataConnectorParser extends AbstractDataConnectorParser {
+
+ /** Schema type name. */
+ @Nonnull public static final QName TYPE_NAME =
+ new QName(AttributeResolverNamespaceHandler.NAMESPACE, "HTTP");
+
+ /** Class logger. */
+ @Nonnull private final Logger log = LoggerFactory.getLogger(HTTPDataConnectorParser.class);
+
+ /** {@inheritDoc} */
+ @Override protected Class<HTTPDataConnector> getNativeBeanClass() {
+ return HTTPDataConnector.class;
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void doV2Parse(@Nonnull final Element config, @Nonnull final ParserContext parserContext,
+ @Nonnull final BeanDefinitionBuilder builder) {
+
+ log.debug("{} Parsing custom configuration {}", getLogPrefix(), config);
+
+ final V2Parser v2Parser = new V2Parser(config, getLogPrefix());
+
+ final String httpClientID = v2Parser.getBeanHttpClientID();
+ if (httpClientID != null) {
+ builder.addPropertyReference("httpClient", httpClientID);
+ }
+
+ final String searchBuilderID = v2Parser.getBeanSearchBuilderID();
+ if (searchBuilderID != null) {
+ builder.addPropertyReference("executableSearchBuilder", searchBuilderID);
+ } else {
+ final BeanDefinition def = v2Parser.createTemplateBuilder();
+ if (def != null) {
+ builder.addPropertyValue("executableSearchBuilder", def);
+ }
+ }
+
+ final String mappingStrategyID = v2Parser.getBeanMappingStrategyID();
+ if (mappingStrategyID != null) {
+ builder.addPropertyReference("mappingStrategy", mappingStrategyID);
+ } else {
+ final BeanDefinition def = v2Parser.createMappingStrategy(config.getAttributeNS(null, "id"));
+ if (def != null) {
+ builder.addPropertyValue("mappingStrategy", def);
+ }
+ }
+
+ final String validatorID = v2Parser.getBeanValidatorID();
+ if (validatorID != null) {
+ builder.addPropertyReference("validator", validatorID);
+ }
+
+ final String resultCacheBeanID = CacheConfigParser.getBeanResultCacheID(config);
+
+ if (null != resultCacheBeanID) {
+ builder.addPropertyReference("resultsCache", resultCacheBeanID);
+ } else {
+ builder.addPropertyValue("resultsCache", v2Parser.createCache(parserContext));
+ }
+
+ builder.setInitMethodName("initialize");
+ builder.setDestroyMethodName("destroy");
+ }
+
+ /**
+ * Utility class for parsing v2 schema configuration.
+ *
+ */
+ protected static class V2Parser {
+
+ /** Base XML element. */
+ @Nonnull private final Element configElement;
+
+ /** Class logger. */
+ @Nonnull private final Logger log = LoggerFactory.getLogger(V2Parser.class);
+
+ /** Parent parser's log prefix.*/
+ @Nonnull @NotEmpty private final String logPrefix;
+
+ /**
+ * Creates a new V2Parser with the supplied element.
+ *
+ * @param config HTTP DataConnector element
+ * @param prefix the parent parser's log prefix.
+ */
+ public V2Parser(@Nonnull final Element config, @Nonnull @NotEmpty final String prefix) {
+ Constraint.isNotNull(config, "HTTP DataConnector element cannot be null");
+ configElement = config;
+ logPrefix = prefix;
+ }
+
+ /**
+ * Get the bean ID of an externally defined HttpClient.
+ *
+ * @return HttpClient bean ID
+ */
+ @Nullable public String getBeanHttpClientID() {
+ return AttributeSupport.getAttributeValue(configElement, new QName("httpClientRef"));
+ }
+
+ /**
+ * Get the bean ID of an externally defined search builder.
+ *
+ * @return search builder bean ID
+ */
+ @Nullable public String getBeanSearchBuilderID() {
+ return AttributeSupport.getAttributeValue(configElement, null, "executableSearchBuilderRef");
+ }
+
+ /**
+ * Create the definition of the template driven search builder.
+ *
+ * @return the bean definition for the template search builder.
+ */
+ @Nonnull public BeanDefinition createTemplateBuilder() {
+ final BeanDefinitionBuilder templateBuilder =
+ BeanDefinitionBuilder.genericBeanDefinition(TemplatedURLBuilder.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);
+
+ final String securityParams =
+ StringSupport.trimOrNull(configElement.getAttributeNS(null, "httpClientSecurityParametersRef"));
+ if (securityParams != null) {
+ templateBuilder.addPropertyReference("httpClientSecurityParameters", securityParams);
+ }
+
+ 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());
+ }
+
+ String url = null;
+ if (!urlTemplates.isEmpty()) {
+ url = urlTemplates.get(0).getTextContent();
+ }
+ templateBuilder.addPropertyValue("templateText", url);
+
+ templateBuilder.setInitMethodName("initialize");
+ templateBuilder.setDestroyMethodName("destroy");
+ return templateBuilder.getBeanDefinition();
+ }
+
+ /**
+ * Get the bean ID of an externally defined mapping strategy.
+ *
+ * @return mapping strategy bean ID
+ */
+ @Nullable public String getBeanMappingStrategyID() {
+ return AttributeSupport.getAttributeValue(configElement, null, "mappingStrategyRef");
+ }
+
+ /**
+ * Create the scripted result mapping strategy.
+ *
+ * @param id the ID of the
+ *
+ * @return mapping strategy
+ */
+ @Nullable public BeanDefinition createMappingStrategy(@Nullable final String id) {
+
+ final List<Element> mappings = ElementSupport.getChildElements(configElement,
+ new QName(AttributeResolverNamespaceHandler.NAMESPACE, "ResponseMapping"));
+
+ if (mappings.size() > 1) {
+ log.warn("{} A maximum of 1 <ResponseMapping> should be specified; the first one has been used",
+ getLogPrefix());
+ }
+
+ final BeanDefinitionBuilder mapper =
+ ScriptTypeBeanParser.parseScriptType(ScriptedResponseMappingStrategy.class, mappings.get(0));
+ if (id != null) {
+ mapper.addPropertyValue("logPrefix", id + ':');
+ }
+
+ final String maxLength = StringSupport.trimOrNull(configElement.getAttributeNS(null, "maxLength"));
+ if (maxLength != null) {
+ mapper.addPropertyValue("maxLength", maxLength);
+ }
+
+ if (configElement.hasAttributeNS(null, "acceptStatuses")) {
+ mapper.addPropertyValue("acceptStatuses",
+ SpringSupport.getAttributeValueAsManagedList(
+ configElement.getAttributeNodeNS(null, "acceptStatuses")));
+ }
+
+ if (configElement.hasAttributeNS(null, "acceptTypes")) {
+ mapper.addPropertyValue("acceptTypes",
+ SpringSupport.getAttributeValueAsManagedList(
+ configElement.getAttributeNodeNS(null, "acceptTypes")));
+ }
+
+ return mapper.getBeanDefinition();
+ }
+
+ /**
+ * Get the bean ID of an externally defined validator.
+ *
+ * @return validator bean ID
+ */
+ @Nullable public String getBeanValidatorID() {
+ return AttributeSupport.getAttributeValue(configElement, null, "validatorRef");
+ }
+
+ /**
+ * Create the results cache. See {@link CacheConfigParser}.
+ *
+ * @param parserContext bean parser context
+ *
+ * @return results cache
+ */
+ @Nullable public BeanDefinition createCache(@Nonnull final ParserContext parserContext) {
+ final CacheConfigParser parser = new CacheConfigParser(configElement);
+ return parser.createCache(parserContext);
+ }
+
+ /** The parent parser's log prefix.
+ * @return the log prefix.
+ */
+ @Nonnull @NotEmpty private String getLogPrefix() {
+ return logPrefix;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/idp-attribute-resolver-spring/src/main/java/net/shibboleth/idp/attribute/resolver/spring/dc/http/impl/package-info.java b/idp-attribute-resolver-spring/src/main/java/net/shibboleth/idp/attribute/resolver/spring/dc/http/impl/package-info.java
new file mode 100644
index 0000000..fca4d36
--- /dev/null
+++ b/idp-attribute-resolver-spring/src/main/java/net/shibboleth/idp/attribute/resolver/spring/dc/http/impl/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You 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.
+ */
+
+/**
+ * The parser for the HTTP Data connector.
+ */
+
+package net.shibboleth.idp.attribute.resolver.spring.dc.http.impl;
\ No newline at end of file
diff --git a/idp-attribute-resolver-spring/src/main/java/net/shibboleth/idp/attribute/resolver/spring/impl/AttributeResolverNamespaceHandler.java b/idp-attribute-resolver-spring/src/main/java/net/shibboleth/idp/attribute/resolver/spring/impl/AttributeResolverNamespaceHandler.java
index 7aca8bb..4b2e60b 100644
--- a/idp-attribute-resolver-spring/src/main/java/net/shibboleth/idp/attribute/resolver/spring/impl/AttributeResolverNamespaceHandler.java
+++ b/idp-attribute-resolver-spring/src/main/java/net/shibboleth/idp/attribute/resolver/spring/impl/AttributeResolverNamespaceHandler.java
@@ -38,6 +38,7 @@ import net.shibboleth.idp.attribute.resolver.spring.ad.impl.TransientIdAttribute
import net.shibboleth.idp.attribute.resolver.spring.ad.mapped.impl.MappedAttributeDefinitionParser;
import net.shibboleth.idp.attribute.resolver.spring.ad.mapped.impl.SourceValueParser;
import net.shibboleth.idp.attribute.resolver.spring.ad.mapped.impl.ValueMapParser;
+import net.shibboleth.idp.attribute.resolver.spring.dc.http.impl.HTTPDataConnectorParser;
import net.shibboleth.idp.attribute.resolver.spring.dc.impl.ComputedIDDataConnectorParser;
import net.shibboleth.idp.attribute.resolver.spring.dc.impl.ScriptDataConnectorParser;
import net.shibboleth.idp.attribute.resolver.spring.dc.impl.StaticDataConnectorParser;
@@ -118,6 +119,7 @@ public class AttributeResolverNamespaceHandler extends BaseSpringNamespaceHandle
new ComputedIDDataConnectorParser());
registerBeanDefinitionParser(RDBMSDataConnectorParser.TYPE_NAME_RESOLVER, new RDBMSDataConnectorParser());
registerBeanDefinitionParser(LDAPDataConnectorParser.TYPE_NAME_RESOLVER, new LDAPDataConnectorParser());
+ registerBeanDefinitionParser(HTTPDataConnectorParser.TYPE_NAME, new HTTPDataConnectorParser());
registerBeanDefinitionParser(ScriptDataConnectorParser.TYPE_NAME_RESOLVER, new ScriptDataConnectorParser());
registerBeanDefinitionParser(StaticDataConnectorParser.TYPE_NAME_RESOLVER, new StaticDataConnectorParser());
registerBeanDefinitionParser(StoredIDDataConnectorParser.TYPE_NAME_RESOLVER, new StoredIDDataConnectorParser());
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
new file mode 100644
index 0000000..c7de646
--- /dev/null
+++ b/idp-attribute-resolver-spring/src/test/java/net/shibboleth/idp/attribute/resolver/spring/dc/http/HTTPDataConnectorParserTest.java
@@ -0,0 +1,239 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You 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 net.shibboleth.idp.attribute.resolver.spring.dc.http;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Map;
+
+import net.shibboleth.ext.spring.config.DurationToLongConverter;
+import net.shibboleth.ext.spring.config.StringToIPRangeConverter;
+import net.shibboleth.ext.spring.config.StringToResourceConverter;
+import net.shibboleth.ext.spring.util.SchemaTypeAwareXMLBeanDefinitionReader;
+import net.shibboleth.idp.attribute.IdPAttribute;
+import net.shibboleth.idp.attribute.resolver.ResolutionException;
+import net.shibboleth.idp.attribute.resolver.context.AttributeResolutionContext;
+import net.shibboleth.idp.attribute.resolver.dc.http.impl.HTTPDataConnector;
+import net.shibboleth.idp.saml.impl.TestSources;
+import net.shibboleth.utilities.java.support.repository.RepositorySupport;
+
+import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
+import org.springframework.context.support.ConversionServiceFactoryBean;
+import org.springframework.context.support.GenericApplicationContext;
+import org.springframework.core.env.PropertySource;
+import org.springframework.mock.env.MockPropertySource;
+import org.testng.Assert;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.Test;
+
+/** Test for {@link HTTPDataConnectorParser}. */
+public class HTTPDataConnectorParserTest {
+
+ private static final String TEST_URL =
+ RepositorySupport.buildHTTPSResourceURL("java-identity-provider",
+ "idp-attribute-resolver-impl/src/test/resources/net/shibboleth/idp/attribute/resolver/impl/dc/http/test.json");
+
+ private static final String SCRIPT_PATH = "/net/shibboleth/idp/attribute/resolver/impl/dc/http/";
+
+ private static final String SCRIPT_PATH_V8 = "/net/shibboleth/idp/attribute/resolver/impl/dc/http/v8/";
+
+ private GenericApplicationContext pendingTeardownContext = null;
+
+ @AfterMethod public void tearDownTestContext() {
+ if (null == pendingTeardownContext ) {
+ return;
+ }
+ pendingTeardownContext.close();
+ pendingTeardownContext = null;
+ }
+
+ private void setTestContext(final GenericApplicationContext context) {
+ tearDownTestContext();
+ pendingTeardownContext = context;
+ }
+
+ @Test public void v2Config() throws Exception {
+
+ final MockPropertySource propSource = singletonPropertySource("serviceURL", TEST_URL);
+ 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.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");
+
+ Assert.assertTrue(connector.getResultsCache().size() == 1);
+ }
+
+ @Test(expectedExceptions=ResolutionException.class) public void v2BadProtocol() throws Exception {
+
+ final MockPropertySource propSource = singletonPropertySource("serviceURL", TEST_URL);
+ 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-badprotocol.xml");
+ Assert.assertNotNull(connector);
+
+ final AttributeResolutionContext context =
+ TestSources.createResolutionContext(TestSources.PRINCIPAL_ID, TestSources.IDP_ENTITY_ID,
+ TestSources.SP_ENTITY_ID);
+
+ connector.resolve(context);
+ }
+
+ @Test(expectedExceptions=ResolutionException.class) public void v2Size() throws Exception {
+
+ final MockPropertySource propSource = singletonPropertySource("serviceURL", TEST_URL);
+ propSource.setProperty("scriptPath", (isV8() ? SCRIPT_PATH_V8 : SCRIPT_PATH) + "testsize.js");
+
+ final HTTPDataConnector connector =
+ getDataConnector(propSource,
+ "net/shibboleth/idp/attribute/resolver/spring/dc/http/http-attribute-resolver-v2.xml");
+ Assert.assertNotNull(connector);
+
+ final AttributeResolutionContext context =
+ TestSources.createResolutionContext(TestSources.PRINCIPAL_ID, TestSources.IDP_ENTITY_ID,
+ TestSources.SP_ENTITY_ID);
+
+ connector.resolve(context);
+ }
+
+ @Test(expectedExceptions=ResolutionException.class) public void v2Missing() throws Exception {
+
+ final MockPropertySource propSource = singletonPropertySource("serviceURL", "http://shibboleth.net/test.json");
+ 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.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 v2MissingOk() throws Exception {
+
+ final MockPropertySource propSource = singletonPropertySource("serviceURL", "http://shibboleth.net/test.json");
+ 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-missingok.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.assertTrue(attrs == null || attrs.isEmpty());
+ }
+
+ @Test public void hybridConfig() throws Exception {
+ final MockPropertySource propSource = singletonPropertySource("serviceURL", TEST_URL);
+ 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-hybrid.xml",
+ "net/shibboleth/idp/attribute/resolver/spring/dc/http/http-attribute-resolver-spring-context.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");
+
+ Assert.assertTrue(connector.getResultsCache().size() == 1);
+ }
+
+ private HTTPDataConnector getDataConnector(final PropertySource propSource, final String... beanDefinitions)
+ throws IOException {
+ final GenericApplicationContext context = new GenericApplicationContext();
+ setTestContext(context);
+ context.setDisplayName("ApplicationContext: " + HTTPDataConnectorParserTest.class);
+
+ final ConversionServiceFactoryBean service = new ConversionServiceFactoryBean();
+ service.setConverters(new HashSet<>(Arrays.asList(new DurationToLongConverter(), new StringToIPRangeConverter(),
+ new StringToResourceConverter())));
+ service.afterPropertiesSet();
+
+ context.getBeanFactory().setConversionService(service.getObject());
+
+ if (propSource != null) {
+ context.getEnvironment().getPropertySources().addFirst(propSource);
+ }
+
+ final XmlBeanDefinitionReader configReader = new SchemaTypeAwareXMLBeanDefinitionReader(context);
+
+ configReader.loadBeanDefinitions("net/shibboleth/idp/attribute/resolver/spring/dc/http/spring-beans.xml");
+
+ final SchemaTypeAwareXMLBeanDefinitionReader beanDefinitionReader =
+ new SchemaTypeAwareXMLBeanDefinitionReader(context);
+
+ beanDefinitionReader.setValidating(true);
+ beanDefinitionReader.loadBeanDefinitions(beanDefinitions);
+ context.refresh();
+
+ return (HTTPDataConnector) context.getBean("myHTTP");
+ }
+
+ private boolean isV8() {
+ final String ver = System.getProperty("java.version");
+ return ver.startsWith("1.8");
+ }
+
+ private MockPropertySource singletonPropertySource(final String name, final String value) {
+ final MockPropertySource propSource = new MockPropertySource("localProperties");
+ propSource.setProperty(name, value);
+ return propSource;
+ }
+
+}
\ No newline at end of file
diff --git a/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/http/http-attribute-resolver-spring-context.xml b/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/http/http-attribute-resolver-spring-context.xml
new file mode 100644
index 0000000..c8e4358
--- /dev/null
+++ b/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/http/http-attribute-resolver-spring-context.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:c="http://www.springframework.org/schema/c"
+ xmlns:p="http://www.springframework.org/schema/p"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd"
+ default-init-method="initialize"
+ default-destroy-method="destroy">
+
+ <bean id="cacheBuilder" class="com.google.common.cache.CacheBuilder" factory-method="from">
+ <constructor-arg value="expireAfterAccess=10s,maximumSize=25" />
+ </bean>
+
+ <bean id="cache" factory-bean="cacheBuilder" factory-method="build" />
+
+ <bean id="template" class="net.shibboleth.idp.attribute.resolver.dc.http.impl.TemplatedURLBuilder"
+ p:velocityEngine-ref="shibboleth.VelocityEngine"
+ p:templateText="%{serviceURL}" />
+
+ <bean id="mapping" class="net.shibboleth.idp.attribute.resolver.dc.http.impl.ScriptedResponseMappingStrategy"
+ factory-method="resourceScript"
+ c:_0="%{scriptPath}"
+ p:acceptStatuses="200"
+ p:acceptTypes="application/json" />
+
+</beans>
\ No newline at end of file
diff --git a/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/http/http-attribute-resolver-v2-badprotocol.xml b/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/http/http-attribute-resolver-v2-badprotocol.xml
new file mode 100644
index 0000000..0043406
--- /dev/null
+++ b/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/http/http-attribute-resolver-v2-badprotocol.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="NoTrustEngineHttpClient"
+ httpClientSecurityParametersRef="BadProtocolParameters">
+
+ <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-hybrid.xml b/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/http/http-attribute-resolver-v2-hybrid.xml
new file mode 100644
index 0000000..e73d4d2
--- /dev/null
+++ b/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/http/http-attribute-resolver-v2-hybrid.xml
@@ -0,0 +1,15 @@
+<?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"
+ executableSearchBuilderRef="template"
+ mappingStrategyRef="mapping">
+
+ <ResultCacheBean>cache</ResultCacheBean>
+
+ </DataConnector>
+
+</AttributeResolver>
diff --git a/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/http/http-attribute-resolver-v2-missingok.xml b/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/http/http-attribute-resolver-v2-missingok.xml
new file mode 100644
index 0000000..6f3a276
--- /dev/null
+++ b/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/http/http-attribute-resolver-v2-missingok.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 404">
+
+ <URLTemplate>%{serviceURL}</URLTemplate>
+
+ <ResponseMapping>
+ <Script>true</Script>
+ </ResponseMapping>
+
+ <ResultCache expireAfterWrite="PT10S" />
+
+ </DataConnector>
+
+</AttributeResolver>
diff --git a/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/http/http-attribute-resolver-v2.xml b/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/http/http-attribute-resolver-v2.xml
new file mode 100644
index 0000000..aef5052
--- /dev/null
+++ b/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/http/http-attribute-resolver-v2.xml
@@ -0,0 +1,21 @@
+<?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>
+
+ <ResponseMapping>
+ <ScriptFile>%{scriptPath}</ScriptFile>
+ </ResponseMapping>
+
+ <ResultCache expireAfterWrite="PT10S" />
+
+ </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
new file mode 100644
index 0000000..6c2f273
--- /dev/null
+++ b/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/http/spring-beans.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:p="http://www.springframework.org/schema/p"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd"
+ default-init-method="initialize"
+ default-destroy-method="destroy">
+
+ <bean id="NoTrustEngineHttpClient"
+ class="net.shibboleth.idp.profile.spring.relyingparty.metadata.HttpClientFactoryBean" />
+
+ <bean id="BadProtocolParameters"
+ class="org.opensaml.security.httpclient.HttpClientSecurityParameters"
+ p:TLSProtocols="SSLv3" />
+
+ <bean id="shibboleth.VelocityEngine" class="org.springframework.ui.velocity.VelocityEngineFactoryBean">
+ <property name="velocityProperties">
+ <props>
+ <prop key="resource.loader">classpath, string</prop>
+ <prop key="classpath.resource.loader.class">
+ org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader
+ </prop>
+ <prop key="string.resource.loader.class">
+ org.apache.velocity.runtime.resource.loader.StringResourceLoader
+ </prop>
+ </props>
+ </property>
+ </bean>
+
+ <bean id="shibboleth.PropertySourcesPlaceholderConfigurer"
+ class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer"
+ p:placeholderPrefix="%{" p:placeholderSuffix="}" />
+
+</beans>
\ No newline at end of file
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 2f46dc1..c6f2102 100644
--- a/idp-schema/src/main/resources/schema/shibboleth-attribute-resolver.xsd
+++ b/idp-schema/src/main/resources/schema/shibboleth-attribute-resolver.xsd
@@ -1252,6 +1252,108 @@
</complexContent>
</complexType>
+ <complexType name="HTTP">
+ <annotation>
+ <documentation>
+ A data connector definition that issues requests and parses responses using HTTP, typically
+ via a form of web service. REST and scripted handling of responses, typically in JSON,
+ is the primary use case.
+ </documentation>
+ </annotation>
+ <complexContent>
+ <extension base="resolver:FlattenedBaseDataConnectorType">
+ <choice maxOccurs="unbounded">
+ <element ref="resolver:Dependency" />
+ <element ref="resolver:InputAttributeDefinition" />
+ <element ref="resolver:InputDataConnector" />
+ <element ref="resolver:FailoverDataConnector" />
+ <element name="URLTemplate" type="string">
+ <annotation>
+ <documentation>
+ A template that will be used to create the absolute URL to request.
+ </documentation>
+ </annotation>
+ </element>
+ <element name="ResponseMapping" type="resolver:ScriptType">
+ <annotation>
+ <documentation>Maps the response into attributes by means of scripting.</documentation>
+ </annotation>
+ </element>
+ <element name="ResultCache" type="resolver:CacheConfigType"/>
+ <element name="ResultCacheBean" type="string"/>
+ </choice>
+ <attribute name="httpClientRef" type="string">
+ <annotation>
+ <documentation>
+ Reference to a Spring bean providing the HttpClient to use.
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="httpClientSecurityParametersRef" type="string">
+ <annotation>
+ <documentation>
+ Reference to a Spring bean providing the HttpClientSecurityParameters to use.
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="templateEngine" type="string">
+ <annotation>
+ <documentation>
+ Name of the template engine defined within the application.
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="maxLength" type="string">
+ <annotation>
+ <documentation>
+ Maximum size of response body to accept.
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="acceptStatuses" >
+ <annotation>
+ <documentation>
+ A space-delimited list of HTTP status codes that should be treated as successful.
+ </documentation>
+ </annotation>
+ <simpleType>
+ <list itemType="string"/>
+ </simpleType>
+ </attribute>
+ <attribute name="acceptTypes" >
+ <annotation>
+ <documentation>
+ A space-delimited list of MIME content types that should be accepted.
+ </documentation>
+ </annotation>
+ <simpleType>
+ <list itemType="string"/>
+ </simpleType>
+ </attribute>
+ <attribute name="executableSearchBuilderRef" type="string">
+ <annotation>
+ <documentation>
+ Reference to a Spring bean providing the ExecutableSearchBuilder implementation to use.
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="mappingStrategyRef" type="string">
+ <annotation>
+ <documentation>
+ Reference to a Spring bean providing the MappingStrategy implementation to use.
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="validatorRef" type="string">
+ <annotation>
+ <documentation>
+ Reference to a Spring bean providing the Validator implementation to use.
+ </documentation>
+ </annotation>
+ </attribute>
+ </extension>
+ </complexContent>
+ </complexType>
<complexType name="ScriptedDataConnector">
<annotation>
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list