[java-opensaml] 02/02: Message handler for SAML client-side inResponseTo validation.
Brent Putman
putmanb at georgetown.edu
Wed Sep 26 23:33:03 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=72d86de8d61b4e474cf1720f6387d2bbdf7c4497
commit 72d86de8d61b4e474cf1720f6387d2bbdf7c4497
Author: Brent Putman <putmanb at georgetown.edu>
AuthorDate: Wed Sep 26 23:21:28 2018 -0400
Message handler for SAML client-side inResponseTo validation.
---
.../security/impl/InResponseToSecurityHandler.java | 102 +++++++++++++++++++++
.../impl/InResponseToSecurityHandlerTest.java | 101 ++++++++++++++++++++
2 files changed, 203 insertions(+)
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/common/binding/security/impl/InResponseToSecurityHandler.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/common/binding/security/impl/InResponseToSecurityHandler.java
new file mode 100644
index 0000000..e96e62f
--- /dev/null
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/common/binding/security/impl/InResponseToSecurityHandler.java
@@ -0,0 +1,102 @@
+/*
+ * 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.security.impl;
+
+import java.util.Objects;
+
+import javax.annotation.Nonnull;
+
+import org.opensaml.messaging.context.InOutOperationContext;
+import org.opensaml.messaging.context.MessageContext;
+import org.opensaml.messaging.handler.AbstractMessageHandler;
+import org.opensaml.messaging.handler.MessageHandlerException;
+import org.opensaml.saml.common.SAMLObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import net.shibboleth.utilities.java.support.primitive.StringSupport;
+
+/**
+ * Client-side message handler for validating that the inbound SAML response inResponseTo ID matches the corresponding
+ * outbound request ID.
+ */
+public class InResponseToSecurityHandler extends AbstractMessageHandler {
+
+ /** Logger. */
+ private Logger log = LoggerFactory.getLogger(InResponseToSecurityHandler.class);
+
+ /** {@inheritDoc} */
+ protected void doInvoke(@Nonnull final MessageContext messageContext) throws MessageHandlerException {
+ final String outboundRequestID = StringSupport.trimOrNull(resolveOutboundRequestID(messageContext));
+ log.debug("Resolved outbound request ID: {}", outboundRequestID);
+
+ final String inboundInResponseTo = StringSupport.trimOrNull(resolveInboundInResponseTo(messageContext));
+ log.debug("Resolved inbound inResponseTo: {}", inboundInResponseTo);
+
+ if (!Objects.equals(outboundRequestID, inboundInResponseTo)) {
+ log.warn("Inbound inResponseTo '{}' did not match outbound request ID '{}'",
+ inboundInResponseTo, outboundRequestID);
+ throw new MessageHandlerException("Inbound inResponseTo did not match outbound request ID");
+ }
+ }
+
+ /**
+ * Resolve the outbound request ID.
+ *
+ * @param messageContext the message context
+ * @return the outbound request ID, or null
+ */
+ private String resolveOutboundRequestID(@Nonnull final MessageContext messageContext) {
+ if (messageContext.getParent() instanceof InOutOperationContext) {
+ final MessageContext outboundContext =
+ ((InOutOperationContext)messageContext.getParent()).getOutboundMessageContext();
+ if (outboundContext != null && outboundContext.getMessage() instanceof SAMLObject) {
+ final SAMLObject outboundMessage = (SAMLObject) outboundContext.getMessage();
+ if (outboundMessage instanceof org.opensaml.saml.saml2.core.RequestAbstractType) {
+ return ((org.opensaml.saml.saml2.core.RequestAbstractType)outboundMessage).getID();
+ } else if (outboundMessage instanceof org.opensaml.saml.saml1.core.RequestAbstractType) {
+ return ((org.opensaml.saml.saml1.core.RequestAbstractType)outboundMessage).getID();
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Resolve the inbound inResponseTo ID.
+ *
+ * @param messageContext the message context
+ * @return the inbound inResponseTo, or null
+ */
+ private String resolveInboundInResponseTo(@Nonnull final MessageContext messageContext) {
+ if (messageContext.getParent() instanceof InOutOperationContext) {
+ final MessageContext inboundContext =
+ ((InOutOperationContext)messageContext.getParent()).getInboundMessageContext();
+ if (inboundContext != null && inboundContext.getMessage() instanceof SAMLObject) {
+ final SAMLObject inboundMessage = (SAMLObject) inboundContext.getMessage();
+ if (inboundMessage instanceof org.opensaml.saml.saml2.core.StatusResponseType) {
+ return ((org.opensaml.saml.saml2.core.StatusResponseType)inboundMessage).getInResponseTo();
+ } else if (inboundMessage instanceof org.opensaml.saml.saml1.core.ResponseAbstractType) {
+ return ((org.opensaml.saml.saml1.core.ResponseAbstractType)inboundMessage).getInResponseTo();
+ }
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/common/binding/security/impl/InResponseToSecurityHandlerTest.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/common/binding/security/impl/InResponseToSecurityHandlerTest.java
new file mode 100644
index 0000000..e98f91a
--- /dev/null
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/common/binding/security/impl/InResponseToSecurityHandlerTest.java
@@ -0,0 +1,101 @@
+/*
+ * 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.security.impl;
+
+import org.opensaml.core.xml.XMLObjectBaseTestCase;
+import org.opensaml.messaging.context.InOutOperationContext;
+import org.opensaml.messaging.context.MessageContext;
+import org.opensaml.messaging.handler.MessageHandlerException;
+import org.opensaml.saml.saml1.core.Request;
+import org.opensaml.saml.saml1.core.Response;
+import org.opensaml.saml.saml2.core.ArtifactResolve;
+import org.opensaml.saml.saml2.core.ArtifactResponse;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
+
+/**
+ *
+ */
+public class InResponseToSecurityHandlerTest extends XMLObjectBaseTestCase {
+
+ private InOutOperationContext opContext;
+
+ private InResponseToSecurityHandler handler;
+
+ @BeforeClass
+ public void setup() throws ComponentInitializationException {
+ handler = new InResponseToSecurityHandler();
+ handler.initialize();
+ opContext = new InOutOperationContext<>(new MessageContext(), new MessageContext());
+ }
+
+ @Test
+ public void testSAML2Match() throws MessageHandlerException {
+ ArtifactResolve request = buildXMLObject(ArtifactResolve.DEFAULT_ELEMENT_NAME);
+ request.setID("abc123");
+ opContext.getOutboundMessageContext().setMessage(request);
+
+ ArtifactResponse response = buildXMLObject(ArtifactResponse.DEFAULT_ELEMENT_NAME);
+ response.setInResponseTo("abc123");
+ opContext.getInboundMessageContext().setMessage(response);
+
+ handler.invoke(opContext.getInboundMessageContext());
+ }
+
+ @Test(expectedExceptions=MessageHandlerException.class)
+ public void testSAML2NonMatch() throws MessageHandlerException {
+ ArtifactResolve request = buildXMLObject(ArtifactResolve.DEFAULT_ELEMENT_NAME);
+ request.setID("abc123");
+ opContext.getOutboundMessageContext().setMessage(request);
+
+ ArtifactResponse response = buildXMLObject(ArtifactResponse.DEFAULT_ELEMENT_NAME);
+ response.setInResponseTo("xyz456");
+ opContext.getInboundMessageContext().setMessage(response);
+
+ handler.invoke(opContext.getInboundMessageContext());
+ }
+
+ @Test
+ public void testSAML1Match() throws MessageHandlerException {
+ Request request = buildXMLObject(Request.DEFAULT_ELEMENT_NAME);
+ request.setID("abc123");
+ opContext.getOutboundMessageContext().setMessage(request);
+
+ Response response = buildXMLObject(Response.DEFAULT_ELEMENT_NAME);
+ response.setInResponseTo("abc123");
+ opContext.getInboundMessageContext().setMessage(response);
+
+ handler.invoke(opContext.getInboundMessageContext());
+ }
+
+ @Test(expectedExceptions=MessageHandlerException.class)
+ public void testSAML1NonMatch() throws MessageHandlerException {
+ Request request = buildXMLObject(Request.DEFAULT_ELEMENT_NAME);
+ request.setID("abc123");
+ opContext.getOutboundMessageContext().setMessage(request);
+
+ Response response = buildXMLObject(Response.DEFAULT_ELEMENT_NAME);
+ response.setInResponseTo("xyz456");
+ opContext.getInboundMessageContext().setMessage(response);
+
+ handler.invoke(opContext.getInboundMessageContext());
+ }
+
+}
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list