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(); + } + + } +}