[java-identity-provider] branch main updated: IDP-1816 - Abstract away session cache dependency on IP address
Scott Cantor
cantor.2 at osu.edu
Wed Jun 16 21:09:16 UTC 2021
This is an automated email from the git hooks/post-receive script.
scantor pushed a commit to branch main
in repository java-identity-provider.
View the commit online:
http://git.shibboleth.net/view/?p=java-identity-provider.git;a=commit;h=0a42022b2946ef184fed4d33f723485f21846eba
The following commit(s) were added to refs/heads/main by this push:
new 0a42022b2 IDP-1816 - Abstract away session cache dependency on IP address
0a42022b2 is described below
commit 0a42022b2946ef184fed4d33f723485f21846eba
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Wed Jun 16 17:09:13 2021 -0400
IDP-1816 - Abstract away session cache dependency on IP address
https://issues.shibboleth.net/jira/browse/IDP-1816
---
.../net/shibboleth/idp/flows/authn/authn-beans.xml | 3 ++-
.../shibboleth/idp/flows/logout/logout-beans.xml | 3 ++-
.../shibboleth/idp/session/AbstractIdPSession.java | 20 ++++++++++-----
.../net/shibboleth/idp/session/IdPSessionTest.java | 4 ++-
.../idp/session/impl/PopulateSessionContext.java | 28 +++++++++++++++++---
.../shibboleth/idp/session/impl/ProcessLogout.java | 30 +++++++++++++++++++---
.../idp/session/impl/StorageBackedIdPSession.java | 7 +----
.../impl/StorageBackedIdPSessionSerializer.java | 12 +++++++++
.../StorageBackedIdPSessionSerializerTest.java | 27 ++++++++-----------
.../impl/StorageBackedSessionManagerTest.java | 10 +++++---
.../idp/session/impl/complexIdPSession.jdk8 | 2 +-
11 files changed, 100 insertions(+), 46 deletions(-)
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/authn/authn-beans.xml b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/authn/authn-beans.xml
index af662e19b..8bc728f50 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/authn/authn-beans.xml
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/authn/authn-beans.xml
@@ -29,7 +29,8 @@
class="net.shibboleth.idp.session.impl.PopulateSessionContext" scope="prototype"
p:activationCondition="%{idp.session.enabled:true}"
p:httpServletRequest-ref="shibboleth.HttpServletRequest"
- p:sessionResolver-ref="shibboleth.SessionManager" />
+ p:sessionResolver-ref="shibboleth.SessionManager"
+ p:addressLookupStrategy="#{getObject('shibboleth.SessionAddressLookupStrategy')}" />
<bean id="SetRPUIInformation"
class="net.shibboleth.idp.ui.impl.SetRPUIInformation" scope="prototype"
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/logout/logout-beans.xml b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/logout/logout-beans.xml
index bb63e2707..23fe25f44 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/logout/logout-beans.xml
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/logout/logout-beans.xml
@@ -46,7 +46,8 @@
<bean id="ProcessLogout"
class="net.shibboleth.idp.session.impl.ProcessLogout" scope="prototype"
p:httpServletRequest-ref="shibboleth.HttpServletRequest"
- p:sessionResolver-ref="shibboleth.SessionManager" />
+ p:sessionResolver-ref="shibboleth.SessionManager"
+ p:addressLookupStrategy="#{getObject('shibboleth.SessionAddressLookupStrategy')}" />
<bean id="DestroySessions"
class="net.shibboleth.idp.session.impl.DestroySessions" scope="prototype"
diff --git a/idp-session-api/src/main/java/net/shibboleth/idp/session/AbstractIdPSession.java b/idp-session-api/src/main/java/net/shibboleth/idp/session/AbstractIdPSession.java
index 18572342b..c17f01a8e 100644
--- a/idp-session-api/src/main/java/net/shibboleth/idp/session/AbstractIdPSession.java
+++ b/idp-session-api/src/main/java/net/shibboleth/idp/session/AbstractIdPSession.java
@@ -86,11 +86,14 @@ public abstract class AbstractIdPSession implements IdPSession {
/** Last activity instant for this session. */
@Nonnull private Instant lastActivityInstant;
- /** Addresses to which the session is bound. */
+ /** An IPv4 address to which the session is bound. */
@Nullable private String ipV4Address;
/** An IPv6 address to which the session is bound. */
@Nullable private String ipV6Address;
+
+ /** An "unknown" address to which the session is bound. */
+ @Nullable private String unknownAddress;
/** Tracks authentication results that have occurred during this session. */
@Nonnull private final ConcurrentMap<String,Optional<AuthenticationResult>> authenticationResults;
@@ -164,10 +167,6 @@ public abstract class AbstractIdPSession implements IdPSession {
@Override
public boolean checkAddress(@Nonnull @NotEmpty final String address) throws SessionException {
final AddressFamily family = getAddressFamily(address);
- if (family == AddressFamily.UNKNOWN) {
- log.warn("Address {} is of unknown type", address);
- return false;
- }
final String bound = getAddress(family);
if (bound != null) {
if (!bound.equals(address)) {
@@ -175,7 +174,7 @@ public abstract class AbstractIdPSession implements IdPSession {
return false;
}
} else {
- log.info("Session {} not yet locked to a {} address, locking it to {}", id, family, address);
+ log.info("Session {} not yet locked to {} address, locking it to {}", id, family, address);
try {
bindToAddress(address);
} catch (final SessionException e) {
@@ -200,6 +199,8 @@ public abstract class AbstractIdPSession implements IdPSession {
return ipV4Address;
case IPV6:
return ipV6Address;
+ case UNKNOWN:
+ return unknownAddress;
default:
return null;
}
@@ -226,6 +227,7 @@ public abstract class AbstractIdPSession implements IdPSession {
public void doBindToAddress(@Nonnull @NotEmpty final String address) {
final String trimmed = Constraint.isNotNull(StringSupport.trimOrNull(address),
"Address cannot be null or empty");
+
switch (getAddressFamily(address)) {
case IPV6:
ipV6Address = StringSupport.trimOrNull(trimmed);
@@ -235,6 +237,10 @@ public abstract class AbstractIdPSession implements IdPSession {
ipV4Address = StringSupport.trimOrNull(trimmed);
break;
+ case UNKNOWN:
+ unknownAddress = StringSupport.trimOrNull(trimmed);
+ break;
+
default:
log.warn("Unsupported address form {}", address);
}
@@ -417,7 +423,7 @@ public abstract class AbstractIdPSession implements IdPSession {
/** {@inheritDoc} */
public String toString() {
return MoreObjects.toStringHelper(this).add("sessionId", id).add("principalName", principalName)
- .add("IPv4", ipV4Address).add("IPv6", ipV6Address)
+ .add("IPv4", ipV4Address).add("IPv6", ipV6Address).add("Unk", unknownAddress)
.add("creationInstant", creationInstant)
.add("lastActivityInstant", lastActivityInstant)
.add("authenticationResults", getAuthenticationResults()).add("spSessions", getSPSessions())
diff --git a/idp-session-api/src/test/java/net/shibboleth/idp/session/IdPSessionTest.java b/idp-session-api/src/test/java/net/shibboleth/idp/session/IdPSessionTest.java
index 8c3a3e978..289c883da 100644
--- a/idp-session-api/src/test/java/net/shibboleth/idp/session/IdPSessionTest.java
+++ b/idp-session-api/src/test/java/net/shibboleth/idp/session/IdPSessionTest.java
@@ -97,7 +97,7 @@ public class IdPSessionTest {
}
/**
- * Tests mutating the last activity instant.
+ * Tests address binding.
*
* @throws Exception if something goes wrong
*/
@@ -110,6 +110,8 @@ public class IdPSessionTest {
Assert.assertTrue(session.checkAddress("::1"));
Assert.assertTrue(session.checkAddress("::1"));
Assert.assertFalse(session.checkAddress("fe80::5a55:caff:fef2:65a3"));
+ Assert.assertTrue(session.checkAddress("zorkmid"));
+ Assert.assertFalse(session.checkAddress("bugbear"));
}
/**
diff --git a/idp-session-impl/src/main/java/net/shibboleth/idp/session/impl/PopulateSessionContext.java b/idp-session-impl/src/main/java/net/shibboleth/idp/session/impl/PopulateSessionContext.java
index 6a046864c..92e66789a 100644
--- a/idp-session-impl/src/main/java/net/shibboleth/idp/session/impl/PopulateSessionContext.java
+++ b/idp-session-impl/src/main/java/net/shibboleth/idp/session/impl/PopulateSessionContext.java
@@ -20,6 +20,7 @@ package net.shibboleth.idp.session.impl;
import java.util.function.Function;
import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
import javax.servlet.http.HttpServletRequest;
import net.shibboleth.idp.profile.AbstractProfileAction;
@@ -66,12 +67,13 @@ public class PopulateSessionContext extends AbstractProfileAction {
/** Function to return {@link CriteriaSet} to give to session resolver. */
@Nonnull private Function<ProfileRequestContext,CriteriaSet> sessionResolverCriteriaStrategy;
+
+ /** Function to override source of address to bind session. */
+ @Nullable private Function<ProfileRequestContext,String> addressLookupStrategy;
/** Constructor. */
public PopulateSessionContext() {
-
sessionContextCreationStrategy = new ChildContextLookup<>(SessionContext.class, true);
-
sessionResolverCriteriaStrategy = prc -> new CriteriaSet(new HttpServletRequestCriterion());
}
@@ -99,6 +101,19 @@ public class PopulateSessionContext extends AbstractProfileAction {
"SessionContext creation strategy cannot be null");
}
+ /**
+ * Set an optional lookup strategy to obtain the address to which to bind the session.
+ *
+ * @param strategy lookup strategy
+ *
+ * @since 4.2.0
+ */
+ public void setAddressLookupStrategy(@Nullable final Function<ProfileRequestContext,String> strategy) {
+ ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+
+ addressLookupStrategy = strategy;
+ }
+
/**
* Set the strategy for building the {@link CriteriaSet} to feed into the {@link SessionResolver}.
*
@@ -134,8 +149,13 @@ public class PopulateSessionContext extends AbstractProfileAction {
return;
}
- final HttpServletRequest request = getHttpServletRequest();
- final String addr = request != null ? HttpServletSupport.getRemoteAddr(request) : null;
+ String addr = null;
+ if (addressLookupStrategy != null) {
+ addr = addressLookupStrategy.apply(profileRequestContext);
+ } else {
+ final HttpServletRequest request = getHttpServletRequest();
+ addr = request != null ? HttpServletSupport.getRemoteAddr(request) : null;
+ }
if (addr != null) {
if (!session.checkAddress(addr)) {
return;
diff --git a/idp-session-impl/src/main/java/net/shibboleth/idp/session/impl/ProcessLogout.java b/idp-session-impl/src/main/java/net/shibboleth/idp/session/impl/ProcessLogout.java
index 92af3e949..6e078ab92 100644
--- a/idp-session-impl/src/main/java/net/shibboleth/idp/session/impl/ProcessLogout.java
+++ b/idp-session-impl/src/main/java/net/shibboleth/idp/session/impl/ProcessLogout.java
@@ -20,6 +20,7 @@ package net.shibboleth.idp.session.impl;
import java.util.function.Function;
import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
import javax.servlet.http.HttpServletRequest;
import net.shibboleth.idp.authn.context.SubjectContext;
@@ -82,6 +83,9 @@ public class ProcessLogout extends AbstractProfileAction {
/** Function to return {@link CriteriaSet} to give to session resolver. */
@Nonnull private Function<ProfileRequestContext,CriteriaSet> sessionResolverCriteriaStrategy;
+ /** Function to override source of address to bind session. */
+ @Nullable private Function<ProfileRequestContext,String> addressLookupStrategy;
+
/** Constructor. */
public ProcessLogout() {
subjectContextCreationStrategy = new ChildContextLookup<>(SubjectContext.class, true);
@@ -151,6 +155,19 @@ public class ProcessLogout extends AbstractProfileAction {
sessionResolverCriteriaStrategy = Constraint.isNotNull(strategy,
"SessionResolver CriteriaSet strategy cannot be null");
}
+
+ /**
+ * Set an optional lookup strategy to obtain the address to which to validate the session.
+ *
+ * @param strategy lookup strategy
+ *
+ * @since 4.2.0
+ */
+ public void setAddressLookupStrategy(@Nullable final Function<ProfileRequestContext,String> strategy) {
+ ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+
+ addressLookupStrategy = strategy;
+ }
/** {@inheritDoc} */
@Override
@@ -176,20 +193,25 @@ public class ProcessLogout extends AbstractProfileAction {
return;
}
- final HttpServletRequest request = getHttpServletRequest();
- final String addr = request != null ? HttpServletSupport.getRemoteAddr(request) : null;
+ String addr = null;
+ if (addressLookupStrategy != null) {
+ addr = addressLookupStrategy.apply(profileRequestContext);
+ } else {
+ final HttpServletRequest request = getHttpServletRequest();
+ addr = request != null ? HttpServletSupport.getRemoteAddr(request) : null;
+ }
if (addr != null) {
try {
if (!session.checkAddress(addr)) {
return;
}
} catch (final SessionException e) {
- log.error("{} Error binding session to client address", getLogPrefix(), e);
+ log.error("{} Error validating session against client address", getLogPrefix(), e);
ActionSupport.buildEvent(profileRequestContext, EventIds.IO_ERROR);
return;
}
} else {
- log.info("{} No client address available, skipping address check for sessions",
+ log.info("{} No client address available, skipping address check for session",
getLogPrefix());
}
diff --git a/idp-session-impl/src/main/java/net/shibboleth/idp/session/impl/StorageBackedIdPSession.java b/idp-session-impl/src/main/java/net/shibboleth/idp/session/impl/StorageBackedIdPSession.java
index 73d53d102..76ad0e778 100644
--- a/idp-session-impl/src/main/java/net/shibboleth/idp/session/impl/StorageBackedIdPSession.java
+++ b/idp-session-impl/src/main/java/net/shibboleth/idp/session/impl/StorageBackedIdPSession.java
@@ -104,11 +104,6 @@ public class StorageBackedIdPSession extends AbstractIdPSession {
public boolean checkAddress(@Nonnull @NotEmpty final String address) throws SessionException {
final AddressFamily family = getAddressFamily(address);
- if (family == AddressFamily.UNKNOWN) {
- log.warn("Address {} is of unknown type", address);
- return false;
- }
-
final String bound = getAddress(family);
if (bound != null) {
if (!sessionManager.getConsistentAddressCondition().test(bound, address)) {
@@ -116,7 +111,7 @@ public class StorageBackedIdPSession extends AbstractIdPSession {
return false;
}
} else {
- log.info("Session {} not yet bound to a {} address, binding to {}", getId(), family, address);
+ log.info("Session {} not yet bound to {} address, binding to {}", getId(), family, address);
try {
bindToAddress(address);
} catch (final SessionException e) {
diff --git a/idp-session-impl/src/main/java/net/shibboleth/idp/session/impl/StorageBackedIdPSessionSerializer.java b/idp-session-impl/src/main/java/net/shibboleth/idp/session/impl/StorageBackedIdPSessionSerializer.java
index 946b7ea76..253763f1d 100644
--- a/idp-session-impl/src/main/java/net/shibboleth/idp/session/impl/StorageBackedIdPSessionSerializer.java
+++ b/idp-session-impl/src/main/java/net/shibboleth/idp/session/impl/StorageBackedIdPSessionSerializer.java
@@ -67,6 +67,9 @@ public class StorageBackedIdPSessionSerializer extends AbstractInitializableComp
/** Field name of IPv6 address. */
@Nonnull @NotEmpty private static final String IPV6_ADDRESS_FIELD = "v6";
+ /** Field name of Unknown address. */
+ @Nonnull @NotEmpty private static final String UNK_ADDRESS_FIELD = "unk";
+
/** Field name of flow ID array. */
@Nonnull @NotEmpty private static final String FLOW_ID_ARRAY_FIELD = "flows";
@@ -97,6 +100,7 @@ public class StorageBackedIdPSessionSerializer extends AbstractInitializableComp
jsonProvider = JsonProvider.provider();
}
+// Checkstyle: CyclomaticComplexity OFF
/** {@inheritDoc} */
@Override @Nonnull @NotEmpty public String serialize(@Nonnull final StorageBackedIdPSession instance)
throws IOException {
@@ -115,6 +119,10 @@ public class StorageBackedIdPSessionSerializer extends AbstractInitializableComp
gen.write(IPV6_ADDRESS_FIELD, instance.getAddress(AbstractIdPSession.AddressFamily.IPV6));
}
+ if (instance.getAddress(AbstractIdPSession.AddressFamily.UNKNOWN) != null) {
+ gen.write(UNK_ADDRESS_FIELD, instance.getAddress(AbstractIdPSession.AddressFamily.UNKNOWN));
+ }
+
final Set<AuthenticationResult> results = instance.getAuthenticationResults();
if (!results.isEmpty()) {
gen.writeStartArray(FLOW_ID_ARRAY_FIELD);
@@ -147,6 +155,7 @@ public class StorageBackedIdPSessionSerializer extends AbstractInitializableComp
throw new IOException("Exception while serializing IdPSession", e);
}
}
+// Checkstyle: CyclomaticComplexity ON
/** {@inheritDoc} */
// Checkstyle: CyclomaticComplexity OFF
@@ -186,6 +195,9 @@ public class StorageBackedIdPSessionSerializer extends AbstractInitializableComp
if (obj.containsKey(IPV6_ADDRESS_FIELD)) {
objectToPopulate.doBindToAddress(obj.getString(IPV6_ADDRESS_FIELD));
}
+ if (obj.containsKey(UNK_ADDRESS_FIELD)) {
+ objectToPopulate.doBindToAddress(obj.getString(UNK_ADDRESS_FIELD));
+ }
objectToPopulate.getAuthenticationResultMap().clear();
if (obj.containsKey(FLOW_ID_ARRAY_FIELD)) {
diff --git a/idp-session-impl/src/test/java/net/shibboleth/idp/session/impl/StorageBackedIdPSessionSerializerTest.java b/idp-session-impl/src/test/java/net/shibboleth/idp/session/impl/StorageBackedIdPSessionSerializerTest.java
index a05445433..30e667515 100644
--- a/idp-session-impl/src/test/java/net/shibboleth/idp/session/impl/StorageBackedIdPSessionSerializerTest.java
+++ b/idp-session-impl/src/test/java/net/shibboleth/idp/session/impl/StorageBackedIdPSessionSerializerTest.java
@@ -27,6 +27,7 @@ import org.opensaml.storage.impl.MemoryStorageService;
import org.testng.Assert;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
+import org.testng.reporters.Files;
import net.shibboleth.idp.authn.AuthenticationResult;
import net.shibboleth.idp.authn.principal.UsernamePrincipal;
@@ -133,6 +134,8 @@ public class StorageBackedIdPSessionSerializerTest {
StorageBackedIdPSession session = new StorageBackedIdPSession(manager, "test", "foo", Instant.ofEpochMilli(INSTANT));
session.doBindToAddress("127.0.0.1");
+ session.doBindToAddress("::1");
+ session.doBindToAddress("zorkmid");
session.doAddAuthenticationResult(new AuthenticationResult("a", new UsernamePrincipal("jdoe")));
session.doAddAuthenticationResult(new AuthenticationResult("b", new UsernamePrincipal("jdoe")));
session.doAddAuthenticationResult(new AuthenticationResult("c", new UsernamePrincipal("jdoe")));
@@ -150,28 +153,18 @@ public class StorageBackedIdPSessionSerializerTest {
Assert.assertEquals(session.getPrincipalName(), session2.getPrincipalName());
Assert.assertEquals(session.getCreationInstant(), session2.getCreationInstant());
Assert.assertEquals(session.getLastActivityInstant(), session2.getLastActivityInstant());
+ Assert.assertTrue(session.checkAddress("127.0.0.1"));
+ Assert.assertTrue(session.checkAddress("::1"));
+ Assert.assertTrue(session.checkAddress("zorkmid"));
+ Assert.assertFalse(session.checkAddress("127.0.0.2"));
+ Assert.assertFalse(session.checkAddress("::1:1"));
+ Assert.assertFalse(session.checkAddress("bugbear"));
}
private String fileToString(String pathname) throws URISyntaxException, IOException {
try (FileInputStream stream = new FileInputStream(
new File(StorageBackedIdPSessionSerializerTest.class.getResource(pathname).toURI()))) {
- int avail = stream.available();
- byte[] data = new byte[avail];
- int numRead = 0;
- int pos = 0;
- do {
- if (pos + avail > data.length) {
- byte[] newData = new byte[pos + avail];
- System.arraycopy(data, 0, newData, 0, pos);
- data = newData;
- }
- numRead = stream.read(data, pos, avail);
- if (numRead >= 0) {
- pos += numRead;
- }
- avail = stream.available();
- } while (avail > 0 && numRead >= 0);
- return new String(data, 0, pos, "UTF-8");
+ return Files.streamToString(stream);
}
}
}
\ No newline at end of file
diff --git a/idp-session-impl/src/test/java/net/shibboleth/idp/session/impl/StorageBackedSessionManagerTest.java b/idp-session-impl/src/test/java/net/shibboleth/idp/session/impl/StorageBackedSessionManagerTest.java
index bf9bb6eeb..214c087b4 100644
--- a/idp-session-impl/src/test/java/net/shibboleth/idp/session/impl/StorageBackedSessionManagerTest.java
+++ b/idp-session-impl/src/test/java/net/shibboleth/idp/session/impl/StorageBackedSessionManagerTest.java
@@ -192,17 +192,17 @@ public class StorageBackedSessionManagerTest extends SessionManagerBaseTestCase
mockRequest.setRemoteAddr("192.168.1.1");
HttpServletRequestResponseContext.loadCurrent(mockRequest, new MockHttpServletResponse());
- // Interleave checks of addresses of the two types.
+ // Interleave checks of addresses of the various types.
IdPSession session = sessionManager.createSession("joe");
Assert.assertTrue(session.checkAddress("192.168.1.1"));
Assert.assertFalse(session.checkAddress("192.168.1.2"));
+ Assert.assertTrue(session.checkAddress("zorkmid"));
Assert.assertTrue(session.checkAddress("fe80::ca2a:14ff:fe2a:3e04"));
+ Assert.assertFalse(session.checkAddress("bugbear"));
Assert.assertTrue(session.checkAddress("fe80::ca2a:14ff:fe2a:3e04"));
Assert.assertFalse(session.checkAddress("fe80::ca2a:14ff:fe2a:3e05"));
Assert.assertTrue(session.checkAddress("192.168.1.1"));
-
- // Try a bad address type.
- Assert.assertFalse(session.checkAddress("1,1,1,1"));
+ Assert.assertTrue(session.checkAddress("zorkmid"));
// Interleave manipulation of a session between two copies to check for resync.
IdPSession one = sessionManager.createSession("joe");
@@ -212,6 +212,8 @@ public class StorageBackedSessionManagerTest extends SessionManagerBaseTestCase
Assert.assertFalse(two.checkAddress("192.168.1.2"));
Assert.assertTrue(two.checkAddress("fe80::ca2a:14ff:fe2a:3e04"));
Assert.assertFalse(one.checkAddress("fe80::ca2a:14ff:fe2a:3e05"));
+ Assert.assertTrue(one.checkAddress("zorkmid"));
+ Assert.assertFalse(two.checkAddress("bugbear"));
sessionManager.destroySession(session.getId(), true);
}
diff --git a/idp-session-impl/src/test/resources/net/shibboleth/idp/session/impl/complexIdPSession.jdk8 b/idp-session-impl/src/test/resources/net/shibboleth/idp/session/impl/complexIdPSession.jdk8
index f2cdc8880..3d885067d 100644
--- a/idp-session-impl/src/test/resources/net/shibboleth/idp/session/impl/complexIdPSession.jdk8
+++ b/idp-session-impl/src/test/resources/net/shibboleth/idp/session/impl/complexIdPSession.jdk8
@@ -1 +1 @@
-{"ts":1378827849463,"nam":"foo","v4":"127.0.0.1","flows":["c","b","a"],"svcs":["bar","baz"]}
\ No newline at end of file
+{"ts":1378827849463,"nam":"foo","v4":"127.0.0.1","v6":"::1","unk":"zorkmid","flows":["c","b","a"],"svcs":["bar","baz"]}
\ 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