Skip to content

Commit fb391c5

Browse files
GitHanterjzheaux
authored andcommitted
Add setMetadataFilename method to Saml2MetadataFilter
Closes gh-9317
1 parent 857830f commit fb391c5

File tree

2 files changed

+69
-4
lines changed

2 files changed

+69
-4
lines changed

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

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2020 the original author or authors.
2+
* Copyright 2002-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -42,10 +42,14 @@
4242
*/
4343
public final class Saml2MetadataFilter extends OncePerRequestFilter {
4444

45+
public static final String DEFAULT_METADATA_FILE_NAME = "saml-{registrationId}-metadata.xml";
46+
4547
private final Converter<HttpServletRequest, RelyingPartyRegistration> relyingPartyRegistrationConverter;
4648

4749
private final Saml2MetadataResolver saml2MetadataResolver;
4850

51+
private String metadataFilename = DEFAULT_METADATA_FILE_NAME;
52+
4953
private RequestMatcher requestMatcher = new AntPathRequestMatcher(
5054
"/saml2/service-provider-metadata/{registrationId}");
5155

@@ -78,8 +82,9 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse
7882
private void writeMetadataToResponse(HttpServletResponse response, String registrationId, String metadata)
7983
throws IOException {
8084
response.setContentType(MediaType.APPLICATION_XML_VALUE);
81-
response.setHeader(HttpHeaders.CONTENT_DISPOSITION,
82-
"attachment; filename=\"saml-" + registrationId + "-metadata.xml\"");
85+
String fileName = this.metadataFilename.replace("{registrationId}", registrationId);
86+
String format = "attachment; filename=\"%s\"";
87+
response.setHeader(HttpHeaders.CONTENT_DISPOSITION, String.format(format, fileName));
8388
response.setContentLength(metadata.length());
8489
response.getWriter().write(metadata);
8590
}
@@ -94,4 +99,20 @@ public void setRequestMatcher(RequestMatcher requestMatcher) {
9499
this.requestMatcher = requestMatcher;
95100
}
96101

102+
/**
103+
* Sets the metadata filename template containing the {@code {registrationId}}
104+
* template variable.
105+
*
106+
* <br />
107+
* The default value is {@code saml-{registrationId}-metadata.xml}
108+
* @param metadataFilename metadata filename, must contain a {registrationId}
109+
* @since 5.5
110+
*/
111+
public void setMetadataFilename(String metadataFilename) {
112+
Assert.hasText(metadataFilename, "metadataFilename cannot be empty");
113+
Assert.isTrue(metadataFilename.contains("{registrationId}"),
114+
"metadataFilename must contain a {registrationId} match variable");
115+
this.metadataFilename = metadataFilename;
116+
}
117+
97118
}

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

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2020 the original author or authors.
2+
* Copyright 2002-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,11 +16,15 @@
1616

1717
package org.springframework.security.saml2.provider.service.web;
1818

19+
import java.net.URLEncoder;
20+
import java.nio.charset.StandardCharsets;
21+
1922
import javax.servlet.FilterChain;
2023

2124
import org.junit.Before;
2225
import org.junit.Test;
2326

27+
import org.springframework.http.HttpHeaders;
2428
import org.springframework.mock.web.MockHttpServletRequest;
2529
import org.springframework.mock.web.MockHttpServletResponse;
2630
import org.springframework.security.saml2.core.TestSaml2X509Credentials;
@@ -31,6 +35,7 @@
3135
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
3236

3337
import static org.assertj.core.api.Assertions.assertThat;
38+
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
3439
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
3540
import static org.mockito.BDDMockito.given;
3641
import static org.mockito.Mockito.mock;
@@ -120,4 +125,43 @@ public void setRequestMatcherWhenNullThenIllegalArgument() {
120125
assertThatIllegalArgumentException().isThrownBy(() -> this.filter.setRequestMatcher(null));
121126
}
122127

128+
@Test
129+
public void setMetadataFilenameWhenEmptyThenThrowsException() {
130+
assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> this.filter.setMetadataFilename(" "))
131+
.withMessage("metadataFilename cannot be empty");
132+
}
133+
134+
@Test
135+
public void setMetadataFilenameWhenMissingRegistrationIdVariableThenThrowsException() {
136+
assertThatExceptionOfType(IllegalArgumentException.class)
137+
.isThrownBy(() -> this.filter.setMetadataFilename("metadata-filename.xml"))
138+
.withMessage("metadataFilename must contain a {registrationId} match variable");
139+
}
140+
141+
@Test
142+
public void doFilterWhenSetMetadataFilenameThenUses() throws Exception {
143+
String testMetadataFilename = "test-{registrationId}-metadata.xml";
144+
this.request.setPathInfo("/saml2/service-provider-metadata/validRegistration");
145+
RelyingPartyRegistration validRegistration = TestRelyingPartyRegistrations.noCredentials()
146+
.assertingPartyDetails((party) -> party.verificationX509Credentials(
147+
(c) -> c.add(TestSaml2X509Credentials.relyingPartyVerifyingCredential())))
148+
.build();
149+
String generatedMetadata = "<xml>test</xml>";
150+
given(this.resolver.resolve(validRegistration)).willReturn(generatedMetadata);
151+
152+
this.filter = new Saml2MetadataFilter((request) -> validRegistration, this.resolver);
153+
this.filter.setMetadataFilename(testMetadataFilename);
154+
this.filter.doFilter(this.request, this.response, this.chain);
155+
156+
verifyNoInteractions(this.chain);
157+
assertThat(this.response.getStatus()).isEqualTo(200);
158+
assertThat(this.response.getContentAsString()).isEqualTo(generatedMetadata);
159+
160+
String fileName = testMetadataFilename.replace("{registrationId}", validRegistration.getRegistrationId());
161+
String encodedFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.name());
162+
assertThat(this.response.getHeaderValue(HttpHeaders.CONTENT_DISPOSITION)).asString()
163+
.isEqualTo("attachment; filename=\"%s\"; filename*=UTF-8''%s", fileName, encodedFileName);
164+
verify(this.resolver).resolve(validRegistration);
165+
}
166+
123167
}

0 commit comments

Comments
 (0)