У меня есть веб-приложение, которое аутентифицировано на сервере ldap. Теперь у меня есть требование добавить аутентификацию с сертификатом x509, который предоставляется картой cac.
До сих пор я достиг: При открытии приложения меня просят ввести пин-код для сертификата на карте 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;
}
}
Мой разъем для кота выглядит так:
<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-адресу, а не при открытии приложения.