[java-opensaml] 07/16: Work on SAMLProtocolAndRole Handler.

Brent Putman putmanb at georgetown.edu
Fri Sep 21 22:48:45 EDT 2018


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

putmanb pushed a commit to branch master
in repository java-opensaml.

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

commit bac2ca37c91c3375fe6f1a3f0ca6dc822947a5f2
Author: Brent Putman <putmanb at georgetown.edu>
AuthorDate: Thu Sep 20 00:21:26 2018 -0400

    Work on SAMLProtocolAndRole Handler.
---
 .../soap/SAMLSOAPClientContextBuilder.java         |  35 ++++-
 .../binding/impl/SAMLProtocolAndRoleHandler.java   |  69 ++++++++--
 .../binding/decoding/impl/HTTPArtifactDecoder.java |   1 +
 .../impl/SAMLProtocolAndRoleHandlerTest.java       | 141 +++++++++++++++++++++
 4 files changed, 232 insertions(+), 14 deletions(-)

diff --git a/opensaml-saml-api/src/main/java/org/opensaml/saml/common/messaging/soap/SAMLSOAPClientContextBuilder.java b/opensaml-saml-api/src/main/java/org/opensaml/saml/common/messaging/soap/SAMLSOAPClientContextBuilder.java
index 22719ad..469e326 100644
--- a/opensaml-saml-api/src/main/java/org/opensaml/saml/common/messaging/soap/SAMLSOAPClientContextBuilder.java
+++ b/opensaml-saml-api/src/main/java/org/opensaml/saml/common/messaging/soap/SAMLSOAPClientContextBuilder.java
@@ -63,13 +63,16 @@ public class SAMLSOAPClientContextBuilder<InboundMessageType extends SAMLObject,
     /** The outbound message. **/
     private OutboundMessageType outboundMessage;
     
+    /** The SAML protocol in use. */
+    private String protocol;
+    
     /** The SAML self entityID. **/
     private String selfEntityID;
     
     /** The SAML peer entityID. **/
     private String peerEntityID;
     
-    /** The SAML peer entity roles. **/
+    /** The SAML peer entity role. **/
     private QName peerEntityRole;
     
     /** The SAML peer EntityDescriptor. **/
@@ -109,6 +112,27 @@ public class SAMLSOAPClientContextBuilder<InboundMessageType extends SAMLObject,
     }
 
     /**
+     * Get the SAML protocol URI.
+     * 
+     * @return the SAML protocol URI
+     */
+    @Nullable public String getProtocol() {
+        return protocol;
+    }
+
+    /**
+     * Set the SAML protocol URI.
+     * 
+     * @param protocol the SAML protocol.
+     * @return this builder instance
+     */
+    @Nonnull public SAMLSOAPClientContextBuilder<InboundMessageType, OutboundMessageType> setProtocol(
+            final String uri) {
+        protocol = uri;
+        return this;
+    }
+
+    /**
      * Get the SAML self entityID.
      * 
      * @return the SAML self entityID
@@ -295,7 +319,7 @@ public class SAMLSOAPClientContextBuilder<InboundMessageType extends SAMLObject,
     /**
      * Set the SOAP client security configuration profile ID to use.
      * 
-     * @param profileID the profile ID, or null
+     * @param profileId the profile ID, or null
      * @return this builder instance
      */
     @Nonnull public SAMLSOAPClientContextBuilder<InboundMessageType, OutboundMessageType>
@@ -330,12 +354,17 @@ public class SAMLSOAPClientContextBuilder<InboundMessageType extends SAMLObject,
         // This is just so it's easy to change.
         final BaseContext parent = opContext;
         
+        if (getProtocol() != null) {
+            parent.getSubcontext(SAMLProtocolContext.class, true).setProtocol(getProtocol());
+        }
+        
         if (getPipelineName() != null) {
             parent.getSubcontext(SOAPClientContext.class, true).setPipelineName(getPipelineName());
         }
         
         if (getSecurityConfigurationProfileId() != null) {
-            parent.getSubcontext(SOAPClientSecurityContext.class, true).setSecurityConfigurationProfileId(getSecurityConfigurationProfileId());
+            parent.getSubcontext(SOAPClientSecurityContext.class, true).setSecurityConfigurationProfileId(
+                    getSecurityConfigurationProfileId());
         }
         
         //TODO is this required always?
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/common/binding/impl/SAMLProtocolAndRoleHandler.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/common/binding/impl/SAMLProtocolAndRoleHandler.java
index cf730ae..e63216a 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/common/binding/impl/SAMLProtocolAndRoleHandler.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/common/binding/impl/SAMLProtocolAndRoleHandler.java
@@ -18,22 +18,25 @@
 package org.opensaml.saml.common.binding.impl;
 
 import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
 import javax.xml.namespace.QName;
 
-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 org.opensaml.messaging.context.BaseContext;
 import org.opensaml.messaging.context.MessageContext;
+import org.opensaml.messaging.context.navigate.ContextDataLookupFunction;
 import org.opensaml.messaging.handler.AbstractMessageHandler;
 import org.opensaml.messaging.handler.MessageHandlerException;
 import org.opensaml.saml.common.messaging.context.AbstractSAMLEntityContext;
 import org.opensaml.saml.common.messaging.context.SAMLPeerEntityContext;
 import org.opensaml.saml.common.messaging.context.SAMLProtocolContext;
 
+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;
+
 /**
  * SAML {@link org.opensaml.messaging.handler.MessageHandler} that attaches protocol
  * and role information to a message context via {@link SAMLProtocolContext} and
@@ -55,6 +58,20 @@ public class SAMLProtocolAndRoleHandler extends AbstractMessageHandler {
      * Defaults to: {@link SAMLPeerEntityContext}. */
     @Nonnull private Class<? extends AbstractSAMLEntityContext> entityContextClass = SAMLPeerEntityContext.class;
     
+    /** Optional lookup function for a context from which to copy the protocol and role data,
+     * for example from a parent operation context. */
+    @Nullable private ContextDataLookupFunction<MessageContext, BaseContext> copyContextLookup;
+    
+    /**
+     * Set the optional lookup function for a context from which to copy the protocol and role data,
+     * for example from a parent operation context.
+     * 
+     * @param lookup the lookup function, may be null
+     */
+    public void setCopyContextLookup(@Nullable final ContextDataLookupFunction<MessageContext, BaseContext> lookup) {
+       copyContextLookup = lookup; 
+    }
+    
     /**
      * Set the class type holding the SAML entity data.
      * 
@@ -91,16 +108,46 @@ public class SAMLProtocolAndRoleHandler extends AbstractMessageHandler {
     protected void doInitialize() throws ComponentInitializationException {
         super.doInitialize();
         
-        if (samlProtocol == null || peerRole == null) {
-            throw new ComponentInitializationException("SAML protocol or peer role was null");
+        if (copyContextLookup == null && (samlProtocol == null || peerRole == null)) {
+            throw new ComponentInitializationException(
+                    "Either SAML protocol and peer role, or context copy function must be supplied");
         }
     }
     
     /** {@inheritDoc} */
     @Override
     protected void doInvoke(final MessageContext messageContext) throws MessageHandlerException {
-        messageContext.getSubcontext(SAMLProtocolContext.class, true).setProtocol(samlProtocol);
-        messageContext.getSubcontext(entityContextClass, true).setRole(peerRole);
+        
+        BaseContext copySource = null;
+        if (copyContextLookup != null) {
+            copySource = copyContextLookup.apply(messageContext);
+        }
+        
+        if (samlProtocol != null) {
+            messageContext.getSubcontext(SAMLProtocolContext.class, true).setProtocol(samlProtocol);
+        } else if (copySource != null) {
+            final SAMLProtocolContext sourceProtocolContext = copySource.getSubcontext(SAMLProtocolContext.class);
+            if (sourceProtocolContext != null) {
+                messageContext.getSubcontext(SAMLProtocolContext.class, true).setProtocol(
+                        sourceProtocolContext.getProtocol());
+            }
+        }
+        if (messageContext.getSubcontext(SAMLProtocolContext.class, true).getProtocol() == null) {
+            throw new MessageHandlerException("SAML protocol was not supplied and could not be dynamically resolved");
+        }
+        
+        if (peerRole != null) {
+            messageContext.getSubcontext(entityContextClass, true).setRole(peerRole);
+        } else if (copySource != null) {
+            final AbstractSAMLEntityContext sourceEntityContext = copySource.getSubcontext(entityContextClass);
+            if (sourceEntityContext != null) {
+                messageContext.getSubcontext(entityContextClass, true).setRole(sourceEntityContext.getRole());
+            }
+        }
+        if (messageContext.getSubcontext(entityContextClass, true).getRole() == null) {
+            throw new MessageHandlerException("SAML role was not supplied and could not be dynamically resolved");
+        }
+        
     }
     
 }
\ No newline at end of file
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/binding/decoding/impl/HTTPArtifactDecoder.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/binding/decoding/impl/HTTPArtifactDecoder.java
index a7c6b25..4ded051 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/binding/decoding/impl/HTTPArtifactDecoder.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/binding/decoding/impl/HTTPArtifactDecoder.java
@@ -453,6 +453,7 @@ public class HTTPArtifactDecoder extends BaseHttpServletRequestXMLMessageDecoder
             final InOutOperationContext<SAMLObject, ArtifactResolve> opContext = new SAMLSOAPClientContextBuilder()
                     .setOutboundMessage(buildArtifactResolveRequestMessage(
                             artifact, ars.getLocation(), peerRoleDescriptor, selfEntityID))
+                    .setProtocol(SAMLConstants.SAML20P_NS)
                     .setPipelineName(getSOAPPipelineName())
                     .setSecurityConfigurationProfileId(getSOAPClientSecurityConfigurationProfileId())
                     .setPeerRoleDescriptor(peerRoleDescriptor)
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/common/binding/impl/SAMLProtocolAndRoleHandlerTest.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/common/binding/impl/SAMLProtocolAndRoleHandlerTest.java
new file mode 100644
index 0000000..ea1986c
--- /dev/null
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/common/binding/impl/SAMLProtocolAndRoleHandlerTest.java
@@ -0,0 +1,141 @@
+/*
+ * 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 org.opensaml.saml.common.binding.impl;
+
+import org.opensaml.messaging.context.InOutOperationContext;
+import org.opensaml.messaging.context.MessageContext;
+import org.opensaml.messaging.context.navigate.RecursiveTypedParentContextLookup;
+import org.opensaml.messaging.handler.MessageHandlerException;
+import org.opensaml.saml.common.SAMLObject;
+import org.opensaml.saml.common.messaging.context.SAMLPeerEntityContext;
+import org.opensaml.saml.common.messaging.context.SAMLPresenterEntityContext;
+import org.opensaml.saml.common.messaging.context.SAMLProtocolContext;
+import org.opensaml.saml.common.xml.SAMLConstants;
+import org.opensaml.saml.saml2.metadata.SPSSODescriptor;
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
+
+/**
+ *
+ */
+public class SAMLProtocolAndRoleHandlerTest {
+    
+    private SAMLProtocolAndRoleHandler handler;
+    private MessageContext<SAMLObject> messageContext;
+    
+    @BeforeMethod
+    public void setup() {
+        handler = new SAMLProtocolAndRoleHandler();
+        messageContext = new MessageContext();
+    }
+    
+    @Test
+    public void testSetters() throws ComponentInitializationException, MessageHandlerException {
+        handler.setProtocol(SAMLConstants.SAML20P_NS); 
+        handler.setRole(SPSSODescriptor.DEFAULT_ELEMENT_NAME);
+        handler.initialize();
+
+        handler.invoke(messageContext);
+
+        Assert.assertNotNull(messageContext.getSubcontext(SAMLProtocolContext.class));
+        Assert.assertEquals(messageContext.getSubcontext(SAMLProtocolContext.class).getProtocol(), SAMLConstants.SAML20P_NS);
+
+        Assert.assertNotNull(messageContext.getSubcontext(SAMLPeerEntityContext.class));
+        Assert.assertEquals(messageContext.getSubcontext(SAMLPeerEntityContext.class).getRole(), SPSSODescriptor.DEFAULT_ELEMENT_NAME);
+    }
+
+    @Test
+    public void testSettersWithEntityClass() throws ComponentInitializationException, MessageHandlerException {
+        handler.setProtocol(SAMLConstants.SAML20P_NS); 
+        handler.setRole(SPSSODescriptor.DEFAULT_ELEMENT_NAME);
+        handler.setEntityContextClass(SAMLPresenterEntityContext.class);
+        handler.initialize();
+
+        handler.invoke(messageContext);
+
+        Assert.assertNotNull(messageContext.getSubcontext(SAMLProtocolContext.class));
+        Assert.assertEquals(messageContext.getSubcontext(SAMLProtocolContext.class).getProtocol(), SAMLConstants.SAML20P_NS);
+
+        Assert.assertNotNull(messageContext.getSubcontext(SAMLPresenterEntityContext.class));
+        Assert.assertEquals(messageContext.getSubcontext(SAMLPresenterEntityContext.class).getRole(), SPSSODescriptor.DEFAULT_ELEMENT_NAME);
+    }
+    
+    @Test
+    public void testCopySource() throws ComponentInitializationException, MessageHandlerException {
+        handler.setCopyContextLookup(new RecursiveTypedParentContextLookup(InOutOperationContext.class));
+        handler.initialize();
+        
+        final InOutOperationContext<SAMLObject, SAMLObject> opContext = 
+                new InOutOperationContext<>(messageContext, new MessageContext<SAMLObject>());
+        opContext.getSubcontext(SAMLProtocolContext.class, true).setProtocol(SAMLConstants.SAML20P_NS); 
+        opContext.getSubcontext(SAMLPeerEntityContext.class, true).setRole(SPSSODescriptor.DEFAULT_ELEMENT_NAME);
+
+        handler.invoke(messageContext);
+
+        Assert.assertNotNull(messageContext.getSubcontext(SAMLProtocolContext.class));
+        Assert.assertEquals(messageContext.getSubcontext(SAMLProtocolContext.class).getProtocol(), SAMLConstants.SAML20P_NS);
+
+        Assert.assertNotNull(messageContext.getSubcontext(SAMLPeerEntityContext.class));
+        Assert.assertEquals(messageContext.getSubcontext(SAMLPeerEntityContext.class).getRole(), SPSSODescriptor.DEFAULT_ELEMENT_NAME);
+    }
+    
+    @Test
+    public void testCopySourceWithEntityClass() throws ComponentInitializationException, MessageHandlerException {
+        handler.setCopyContextLookup(new RecursiveTypedParentContextLookup(InOutOperationContext.class));
+        handler.setEntityContextClass(SAMLPresenterEntityContext.class);
+        handler.initialize();
+        
+        final InOutOperationContext<SAMLObject, SAMLObject> opContext = 
+                new InOutOperationContext<>(messageContext, new MessageContext<SAMLObject>());
+        opContext.getSubcontext(SAMLProtocolContext.class, true).setProtocol(SAMLConstants.SAML20P_NS); 
+        opContext.getSubcontext(SAMLPresenterEntityContext.class, true).setRole(SPSSODescriptor.DEFAULT_ELEMENT_NAME);
+
+        handler.invoke(messageContext);
+
+        Assert.assertNotNull(messageContext.getSubcontext(SAMLProtocolContext.class));
+        Assert.assertEquals(messageContext.getSubcontext(SAMLProtocolContext.class).getProtocol(), SAMLConstants.SAML20P_NS);
+
+        Assert.assertNotNull(messageContext.getSubcontext(SAMLPresenterEntityContext.class));
+        Assert.assertEquals(messageContext.getSubcontext(SAMLPresenterEntityContext.class).getRole(), SPSSODescriptor.DEFAULT_ELEMENT_NAME);
+    }
+
+    @Test(expectedExceptions=ComponentInitializationException.class)
+    public void testMissingConfiguredProtocol() throws ComponentInitializationException, MessageHandlerException {
+        handler.setRole(SPSSODescriptor.DEFAULT_ELEMENT_NAME);
+        handler.setEntityContextClass(SAMLPresenterEntityContext.class);
+        handler.initialize();
+    }
+    
+    @Test(expectedExceptions=ComponentInitializationException.class)
+    public void testMissingConfiguredRole() throws ComponentInitializationException, MessageHandlerException {
+        handler.setProtocol(SAMLConstants.SAML20P_NS);
+        handler.setEntityContextClass(SAMLPresenterEntityContext.class);
+        handler.initialize();
+    }
+    
+    @Test(expectedExceptions=MessageHandlerException.class)
+    public void testResolverWithNoCopySource() throws ComponentInitializationException, MessageHandlerException {
+        handler.setCopyContextLookup(new RecursiveTypedParentContextLookup(InOutOperationContext.class));
+        handler.initialize();
+        
+        handler.invoke(messageContext);
+    }
+}

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


More information about the commits mailing list