Selaa lähdekoodia

Set charset of BasicAuthenticationFilter converter

Allow BasicAuthenticationFilter to pick up the given credentials charset.

Fixes: gh-7835
Peter Keller 5 vuotta sitten
vanhempi
commit
e62fb755e8

+ 2 - 0
web/src/main/java/org/springframework/security/web/authentication/www/BasicAuthenticationFilter.java

@@ -17,6 +17,7 @@
 package org.springframework.security.web.authentication.www;
 
 import java.io.IOException;
+import java.nio.charset.Charset;
 
 import javax.servlet.FilterChain;
 import javax.servlet.ServletException;
@@ -276,6 +277,7 @@ public class BasicAuthenticationFilter extends OncePerRequestFilter {
 	public void setCredentialsCharset(String credentialsCharset) {
 		Assert.hasText(credentialsCharset, "credentialsCharset cannot be null or empty");
 		this.credentialsCharset = credentialsCharset;
+		this.authenticationConverter.setCredentialsCharset(Charset.forName(credentialsCharset));
 	}
 
 	protected String getCredentialsCharset(HttpServletRequest httpRequest) {

+ 105 - 1
web/src/test/java/org/springframework/security/web/authentication/www/BasicAuthenticationFilterTests.java

@@ -16,13 +16,14 @@
 
 package org.springframework.security.web.authentication.www;
 
-import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.*;
 import static org.mockito.AdditionalMatchers.not;
 import static org.mockito.Mockito.*;
 
 import javax.servlet.FilterChain;
 import javax.servlet.ServletRequest;
 import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletResponse;
 
 import org.apache.commons.codec.binary.Base64;
 import org.junit.After;
@@ -40,6 +41,8 @@ import org.springframework.security.core.context.SecurityContextHolder;
 import org.springframework.security.web.authentication.WebAuthenticationDetails;
 import org.springframework.web.util.WebUtils;
 
+import java.nio.charset.StandardCharsets;
+
 /**
  * Tests {@link BasicAuthenticationFilter}.
  *
@@ -320,4 +323,105 @@ public class BasicAuthenticationFilterTests {
 
 		assertThat(response.getStatus()).isEqualTo(200);
 	}
+
+	@Test
+	public void doFilterWhenTokenAndFilterCharsetMatchDefaultThenAuthenticated() throws Exception {
+		SecurityContextHolder.clearContext();
+
+		UsernamePasswordAuthenticationToken rodRequest = new UsernamePasswordAuthenticationToken("rod", "äöü");
+		rodRequest.setDetails(new WebAuthenticationDetails(new MockHttpServletRequest()));
+		Authentication rod = new UsernamePasswordAuthenticationToken("rod", "äöü", AuthorityUtils.createAuthorityList("ROLE_1"));
+
+		manager = mock(AuthenticationManager.class);
+		when(manager.authenticate(rodRequest)).thenReturn(rod);
+		when(manager.authenticate(not(eq(rodRequest)))).thenThrow(new BadCredentialsException(""));
+
+		filter = new BasicAuthenticationFilter(manager, new BasicAuthenticationEntryPoint());
+
+		String token = "rod:äöü";
+		MockHttpServletRequest request = new MockHttpServletRequest();
+		request.addHeader("Authorization", "Basic " + new String(Base64.encodeBase64(token.getBytes(StandardCharsets.UTF_8))));
+		request.setServletPath("/some_file.html");
+
+		MockHttpServletResponse response = new MockHttpServletResponse();
+
+		// Test
+		assertThat(SecurityContextHolder.getContext().getAuthentication()).isNull();
+		FilterChain chain = mock(FilterChain.class);
+
+		filter.doFilter(request, response, chain);
+
+		assertThat(response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
+		verify(chain).doFilter(any(ServletRequest.class), any(ServletResponse.class));
+		assertThat(SecurityContextHolder.getContext().getAuthentication().getName()).isEqualTo("rod");
+		assertThat(SecurityContextHolder.getContext().getAuthentication().getCredentials()).isEqualTo("äöü");
+	}
+
+	@Test
+	public void doFilterWhenTokenAndFilterCharsetMatchNonDefaultThenAuthenticated() throws Exception {
+		SecurityContextHolder.clearContext();
+
+		UsernamePasswordAuthenticationToken rodRequest = new UsernamePasswordAuthenticationToken("rod", "äöü");
+		rodRequest.setDetails(new WebAuthenticationDetails(new MockHttpServletRequest()));
+		Authentication rod = new UsernamePasswordAuthenticationToken("rod", "äöü", AuthorityUtils.createAuthorityList("ROLE_1"));
+
+		manager = mock(AuthenticationManager.class);
+		when(manager.authenticate(rodRequest)).thenReturn(rod);
+		when(manager.authenticate(not(eq(rodRequest)))).thenThrow(new BadCredentialsException(""));
+
+		filter = new BasicAuthenticationFilter(manager, new BasicAuthenticationEntryPoint());
+		filter.setCredentialsCharset("ISO-8859-1");
+
+		String token = "rod:äöü";
+		MockHttpServletRequest request = new MockHttpServletRequest();
+		request.addHeader("Authorization", "Basic " + new String(Base64.encodeBase64(token.getBytes(StandardCharsets.ISO_8859_1))));
+		request.setServletPath("/some_file.html");
+
+		MockHttpServletResponse response = new MockHttpServletResponse();
+
+		// Test
+		assertThat(SecurityContextHolder.getContext().getAuthentication()).isNull();
+		FilterChain chain = mock(FilterChain.class);
+
+		filter.doFilter(request, response, chain);
+
+		assertThat(response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
+		verify(chain).doFilter(any(ServletRequest.class), any(ServletResponse.class));
+		assertThat(SecurityContextHolder.getContext().getAuthentication().getName()).isEqualTo("rod");
+		assertThat(SecurityContextHolder.getContext().getAuthentication().getCredentials()).isEqualTo("äöü");
+	}
+
+	@Test
+	public void doFilterWhenTokenAndFilterCharsetDoNotMatchThenUnauthorized() throws Exception {
+		SecurityContextHolder.clearContext();
+
+		UsernamePasswordAuthenticationToken rodRequest = new UsernamePasswordAuthenticationToken("rod", "äöü");
+		rodRequest.setDetails(new WebAuthenticationDetails(new MockHttpServletRequest()));
+		Authentication rod = new UsernamePasswordAuthenticationToken("rod", "äöü", AuthorityUtils.createAuthorityList("ROLE_1"));
+
+		manager = mock(AuthenticationManager.class);
+		when(manager.authenticate(rodRequest)).thenReturn(rod);
+		when(manager.authenticate(not(eq(rodRequest)))).thenThrow(new BadCredentialsException(""));
+
+		filter = new BasicAuthenticationFilter(manager, new BasicAuthenticationEntryPoint());
+		filter.setCredentialsCharset("ISO-8859-1");
+
+		String token = "rod:äöü";
+		MockHttpServletRequest request = new MockHttpServletRequest();
+		request.addHeader("Authorization", "Basic " + new String(Base64.encodeBase64(token.getBytes(StandardCharsets.UTF_8))));
+		request.setServletPath("/some_file.html");
+
+		MockHttpServletResponse response = new MockHttpServletResponse();
+
+		// Test
+		assertThat(SecurityContextHolder.getContext().getAuthentication()).isNull();
+		FilterChain chain = mock(FilterChain.class);
+
+		filter.doFilter(request, response, chain);
+
+		assertThat(response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
+		verify(chain, never()).doFilter(any(ServletRequest.class), any(ServletResponse.class));
+		assertThat(SecurityContextHolder.getContext().getAuthentication()).isNull();
+	}
+
 }