我有一个针对ldap服务器进行身份验证的Web应用程序。现在,我需要添加带有CAC卡提供的x509证书的身份验证。
到目前为止,我已经实现了:打开应用程序时,要求输入cac卡上证书的密码,然后通过ldap查找角色。之后,我以正确的用户身份登录。
如果在我要求通过证书进行身份验证时单击“取消”,我将获得ldap的正常登录表单,并且可以登录,也可以正常工作。
现在我的问题是,我不想立即被要求提供证书。相反,我想显示登录表单,然后为用户提供选择,可以通过cac卡还是通过常规ldap登录。
所以我只想在某个URL上触发对证书身份验证的询问...
我当前的安全配置如下。
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Value("${ldap.url}")
private String ldapUrl;
@Value("${ldap.technical.username}")
private String ldapTechnicalUsername;
@Value("${ldap.technical.password}")
private String ldapTechnicalPassword;
@Autowired
private LdapUserDetailsMapper ldapUserDetailsMapper;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.addFilterBefore(new LogMDCFilter(), AbstractPreAuthenticatedProcessingFilter.class);
http.addFilterBefore(new AjaxExpiredFilter(), AbstractPreAuthenticatedProcessingFilter.class);
http
.requiresChannel()
.antMatchers("/pages/login/certLogin.xhtml")
.requiresSecure()
.and()
.x509()
.authenticationUserDetailsService(ldapUserDetailsService());
http
.authorizeRequests()
.antMatchers(
"/error/**",
"/failure/**",
"/login/openid/**",
"/javax.faces.resource/**",
"/services/**",
"/actuator/**")
.permitAll()
.antMatchers("/index.xhtml", "/error.xhtml").hasAuthority("IS_AUTHENTICATED_ANONYMOUSLY")
.antMatchers("/pages/customer/customerSearch.xhtml").hasAuthority("search_customer")
.anyRequest()
.authenticated()
.and()
.formLogin()
.loginPage("/pages/login/login.xhtml")
.permitAll()
.and()
.exceptionHandling()
.accessDeniedPage("/pages/login/accessDenied.xhtml")
.and()
.logout()
.clearAuthentication(true)
.logoutUrl("/logout")
.logoutSuccessUrl("/pages/login/login.xhtml")
.invalidateHttpSession(true)
.deleteCookies("JSESSIONID")
.permitAll()
.and()
.headers()
.frameOptions()
.sameOrigin()
.and()
.csrf()
.disable();
}
/**
* Used when authenicated via LDAP
*/
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.ldapAuthentication()
.contextSource()
.url(ldapUrl)
.managerDn(ldapTechnicalUsername)
.managerPassword(ldapTechnicalPassword)
.and()
.userDnPatterns("uid={0},ou=People")
.userSearchFilter("ismemberof")
.userDetailsContextMapper(ldapUserDetailsMapper)
.authoritiesMapper(new NullAuthoritiesMapper());
}
private LdapUserDetailsService ldapUserDetailsService() {
return new LdapUserDetailsService(createLdapContextSource(), ldapUserDetailsMapper);
}
private LdapContextSource createLdapContextSource() {
LdapContextSource contextSource = new LdapContextSource();
contextSource.setUrl(ldapUrl);
contextSource.setUserDn(ldapTechnicalUsername);
contextSource.setPassword(ldapTechnicalPassword);
contextSource.afterPropertiesSet();
return contextSource;
}
}
我的tomcat连接器看起来像这样:
<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true" scheme="https" secure="true"
clientAuth="want" sslProtocol="TLS"
keystoreFile="${catalina.home}/conf/keystore"
keystoreType="JKS" keystorePass="password"
truststoreFile="${catalina.home}/conf/truststore"
truststoreType="JKS" truststorePass="truststore"/>
这很重要,它可以正常工作,但是我希望仅在特定的URL上触发证书身份验证,而不是在打开应用程序时触发。