diff --git a/myconext-gui/src/api/index.js b/myconext-gui/src/api/index.js index a1d02cba..af67c9e1 100644 --- a/myconext-gui/src/api/index.js +++ b/myconext-gui/src/api/index.js @@ -135,7 +135,9 @@ export function logout() { credentials: "same-origin", redirect: "manual" }; - return fetchJson("/myconext/api/sp/logout").then(() => fetch("/Shibboleth.sso/Logout", fetchOptions)); + return forgetMe().then(() => + fetchJson("/myconext/api/sp/logout").then(() => fetch("/Shibboleth.sso/Logout", fetchOptions)) + ); } export function forgetMe() { diff --git a/myconext-server/src/main/java/myconext/aa/UserAttribute.java b/myconext-server/src/main/java/myconext/aa/UserAttribute.java index 72b3f5d3..76dbf648 100644 --- a/myconext-server/src/main/java/myconext/aa/UserAttribute.java +++ b/myconext-server/src/main/java/myconext/aa/UserAttribute.java @@ -2,12 +2,14 @@ import lombok.Getter; import lombok.NoArgsConstructor; +import lombok.ToString; import java.util.Collections; import java.util.List; @Getter @NoArgsConstructor +@ToString public class UserAttribute { private String name; diff --git a/myconext-server/src/main/java/myconext/security/GuestIdpAuthenticationRequestFilter.java b/myconext-server/src/main/java/myconext/security/GuestIdpAuthenticationRequestFilter.java index ec50ef21..28f627f7 100644 --- a/myconext-server/src/main/java/myconext/security/GuestIdpAuthenticationRequestFilter.java +++ b/myconext-server/src/main/java/myconext/security/GuestIdpAuthenticationRequestFilter.java @@ -45,6 +45,7 @@ import java.util.concurrent.Executors; import java.util.stream.Collectors; +import static java.nio.charset.StandardCharsets.UTF_8; import static java.util.function.Function.identity; import static java.util.stream.Collectors.toList; import static java.util.stream.Collectors.toMap; @@ -69,9 +70,11 @@ public class GuestIdpAuthenticationRequestFilter extends OncePerRequestFilter im private final AntPathRequestMatcher ssoSamlRequestMatcher; private final AntPathRequestMatcher magicSamlRequestMatcher; - private final AntPathRequestMatcher continueAfterloginSamlRequestMatcher; + private final AntPathRequestMatcher continueAfterLoginSamlRequestMatcher; + private final AntPathRequestMatcher metaDataSamlRequestMatcher; private final String redirectUrl; private final AuthenticationRequestRepository authenticationRequestRepository; + private final IdentityProviderMetaData identityProviderMetaData; private UserRepository userRepository; private final UserLoginRepository userLoginRepository; private final List accountLinkingContextClassReferences; @@ -107,10 +110,12 @@ public GuestIdpAuthenticationRequestFilter(String redirectUrl, long ssoMFADurationSeconds, String mobileAppROEntityId, boolean featureDefaultRememberMe, - SAMLConfiguration configuration) { + SAMLConfiguration configuration, + IdentityProviderMetaData identityProviderMetaData) { this.ssoSamlRequestMatcher = new AntPathRequestMatcher("/saml/guest-idp/SSO/**"); this.magicSamlRequestMatcher = new AntPathRequestMatcher("/saml/guest-idp/magic/**"); - this.continueAfterloginSamlRequestMatcher = new AntPathRequestMatcher("/saml/guest-idp/continue/**"); + this.continueAfterLoginSamlRequestMatcher = new AntPathRequestMatcher("/saml/guest-idp/continue/**"); + this.metaDataSamlRequestMatcher = new AntPathRequestMatcher("/saml/guest-idp/metadata/**"); this.redirectUrl = redirectUrl; this.serviceProviderResolver = serviceProviderResolver; this.authenticationRequestRepository = authenticationRequestRepository; @@ -130,6 +135,7 @@ public GuestIdpAuthenticationRequestFilter(String redirectUrl, this.featureDefaultRememberMe = featureDefaultRememberMe; this.samlIdpService = new DefaultSAMLIdPService(configuration); this.executor = Executors.newSingleThreadExecutor(); + this.identityProviderMetaData = identityProviderMetaData; } @Override @@ -142,10 +148,14 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse LOG.debug("Starting magic filter"); this.magic(request, response); return; - } else if (this.continueAfterloginSamlRequestMatcher.matches(request)) { + } else if (this.continueAfterLoginSamlRequestMatcher.matches(request)) { LOG.debug("Starting continue after login filter"); this.continueAfterLogin(request, response); return; + } else if (this.metaDataSamlRequestMatcher.matches(request)) { + LOG.debug("Starting metadata filter"); + this.metaData(response); + return; } filterChain.doFilter(request, response); } @@ -761,4 +771,19 @@ private SAMLAttribute attribute(String name, String value) { return new SAMLAttribute(name, value); } + private void metaData(HttpServletResponse servletResponse) throws IOException { + servletResponse.setContentType("text/xml"); + servletResponse.setCharacterEncoding(UTF_8.name()); + + servletResponse.setHeader("Cache-Control", "private"); + String metaData = this.samlIdpService.metaData( + this.identityProviderMetaData.getSingleSignOnServiceURI(), + this.identityProviderMetaData.getName(), + this.identityProviderMetaData.getDescription(), + this.identityProviderMetaData.getLogoURI() + ); + servletResponse.getWriter().write(metaData); + } + + } diff --git a/myconext-server/src/main/java/myconext/security/IdentityProviderMetaData.java b/myconext-server/src/main/java/myconext/security/IdentityProviderMetaData.java new file mode 100644 index 00000000..c2c29060 --- /dev/null +++ b/myconext-server/src/main/java/myconext/security/IdentityProviderMetaData.java @@ -0,0 +1,19 @@ +package myconext.security; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.springframework.boot.context.properties.ConfigurationProperties; + +@Getter +@Setter +@NoArgsConstructor +@ConfigurationProperties(prefix = "identity-provider-meta-data") +public class IdentityProviderMetaData { + + private String singleSignOnServiceURI; + private String name; + private String description; + private String logoURI; + +} diff --git a/myconext-server/src/main/java/myconext/security/SecurityConfiguration.java b/myconext-server/src/main/java/myconext/security/SecurityConfiguration.java index dd81da79..ee5ebffa 100644 --- a/myconext-server/src/main/java/myconext/security/SecurityConfiguration.java +++ b/myconext-server/src/main/java/myconext/security/SecurityConfiguration.java @@ -16,6 +16,7 @@ import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Configuration; import org.springframework.core.annotation.Order; import org.springframework.core.env.Environment; @@ -50,6 +51,7 @@ public class SecurityConfiguration { @Configuration @Order(1) + @EnableConfigurationProperties(IdentityProviderMetaData.class) public static class SamlSecurity extends WebSecurityConfigurerAdapter { private final GuestIdpAuthenticationRequestFilter guestIdpAuthenticationRequestFilter; @@ -80,7 +82,8 @@ public SamlSecurity(@Value("${private_key_path}") Resource privateKeyPath, UserLoginRepository userLoginRepository, GeoLocation geoLocation, MailBox mailBox, - ServiceProviderResolver serviceProviderResolver) { + ServiceProviderResolver serviceProviderResolver, + IdentityProviderMetaData identityProviderMetaData) { String[] keys = this.getKeys(certificatePath, privateKeyPath); final List serviceProviders = new ArrayList<>(); @@ -112,7 +115,8 @@ public SamlSecurity(@Value("${private_key_path}") Resource privateKeyPath, ssoMFADurationSeconds, mobileAppROEntityId, featureDefaultRememberMe, - configuration + configuration, + identityProviderMetaData ); } diff --git a/myconext-server/src/main/resources/application.yml b/myconext-server/src/main/resources/application.yml index cfa17e91..b813da4c 100644 --- a/myconext-server/src/main/resources/application.yml +++ b/myconext-server/src/main/resources/application.yml @@ -32,6 +32,12 @@ email: # mail-templates-directory: file://opt/build/main/resources/mail_templates mail-templates-directory: classpath:mail_templates +identity-provider-meta-data: + single_sign_on_service_uri: "https://login.test.eduid.nl/saml/guest-idp/SSO" + name: "eduID IdP" + description: "eduID IdP" + logo_uri: "https://static.surfconext.nl/media/idp/eduid.png" + schac_home_organization: eduid.nl cron: