Allow configuration of x509 through nested builder
Issue: gh-5557
This commit is contained in:
parent
bfc9538da1
commit
ae9eb6f56b
|
@ -861,6 +861,42 @@ public final class HttpSecurity extends
|
||||||
return getOrApply(new X509Configurer<>());
|
return getOrApply(new X509Configurer<>());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configures X509 based pre authentication.
|
||||||
|
*
|
||||||
|
* <h2>Example Configuration</h2>
|
||||||
|
*
|
||||||
|
* The following configuration will attempt to extract the username from the X509
|
||||||
|
* certificate. Remember that the Servlet Container will need to be configured to
|
||||||
|
* request client certificates in order for this to work.
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* @Configuration
|
||||||
|
* @EnableWebSecurity
|
||||||
|
* public class X509SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||||
|
*
|
||||||
|
* @Override
|
||||||
|
* protected void configure(HttpSecurity http) throws Exception {
|
||||||
|
* http
|
||||||
|
* .authorizeRequests()
|
||||||
|
* .antMatchers("/**")
|
||||||
|
* .hasRole("USER")
|
||||||
|
* .and()
|
||||||
|
* .x509(withDefaults());
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @param x509Customizer the {@link Customizer} to provide more options for
|
||||||
|
* the {@link X509Configurer}
|
||||||
|
* @return the {@link HttpSecurity} for further customizations
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public HttpSecurity x509(Customizer<X509Configurer<HttpSecurity>> x509Customizer) throws Exception {
|
||||||
|
x509Customizer.customize(getOrApply(new X509Configurer<>()));
|
||||||
|
return HttpSecurity.this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allows configuring of Remember Me authentication.
|
* Allows configuring of Remember Me authentication.
|
||||||
*
|
*
|
||||||
|
|
|
@ -38,6 +38,7 @@ import java.security.cert.X509Certificate;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.Mockito.spy;
|
import static org.mockito.Mockito.spy;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.springframework.security.config.Customizer.withDefaults;
|
||||||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.x509;
|
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.x509;
|
||||||
import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated;
|
import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated;
|
||||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||||
|
@ -122,6 +123,69 @@ public class X509ConfigurerTests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void x509WhenConfiguredInLambdaThenUsesDefaults() throws Exception {
|
||||||
|
this.spring.register(DefaultsInLambdaConfig.class).autowire();
|
||||||
|
X509Certificate certificate = loadCert("rod.cer");
|
||||||
|
|
||||||
|
this.mvc.perform(get("/")
|
||||||
|
.with(x509(certificate)))
|
||||||
|
.andExpect(authenticated().withUsername("rod"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@EnableWebSecurity
|
||||||
|
static class DefaultsInLambdaConfig extends WebSecurityConfigurerAdapter {
|
||||||
|
@Override
|
||||||
|
protected void configure(HttpSecurity http) throws Exception {
|
||||||
|
// @formatter:off
|
||||||
|
http
|
||||||
|
.x509(withDefaults());
|
||||||
|
// @formatter:on
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||||
|
// @formatter:off
|
||||||
|
auth
|
||||||
|
.inMemoryAuthentication()
|
||||||
|
.withUser("rod").password("password").roles("USER", "ADMIN");
|
||||||
|
// @formatter:on
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void x509WhenSubjectPrincipalRegexInLambdaThenUsesRegexToExtractPrincipal() throws Exception {
|
||||||
|
this.spring.register(SubjectPrincipalRegexInLambdaConfig.class).autowire();
|
||||||
|
X509Certificate certificate = loadCert("rodatexampledotcom.cer");
|
||||||
|
|
||||||
|
this.mvc.perform(get("/")
|
||||||
|
.with(x509(certificate)))
|
||||||
|
.andExpect(authenticated().withUsername("rod"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@EnableWebSecurity
|
||||||
|
static class SubjectPrincipalRegexInLambdaConfig extends WebSecurityConfigurerAdapter {
|
||||||
|
@Override
|
||||||
|
protected void configure(HttpSecurity http) throws Exception {
|
||||||
|
// @formatter:off
|
||||||
|
http
|
||||||
|
.x509(x509 ->
|
||||||
|
x509
|
||||||
|
.subjectPrincipalRegex("CN=(.*?)@example.com(?:,|$)")
|
||||||
|
);
|
||||||
|
// @formatter:on
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||||
|
// @formatter:off
|
||||||
|
auth
|
||||||
|
.inMemoryAuthentication()
|
||||||
|
.withUser("rod").password("password").roles("USER", "ADMIN");
|
||||||
|
// @formatter:on
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private <T extends Certificate> T loadCert(String location) {
|
private <T extends Certificate> T loadCert(String location) {
|
||||||
try (InputStream is = new ClassPathResource(location).getInputStream()) {
|
try (InputStream is = new ClassPathResource(location).getInputStream()) {
|
||||||
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
|
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
|
||||||
|
|
Loading…
Reference in New Issue