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

Scott Cantor cantor.2 at osu.edu
Fri Aug 18 14:28:37 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=104d00813333aeaf79e5a1be2c549dfa9aa3eebb

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

commit 104d00813333aeaf79e5a1be2c549dfa9aa3eebb
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Fri Aug 18 14:28:34 2017 -0400

    IDP-1170 - REST DataConnector
    
    https://issues.shibboleth.net/jira/browse/IDP-1170
    
    Some reorg of search builder base class and a POST-capable
    subclass with a template-based request body.
---
 .../dc/http/impl/AbstractHTTPSearchBuilder.java    |  87 ++++-
 .../dc/http/impl/TemplatedBodyBuilder.java         | 403 +++++++++++++++++++++
 .../dc/http/impl/HTTPDataConnectorTest.java        |  98 +++++
 3 files changed, 582 insertions(+), 6 deletions(-)

diff --git a/idp-attribute-resolver-impl/src/main/java/net/shibboleth/idp/attribute/resolver/dc/http/impl/AbstractHTTPSearchBuilder.java b/idp-attribute-resolver-impl/src/main/java/net/shibboleth/idp/attribute/resolver/dc/http/impl/AbstractHTTPSearchBuilder.java
index 1f9b951..c91d517 100644
--- a/idp-attribute-resolver-impl/src/main/java/net/shibboleth/idp/attribute/resolver/dc/http/impl/AbstractHTTPSearchBuilder.java
+++ b/idp-attribute-resolver-impl/src/main/java/net/shibboleth/idp/attribute/resolver/dc/http/impl/AbstractHTTPSearchBuilder.java
@@ -18,6 +18,8 @@
 package net.shibboleth.idp.attribute.resolver.dc.http.impl;
 
 import java.io.IOException;
+import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
@@ -32,15 +34,21 @@ import org.apache.http.client.protocol.HttpClientContext;
 import org.opensaml.security.httpclient.HttpClientSecurityParameters;
 import org.opensaml.security.httpclient.HttpClientSecuritySupport;
 
+import com.google.common.collect.ImmutableMap;
+
 import net.shibboleth.idp.attribute.IdPAttribute;
 import net.shibboleth.idp.attribute.IdPAttributeValue;
 import net.shibboleth.idp.attribute.resolver.ResolutionException;
 import net.shibboleth.idp.attribute.resolver.context.AttributeResolutionContext;
 import net.shibboleth.idp.attribute.resolver.dc.impl.ExecutableSearchBuilder;
+import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
 import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
+import net.shibboleth.utilities.java.support.annotation.constraint.NotLive;
+import net.shibboleth.utilities.java.support.annotation.constraint.Unmodifiable;
 import net.shibboleth.utilities.java.support.component.AbstractInitializableComponent;
 import net.shibboleth.utilities.java.support.component.ComponentSupport;
 import net.shibboleth.utilities.java.support.logic.Constraint;
+import net.shibboleth.utilities.java.support.primitive.StringSupport;
 
 /**
  * Basis of request builder. Derived classes just have to provide the per request URI but may override
@@ -56,9 +64,48 @@ import net.shibboleth.utilities.java.support.logic.Constraint;
 public abstract class AbstractHTTPSearchBuilder extends AbstractInitializableComponent implements
         ExecutableSearchBuilder<HTTPSearch> {
     
+    /** Map of headers to set. */
+    @Nonnull @NonnullElements private Map<String,String> headerMap;
+    
     /** HTTP client security parameters. */
     @Nullable private HttpClientSecurityParameters httpClientSecurityParameters;
     
+    /** Constructor. */
+    public AbstractHTTPSearchBuilder() {
+        headerMap = Collections.emptyMap();
+    }
+    
+    /**
+     * Get map of headers that will be set on request.
+     * 
+     * @return map of headers
+     */
+    @Nonnull @NonnullElements @NotLive @Unmodifiable public Map<String,String> getHeaders() {
+        return ImmutableMap.copyOf(headerMap);
+    }
+    
+    /**
+     * Set map of headers that will be set on request.
+     * 
+     * <p>These will be *set*, so replacing any existing headers and not allowing multiple.</p>
+     * 
+     * @param headers map of headers
+     */
+    public void setHeaders(@Nonnull @NonnullElements final Map<String,String> headers) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+        ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);
+                
+        Constraint.isNotNull(headers, "Map of headers cannot be null");
+        headerMap = new HashMap<>(headers.size());
+        
+        for (final Map.Entry<String,String> entry : headers.entrySet()) {
+            final String key = StringSupport.trimOrNull(entry.getKey());
+            final String value = StringSupport.trimOrNull(entry.getValue());
+            if (key != null && value != null) {
+                headerMap.put(key, value);
+            }
+        }
+    }
     
     /**
      * Get the optional client security parameters.
@@ -94,14 +141,19 @@ public abstract class AbstractHTTPSearchBuilder extends AbstractInitializableCom
             @Nonnull final Map<String, List<IdPAttributeValue<?>>> dependencyAttributes) throws ResolutionException {
         
         final HttpUriRequest request = getHttpRequest(resolutionContext, dependencyAttributes);
+        
+        for (final Map.Entry<String,String> entry : headerMap.entrySet()) {
+            request.setHeader(entry.getKey(), entry.getValue());
+        }
 
 // Checkstyle: AnonInnerLength OFF
         return new HTTPSearch() {
             
             /** {@inheritDoc} */
-            @Nonnull public String getResultCacheKey() {
-                Constraint.isTrue(request instanceof HttpGet, "Only GET requests are cacheable");
-                return ((HttpGet) request).getURI().toString();
+            @Nullable public String getResultCacheKey() {
+                // Delegate to the outer class to allow override.
+                return AbstractHTTPSearchBuilder.this.getResultCacheKey(request, resolutionContext,
+                        dependencyAttributes);
             }
 
             /** {@inheritDoc} */
@@ -129,14 +181,18 @@ public abstract class AbstractHTTPSearchBuilder extends AbstractInitializableCom
     /**
      * Method to return the URL to access via GET.
      * 
+     * <p>Subclasses may override this method to support simple GET requests.</p>
+     * 
      * @param resolutionContext the context of the resolution
      * @param dependencyAttributes made available to the request
      * 
      * @return the URL to GET
      * @throws ResolutionException if an error occurs
      */
-    @Nonnull @NotEmpty protected abstract String getURL(@Nonnull final AttributeResolutionContext resolutionContext,
-            @Nonnull final Map<String,List<IdPAttributeValue<?>>> dependencyAttributes) throws ResolutionException;
+    @Nonnull @NotEmpty protected String getURL(@Nonnull final AttributeResolutionContext resolutionContext,
+            @Nonnull final Map<String,List<IdPAttributeValue<?>>> dependencyAttributes) throws ResolutionException {
+        throw new UnsupportedOperationException("getURL method not overridden by subclass");
+    }
     
     /**
      * Default implementation just supports GET and builds a request around a URL.
@@ -157,5 +213,24 @@ public abstract class AbstractHTTPSearchBuilder extends AbstractInitializableCom
             throw new ResolutionException(e);
         }
     }
-        
+
+    /**
+     * Default implementation just allows caching of GET requests and returns the URI itself.
+     * 
+     * @param request the HTTP request about to be executed
+     * @param resolutionContext the attribute resolution context
+     * @param dependencyAttributes dependencies
+     * 
+     * @return the cache key
+     */
+    @Nullable protected String getResultCacheKey(@Nonnull final HttpUriRequest request,
+            @Nonnull final AttributeResolutionContext resolutionContext,
+            @Nonnull final Map<String, List<IdPAttributeValue<?>>> dependencyAttributes) {
+        if (request instanceof HttpGet) {
+            return ((HttpGet) request).getURI().toString();
+        } else {
+            return null;
+        }
+    }
+
 }
\ No newline at end of file
diff --git a/idp-attribute-resolver-impl/src/main/java/net/shibboleth/idp/attribute/resolver/dc/http/impl/TemplatedBodyBuilder.java b/idp-attribute-resolver-impl/src/main/java/net/shibboleth/idp/attribute/resolver/dc/http/impl/TemplatedBodyBuilder.java
new file mode 100644
index 0000000..6d634be
--- /dev/null
+++ b/idp-attribute-resolver-impl/src/main/java/net/shibboleth/idp/attribute/resolver/dc/http/impl/TemplatedBodyBuilder.java
@@ -0,0 +1,403 @@
+/*
+ * 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.dc.http.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import net.shibboleth.idp.attribute.IdPAttributeValue;
+import net.shibboleth.idp.attribute.resolver.ResolutionException;
+import net.shibboleth.idp.attribute.resolver.context.AttributeResolutionContext;
+import net.shibboleth.utilities.java.support.annotation.constraint.NonnullAfterInit;
+import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
+import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
+import net.shibboleth.utilities.java.support.component.ComponentSupport;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+import net.shibboleth.utilities.java.support.primitive.StringSupport;
+import net.shibboleth.utilities.java.support.velocity.Template;
+
+import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.methods.HttpPut;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.entity.ContentType;
+import org.apache.http.entity.StringEntity;
+import org.apache.velocity.VelocityContext;
+import org.apache.velocity.app.VelocityEngine;
+import org.apache.velocity.exception.VelocityException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.escape.Escaper;
+import com.google.common.net.UrlEscapers;
+import com.google.common.xml.XmlEscapers;
+
+/**
+ * An {@link net.shibboleth.idp.attribute.resolver.dc.impl.ExecutableSearchBuilder} that generates a
+ * request by evaluating {@link Template}s against the currently resolved attributes within an
+ * {@link AttributeResolutionContext} to produce a URL and body, via GET or POST, and a configurable
+ * cache key.
+ */
+public class TemplatedBodyBuilder extends AbstractHTTPSearchBuilder {
+
+    /** Class logger. */
+    @Nonnull private final Logger log = LoggerFactory.getLogger(TemplatedBodyBuilder.class);
+
+    /** URL template to be evaluated. */
+    @NonnullAfterInit private Template urlTemplate;
+
+    /** Body template to be evaluated. */
+    @NonnullAfterInit private Template bodyTemplate;
+
+    /** Cache key template to be evaluated. */
+    @NonnullAfterInit private Template cacheKeyTemplate;
+    
+    /** Text of URL template to be evaluated. */
+    @NonnullAfterInit private String urlTemplateText;
+
+    /** Text of body template to be evaluated. */
+    @NonnullAfterInit private String bodyTemplateText;
+
+    /** Text of cache key template to be evaluated. */
+    @NonnullAfterInit private String cacheKeyTemplateText;
+
+    /** VelocityEngine. */
+    @NonnullAfterInit private VelocityEngine engine;
+    
+    /** HTTP method. */
+    @Nonnull @NotEmpty private String method;
+
+    /** MIME type. */
+    @Nonnull @NotEmpty private String mimeType;
+
+    /** Character set. */
+    @Nullable private String charset;
+    
+    /** Content type. */
+    @NonnullAfterInit private ContentType contentType;
+    
+    /** Escaper for form parameters. */
+    @Nonnull private final Escaper paramEscaper;
+
+    /** Escaper for fragments. */
+    @Nonnull private final Escaper fragmentEscaper;
+
+    /** Escaper for path segments. */
+    @Nonnull private final Escaper pathEscaper;
+
+    /** Escaper for XML Attributes. */
+    @Nonnull private final Escaper xmlAttributeEscaper;
+
+    /** Escaper for XML content. */
+    @Nonnull private final Escaper xmlContentEscaper;
+
+    /** Constructor. */
+    public TemplatedBodyBuilder() {
+        method = "POST";
+        mimeType ="text/plain";
+        
+        paramEscaper = UrlEscapers.urlFormParameterEscaper();
+        fragmentEscaper = UrlEscapers.urlFragmentEscaper();
+        pathEscaper = UrlEscapers.urlPathSegmentEscaper();
+        xmlAttributeEscaper = XmlEscapers.xmlAttributeEscaper();
+        xmlContentEscaper = XmlEscapers.xmlContentEscaper();
+    }
+    
+    /**
+     * Get the URL template to be evaluated.
+     * 
+     * @return template
+     */
+    @NonnullAfterInit public Template getURLTemplate() {
+        return urlTemplate;
+    }
+
+    /**
+     * Get the body template to be evaluated.
+     * 
+     * @return template
+     */
+    @NonnullAfterInit public Template getBodyTemplate() {
+        return bodyTemplate;
+    }
+
+    /**
+     * Get the cache key template to be evaluated.
+     * 
+     * @return template
+     */
+    @Nullable public Template getCacheKeyTemplate() {
+        return cacheKeyTemplate;
+    }
+
+    /**
+     * Get the URL template text to be evaluated.
+     * 
+     * @return template text
+     */
+    @NonnullAfterInit public String getURLTemplateText() {
+        return urlTemplateText;
+    }
+
+    /**
+     * Set the URL template to be evaluated.
+     * 
+     * @param text template to be evaluated
+     */
+    public void setURLTemplateText(@Nullable final String text) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+        ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);
+
+        urlTemplateText = StringSupport.trimOrNull(text);
+    }
+
+    /**
+     * Get the body template text to be evaluated.
+     * 
+     * @return template text
+     */
+    @NonnullAfterInit public String getBodyTemplateText() {
+        return bodyTemplateText;
+    }
+
+    /**
+     * Set the body template to be evaluated.
+     * 
+     * @param text template to be evaluated
+     */
+    public void setBodyTemplateText(@Nullable final String text) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+        ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);
+
+        bodyTemplateText = StringSupport.trimOrNull(text);
+    }
+
+    /**
+     * Get the cache key template text to be evaluated.
+     * 
+     * @return template text
+     */
+    @Nullable public String getCacheKeyTemplateText() {
+        return cacheKeyTemplateText;
+    }
+
+    /**
+     * Set the cache key template to be evaluated.
+     * 
+     * @param text template to be evaluated
+     */
+    public void setCacheKeyTemplateText(@Nullable final String text) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+        ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);
+
+        cacheKeyTemplateText = StringSupport.trimOrNull(text);
+    }
+    
+    /**
+     * Get the {@link VelocityEngine} to be used.
+     * 
+     * @return template engine
+     */
+    @NonnullAfterInit public VelocityEngine getVelocityEngine() {
+        return engine;
+    }
+
+    /**
+     * Set the {@link VelocityEngine} to be used.
+     * 
+     * @param velocityEngine engine to be used
+     */
+    public void setVelocityEngine(@Nonnull final VelocityEngine velocityEngine) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+        ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);
+
+        engine = Constraint.isNotNull(velocityEngine, "Velocity engine cannot be null");
+    }
+    
+    /**
+     * Set the HTTP method.
+     * 
+     * <p>Defaults to "POST".</p>
+     * 
+     * @param m method
+     */
+    public void setMethod(@Nonnull @NotEmpty final String m) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+        ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);
+
+        method = Constraint.isNotNull(StringSupport.trimOrNull(m), "HTTP method cannot be null or empty");
+        Constraint.isTrue(HttpPost.METHOD_NAME.equals(method) || HttpPut.METHOD_NAME.equals(method),
+                "HTTP method must be POST or PUT");
+    }
+
+    /**
+     * Set the MIME type.
+     * 
+     * <p>Defaults to "text/plain".</p>
+     * 
+     * @param type MIME type
+     */
+    public void setMIMEType(@Nonnull @NotEmpty final String type) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+        ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);
+
+        mimeType = Constraint.isNotNull(StringSupport.trimOrNull(type), "MIME type cannot be null or empty");
+    }
+
+    /**
+     * Set the character set.
+     * 
+     * @param c character set
+     */
+    public void setCharacterSet(@Nullable final String c) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+        ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);
+
+        charset = StringSupport.trimOrNull(c);
+    }
+    
+    /** {@inheritDoc} */
+    @Override protected void doInitialize() throws ComponentInitializationException {
+        super.doInitialize();
+
+        if (null == engine) {
+            throw new ComponentInitializationException("Velocity engine cannot be null");
+        }
+
+        if (null == urlTemplateText) {
+            throw new ComponentInitializationException("URL template text cannot be null");
+        } else if (null == bodyTemplateText) {
+            throw new ComponentInitializationException("Body template text cannot be null");
+        }
+
+        urlTemplate = Template.fromTemplate(engine, urlTemplateText);
+        bodyTemplate = Template.fromTemplate(engine, bodyTemplateText);
+        
+        if (null != cacheKeyTemplateText) {
+            cacheKeyTemplate = Template.fromTemplate(engine, cacheKeyTemplateText);
+        }
+        
+        contentType = ContentType.create(mimeType, charset);
+    }
+
+    /**
+     * Invokes {@link Template#merge(org.apache.velocity.context.Context)} on the supplied template and context.
+     * 
+     * @param template template to merge
+     * @param context to merge
+     * 
+     * @return result of the merge operation
+     */
+    @Nonnull @NotEmpty protected String merge(@Nonnull final Template template,
+            @Nonnull final VelocityContext context) {
+        return template.merge(context);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    @Nonnull protected HttpUriRequest getHttpRequest(@Nonnull final AttributeResolutionContext resolutionContext,
+            @Nonnull final Map<String, List<IdPAttributeValue<?>>> dependencyAttributes) throws ResolutionException {
+
+        final VelocityContext context = new VelocityContext();
+        log.trace("Creating request using attribute resolution context {}", resolutionContext);
+        context.put("resolutionContext", resolutionContext);
+
+        context.put("httpClientSecurityParameters", getHttpClientSecurityParameters());
+        context.put("paramEscaper", paramEscaper);
+        context.put("fragmentEscaper", fragmentEscaper);
+        context.put("pathEscaper", pathEscaper);
+        context.put("xmlAttributeEscaper", xmlAttributeEscaper);
+        context.put("xmlContentEscaper", xmlContentEscaper);
+
+        // inject dependencies
+        if (dependencyAttributes != null && !dependencyAttributes.isEmpty()) {
+            for (final Map.Entry<String, List<IdPAttributeValue<?>>> entry : dependencyAttributes.entrySet()) {
+                final List<Object> values = new ArrayList<>(entry.getValue().size());
+                for (final IdPAttributeValue<?> value : entry.getValue()) {
+                    values.add(value.getValue());
+                }
+                log.trace("Adding dependency {} to context with {} value(s)", entry.getKey(), values.size());
+                context.put(entry.getKey(), values);
+            }
+        }
+
+        final String url;
+        final String body;
+        final HttpEntityEnclosingRequestBase request;
+        
+        try {
+            url = merge(urlTemplate, context);
+            body = merge(bodyTemplate, context);
+        } catch (final VelocityException e) {
+            log.error("Error running template engine", e);
+            throw new ResolutionException("Error running template engine", e);
+        }
+        
+        try {
+            if (HttpPost.METHOD_NAME.equals(method)) {
+                request = new HttpPost(url);
+            } else if (HttpPut.METHOD_NAME.equals(method)) {
+                request = new HttpPut(url);
+            } else {
+                throw new ResolutionException("Unsupported HTTP method");
+            }
+            
+            request.setEntity(new StringEntity(body, contentType));
+        } catch (final IllegalArgumentException e) {
+            throw new ResolutionException(e);
+        }
+        
+        return request;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    @Nonnull @NotEmpty protected String getResultCacheKey(@Nonnull final HttpUriRequest request,
+            @Nonnull final AttributeResolutionContext resolutionContext,
+            @Nonnull final Map<String, List<IdPAttributeValue<?>>> dependencyAttributes) {
+        
+        if (cacheKeyTemplate == null) {
+            return null;
+        }
+        
+        final VelocityContext context = new VelocityContext();
+        log.trace("Creating cache key using attribute resolution context {}", resolutionContext);
+        context.put("resolutionContext", resolutionContext);
+
+        context.put("httpClientSecurityParameters", getHttpClientSecurityParameters());
+        
+        // inject dependencies
+        if (dependencyAttributes != null && !dependencyAttributes.isEmpty()) {
+            for (final Map.Entry<String, List<IdPAttributeValue<?>>> entry : dependencyAttributes.entrySet()) {
+                final List<Object> values = new ArrayList<>(entry.getValue().size());
+                for (final IdPAttributeValue<?> value : entry.getValue()) {
+                    values.add(value.getValue());
+                }
+                log.trace("Adding dependency {} to context with {} value(s)", entry.getKey(), values.size());
+                context.put(entry.getKey(), values);
+            }
+        }
+
+        return merge(cacheKeyTemplate, context);
+    }
+
+}
\ No newline at end of file
diff --git a/idp-attribute-resolver-impl/src/test/java/net/shibboleth/idp/attribute/resolver/dc/http/impl/HTTPDataConnectorTest.java b/idp-attribute-resolver-impl/src/test/java/net/shibboleth/idp/attribute/resolver/dc/http/impl/HTTPDataConnectorTest.java
index 6a8ffe4..04976f4 100644
--- a/idp-attribute-resolver-impl/src/test/java/net/shibboleth/idp/attribute/resolver/dc/http/impl/HTTPDataConnectorTest.java
+++ b/idp-attribute-resolver-impl/src/test/java/net/shibboleth/idp/attribute/resolver/dc/http/impl/HTTPDataConnectorTest.java
@@ -244,4 +244,102 @@ public class HTTPDataConnectorTest {
         Assert.assertEquals(cache.iterator().next(), optional);
     }
     
+    @Test(enabled=false) public void testPOST() throws ComponentInitializationException, ResolutionException, ScriptException, IOException {
+        final TemplatedBodyBuilder builder = new TemplatedBodyBuilder();
+        builder.setURLTemplateText("https://shibboleth.net/cgi-bin/_frobnitz.cgi");
+        builder.setBodyTemplateText("[{\"name\" : \"foo\",\"values\" : [ \"foo1\" ]},{\"name\" : \"bar\",\"values\" : [ \"bar1\", \"bar2\" ]}]");
+        builder.setMIMEType("application/json");
+        builder.setVelocityEngine(VelocityEngine.newVelocityEngine());
+        builder.initialize();
+        connector.setExecutableSearchBuilder(builder);
+        
+        final ScriptedResponseMappingStrategy mapping =
+                ScriptedResponseMappingStrategy.resourceScript(
+                        ResourceHelper.of(new ClassPathResource((isV8() ? SCRIPT_PATH_V8 : SCRIPT_PATH) + "test.js")));
+        mapping.setLogPrefix(TEST_CONNECTOR_NAME + ":");
+        mapping.setAcceptStatuses(Collections.singleton(HttpStatus.SC_OK));
+        mapping.setAcceptTypes(Collections.singleton("application/json"));
+        connector.setMappingStrategy(mapping);
+        connector.initialize();
+        
+        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");
+    }
+
+    @Test(enabled=false) public void testCacheable() throws ComponentInitializationException, ResolutionException, ScriptException, IOException {
+        final TemplatedBodyBuilder builder = new TemplatedBodyBuilder();
+        builder.setURLTemplateText("https://shibboleth.net/cgi-bin/_frobnitz.cgi");
+        builder.setBodyTemplateText("[{\"name\" : \"foo\",\"values\" : [ \"foo1\" ]},{\"name\" : \"bar\",\"values\" : [ \"bar1\", \"bar2\" ]}]");
+        builder.setCacheKeyTemplateText("foo");
+        builder.setMIMEType("application/json");
+        builder.setVelocityEngine(VelocityEngine.newVelocityEngine());
+        builder.initialize();
+        connector.setExecutableSearchBuilder(builder);
+        
+        final ScriptedResponseMappingStrategy mapping =
+                ScriptedResponseMappingStrategy.resourceScript(
+                        ResourceHelper.of(new ClassPathResource((isV8() ? SCRIPT_PATH_V8 : SCRIPT_PATH) + "test.js")));
+        mapping.setLogPrefix(TEST_CONNECTOR_NAME + ":");
+        mapping.setAcceptStatuses(Collections.singleton(HttpStatus.SC_OK));
+        mapping.setAcceptTypes(Collections.singleton("application/json"));
+        connector.setMappingStrategy(mapping);
+        
+        final TestCache cache = new TestCache();
+        connector.setResultsCache(cache);
+        
+        connector.initialize();
+        
+        final AttributeResolutionContext context =
+                TestSources.createResolutionContext(TestSources.PRINCIPAL_ID, TestSources.IDP_ENTITY_ID,
+                        TestSources.SP_ENTITY_ID);
+        
+        Assert.assertTrue(cache.size() == 0);
+        final Map<String,IdPAttribute> optional = connector.resolve(context);
+        Assert.assertTrue(cache.size() == 1);
+        Assert.assertEquals(cache.iterator().next(), optional);
+    }
+    
+    @Test(enabled=false) public void testUncacheable() throws ComponentInitializationException, ResolutionException, ScriptException, IOException {
+        final TemplatedBodyBuilder builder = new TemplatedBodyBuilder();
+        builder.setURLTemplateText("https://shibboleth.net/cgi-bin/_frobnitz.cgi");
+        builder.setBodyTemplateText("[{\"name\" : \"foo\",\"values\" : [ \"foo1\" ]},{\"name\" : \"bar\",\"values\" : [ \"bar1\", \"bar2\" ]}]");
+        builder.setMIMEType("application/json");
+        builder.setVelocityEngine(VelocityEngine.newVelocityEngine());
+        builder.initialize();
+        connector.setExecutableSearchBuilder(builder);
+        
+        final ScriptedResponseMappingStrategy mapping =
+                ScriptedResponseMappingStrategy.resourceScript(
+                        ResourceHelper.of(new ClassPathResource((isV8() ? SCRIPT_PATH_V8 : SCRIPT_PATH) + "test.js")));
+        mapping.setLogPrefix(TEST_CONNECTOR_NAME + ":");
+        mapping.setAcceptStatuses(Collections.singleton(HttpStatus.SC_OK));
+        mapping.setAcceptTypes(Collections.singleton("application/json"));
+        connector.setMappingStrategy(mapping);
+        
+        final TestCache cache = new TestCache();
+        connector.setResultsCache(cache);
+        
+        connector.initialize();
+        
+        final AttributeResolutionContext context =
+                TestSources.createResolutionContext(TestSources.PRINCIPAL_ID, TestSources.IDP_ENTITY_ID,
+                        TestSources.SP_ENTITY_ID);
+        
+        Assert.assertTrue(cache.size() == 0);
+        connector.resolve(context);
+        Assert.assertTrue(cache.size() == 0);
+    }
+    
 }
\ No newline at end of file

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


More information about the commits mailing list