[java-identity-provider] branch master updated: IDP-1297 - Missing qualifiers in LogoutRequest result in mismatch

Scott Cantor cantor.2 at osu.edu
Tue Jul 24 10:12:13 EDT 2018


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=5e497a1f467afc18de5367ff1037b23cb8f95825

The following commit(s) were added to refs/heads/master by this push:
       new  5e497a1   IDP-1297 - Missing qualifiers in LogoutRequest result in mismatch
5e497a1 is described below

commit 5e497a1f467afc18de5367ff1037b23cb8f95825
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Tue Jul 24 10:12:09 2018 -0400

    IDP-1297 - Missing qualifiers in LogoutRequest result in mismatch
    
    https://issues.shibboleth.net/jira/browse/IDP-1297
---
 .../system/conf/relying-party-mddriven.xml         |   3 +
 .../QualifiedNameIDFormatsLookupFunction.java      |  65 +++++++++++
 .../config/SingleLogoutProfileConfiguration.java   |  67 +++++++++++
 .../saml2/profile/impl/ProcessLogoutRequest.java   | 122 +++++++++++++++++++--
 .../profile/impl/ProcessLogoutRequestTest.java     |  81 +++++++++++++-
 5 files changed, 329 insertions(+), 9 deletions(-)

diff --git a/idp-conf/src/main/resources/system/conf/relying-party-mddriven.xml b/idp-conf/src/main/resources/system/conf/relying-party-mddriven.xml
index 200d240..2c0b6b1 100644
--- a/idp-conf/src/main/resources/system/conf/relying-party-mddriven.xml
+++ b/idp-conf/src/main/resources/system/conf/relying-party-mddriven.xml
@@ -383,6 +383,9 @@
                 </constructor-arg>
             </bean>
         </property>
+        <property name="qualifiedNameIDFormatsLookupStrategy">
+            <bean parent="shibboleth.MDDrivenListProperty" p:propertyName="qualifiedNameIDFormats" />
+        </property>
     </bean>
 
     <bean id="SAML2.AttributeQuery.MDDriven" parent="AbstractMDDrivenSAML2Profile" lazy-init="true"
diff --git a/idp-saml-api/src/main/java/net/shibboleth/idp/saml/profile/config/navigate/QualifiedNameIDFormatsLookupFunction.java b/idp-saml-api/src/main/java/net/shibboleth/idp/saml/profile/config/navigate/QualifiedNameIDFormatsLookupFunction.java
new file mode 100644
index 0000000..e9c5700
--- /dev/null
+++ b/idp-saml-api/src/main/java/net/shibboleth/idp/saml/profile/config/navigate/QualifiedNameIDFormatsLookupFunction.java
@@ -0,0 +1,65 @@
+/*
+ * 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.saml.profile.config.navigate;
+
+import java.util.Collection;
+import java.util.Collections;
+
+import javax.annotation.Nullable;
+
+import net.shibboleth.idp.profile.config.ProfileConfiguration;
+import net.shibboleth.idp.profile.context.RelyingPartyContext;
+import net.shibboleth.idp.profile.context.navigate.AbstractRelyingPartyLookupFunction;
+import net.shibboleth.idp.saml.saml2.profile.config.SingleLogoutProfileConfiguration;
+import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
+import net.shibboleth.utilities.java.support.annotation.constraint.NotLive;
+import net.shibboleth.utilities.java.support.annotation.constraint.Unmodifiable;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+
+import com.google.common.collect.ImmutableList;
+
+/**
+ * A function that returns the {@link org.opensaml.saml.saml2.core.NameID} Formats
+ * whose NameQualifier attributes should allow for defaulting based on the result of
+ * {@link SingleLogoutProfileConfiguration#getQualifiedNameIDFormats()}
+ * if such a profile is available from a {@link RelyingPartyContext} obtained via a lookup function,
+ * by default a child of the {@link ProfileRequestContext}.
+ * 
+ * <p>If a specific setting is unavailable, no values are returned.</p>
+ * 
+ * @since 3.4.0
+ */
+public class QualifiedNameIDFormatsLookupFunction extends AbstractRelyingPartyLookupFunction<Collection<String>> {
+
+    /** {@inheritDoc} */
+    @Override
+    @Nullable @NonnullElements @NotLive @Unmodifiable public Collection<String> apply(
+            @Nullable final ProfileRequestContext input) {
+        final RelyingPartyContext rpc = getRelyingPartyContextLookupStrategy().apply(input);
+        if (rpc != null) {
+            final ProfileConfiguration pc = rpc.getProfileConfig();
+            if (pc != null && pc instanceof SingleLogoutProfileConfiguration) {
+                return ImmutableList.copyOf(((SingleLogoutProfileConfiguration) pc).getQualifiedNameIDFormats());
+            }
+        }
+        
+        return Collections.emptyList();
+    }
+
+}
\ No newline at end of file
diff --git a/idp-saml-api/src/main/java/net/shibboleth/idp/saml/saml2/profile/config/SingleLogoutProfileConfiguration.java b/idp-saml-api/src/main/java/net/shibboleth/idp/saml/saml2/profile/config/SingleLogoutProfileConfiguration.java
index 93090ac..fe515f8 100644
--- a/idp-saml-api/src/main/java/net/shibboleth/idp/saml/saml2/profile/config/SingleLogoutProfileConfiguration.java
+++ b/idp-saml-api/src/main/java/net/shibboleth/idp/saml/saml2/profile/config/SingleLogoutProfileConfiguration.java
@@ -17,12 +17,22 @@
 
 package net.shibboleth.idp.saml.saml2.profile.config;
 
+import java.util.Collection;
+import java.util.Collections;
+
 import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
 
+import org.opensaml.profile.context.ProfileRequestContext;
 import org.opensaml.profile.logic.NoConfidentialityMessageChannelPredicate;
 import org.opensaml.profile.logic.NoIntegrityMessageChannelPredicate;
 
+import com.google.common.base.Function;
+import com.google.common.collect.ImmutableList;
+
+import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
 import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
+import net.shibboleth.utilities.java.support.primitive.StringSupport;
 
 /** Configuration support for SAML 2 Single Logout. */
 public class SingleLogoutProfileConfiguration extends AbstractSAML2ArtifactAwareProfileConfiguration {
@@ -30,6 +40,12 @@ public class SingleLogoutProfileConfiguration extends AbstractSAML2ArtifactAware
     /** ID for this profile configuration. */
     public static final String PROFILE_ID = "http://shibboleth.net/ns/profiles/saml2/logout";
 
+    /** Lookup function to supply {@link #qualifiedNameIDFormats} property. */
+    @Nullable private Function<ProfileRequestContext,Collection<String>> qualifiedNameIDFormatsLookupStrategy;
+    
+    /** NameID formats whose matching rules accomodate defaulted qualifiers. */
+    @Nonnull @NonnullElements private Collection<String> qualifiedNameIDFormats;
+    
     /** Constructor. */
     public SingleLogoutProfileConfiguration() {
         this(PROFILE_ID);
@@ -45,6 +61,57 @@ public class SingleLogoutProfileConfiguration extends AbstractSAML2ArtifactAware
         setSignRequests(new NoIntegrityMessageChannelPredicate());
         setSignResponses(new NoIntegrityMessageChannelPredicate());
         setEncryptNameIDs(new NoConfidentialityMessageChannelPredicate());
+
+        qualifiedNameIDFormats = Collections.emptyList();
+    }
+
+    /**
+     * Get a collection of {@link org.opensaml.saml.saml2.core.NameID} Format values for which the use of
+     * the NameQualifier and SPNameQualifier attributes is defined to allow default/implicit values
+     * derived from the asserting and relying parties.
+     * 
+     * <p>In the core standard, only the {@link org.opensaml.saml.saml2.core.NameIDType.PERSISTENT} and
+     * {@link org.opensaml.saml.saml2.core.NameIDType.TRANSIENT} Formats are defined in this manner. This
+     * setting identifies <strong>additional</strong> Formats that should be handled in this way.</p>  
+     * 
+     * @return additional Formats for which defaulting of qualifiers is permissable
+     * 
+     * @since 3.4.0
+     */
+    public Collection<String> getQualifiedNameIDFormats() {
+        return ImmutableList.copyOf(getIndirectProperty(qualifiedNameIDFormatsLookupStrategy, qualifiedNameIDFormats));
     }
 
+    /**
+     * Set a collection of {@link org.opensaml.saml.saml2.core.NameID} Format values for which the use of
+     * the NameQualifier and SPNameQualifier attributes is defined to allow default/implicit values
+     * derived from the asserting and relying parties.
+     * 
+     * <p>In the core standard, only the {@link org.opensaml.saml.saml2.core.NameIDType.PERSISTENT} and
+     * {@link org.opensaml.saml.saml2.core.NameIDType.TRANSIENT} Formats are defined in this manner. This
+     * setting identifies <strong>additional</strong> Formats that should be handled in this way.</p>  
+     * 
+     * @param formats additional Formats for which defaulting of qualifiers is permissable
+     * 
+     * @since 3.4.0
+     */
+    public void setQualifiedNameIDFormats(@Nullable @NonnullElements final Collection<String> formats) {
+        if (formats == null) {
+            qualifiedNameIDFormats = Collections.emptyList();
+        } else {
+            qualifiedNameIDFormats = StringSupport.normalizeStringCollection(formats);
+        }
+    }
+
+    /**
+     * Set a lookup strategy for the {@link #qualifiedNameIDFormats} property.
+     *
+     * @param strategy  lookup strategy
+     * 
+     * @since 3.4.0
+     */
+    public void setQualifiedNameIDFormatsLookupStrategy(
+            @Nullable final Function<ProfileRequestContext,Collection<String>> strategy) {
+        qualifiedNameIDFormatsLookupStrategy = strategy;
+    }
 }
\ No newline at end of file
diff --git a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/ProcessLogoutRequest.java b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/ProcessLogoutRequest.java
index b4318f0..362bb0c 100644
--- a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/ProcessLogoutRequest.java
+++ b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/ProcessLogoutRequest.java
@@ -17,13 +17,20 @@
 
 package net.shibboleth.idp.saml.saml2.profile.impl;
 
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
 import java.util.Iterator;
+import java.util.Set;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
 import net.shibboleth.idp.authn.context.SubjectContext;
 import net.shibboleth.idp.profile.AbstractProfileAction;
+import net.shibboleth.idp.profile.context.navigate.RelyingPartyIdLookupFunction;
+import net.shibboleth.idp.profile.context.navigate.ResponderIdLookupFunction;
+import net.shibboleth.idp.saml.profile.config.navigate.QualifiedNameIDFormatsLookupFunction;
 import net.shibboleth.idp.saml.session.SAML2SPSession;
 import net.shibboleth.idp.session.IdPSession;
 import net.shibboleth.idp.session.SPSession;
@@ -49,6 +56,7 @@ import org.opensaml.profile.context.navigate.InboundMessageContextLookup;
 import org.opensaml.saml.common.profile.SAMLEventIds;
 import org.opensaml.saml.ext.saml2aslo.Asynchronous;
 import org.opensaml.saml.saml2.core.LogoutRequest;
+import org.opensaml.saml.saml2.core.NameID;
 import org.opensaml.saml.saml2.core.SessionIndex;
 import org.opensaml.saml.saml2.profile.SAML2ObjectSupport;
 import org.slf4j.Logger;
@@ -103,10 +111,28 @@ public class ProcessLogoutRequest extends AbstractProfileAction {
     
     /** Lookup strategy for {@link LogoutRequest} to process. */
     @Nonnull private Function<ProfileRequestContext,LogoutRequest> logoutRequestLookupStrategy;
+
+    /** Lookup strategy for obtaining qualifier-defaultable NameID Formats. */
+    @Nonnull private Function<ProfileRequestContext,Collection<String>> qualifiedNameIDFormatsLookupStrategy;
+    
+    /** Optional lookup function for obtaining default NameQualifier. */
+    @Nullable private Function<ProfileRequestContext,String> assertingPartyLookupStrategy;
+    
+    /** Optional lookup function for obtaining default SPNameQualifier. */
+    @Nullable private Function<ProfileRequestContext,String> relyingPartyLookupStrategy;
     
     /** LogoutRequest to process. */
     @Nullable private LogoutRequest logoutRequest;
     
+    /** {@link NameID} Formats allowing defaulted qualifiers. */
+    @Nonnull private Set<String> qualifiedNameIDFormats;
+    
+    /** Cached lookup of assertingParty name. */
+    @Nullable private String assertingParty;
+    
+    /** Cached lookup of relyingParty name. */
+    @Nullable private String relyingParty;
+    
     /** Constructor. */
     public ProcessLogoutRequest() {
         subjectContextCreationStrategy = new ChildContextLookup<>(SubjectContext.class, true);
@@ -127,6 +153,13 @@ public class ProcessLogoutRequest extends AbstractProfileAction {
     
         logoutRequestLookupStrategy = Functions.compose(new MessageLookup<>(LogoutRequest.class),
                 new InboundMessageContextLookup());
+        
+        qualifiedNameIDFormatsLookupStrategy = new QualifiedNameIDFormatsLookupFunction();
+
+        qualifiedNameIDFormats = Collections.emptySet();
+        
+        setAssertingPartyLookupStrategy(new ResponderIdLookupFunction());
+        setRelyingPartyLookupStrategy(new RelyingPartyIdLookupFunction());
     }
     
     /**
@@ -213,6 +246,49 @@ public class ProcessLogoutRequest extends AbstractProfileAction {
         logoutRequestLookupStrategy = Constraint.isNotNull(strategy, "LogoutRequest lookup strategy cannot be null");
     }
     
+    /**
+     * Set the lookup strategy for the {@link NameID} Formats to allow defaulted qualifiers.
+     * 
+     * @param strategy lookup strategy
+     * 
+     * @since 3.4.0
+     */
+    public void setQualifiedNameIDFormatsLookupStrategy(
+            @Nonnull final Function<ProfileRequestContext,Collection<String>> strategy) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+        
+        qualifiedNameIDFormatsLookupStrategy = Constraint.isNotNull(strategy,
+                "Qualified NameID Formats lookup strategy cannot be null");
+    }
+    
+    /**
+     * Set the lookup strategy to obtain the default IdP NameQualifier.
+     * 
+     * @param strategy lookup strategy
+     * 
+     * @since 3.4.0
+     */
+    public void setAssertingPartyLookupStrategy(
+            @Nullable final Function<ProfileRequestContext,String> strategy) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+        
+        assertingPartyLookupStrategy = strategy;
+    }
+    
+    /**
+     * Set the lookup strategy to obtain the default SPNameQualifier.
+     * 
+     * @param strategy lookup strategy
+     * 
+     * @since 3.4.0
+     */
+    public void setRelyingPartyLookupStrategy(
+            @Nullable final Function<ProfileRequestContext,String> strategy) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+        
+        relyingPartyLookupStrategy = strategy;
+    }
+    
     /** {@inheritDoc} */
     @Override
     protected void doInitialize() throws ComponentInitializationException {
@@ -255,6 +331,8 @@ public class ProcessLogoutRequest extends AbstractProfileAction {
             log.debug("{} LogoutRequest contained Asynchronous extension", getLogPrefix());
         }
         
+        qualifiedNameIDFormats = new HashSet<>(qualifiedNameIDFormatsLookupStrategy.apply(profileRequestContext));
+        
         return true;
     }
     
@@ -274,7 +352,7 @@ public class ProcessLogoutRequest extends AbstractProfileAction {
             while (sessionIterator.hasNext()) {
                 final IdPSession session = sessionIterator.next();
                 
-                if (!sessionMatches(session)) {
+                if (!sessionMatches(profileRequestContext, session)) {
                     log.debug("{} IdP session {} does not contain a matching SP session", getLogPrefix(),
                             session.getId());
                     continue;
@@ -300,7 +378,7 @@ public class ProcessLogoutRequest extends AbstractProfileAction {
                 }
                 
                 for (final SPSession spSession : session.getSPSessions()) {
-                    if (!sessionMatches(spSession)) {
+                    if (!sessionMatches(profileRequestContext, spSession)) {
                         logoutCtx.getSessionMap().put(spSession.getId(), spSession);
                         logoutCtx.getKeyedSessionMap().put(Integer.toString(count++), spSession);
                     }
@@ -335,14 +413,16 @@ public class ProcessLogoutRequest extends AbstractProfileAction {
     /**
      * Check if the session contains a {@link SAML2SPSession} with the appropriate service ID and SessionIndex.
      * 
+     * @param profileRequestContext current profile request context
      * @param session {@link IdPSession} to check
      * 
      * @return  true iff the set of {@link SPSession}s includes one applicable to the logout request
      */
-    private boolean sessionMatches(@Nonnull final IdPSession session) {
+    private boolean sessionMatches(@Nonnull final ProfileRequestContext profileRequestContext,
+            @Nonnull final IdPSession session) {
         
         for (final SPSession spSession : session.getSPSessions()) {
-            if (sessionMatches(spSession)) {
+            if (sessionMatches(profileRequestContext, spSession)) {
                 return true;
             }
         }
@@ -353,20 +433,46 @@ public class ProcessLogoutRequest extends AbstractProfileAction {
     /**
      * Check if the {@link SPSession} has the appropriate service ID and SessionIndex.
      * 
+     * @param profileRequestContext current profile request context
      * @param session {@link SPSession} to check
      * 
      * @return  true iff the {@link SPSession} directly matches the logout request
      */
-    private boolean sessionMatches(@Nonnull final SPSession session) {
+    private boolean sessionMatches(@Nonnull final ProfileRequestContext profileRequestContext,
+            @Nonnull final SPSession session) {
         if (session instanceof SAML2SPSession) {
             final SAML2SPSession saml2Session = (SAML2SPSession) session;
             
+            // Make sure the SP matches.
             if (!saml2Session.getId().equals(logoutRequest.getIssuer().getValue())) {
                 return false;
-            } else if (!SAML2ObjectSupport.areNameIDsEquivalent(
-                    logoutRequest.getNameID(), saml2Session.getNameID())) {
+            } 
+            
+            // Use the format of the original NameID to determine whether to
+            // allow the qualifiers to be defaulted. If the formats don't match
+            // the eventual check will fail anyway.
+            String format = saml2Session.getNameID().getFormat();
+            if (format == null)
+                format = NameID.UNSPECIFIED;
+            if (NameID.PERSISTENT.equals(format) || NameID.TRANSIENT.equals(format)
+                    || qualifiedNameIDFormats.contains(format)) {
+                
+                if (assertingParty == null)
+                    assertingParty = assertingPartyLookupStrategy.apply(profileRequestContext);
+                if (relyingParty == null)
+                    relyingParty = relyingPartyLookupStrategy.apply(profileRequestContext);
+                
+                if (!SAML2ObjectSupport.areNameIDsEquivalent(logoutRequest.getNameID(), saml2Session.getNameID(),
+                        assertingParty, relyingParty)) {
+                    return false;
+                }
+            } else if (!SAML2ObjectSupport.areNameIDsEquivalent(logoutRequest.getNameID(), saml2Session.getNameID())) {
                 return false;
-            } else if (logoutRequest.getSessionIndexes().isEmpty()) {
+            }
+            
+            // Check SessionIndex match.
+            
+            if (logoutRequest.getSessionIndexes().isEmpty()) {
                 return true;
             }
             
diff --git a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/saml2/profile/impl/ProcessLogoutRequestTest.java b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/saml2/profile/impl/ProcessLogoutRequestTest.java
index 5998857..158fe8a 100644
--- a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/saml2/profile/impl/ProcessLogoutRequestTest.java
+++ b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/saml2/profile/impl/ProcessLogoutRequestTest.java
@@ -17,6 +17,7 @@
 
 package net.shibboleth.idp.saml.saml2.profile.impl;
 
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -25,8 +26,10 @@ import javax.servlet.http.Cookie;
 import net.shibboleth.idp.authn.context.SubjectContext;
 import net.shibboleth.idp.profile.ActionTestingSupport;
 import net.shibboleth.idp.profile.RequestContextBuilder;
+import net.shibboleth.idp.profile.config.ProfileConfiguration;
 import net.shibboleth.idp.profile.context.navigate.WebflowRequestContextProfileRequestContextLookup;
 import net.shibboleth.idp.saml.saml2.profile.SAML2ActionTestingSupport;
+import net.shibboleth.idp.saml.saml2.profile.config.SingleLogoutProfileConfiguration;
 import net.shibboleth.idp.saml.session.SAML1SPSession;
 import net.shibboleth.idp.saml.session.SAML2SPSession;
 import net.shibboleth.idp.saml.session.impl.SAML1SPSessionSerializer;
@@ -78,7 +81,11 @@ public class ProcessLogoutRequestTest extends SessionManagerBaseTestCase {
                 XMLObjectProviderRegistrySupport.getBuilderFactory().<SessionIndex>getBuilderOrThrow(
                         SessionIndex.DEFAULT_ELEMENT_NAME);
 
-        src = new RequestContextBuilder().buildRequestContext();
+        final SingleLogoutProfileConfiguration logoutConfig = new SingleLogoutProfileConfiguration();
+        logoutConfig.setQualifiedNameIDFormats(Collections.singletonList(NameID.UNSPECIFIED));
+        src = new RequestContextBuilder().setRelyingPartyProfileConfigurations(
+                Collections.<ProfileConfiguration>singletonList(logoutConfig)).buildRequestContext();
+        
         prc = new WebflowRequestContextProfileRequestContextLookup().apply(src);
         
         action = new ProcessLogoutRequest();
@@ -173,6 +180,78 @@ public class ProcessLogoutRequestTest extends SessionManagerBaseTestCase {
         sessionManager.destroySession(session.getId(), false);
     }
 
+    @Test public void testDefaultedRequestQualifiers() throws SessionException, ResolverException {
+        final Cookie cookie = createSession("joe");
+
+        final NameID nameId = SAML2ActionTestingSupport.buildNameID("joe");
+        nameId.setNameQualifier(ActionTestingSupport.OUTBOUND_MSG_ISSUER);
+        nameId.setSPNameQualifier(ActionTestingSupport.INBOUND_MSG_ISSUER);
+        prc.getInboundMessageContext().setMessage(SAML2ActionTestingSupport.buildLogoutRequest(nameId));
+        
+        HttpServletRequestResponseContext.loadCurrent(new MockHttpServletRequest(), new MockHttpServletResponse());
+        ((MockHttpServletRequest) HttpServletRequestResponseContext.getRequest()).setCookies(cookie);
+        
+        final long creation = System.currentTimeMillis();
+        final long expiration = creation + 3600 * 60 * 1000;
+        
+        final IdPSession session = sessionManager.resolveSingle(new CriteriaSet(new HttpServletRequestCriterion()));
+        Assert.assertNotNull(session);
+        final NameID nameIdForSession = SAML2ActionTestingSupport.buildNameID("joe");
+        session.addSPSession(new SAML2SPSession(ActionTestingSupport.INBOUND_MSG_ISSUER, creation, expiration,
+                nameIdForSession, "index"));
+                
+        final Event event = action.execute(src);
+        ActionTestingSupport.assertProceedEvent(event);
+        final SubjectContext subjectCtx = prc.getSubcontext(SubjectContext.class);
+        Assert.assertNotNull(subjectCtx);
+        Assert.assertEquals(subjectCtx.getPrincipalName(), "joe");
+        
+        final SessionContext sessionCtx = prc.getSubcontext(SessionContext.class);
+        Assert.assertNotNull(sessionCtx);
+        Assert.assertEquals(session.getId(), sessionCtx.getIdPSession().getId());
+        
+        final LogoutContext logoutCtx = prc.getSubcontext(LogoutContext.class);
+        if (logoutCtx != null) {
+            Assert.assertEquals(logoutCtx.getSessionMap().size(), 0);
+        }
+    }
+
+    @Test public void testDefaultedSessionQualifiers() throws SessionException, ResolverException {
+        final Cookie cookie = createSession("joe");
+
+        final NameID nameId = SAML2ActionTestingSupport.buildNameID("joe");
+        prc.getInboundMessageContext().setMessage(SAML2ActionTestingSupport.buildLogoutRequest(nameId));
+        
+        HttpServletRequestResponseContext.loadCurrent(new MockHttpServletRequest(), new MockHttpServletResponse());
+        ((MockHttpServletRequest) HttpServletRequestResponseContext.getRequest()).setCookies(cookie);
+        
+        final long creation = System.currentTimeMillis();
+        final long expiration = creation + 3600 * 60 * 1000;
+        
+        final IdPSession session = sessionManager.resolveSingle(new CriteriaSet(new HttpServletRequestCriterion()));
+        Assert.assertNotNull(session);
+        final NameID nameIdForSession = SAML2ActionTestingSupport.buildNameID("joe");
+        nameIdForSession.setNameQualifier(ActionTestingSupport.OUTBOUND_MSG_ISSUER);
+        nameIdForSession.setSPNameQualifier(ActionTestingSupport.INBOUND_MSG_ISSUER);
+        session.addSPSession(new SAML2SPSession(ActionTestingSupport.INBOUND_MSG_ISSUER, creation, expiration,
+                nameIdForSession, "index"));
+                
+        final Event event = action.execute(src);
+        ActionTestingSupport.assertProceedEvent(event);
+        final SubjectContext subjectCtx = prc.getSubcontext(SubjectContext.class);
+        Assert.assertNotNull(subjectCtx);
+        Assert.assertEquals(subjectCtx.getPrincipalName(), "joe");
+        
+        final SessionContext sessionCtx = prc.getSubcontext(SessionContext.class);
+        Assert.assertNotNull(sessionCtx);
+        Assert.assertEquals(session.getId(), sessionCtx.getIdPSession().getId());
+        
+        final LogoutContext logoutCtx = prc.getSubcontext(LogoutContext.class);
+        if (logoutCtx != null) {
+            Assert.assertEquals(logoutCtx.getSessionMap().size(), 0);
+        }
+    }
+    
     @Test public void testSessionOneSPSession() throws SessionException, ResolverException {
         final Cookie cookie = createSession("joe");
 

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


More information about the commits mailing list