package gov.samhsa.consent2share.web.config.di.root;
import gov.samhsa.consent2share.domain.account.UsersRepository;
import gov.samhsa.consent2share.service.account.AccountUserDetailsService;
import gov.samhsa.consent2share.web.AjaxTimeoutRedirectFilter;
import gov.samhsa.consent2share.web.CustomAccessDeniedHandler;
import java.util.HashMap;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.authentication.configuration.EnableGlobalAuthentication;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity;
import org.springframework.security.crypto.password.StandardPasswordEncoder;
import org.springframework.security.provisioning.JdbcUserDetailsManager;
import org.springframework.security.provisioning.UserDetailsManager;
import org.springframework.security.web.access.ExceptionTranslationFilter;
import org.springframework.security.web.authentication.ExceptionMappingAuthenticationFailureHandler;
@Configuration
@EnableWebSecurity
@EnableWebMvcSecurity
@EnableGlobalAuthentication
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Value("${maximum_failed_attempts}")
private String maximumFailedAttemptsValue;
@Value("${auto_unlock_interval}")
private String autoUnlockIntervalValue;
@Autowired
UsersRepository usersRepository;
@Autowired
DataAccessConfig dataAccessConfig;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf()
.and()
.headers()
.cacheControl()
.frameOptions()
.xssProtection()
.httpStrictTransportSecurity()
.and()
.authorizeRequests()
.antMatchers("/sysadmin/lookupService/**").permitAll()
.antMatchers("/Administrator/**").hasRole("ADMIN")
.antMatchers("/sysadmin/**").hasRole("SYSADMIN")
.antMatchers("/instrumentation/**").hasRole("SYSADMIN")
.antMatchers("/patients/**", "/clinicaldocuments/**","/consents/**").hasRole("USER")
.antMatchers("/**", "/sysadmin/lookupService/**","/index.html", "/registration.html").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/")
.usernameParameter("j_username")
.passwordParameter("j_password")
.loginProcessingUrl("/resources/j_spring_security_check")
.permitAll()
.defaultSuccessUrl("/defaultLoginPage.html")
.failureHandler(loginMappingFailureHandler())
.and()
.logout()
.logoutUrl("/resources/j_spring_security_logout")
.logoutSuccessUrl("/")
.invalidateHttpSession(true)
.deleteCookies("JSESSIONID")
.and()
.exceptionHandling().accessDeniedPage("/views/dataAccessFailure.html")
.and()
.sessionManagement()
.sessionFixation()
.migrateSession()
.maximumSessions(1)
.expiredUrl("/index.html?expired=true")
.maxSessionsPreventsLogin(false);
http.addFilterAfter(ajaxTimeoutRedirectFilter(),
ExceptionTranslationFilter.class);
}
// Configure Authentication mechanism
@Autowired
public void configureGlobal(AuthenticationManagerBuilder authenticationManagerBuilder)
throws Exception {
authenticationManagerBuilder.userDetailsService(accountUserDetailsService())
.passwordEncoder(passwordEncoder());
}
@Bean
public AccountUserDetailsService accountUserDetailsService() {
short maxFailedAttempts = Short.parseShort(maximumFailedAttemptsValue);
long autoUnlockInterval = Long.parseLong(autoUnlockIntervalValue);
AccountUserDetailsService accountUserDetailsService = new AccountUserDetailsService(
maxFailedAttempts, autoUnlockInterval, usersRepository);
return accountUserDetailsService;
}
// Create a custom filter, Custom HTTP error code as 440.
// This filter is configured in configure(HttpSecurity http) method
@Bean
public AjaxTimeoutRedirectFilter ajaxTimeoutRedirectFilter() {
AjaxTimeoutRedirectFilter ajaxTimeoutRedirectFilter = new AjaxTimeoutRedirectFilter();
ajaxTimeoutRedirectFilter.setCustomSessionExpiredErrorCode(440);
return ajaxTimeoutRedirectFilter;
}
@Bean
public UserDetailsManager jdbcUserDetailsManager(DataSource dataSource) {
JdbcUserDetailsManager u = new JdbcUserDetailsManager();
u.setDataSource(dataAccessConfig.dataSource());
return u;
}
@Bean
public ExceptionMappingAuthenticationFailureHandler loginMappingFailureHandler() {
ExceptionMappingAuthenticationFailureHandler exceptionMapping = new ExceptionMappingAuthenticationFailureHandler();
HashMap<String, String> failureUrlMap = new HashMap<String, String>();
failureUrlMap
.put("org.springframework.security.authentication.BadCredentialsException",
"/index.html?login_error=bad_credentials");
failureUrlMap.put(
"org.springframework.security.authentication.LockedException",
"/index.html?login_error=account_locked");
failureUrlMap
.put("org.springframework.security.authentication.DisabledException",
"/index.html?login_error=account_disabled");
failureUrlMap
.put("org.springframework.security.authentication.AccountExpiredException",
"/index.html?login_error=auth_service_error");
failureUrlMap
.put("org.springframework.security.authentication.CredentialsExpiredException",
"/index.html?login_error=auth_service_error");
failureUrlMap
.put("org.springframework.security.authentication.AuthenticationServiceException",
"/index.html?login_error=auth_service_error");
exceptionMapping.setExceptionMappings(failureUrlMap);
return exceptionMapping;
}
// Uses SHA-256 with multiple iterations and a random salt value.
@Bean
public StandardPasswordEncoder passwordEncoder() {
return new StandardPasswordEncoder();
}
}