Selaa lähdekoodia

Use Federation Support

Closes gh-132
Josh Cummings 2 vuotta sitten
vanhempi
commit
2f8a63dbe3

+ 2 - 2
servlet/spring-boot/java/saml2/saml-extension-federation/gradle.properties

@@ -1,2 +1,2 @@
-version=6.0.0-SNAPSHOT
-spring-security.version=6.0.0-SNAPSHOT
+version=6.1.0-SNAPSHOT
+spring-security.version=6.1.0-SNAPSHOT

+ 0 - 101
servlet/spring-boot/java/saml2/saml-extension-federation/src/main/java/example/EntityIdRelyingPartyRegistrationResolver.java

@@ -1,101 +0,0 @@
-/*
- * Copyright 2023 the original author or authors.
- *
- * Licensed 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
- *
- *      https://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 example;
-
-import java.io.ByteArrayInputStream;
-import java.nio.charset.StandardCharsets;
-import java.util.Base64;
-
-import jakarta.servlet.http.HttpServletRequest;
-import net.shibboleth.utilities.java.support.xml.ParserPool;
-import org.opensaml.core.config.ConfigurationService;
-import org.opensaml.core.xml.config.XMLObjectProviderRegistry;
-import org.opensaml.saml.saml2.core.Response;
-import org.opensaml.saml.saml2.core.impl.ResponseUnmarshaller;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-
-import org.springframework.security.saml2.core.OpenSamlInitializationService;
-import org.springframework.security.saml2.core.Saml2Error;
-import org.springframework.security.saml2.core.Saml2ErrorCodes;
-import org.springframework.security.saml2.core.Saml2ParameterNames;
-import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException;
-import org.springframework.security.saml2.provider.service.registration.InMemoryRelyingPartyRegistrationRepository;
-import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
-import org.springframework.security.saml2.provider.service.web.RelyingPartyRegistrationResolver;
-
-public class EntityIdRelyingPartyRegistrationResolver implements RelyingPartyRegistrationResolver {
-
-	static {
-		OpenSamlInitializationService.initialize();
-	}
-
-	private final ResponseUnmarshaller responseUnmarshaller;
-
-	private final ParserPool parserPool;
-
-	private final InMemoryRelyingPartyRegistrationRepository registrations;
-
-	public EntityIdRelyingPartyRegistrationResolver(InMemoryRelyingPartyRegistrationRepository registrations) {
-		XMLObjectProviderRegistry registry = ConfigurationService.get(XMLObjectProviderRegistry.class);
-		this.responseUnmarshaller = (ResponseUnmarshaller) registry.getUnmarshallerFactory()
-				.getUnmarshaller(Response.DEFAULT_ELEMENT_NAME);
-		this.parserPool = registry.getParserPool();
-		this.registrations = registrations;
-	}
-
-	@Override
-	public RelyingPartyRegistration resolve(HttpServletRequest request, String relyingPartyRegistrationId) {
-		if (relyingPartyRegistrationId != null) {
-			return this.registrations.findByRegistrationId(relyingPartyRegistrationId);
-		}
-		String entityId = resolveEntityId(request);
-		if (entityId == null) {
-			return null;
-		}
-		for (RelyingPartyRegistration registration : this.registrations) {
-			if (entityId.equals(registration.getAssertingPartyDetails().getEntityId())) {
-				return registration;
-			}
-		}
-		return null;
-	}
-
-	private String resolveEntityId(HttpServletRequest request) {
-		String saml2Response = request.getParameter(Saml2ParameterNames.SAML_RESPONSE);
-		if (saml2Response == null) {
-			return null;
-		}
-		byte[] decoded = Base64.getMimeDecoder().decode(saml2Response);
-		String serialized = new String(decoded, StandardCharsets.UTF_8);
-		return parseResponse(serialized).getIssuer().getValue();
-	}
-
-	private Response parseResponse(String serialized) {
-		try {
-			Document document = this.parserPool
-					.parse(new ByteArrayInputStream(serialized.getBytes(StandardCharsets.UTF_8)));
-			Element element = document.getDocumentElement();
-			return (Response) this.responseUnmarshaller.unmarshall(element);
-		}
-		catch (Exception ex) {
-			Saml2Error error = new Saml2Error(Saml2ErrorCodes.MALFORMED_RESPONSE_DATA, ex.getMessage());
-			throw new Saml2AuthenticationException(error, ex.getMessage());
-		}
-	}
-
-}

+ 0 - 71
servlet/spring-boot/java/saml2/saml-extension-federation/src/main/java/example/SamlExtensionUrlForwardingFilter.java

@@ -1,71 +0,0 @@
-/*
- * Copyright 2002-2022 the original author or authors.
- *
- * Licensed 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
- *
- *      https://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 example;
-
-import java.io.IOException;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import jakarta.servlet.FilterChain;
-import jakarta.servlet.RequestDispatcher;
-import jakarta.servlet.ServletException;
-import jakarta.servlet.http.HttpServletRequest;
-import jakarta.servlet.http.HttpServletResponse;
-
-import org.springframework.core.annotation.Order;
-import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
-import org.springframework.security.web.util.matcher.OrRequestMatcher;
-import org.springframework.security.web.util.matcher.RequestMatcher;
-import org.springframework.stereotype.Component;
-import org.springframework.web.filter.OncePerRequestFilter;
-
-@Component
-@Order(-102) // To run before FilterChainProxy
-public class SamlExtensionUrlForwardingFilter extends OncePerRequestFilter {
-
-	// @formatter:off
-	private static final Map<String, String> urlMapping = Map.of("/saml/SSO", "/login/saml2/sso/sp",
-			"/saml/logout", "/logout/saml2/slo",
-			"/saml/SingleLogout", "/logout/saml2/slo",
-			"/saml/metadata", "/saml2/service-provider-metadata/sp");
-	// @formatter:on
-
-	private final RequestMatcher matcher = createRequestMatcher();
-
-	private RequestMatcher createRequestMatcher() {
-		Set<String> urls = urlMapping.keySet();
-		List<RequestMatcher> matchers = new LinkedList<>();
-		urls.forEach((url) -> matchers.add(new AntPathRequestMatcher(url)));
-		return new OrRequestMatcher(matchers);
-	}
-
-	@Override
-	protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
-			throws ServletException, IOException {
-		boolean match = this.matcher.matches(request);
-		if (!match) {
-			filterChain.doFilter(request, response);
-			return;
-		}
-		String forwardUrl = urlMapping.get(request.getRequestURI());
-		RequestDispatcher dispatcher = request.getRequestDispatcher(forwardUrl);
-		dispatcher.forward(request, response);
-	}
-
-}

+ 4 - 24
servlet/spring-boot/java/saml2/saml-extension-federation/src/main/java/example/SecurityConfiguration.java

@@ -30,21 +30,13 @@ import java.util.stream.Collectors;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.boot.autoconfigure.security.saml2.Saml2RelyingPartyProperties;
 import org.springframework.boot.autoconfigure.security.saml2.Saml2RelyingPartyProperties.Registration;
-import org.springframework.boot.web.servlet.FilterRegistrationBean;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
-import org.springframework.core.annotation.Order;
-import org.springframework.security.config.Customizer;
 import org.springframework.security.config.annotation.web.builders.HttpSecurity;
 import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
 import org.springframework.security.saml2.core.Saml2X509Credential;
-import org.springframework.security.saml2.provider.service.metadata.OpenSamlMetadataResolver;
 import org.springframework.security.saml2.provider.service.registration.InMemoryRelyingPartyRegistrationRepository;
-import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
 import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrations;
-import org.springframework.security.saml2.provider.service.web.DefaultRelyingPartyRegistrationResolver;
-import org.springframework.security.saml2.provider.service.web.Saml2AuthenticationTokenConverter;
-import org.springframework.security.saml2.provider.service.web.Saml2MetadataFilter;
 import org.springframework.security.web.SecurityFilterChain;
 
 @Configuration
@@ -59,26 +51,14 @@ public class SecurityConfiguration {
 				.requestMatchers("/error").permitAll()
 				.anyRequest().authenticated()
 			)
-			.saml2Login(Customizer.withDefaults())
-			.saml2Logout(Customizer.withDefaults());
+			.saml2Login((saml2) -> saml2.loginProcessingUrl("/saml/SSO"))
+			.saml2Logout((saml2) -> saml2.logoutRequest((request) -> request.logoutUrl("/saml/logout")))
+			.saml2Logout((saml2) -> saml2.logoutResponse((response) -> response.logoutUrl("/saml/SingleLogout")))
+			.saml2Metadata((saml2) -> saml2.metadataUrl("/saml/metadata"));
 		// @formatter:on
 		return http.build();
 	}
 
-	@Bean
-	Saml2AuthenticationTokenConverter usingEntityId(InMemoryRelyingPartyRegistrationRepository repository) {
-		var registrations = new EntityIdRelyingPartyRegistrationResolver(repository);
-		return new Saml2AuthenticationTokenConverter(registrations);
-	}
-
-	@Bean
-	@Order(-101)
-	FilterRegistrationBean<Saml2MetadataFilter> metadata(Iterable<RelyingPartyRegistration> repository) {
-		var registrations = new DefaultRelyingPartyRegistrationResolver((id) -> repository.iterator().next());
-		var filter = new Saml2MetadataFilter(registrations, new OpenSamlMetadataResolver());
-		return new FilterRegistrationBean<>(filter);
-	}
-
 	@Bean
 	InMemoryRelyingPartyRegistrationRepository repository(Saml2RelyingPartyProperties properties,
 			@Value("classpath:credentials/rp-private.key") RSAPrivateKey key,

+ 5 - 5
servlet/spring-boot/java/saml2/saml-extension-federation/src/main/resources/application.yml

@@ -8,12 +8,12 @@ spring:
     saml2:
       relyingparty:
         registration:
-          sp:
-            entity-id: "http://localhost:8080/saml2/service-provider-metadata/one"
+          metadata:
+            entity-id: "{baseUrl}/saml2/service-provider-metadata/one"
             singlelogout:
               binding: POST
-              url: "http://localhost:8080/saml/logout"
-              responseUrl: "http://localhost:8080/saml/SingleLogout"
+              url: "{baseUrl}/saml/logout"
+              responseUrl: "{baseUrl}/saml/SingleLogout"
             acs:
-              location: "http://localhost:8080/saml/SSO"
+              location: "{baseUrl}/saml/SSO"
             assertingparty.metadata-uri: https://dev-05937739.okta.com/app/exk598vc9bHhwoTXM5d7/sso/saml/metadata