Переглянути джерело

Add setMetadataFilename method to Saml2MetadataFilter

Closes gh-9317
Han YanJing 4 роки тому
батько
коміт
fb391c5dcd

+ 24 - 3
saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/Saml2MetadataFilter.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2020 the original author or authors.
+ * Copyright 2002-2021 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.
@@ -42,10 +42,14 @@ import org.springframework.web.filter.OncePerRequestFilter;
  */
 public final class Saml2MetadataFilter extends OncePerRequestFilter {
 
+	public static final String DEFAULT_METADATA_FILE_NAME = "saml-{registrationId}-metadata.xml";
+
 	private final Converter<HttpServletRequest, RelyingPartyRegistration> relyingPartyRegistrationConverter;
 
 	private final Saml2MetadataResolver saml2MetadataResolver;
 
+	private String metadataFilename = DEFAULT_METADATA_FILE_NAME;
+
 	private RequestMatcher requestMatcher = new AntPathRequestMatcher(
 			"/saml2/service-provider-metadata/{registrationId}");
 
@@ -78,8 +82,9 @@ public final class Saml2MetadataFilter extends OncePerRequestFilter {
 	private void writeMetadataToResponse(HttpServletResponse response, String registrationId, String metadata)
 			throws IOException {
 		response.setContentType(MediaType.APPLICATION_XML_VALUE);
-		response.setHeader(HttpHeaders.CONTENT_DISPOSITION,
-				"attachment; filename=\"saml-" + registrationId + "-metadata.xml\"");
+		String fileName = this.metadataFilename.replace("{registrationId}", registrationId);
+		String format = "attachment; filename=\"%s\"";
+		response.setHeader(HttpHeaders.CONTENT_DISPOSITION, String.format(format, fileName));
 		response.setContentLength(metadata.length());
 		response.getWriter().write(metadata);
 	}
@@ -94,4 +99,20 @@ public final class Saml2MetadataFilter extends OncePerRequestFilter {
 		this.requestMatcher = requestMatcher;
 	}
 
+	/**
+	 * Sets the metadata filename template containing the {@code {registrationId}}
+	 * template variable.
+	 *
+	 * <br />
+	 * The default value is {@code saml-{registrationId}-metadata.xml}
+	 * @param metadataFilename metadata filename, must contain a {registrationId}
+	 * @since 5.5
+	 */
+	public void setMetadataFilename(String metadataFilename) {
+		Assert.hasText(metadataFilename, "metadataFilename cannot be empty");
+		Assert.isTrue(metadataFilename.contains("{registrationId}"),
+				"metadataFilename must contain a {registrationId} match variable");
+		this.metadataFilename = metadataFilename;
+	}
+
 }

+ 45 - 1
saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/web/Saml2MetadataFilterTests.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2020 the original author or authors.
+ * Copyright 2002-2021 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.
@@ -16,11 +16,15 @@
 
 package org.springframework.security.saml2.provider.service.web;
 
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+
 import javax.servlet.FilterChain;
 
 import org.junit.Before;
 import org.junit.Test;
 
+import org.springframework.http.HttpHeaders;
 import org.springframework.mock.web.MockHttpServletRequest;
 import org.springframework.mock.web.MockHttpServletResponse;
 import org.springframework.security.saml2.core.TestSaml2X509Credentials;
@@ -31,6 +35,7 @@ import org.springframework.security.saml2.provider.service.registration.TestRely
 import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
 import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
 import static org.mockito.BDDMockito.given;
 import static org.mockito.Mockito.mock;
@@ -120,4 +125,43 @@ public class Saml2MetadataFilterTests {
 		assertThatIllegalArgumentException().isThrownBy(() -> this.filter.setRequestMatcher(null));
 	}
 
+	@Test
+	public void setMetadataFilenameWhenEmptyThenThrowsException() {
+		assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> this.filter.setMetadataFilename(" "))
+				.withMessage("metadataFilename cannot be empty");
+	}
+
+	@Test
+	public void setMetadataFilenameWhenMissingRegistrationIdVariableThenThrowsException() {
+		assertThatExceptionOfType(IllegalArgumentException.class)
+				.isThrownBy(() -> this.filter.setMetadataFilename("metadata-filename.xml"))
+				.withMessage("metadataFilename must contain a {registrationId} match variable");
+	}
+
+	@Test
+	public void doFilterWhenSetMetadataFilenameThenUses() throws Exception {
+		String testMetadataFilename = "test-{registrationId}-metadata.xml";
+		this.request.setPathInfo("/saml2/service-provider-metadata/validRegistration");
+		RelyingPartyRegistration validRegistration = TestRelyingPartyRegistrations.noCredentials()
+				.assertingPartyDetails((party) -> party.verificationX509Credentials(
+						(c) -> c.add(TestSaml2X509Credentials.relyingPartyVerifyingCredential())))
+				.build();
+		String generatedMetadata = "<xml>test</xml>";
+		given(this.resolver.resolve(validRegistration)).willReturn(generatedMetadata);
+
+		this.filter = new Saml2MetadataFilter((request) -> validRegistration, this.resolver);
+		this.filter.setMetadataFilename(testMetadataFilename);
+		this.filter.doFilter(this.request, this.response, this.chain);
+
+		verifyNoInteractions(this.chain);
+		assertThat(this.response.getStatus()).isEqualTo(200);
+		assertThat(this.response.getContentAsString()).isEqualTo(generatedMetadata);
+
+		String fileName = testMetadataFilename.replace("{registrationId}", validRegistration.getRegistrationId());
+		String encodedFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.name());
+		assertThat(this.response.getHeaderValue(HttpHeaders.CONTENT_DISPOSITION)).asString()
+				.isEqualTo("attachment; filename=\"%s\"; filename*=UTF-8''%s", fileName, encodedFileName);
+		verify(this.resolver).resolve(validRegistration);
+	}
+
 }