[java-opensaml] 01/02: Implement message channel security support for SOAP client case
Brent Putman
putmanb at georgetown.edu
Wed Sep 26 23:33:02 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=00a87cea5cd32d33cb465f83b58083fe5a2314d2
commit 00a87cea5cd32d33cb465f83b58083fe5a2314d2
Author: Brent Putman <putmanb at georgetown.edu>
AuthorDate: Wed Sep 26 21:17:03 2018 -0400
Implement message channel security support for SOAP client case
---
.../NoConfidentialityMessageChannelPredicate.java | 42 ++++++
.../logic/NoIntegrityMessageChannelPredicate.java | 41 +++++
.../org/opensaml/messaging/logic/package-info.java | 19 +++
.../impl/AbstractMessageChannelSecurity.java | 95 ++++++++++++
.../handler/impl/StaticMessageChannelSecurity.java | 81 ++++++++++
.../impl/URLEvaluatingMessageChannelSecurity.java | 147 ++++++++++++++++++
.../URLEvaluatingMessageChannelSecurityTest.java | 166 +++++++++++++++++++++
...opulateHttpClientSecurityParametersHandler.java | 13 +-
.../opensaml/soap/client/SOAPClientContext.java | 21 +++
.../http/AbstractPipelineHttpSOAPClient.java | 8 +-
.../messaging/SOAPClientDestinationURILookup.java | 54 +++++++
.../soap/client/messaging/package-info.java | 19 +++
12 files changed, 701 insertions(+), 5 deletions(-)
diff --git a/opensaml-messaging-api/src/main/java/org/opensaml/messaging/logic/NoConfidentialityMessageChannelPredicate.java b/opensaml-messaging-api/src/main/java/org/opensaml/messaging/logic/NoConfidentialityMessageChannelPredicate.java
new file mode 100644
index 0000000..a99e32d
--- /dev/null
+++ b/opensaml-messaging-api/src/main/java/org/opensaml/messaging/logic/NoConfidentialityMessageChannelPredicate.java
@@ -0,0 +1,42 @@
+/*
+ * 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.messaging.logic;
+
+import javax.annotation.Nullable;
+
+import org.opensaml.messaging.context.MessageChannelSecurityContext;
+import org.opensaml.messaging.context.MessageContext;
+
+import com.google.common.base.Predicate;
+
+/**
+ * A predicate implementation that indicates whether the message channel does
+ * <strong>NOT</strong> support confidentiality end-to-end.
+ *
+ * <p>Typically but not exclusively used as a predicate for whether to encrypt something.</p>
+ */
+public class NoConfidentialityMessageChannelPredicate implements Predicate<MessageContext> {
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean apply(@Nullable final MessageContext input) {
+ return input == null
+ || !input.getSubcontext(MessageChannelSecurityContext.class, true).isConfidentialityActive();
+ }
+
+}
\ No newline at end of file
diff --git a/opensaml-messaging-api/src/main/java/org/opensaml/messaging/logic/NoIntegrityMessageChannelPredicate.java b/opensaml-messaging-api/src/main/java/org/opensaml/messaging/logic/NoIntegrityMessageChannelPredicate.java
new file mode 100644
index 0000000..7478a53
--- /dev/null
+++ b/opensaml-messaging-api/src/main/java/org/opensaml/messaging/logic/NoIntegrityMessageChannelPredicate.java
@@ -0,0 +1,41 @@
+/*
+ * 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.messaging.logic;
+
+import javax.annotation.Nullable;
+
+import org.opensaml.messaging.context.MessageChannelSecurityContext;
+import org.opensaml.messaging.context.MessageContext;
+
+import com.google.common.base.Predicate;
+
+/**
+ * A predicate implementation that indicates whether the message channel does
+ * <strong>NOT</strong> support integrity end-to-end.
+ *
+ * <p>Typically but not exclusively used as a predicate for whether to sign something.</p>
+ */
+public class NoIntegrityMessageChannelPredicate implements Predicate<MessageContext> {
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean apply(@Nullable final MessageContext input) {
+ return input == null || !input.getSubcontext(MessageChannelSecurityContext.class, true).isIntegrityActive();
+ }
+
+}
\ No newline at end of file
diff --git a/opensaml-messaging-api/src/main/java/org/opensaml/messaging/logic/package-info.java b/opensaml-messaging-api/src/main/java/org/opensaml/messaging/logic/package-info.java
new file mode 100644
index 0000000..3e261d8
--- /dev/null
+++ b/opensaml-messaging-api/src/main/java/org/opensaml/messaging/logic/package-info.java
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+
+/** Interfaces and classes for messaging logic. */
+package org.opensaml.messaging.logic;
\ No newline at end of file
diff --git a/opensaml-messaging-impl/src/main/java/org/opensaml/messaging/handler/impl/AbstractMessageChannelSecurity.java b/opensaml-messaging-impl/src/main/java/org/opensaml/messaging/handler/impl/AbstractMessageChannelSecurity.java
new file mode 100644
index 0000000..b8a68d0
--- /dev/null
+++ b/opensaml-messaging-impl/src/main/java/org/opensaml/messaging/handler/impl/AbstractMessageChannelSecurity.java
@@ -0,0 +1,95 @@
+/*
+ * 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.messaging.handler.impl;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.messaging.context.BaseContext;
+import org.opensaml.messaging.context.MessageContext;
+import org.opensaml.messaging.handler.AbstractMessageHandler;
+import org.opensaml.messaging.handler.MessageHandlerException;
+
+import com.google.common.base.Function;
+
+import net.shibboleth.utilities.java.support.component.ComponentSupport;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+
+/**
+ * Abstract base class for message handlers which populate a
+ * {@link org.opensaml.messaging.context.MessageChannelSecurityContext} on a {@link BaseContext},
+ * where the latter is located using a lookup strategy.
+ *
+ * @param <MessageType> the type of message being carried
+ */
+public abstract class AbstractMessageChannelSecurity<MessageType> extends AbstractMessageHandler<MessageType> {
+
+ /**
+ * Strategy used to look up the parent {@link BaseContext} on which the
+ * {@link org.opensaml.messaging.context.MessageChannelSecurityContext} will be populated.
+ */
+ @Nonnull private Function<MessageContext, BaseContext> parentContextLookupStrategy;
+
+ /** Parent for eventual context. */
+ @Nullable private BaseContext parentContext;
+
+ /** Constructor. */
+ public AbstractMessageChannelSecurity() {
+ //TODO this just returns the input MC - need better default?
+ parentContextLookupStrategy = new Function<MessageContext, BaseContext>() {
+ @Nullable public BaseContext apply(@Nullable final MessageContext input) {
+ return input;
+ }
+ };
+ }
+
+ /**
+ * Set the strategy used to look up the parent {@link BaseContext} on which the
+ * {@link org.opensaml.messaging.context.MessageChannelSecurityContext} will be populated.
+ *
+ * @param strategy strategy used to look up the parent {@link BaseContext} on which to populate
+ * the {@link org.opensaml.messaging.context.MessageChannelSecurityContext}
+ */
+ public void setParentContextLookupStrategy(@Nonnull final Function<MessageContext, BaseContext> strategy) {
+ ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+
+ parentContextLookupStrategy = Constraint.isNotNull(strategy, "Parent context lookup strategy cannot be null");
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected boolean doPreInvoke(@Nonnull final MessageContext messageContext) throws MessageHandlerException {
+
+ parentContext = parentContextLookupStrategy.apply(messageContext);
+ if (parentContext != null) {
+ return super.doPreInvoke(messageContext);
+ }
+ return false;
+ }
+
+ /**
+ * Get the parent context on which the {@link org.opensaml.messaging.context.MessageChannelSecurityContext}
+ * will be populated.
+ *
+ * @return the parent context
+ */
+ protected BaseContext getParentContext() {
+ return parentContext;
+ }
+
+}
\ No newline at end of file
diff --git a/opensaml-messaging-impl/src/main/java/org/opensaml/messaging/handler/impl/StaticMessageChannelSecurity.java b/opensaml-messaging-impl/src/main/java/org/opensaml/messaging/handler/impl/StaticMessageChannelSecurity.java
new file mode 100644
index 0000000..bf70a0c
--- /dev/null
+++ b/opensaml-messaging-impl/src/main/java/org/opensaml/messaging/handler/impl/StaticMessageChannelSecurity.java
@@ -0,0 +1,81 @@
+/*
+ * 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.messaging.handler.impl;
+
+import javax.annotation.Nonnull;
+
+import org.opensaml.messaging.context.MessageChannelSecurityContext;
+import org.opensaml.messaging.context.MessageContext;
+
+/**
+ * Message handler which populates a {@link MessageChannelSecurityContext} based on static configuration flags.
+ */
+public class StaticMessageChannelSecurity extends AbstractMessageChannelSecurity {
+
+ /** Message channel confidentiality flag. */
+ private boolean confidentialityActive;
+
+ /** Message channel integrity flag. */
+ private boolean integrityActive;
+
+ /**
+ * Get whether message channel confidentiality is active.
+ *
+ * @return Returns the confidentialityActive.
+ */
+ public boolean isConfidentialityActive() {
+ return confidentialityActive;
+ }
+
+ /**
+ * Set whether message channel confidentiality is active.
+ *
+ * @param flag The confidentialityActive to set.
+ */
+ public void setConfidentialityActive(final boolean flag) {
+ confidentialityActive = flag;
+ }
+
+ /**
+ * Get whether message channel integrity is active.
+ *
+ * @return Returns the integrityActive.
+ */
+ public boolean isIntegrityActive() {
+ return integrityActive;
+ }
+
+ /**
+ * Set whether message channel integrity is active.
+ *
+ * @param flag The integrityActive to set.
+ */
+ public void setIntegrityActive(final boolean flag) {
+ integrityActive = flag;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void doInvoke(@Nonnull final MessageContext messageContext) {
+ final MessageChannelSecurityContext channelContext =
+ getParentContext().getSubcontext(MessageChannelSecurityContext.class, true);
+ channelContext.setConfidentialityActive(isConfidentialityActive());
+ channelContext.setIntegrityActive(isIntegrityActive());
+ }
+
+}
\ No newline at end of file
diff --git a/opensaml-messaging-impl/src/main/java/org/opensaml/messaging/handler/impl/URLEvaluatingMessageChannelSecurity.java b/opensaml-messaging-impl/src/main/java/org/opensaml/messaging/handler/impl/URLEvaluatingMessageChannelSecurity.java
new file mode 100644
index 0000000..37f819a
--- /dev/null
+++ b/opensaml-messaging-impl/src/main/java/org/opensaml/messaging/handler/impl/URLEvaluatingMessageChannelSecurity.java
@@ -0,0 +1,147 @@
+/*
+ * 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.messaging.handler.impl;
+
+import java.net.MalformedURLException;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.messaging.context.MessageChannelSecurityContext;
+import org.opensaml.messaging.context.MessageContext;
+import org.opensaml.messaging.handler.MessageHandlerException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Function;
+
+import net.shibboleth.utilities.java.support.annotation.constraint.NonnullAfterInit;
+import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
+import net.shibboleth.utilities.java.support.component.ComponentSupport;
+import net.shibboleth.utilities.java.support.net.URLBuilder;
+
+/**
+ * Message handler which populates a {@link MessageChannelSecurityContext} based on evaluating a
+ * target URL resolved via a configured strategy function.
+ */
+public class URLEvaluatingMessageChannelSecurity extends AbstractMessageChannelSecurity {
+
+ /** Logger. */
+ private Logger log = LoggerFactory.getLogger(URLEvaluatingMessageChannelSecurity.class);
+
+ /** Flag controlling whether traffic on the default TLS port is "secure". */
+ private boolean defaultPortInsecure;
+
+ /** Function which looks up the URL to evaluate. */
+ @NonnullAfterInit private Function<MessageContext, String> urlLookup;
+
+ /** The target resolved URL. */
+ @Nullable private String url;
+
+ /** Target resolved and parsed URL. */
+ @Nullable private URLBuilder urlBuilder;
+
+ /** Constructor. */
+ public URLEvaluatingMessageChannelSecurity() {
+ defaultPortInsecure = true;
+ }
+
+ /**
+ * Set whether traffic on the default TLS port is "secure" for the purposes of this action.
+ *
+ * <p>Defaults to "true"</p>
+ *
+ * <p>Ordinarily TLS is considered a "secure" channel, but traffic to a default port meant
+ * for browser access tends to rely on server certificates that are unsuited to secure messaging
+ * use cases. This flag allows software layers to recognize traffic on this port as "insecure" and
+ * needing additional security measures.</p>
+ *
+ * @param flag flag to set
+ */
+ public void setDefaultPortInsecure(final boolean flag) {
+ ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+
+ defaultPortInsecure = flag;
+ }
+
+ /**
+ * Set the function which looks up the destination URL to evaluate.
+ *
+ * @param function the lookup function
+ */
+ public void setURLLookup(@Nullable final Function<MessageContext, String> function) {
+ urlLookup = function;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void doInitialize() throws ComponentInitializationException {
+ super.doInitialize();
+ if (urlLookup == null) {
+ throw new ComponentInitializationException("Destination URL lookup function is required");
+ }
+ }
+
+ /** {@inheritDoc} */
+ protected boolean doPreInvoke(@Nonnull final MessageContext messageContext) throws MessageHandlerException {
+ url = urlLookup.apply(messageContext);
+ if (url != null) {
+ try {
+ urlBuilder = new URLBuilder(url);
+ return super.doPreInvoke(messageContext);
+ } catch (final MalformedURLException e){
+ log.warn("Unable to parse resolved target URL: {}", url, e);
+ return false;
+ }
+ } else {
+ log.warn("No target URL resolved, skipping MessageChannelSecurityContext population");
+ return false;
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void doInvoke(final MessageContext messageContext) {
+ final MessageChannelSecurityContext channelContext =
+ getParentContext().getSubcontext(MessageChannelSecurityContext.class, true);
+
+ final String scheme = urlBuilder.getScheme();
+ // Note that below we don't care about port if scheme != https,
+ // so only need to worry about default port for https, not all possible schemes.
+ final Integer port = urlBuilder.getPort() != null
+ ? urlBuilder.getPort()
+ : "https".equalsIgnoreCase(scheme) ? 443 : null;
+
+ log.debug("Evaluating message channel security for scheme '{}' and port '{}' for URL: {}",
+ scheme, port, url);
+
+ if ("https".equalsIgnoreCase(scheme) && (!defaultPortInsecure || port != 443)) {
+ channelContext.setConfidentialityActive(true);
+ channelContext.setIntegrityActive(true);
+ } else {
+ channelContext.setConfidentialityActive(false);
+ channelContext.setIntegrityActive(false);
+ }
+
+ log.debug("Set MessageChannelSecurityContext isIntegrityActive: {}",
+ channelContext.isIntegrityActive());
+ log.debug("Set MessageChannelSecurityContext isConfidentialityActive: {}",
+ channelContext.isConfidentialityActive());
+ }
+
+}
\ No newline at end of file
diff --git a/opensaml-messaging-impl/src/test/java/org/opensaml/messaging/handler/impl/URLEvaluatingMessageChannelSecurityTest.java b/opensaml-messaging-impl/src/test/java/org/opensaml/messaging/handler/impl/URLEvaluatingMessageChannelSecurityTest.java
new file mode 100644
index 0000000..c81eabb
--- /dev/null
+++ b/opensaml-messaging-impl/src/test/java/org/opensaml/messaging/handler/impl/URLEvaluatingMessageChannelSecurityTest.java
@@ -0,0 +1,166 @@
+/*
+ * 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.messaging.handler.impl;
+
+import org.opensaml.messaging.context.MessageChannelSecurityContext;
+import org.opensaml.messaging.context.MessageContext;
+import org.opensaml.messaging.handler.MessageHandlerException;
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Function;
+
+import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
+
+public class URLEvaluatingMessageChannelSecurityTest {
+
+ private URLEvaluatingMessageChannelSecurity handler;
+
+ private MessageContext messageContext;
+
+ @BeforeMethod
+ public void setUp() throws ComponentInitializationException {
+ handler = new URLEvaluatingMessageChannelSecurity();
+ messageContext = new MessageContext();
+ }
+
+ @Test
+ public void testHTTPSNoPort() throws ComponentInitializationException, MessageHandlerException {
+ handler.setURLLookup(new MockURLLookup("https://www.example.edu"));
+ handler.initialize();
+
+ handler.invoke(messageContext);
+
+ MessageChannelSecurityContext channelSecurityContext = messageContext.getSubcontext(MessageChannelSecurityContext.class);
+ Assert.assertNotNull(channelSecurityContext);
+ Assert.assertFalse(channelSecurityContext.isIntegrityActive());
+ Assert.assertFalse(channelSecurityContext.isConfidentialityActive());
+ }
+
+ @Test
+ public void testHTTPSWithDefaultPort() throws ComponentInitializationException, MessageHandlerException {
+ handler.setURLLookup(new MockURLLookup("https://www.example.edu:443"));
+ handler.initialize();
+
+ handler.invoke(messageContext);
+
+ MessageChannelSecurityContext channelSecurityContext = messageContext.getSubcontext(MessageChannelSecurityContext.class);
+ Assert.assertNotNull(channelSecurityContext);
+ Assert.assertFalse(channelSecurityContext.isIntegrityActive());
+ Assert.assertFalse(channelSecurityContext.isConfidentialityActive());
+ }
+
+ @Test
+ public void testHTTPSWithDefaultPortAsSecure() throws ComponentInitializationException, MessageHandlerException {
+ handler.setURLLookup(new MockURLLookup("https://www.example.edu:443"));
+ handler.setDefaultPortInsecure(false);
+ handler.initialize();
+
+ handler.invoke(messageContext);
+
+ MessageChannelSecurityContext channelSecurityContext = messageContext.getSubcontext(MessageChannelSecurityContext.class);
+ Assert.assertNotNull(channelSecurityContext);
+ Assert.assertTrue(channelSecurityContext.isIntegrityActive());
+ Assert.assertTrue(channelSecurityContext.isConfidentialityActive());
+ }
+
+ @Test
+ public void testHTTPSNoPortAsSecure() throws ComponentInitializationException, MessageHandlerException {
+ handler.setURLLookup(new MockURLLookup("https://www.example.edu"));
+ handler.setDefaultPortInsecure(false);
+ handler.initialize();
+
+ handler.invoke(messageContext);
+
+ MessageChannelSecurityContext channelSecurityContext = messageContext.getSubcontext(MessageChannelSecurityContext.class);
+ Assert.assertNotNull(channelSecurityContext);
+ Assert.assertTrue(channelSecurityContext.isIntegrityActive());
+ Assert.assertTrue(channelSecurityContext.isConfidentialityActive());
+ }
+
+ @Test
+ public void testHTTPSWithNonDefaultPort() throws ComponentInitializationException, MessageHandlerException {
+ handler.setURLLookup(new MockURLLookup("https://www.example.edu:8443"));
+ handler.initialize();
+
+ handler.invoke(messageContext);
+
+ MessageChannelSecurityContext channelSecurityContext = messageContext.getSubcontext(MessageChannelSecurityContext.class);
+ Assert.assertNotNull(channelSecurityContext);
+ Assert.assertTrue(channelSecurityContext.isIntegrityActive());
+ Assert.assertTrue(channelSecurityContext.isConfidentialityActive());
+ }
+
+ @Test
+ public void testHTTPNoPort() throws ComponentInitializationException, MessageHandlerException {
+ handler.setURLLookup(new MockURLLookup("http://www.example.edu"));
+ handler.initialize();
+
+ handler.invoke(messageContext);
+
+ MessageChannelSecurityContext channelSecurityContext = messageContext.getSubcontext(MessageChannelSecurityContext.class);
+ Assert.assertNotNull(channelSecurityContext);
+ Assert.assertFalse(channelSecurityContext.isIntegrityActive());
+ Assert.assertFalse(channelSecurityContext.isConfidentialityActive());
+ }
+
+ @Test
+ public void testHTTPWithPort() throws ComponentInitializationException, MessageHandlerException {
+ handler.setURLLookup(new MockURLLookup("http://www.example.edu:80"));
+ handler.initialize();
+
+ handler.invoke(messageContext);
+
+ MessageChannelSecurityContext channelSecurityContext = messageContext.getSubcontext(MessageChannelSecurityContext.class);
+ Assert.assertNotNull(channelSecurityContext);
+ Assert.assertFalse(channelSecurityContext.isIntegrityActive());
+ Assert.assertFalse(channelSecurityContext.isConfidentialityActive());
+ }
+
+ @Test
+ public void testBadURL() throws ComponentInitializationException, MessageHandlerException {
+ handler.setURLLookup(new MockURLLookup("foobar"));
+ handler.initialize();
+
+ handler.invoke(messageContext);
+
+ MessageChannelSecurityContext channelSecurityContext = messageContext.getSubcontext(MessageChannelSecurityContext.class);
+ Assert.assertNull(channelSecurityContext);
+ }
+
+ @Test(expectedExceptions=ComponentInitializationException.class)
+ public void testMissingURLLookup() throws ComponentInitializationException {
+ handler.initialize();
+ }
+
+ private static class MockURLLookup implements Function<MessageContext, String> {
+
+ private String url;
+
+ public MockURLLookup(String value) {
+ url = value;
+ }
+
+ /** {@inheritDoc} */
+ public String apply(MessageContext input) {
+ return url;
+ }
+
+ }
+}
diff --git a/opensaml-security-impl/src/main/java/org/opensaml/security/messaging/impl/PopulateHttpClientSecurityParametersHandler.java b/opensaml-security-impl/src/main/java/org/opensaml/security/messaging/impl/PopulateHttpClientSecurityParametersHandler.java
index 06a7f37..900e40f 100644
--- a/opensaml-security-impl/src/main/java/org/opensaml/security/messaging/impl/PopulateHttpClientSecurityParametersHandler.java
+++ b/opensaml-security-impl/src/main/java/org/opensaml/security/messaging/impl/PopulateHttpClientSecurityParametersHandler.java
@@ -239,9 +239,16 @@ public class PopulateHttpClientSecurityParametersHandler extends AbstractMessage
protected void postProcessParams(@Nonnull final MessageContext messageContext,
@Nonnull final HttpClientSecurityParameters params) {
- if (clientTLSPredicate != null && ! clientTLSPredicate.apply(messageContext)) {
- log.debug("Configured client TLS predicate indicates to exclude client TLS credential");
- params.setClientTLSCredential(null);
+ if (clientTLSPredicate != null) {
+ if (!clientTLSPredicate.apply(messageContext)) {
+ log.debug("Configured client TLS predicate indicates to exclude client TLS credential");
+ params.setClientTLSCredential(null);
+ } else {
+ if (params.getClientTLSCredential() == null) {
+ log.warn("Configured client TLS predicate indicates to include client TLS credential, " +
+ "but no client TLS credential was present in resolved parameters");
+ }
+ }
}
}
diff --git a/opensaml-soap-api/src/main/java/org/opensaml/soap/client/SOAPClientContext.java b/opensaml-soap-api/src/main/java/org/opensaml/soap/client/SOAPClientContext.java
index c8fb849..acc19e6 100644
--- a/opensaml-soap-api/src/main/java/org/opensaml/soap/client/SOAPClientContext.java
+++ b/opensaml-soap-api/src/main/java/org/opensaml/soap/client/SOAPClientContext.java
@@ -33,6 +33,9 @@ public class SOAPClientContext extends BaseContext {
/** Name of the specific SOAP client pipeline to use, for example with {@link PipelineFactoryHttpSOAPClient}. */
@Nullable private String pipelineName;
+
+ /** The destination URI for the SOAP message being sent. */
+ @Nullable private String destinationURI;
/**
* Gets a set of binding/transport-specific request parameters.
@@ -71,5 +74,23 @@ public class SOAPClientContext extends BaseContext {
public void setPipelineName(@Nullable final String name) {
pipelineName = StringSupport.trimOrNull(name);
}
+
+ /**
+ * Get the the destination URI for the SOAP message being sent.
+ *
+ * @return the destination URI, or null
+ */
+ @Nullable public String getDestinationURI() {
+ return destinationURI;
+ }
+
+ /**
+ * Set the destination URI for the SOAP message being sent.
+ *
+ * @param uri the destination URI, or null
+ */
+ public void setDestinationURI(@Nullable final String uri) {
+ destinationURI = StringSupport.trimOrNull(uri);
+ }
}
\ No newline at end of file
diff --git a/opensaml-soap-api/src/main/java/org/opensaml/soap/client/http/AbstractPipelineHttpSOAPClient.java b/opensaml-soap-api/src/main/java/org/opensaml/soap/client/http/AbstractPipelineHttpSOAPClient.java
index 57636dd..2f32c92 100644
--- a/opensaml-soap-api/src/main/java/org/opensaml/soap/client/http/AbstractPipelineHttpSOAPClient.java
+++ b/opensaml-soap-api/src/main/java/org/opensaml/soap/client/http/AbstractPipelineHttpSOAPClient.java
@@ -60,6 +60,7 @@ import org.opensaml.security.httpclient.HttpClientSecurityParameters;
import org.opensaml.security.httpclient.HttpClientSecuritySupport;
import org.opensaml.security.messaging.HttpClientSecurityContext;
import org.opensaml.soap.client.SOAPClient;
+import org.opensaml.soap.client.SOAPClientContext;
import org.opensaml.soap.client.SOAPFaultException;
import org.opensaml.soap.common.SOAP11FaultDecodingException;
import org.opensaml.soap.common.SOAPException;
@@ -185,7 +186,7 @@ public abstract class AbstractPipelineHttpSOAPClient<OutboundMessageType, Inboun
}
/** {@inheritDoc} */
- // Checkstyle: CyclomaticComplexity OFF
+ // Checkstyle: CyclomaticComplexity|MethodLength OFF
public void send(@Nonnull @NotEmpty final String endpoint, @Nonnull final InOutOperationContext operationContext)
throws SOAPException, SecurityException {
Constraint.isNotNull(endpoint, "Endpoint cannot be null");
@@ -193,6 +194,9 @@ public abstract class AbstractPipelineHttpSOAPClient<OutboundMessageType, Inboun
HttpClientMessagePipeline<InboundMessageType, OutboundMessageType> pipeline = null;
try {
+ // Store the endpoint URI
+ operationContext.getSubcontext(SOAPClientContext.class, true).setDestinationURI(endpoint);
+
// Pipeline resolution
pipeline = resolvePipeline(operationContext);
@@ -256,7 +260,7 @@ public abstract class AbstractPipelineHttpSOAPClient<OutboundMessageType, Inboun
}
}
}
- // Checkstyle: CyclomaticComplexity ON
+ // Checkstyle: CyclomaticComplexity|MethodLength ON
/**
* Resolve and return a new instance of the {@link HttpClientMessagePipeline} to be processed.
diff --git a/opensaml-soap-api/src/main/java/org/opensaml/soap/client/messaging/SOAPClientDestinationURILookup.java b/opensaml-soap-api/src/main/java/org/opensaml/soap/client/messaging/SOAPClientDestinationURILookup.java
new file mode 100644
index 0000000..9e7fac0
--- /dev/null
+++ b/opensaml-soap-api/src/main/java/org/opensaml/soap/client/messaging/SOAPClientDestinationURILookup.java
@@ -0,0 +1,54 @@
+/*
+ * 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.soap.client.messaging;
+
+import javax.annotation.Nullable;
+
+import org.opensaml.messaging.context.InOutOperationContext;
+import org.opensaml.messaging.context.MessageContext;
+import org.opensaml.soap.client.SOAPClientContext;
+
+import com.google.common.base.Function;
+
+/**
+ * Function which resolves and returns the intended SOAP client message destination URI
+ * via the {@link SOAPClientContext#getDestinationURI()} of the message context's
+ * parent {@link {@link InOutOperationContext}.
+ */
+public class SOAPClientDestinationURILookup implements Function<MessageContext, String> {
+
+ /** {@inheritDoc} */
+ public String apply(@Nullable final MessageContext messageContext) {
+ if (messageContext == null) {
+ return null;
+ }
+
+ if (!(messageContext.getParent() instanceof InOutOperationContext)) {
+ return null;
+ }
+
+ final InOutOperationContext opContext = (InOutOperationContext) messageContext.getParent();
+
+ if (opContext.getSubcontext(SOAPClientContext.class) == null) {
+ return null;
+ } else {
+ return opContext.getSubcontext(SOAPClientContext.class).getDestinationURI();
+ }
+ }
+
+}
diff --git a/opensaml-soap-api/src/main/java/org/opensaml/soap/client/messaging/package-info.java b/opensaml-soap-api/src/main/java/org/opensaml/soap/client/messaging/package-info.java
new file mode 100644
index 0000000..d76d6c6
--- /dev/null
+++ b/opensaml-soap-api/src/main/java/org/opensaml/soap/client/messaging/package-info.java
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+
+/** SOAP HTTP client messaging functionality. */
+package org.opensaml.soap.client.messaging;
\ 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