[java-opensaml] 06/16: Handler for HttpClient server TLS.

Brent Putman putmanb at georgetown.edu
Fri Sep 21 22:48:44 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=a043c2e5c06f87807d047b48442432b0b8859078

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

    Handler for HttpClient server TLS.
---
 ...ecordServerTLSEntityAuthenticationtHandler.java | 208 +++++++++++++++++++++
 1 file changed, 208 insertions(+)

diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/common/binding/security/impl/CheckAndRecordServerTLSEntityAuthenticationtHandler.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/common/binding/security/impl/CheckAndRecordServerTLSEntityAuthenticationtHandler.java
new file mode 100644
index 0000000..484cc11
--- /dev/null
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/common/binding/security/impl/CheckAndRecordServerTLSEntityAuthenticationtHandler.java
@@ -0,0 +1,208 @@
+/*
+ * 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 javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.protocol.HttpClientContext;
+import org.opensaml.messaging.context.InOutOperationContext;
+import org.opensaml.messaging.context.MessageContext;
+import org.opensaml.messaging.context.httpclient.HttpClientRequestContext;
+import org.opensaml.messaging.context.navigate.ContextDataLookupFunction;
+import org.opensaml.messaging.context.navigate.RecursiveTypedParentContextLookup;
+import org.opensaml.messaging.handler.AbstractMessageHandler;
+import org.opensaml.messaging.handler.MessageHandlerException;
+import org.opensaml.saml.common.messaging.context.AbstractAuthenticatableSAMLEntityContext;
+import org.opensaml.saml.common.messaging.context.SAMLPeerEntityContext;
+import org.opensaml.security.httpclient.HttpClientSecurityConstants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import net.shibboleth.utilities.java.support.component.ComponentSupport;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+
+/**
+ * Handler implementation that checks and records the result of {@link HttpClient} server TLS authentication 
+ * as stored in the @link {@link HttpClientContext} resolved via strategy function.
+ * 
+ * <p>
+ * If server TLS was performed and successful, 
+ * store a positive authentication result in the configured {@link AbstractAuthenticatableSAMLEntityContext}.
+ * If the entity context's entityID is not already populated, and the appropriate entityID strategy function 
+ * is configured, also attempt to resolve the authenticated entityID and if successful populate the entity context.
+ * </p>
+ */
+public class CheckAndRecordServerTLSEntityAuthenticationtHandler extends AbstractMessageHandler {
+    
+    /** Logger. */
+    private Logger log = LoggerFactory.getLogger(CheckAndRecordServerTLSEntityAuthenticationtHandler.class);
+    
+    /** The strategy function for resolving the {@link HttpClientContext to evaluate}. */
+    @Nonnull private ContextDataLookupFunction<MessageContext, HttpClientContext> httpClientContextLookup;
+    
+    /** The strategy function for resolving the authenticated entityID. */
+    @Nonnull private ContextDataLookupFunction<MessageContext, String> entityIDLookup;
+    
+    /** The actual context class holding the authenticatable SAML entity. */
+    @Nonnull private Class<? extends AbstractAuthenticatableSAMLEntityContext> entityContextClass;
+    
+    /** Constructor. */
+    public CheckAndRecordServerTLSEntityAuthenticationtHandler() {
+        super();
+        entityContextClass = SAMLPeerEntityContext.class;
+        httpClientContextLookup = new DefaultHttpClientContextLookup();
+        entityIDLookup = new DefaultEntityIDLookup();
+    }
+    
+    /**
+     * Set the strategy function for resolving the {@link HttpClientContext to evaluate}.
+     * 
+     * @param strategy the new strategy function
+     */
+    public void setHttpClientContextLookup(
+            @Nonnull final ContextDataLookupFunction<MessageContext, HttpClientContext> strategy) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+        httpClientContextLookup = Constraint.isNotNull(strategy, 
+                "The HttpClientContext lookup strategy may not be null");
+    }
+
+    /**
+     * Set the class type holding the authenticatable SAML entity data.
+     * 
+     * <p>Defaults to: {@link SAMLPeerEntityContext}.</p>
+     * 
+     * @param clazz the entity context class type
+     */
+    public void setEntityContextClass(@Nonnull final Class<? extends AbstractAuthenticatableSAMLEntityContext> clazz) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+        entityContextClass = Constraint.isNotNull(clazz, "The SAML entity context class may not be null");
+    }
+
+    /**
+     * Set the strategy function for resolving the authenticated entityID.
+     * 
+     * @param strategy the new strategy function, or null
+     */
+    public void setEntityIDLookup(@Nullable final ContextDataLookupFunction<MessageContext, String> strategy) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+        entityIDLookup = strategy;
+    }
+
+    /** {@inheritDoc} */
+    protected void doInvoke(@Nonnull final MessageContext messageContext) throws MessageHandlerException {
+        final HttpClientContext clientContext = httpClientContextLookup.apply(messageContext);
+        if (clientContext == null) {
+            log.debug("Could not resolve HttpClientContext");
+            return;
+        }
+        
+        final Boolean trusted = clientContext.getAttribute(
+                HttpClientSecurityConstants.CONTEXT_KEY_SERVER_TLS_CREDENTIAL_TRUSTED, Boolean.class);
+        if (trusted == null) {
+            log.debug("HttpClientContext attribute not found: {}", 
+                    HttpClientSecurityConstants.CONTEXT_KEY_SERVER_TLS_CREDENTIAL_TRUSTED);
+        } else {
+            if (trusted) {
+                log.debug("HttpClientContext indicates successful server TLS, storing result in entity context {}", 
+                        entityContextClass.getName());
+                final AbstractAuthenticatableSAMLEntityContext entityContext = 
+                        messageContext.getSubcontext(entityContextClass, true);
+                entityContext.setAuthenticated(true);
+                if (entityContext.getEntityId() == null && entityIDLookup != null) {
+                    log.debug("Context entityID was null, attempting to resolve");
+                    final String entityID = entityIDLookup.apply(messageContext);
+                    if (entityID != null) {
+                        log.debug("Resolved authenticated entityID, populating on entity context: {}", entityID);
+                        entityContext.setEntityId(entityID);
+                    } else {
+                        log.debug("Unable to resolve authenticated entityID");
+                    }
+                }
+            } else {
+                log.debug("HttpClientContext indicates non-successful server TLS");
+            }
+        }
+        
+    }
+
+    /**
+     * The default {@link HttpClientContext} strategy function, which resolves from the {@link HttpClientRequestContext}
+     * of the outbound {@link MessageContext} of the parent {@link InOutOperationContext.
+     */
+    public class DefaultHttpClientContextLookup 
+            implements ContextDataLookupFunction<MessageContext, HttpClientContext> {
+
+        /** {@inheritDoc} */
+        public HttpClientContext apply(@Nullable final MessageContext messageContext) {
+            if (messageContext == null) {
+                return null;
+            }
+            
+            final InOutOperationContext opContext = 
+                    new RecursiveTypedParentContextLookup<>(InOutOperationContext.class).apply(messageContext);
+            if (opContext == null) {
+                return null;
+            }
+            
+            final MessageContext outboundMessageContext = opContext.getOutboundMessageContext();
+            if (outboundMessageContext == null) {
+                return null;
+            }
+            
+            final HttpClientRequestContext requestContext = 
+                    outboundMessageContext.getSubcontext(HttpClientRequestContext.class);
+            if (requestContext == null) {
+                return null;
+            }
+            
+            return requestContext.getHttpClientContext();
+        }
+        
+    }
+    
+    /**
+     * The default entityID strategy function, which resolves from the configured 
+     * {@link AbstractAuthenticatableSAMLEntityContext} of the parent {@link InOutOperationContext}.
+     */
+    public class DefaultEntityIDLookup implements ContextDataLookupFunction<MessageContext, String> {
+
+        /** {@inheritDoc} */
+        public String apply(@Nullable final MessageContext messageContext) {
+            if (messageContext == null) {
+                return null;
+            }
+            
+            final InOutOperationContext opContext = 
+                    new RecursiveTypedParentContextLookup<>(InOutOperationContext.class).apply(messageContext);
+            if (opContext == null) {
+                return null;
+            }
+            
+            final AbstractAuthenticatableSAMLEntityContext entityContext = opContext.getSubcontext(entityContextClass);
+            if (entityContext == null) {
+                return null;
+            }
+            
+            return entityContext.getEntityId();
+        }
+        
+    }
+
+}

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


More information about the commits mailing list