diff --git a/uw-spring-security-sample-war/pom.xml b/uw-spring-security-sample-war/pom.xml
index be90c32fad2a3b16c226e0ebd3f6871bb74d7131..b645c1e7b421a80ee3e16d18f6bbbecfb1a8d590 100644
--- a/uw-spring-security-sample-war/pom.xml
+++ b/uw-spring-security-sample-war/pom.xml
@@ -106,13 +106,13 @@
 		<profile>
 			<id>combined</id>
 			<properties>
-				<activeProfiles>local-users,preauth</activeProfiles>
+				<activeProfiles>local-users,preauth,edu.wisc.uwss.simulated-shibboleth</activeProfiles>
 			</properties>
 		</profile>
 		<profile>
 			<id>combined-simulate-netid</id>
 			<properties>
-				<activeProfiles>local-users,preauth,preauth-simulate-netid</activeProfiles>
+				<activeProfiles>local-users,preauth,preauth-simulate-netid,edu.wisc.uwss.simulated-shibboleth</activeProfiles>
 			</properties>
 		</profile>
 	</profiles>
diff --git a/uw-spring-security-web/src/main/java/edu/wisc/uwss/web/shibboleth/Attribute.java b/uw-spring-security-web/src/main/java/edu/wisc/uwss/web/shibboleth/Attribute.java
new file mode 100644
index 0000000000000000000000000000000000000000..faf0619cd0b8bd7b8ae1956d6bcba740d43a6bfa
--- /dev/null
+++ b/uw-spring-security-web/src/main/java/edu/wisc/uwss/web/shibboleth/Attribute.java
@@ -0,0 +1,32 @@
+package edu.wisc.uwss.web.shibboleth;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Part of {@link SimulatedResponse}.
+ *
+ * @author Nicholas Blair
+ */
+public class Attribute {
+
+  private final String name;
+  private final List<String> values;
+
+  public Attribute(String name, String value) {
+    this(name, Arrays.asList(value));
+  }
+  public Attribute(String name, List<String> values) {
+    this.name = name;
+    this.values = Collections.unmodifiableList(values);
+  }
+
+  public String getName() {
+    return name;
+  }
+
+  public List<String> getValues() {
+    return values;
+  }
+}
diff --git a/uw-spring-security-web/src/main/java/edu/wisc/uwss/web/shibboleth/SimulatedResponse.java b/uw-spring-security-web/src/main/java/edu/wisc/uwss/web/shibboleth/SimulatedResponse.java
new file mode 100644
index 0000000000000000000000000000000000000000..fd7cb06a63d35e50b13e3f6bc749c937b5c5e60a
--- /dev/null
+++ b/uw-spring-security-web/src/main/java/edu/wisc/uwss/web/shibboleth/SimulatedResponse.java
@@ -0,0 +1,74 @@
+package edu.wisc.uwss.web.shibboleth;
+
+import org.apache.commons.lang3.StringUtils;
+
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import edu.wisc.uwss.UWUserDetails;
+
+/**
+ * Object matching the JSON model from /Shibboleth.sso/Session.json.
+ *
+ * @author Nicholas Blair
+ */
+public class SimulatedResponse {
+
+  // computed from session length
+  private Integer expiration = 480;
+  private String client_address;
+  private final String protocol = "urn:oasis:names:tc:SAML:2.0:protocol";
+  private final String identity_provider = "https://logintest.wisc.edu/idp/shibboleth";
+  private final String authn_instant = LocalDateTime.now(ZoneOffset.UTC).toString();
+  private final String authncontext_class = "urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport";
+
+  private List<Attribute> attributes = new ArrayList<>();
+
+  public SimulatedResponse(UWUserDetails userDetails, String client_address) {
+    this.client_address = client_address;
+
+    List<Attribute> attributes = new ArrayList<>();
+    if(StringUtils.isNotBlank(userDetails.getEppn())) {
+      attributes.add(new Attribute("eppn", userDetails.getEppn()));
+    }
+    attributes.add(new Attribute("persistent-id", "https://logintest.wisc.edu/idp/shibboleth!https://fake.wisc.edu/shibboleth!thisis/fake/PE="));
+    attributes.add(new Attribute("uid", userDetails.getUsername()));
+    attributes.add(new Attribute("pubcookie-user", userDetails.getUsername()));
+    if(StringUtils.isNotBlank(userDetails.getPvi())) {
+      attributes.add(new Attribute("wiscEduPVI", userDetails.getPvi()));
+    }
+
+    this.attributes = Collections.unmodifiableList(attributes);
+  }
+
+  public Integer getExpiration() {
+    return expiration;
+  }
+
+  public String getClient_address() {
+    return client_address;
+  }
+
+  public String getProtocol() {
+    return protocol;
+  }
+
+  public String getIdentity_provider() {
+    return identity_provider;
+  }
+
+  public String getAuthn_instant() {
+    return authn_instant;
+  }
+
+  public String getAuthncontext_class() {
+    return authncontext_class;
+  }
+
+  public List<Attribute> getAttributes() {
+    return attributes;
+  }
+}
diff --git a/uw-spring-security-web/src/main/java/edu/wisc/uwss/web/shibboleth/SimulatedShibbolethSessionController.java b/uw-spring-security-web/src/main/java/edu/wisc/uwss/web/shibboleth/SimulatedShibbolethSessionController.java
new file mode 100644
index 0000000000000000000000000000000000000000..31cd9d16eb3675cd6dff4fc7428d7d61da5e9b90
--- /dev/null
+++ b/uw-spring-security-web/src/main/java/edu/wisc/uwss/web/shibboleth/SimulatedShibbolethSessionController.java
@@ -0,0 +1,36 @@
+package edu.wisc.uwss.web.shibboleth;
+
+import org.springframework.context.annotation.Profile;
+import org.springframework.security.core.annotation.AuthenticationPrincipal;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import java.util.Collections;
+
+import javax.servlet.http.HttpServletRequest;
+
+import edu.wisc.uwss.UWUserDetails;
+
+/**
+ * {@link Controller} intended to simulate the JSON response from /Shibboleth.sso/Session.json,
+ * using the current authenticated {@link UWUserDetails} as the principal.
+ *
+ * @author Nicholas Blair
+ */
+@Controller
+@Profile("edu.wisc.uwss.simulated-shibboleth")
+public class SimulatedShibbolethSessionController {
+
+  @RequestMapping(value="/Shibboleth.sso/Session.json", method=RequestMethod.GET)
+  public @ResponseBody Object shibbolethSessionProfile(@AuthenticationPrincipal Object principal, HttpServletRequest request) {
+
+    if(principal instanceof UWUserDetails) {
+      return new SimulatedResponse((UWUserDetails) principal, request.getRemoteAddr());
+    } else {
+      return Collections.emptyMap();
+    }
+
+  }
+}