SecurityConfig.java
package org.flasby.security;
import java.io.IOException;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.flasby.entity.ChristmasUser;
import org.flasby.entity.Users;
import org.flasby.entity.Authority;
import org.flasby.entity.repository.UserRepository;
import org.flasby.christmas.Config;
import org.flasby.security.IpAddressAuthProvider.BannedIpAddressException;
import org.flasby.security.servlet.ServletAuthenticationDetailsSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.ExceptionMappingAuthenticationFailureHandler;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import lombok.extern.log4j.Log4j2;
@Log4j2
@Configuration
@EnableGlobalMethodSecurity(
prePostEnabled = true,
jsr250Enabled = true,
securedEnabled = true)
@EnableWebSecurity
@ComponentScan("org.flasby.entity")
public class SecurityConfig<TheUser extends Users<Authority>> extends WebSecurityConfigurerAdapter {
@Autowired
Environment env;
@Autowired
UserRepository<ChristmasUser> users;
@Autowired
Config config;
protected UserDetailsService userDetailsService = new UserDetailsService() {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
final ChristmasUser user = users.findByName(username);
log.warn("=========================>> Looking for UserDetails of " + username);
UserDetails ud = new UserDetails() {
private static final long serialVersionUID = 1L;
@Override
public Collection<SimpleGrantedAuthority> getAuthorities() {
List<SimpleGrantedAuthority> auths = new ArrayList<>();
user.getRoles().forEach((a) -> auths.add(new SimpleGrantedAuthority(a.getAuthority())));
return auths;
}
@Override
public String getPassword() {
return user.getPassword();
}
@Override
public String getUsername() {
return user.getName();
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return ! user.isDisabled();
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return ! user.isDisabled();
}
@Override
public String toString() {
return getUsername();
}
};
return ud;
}
};
@Bean
LogoutSuccessHandler logoutSuccessHandler() {
return new LogoutSuccessHandler() {
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
response.setStatus(HttpStatus.OK.value());
response.sendRedirect(request.getContextPath() + "/loggedout.html");
}
};
}
@Bean
AuthenticationSuccessHandler loginSuccessHandler() {
return new AuthenticationSuccessHandler() {
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
response.setStatus(HttpStatus.OK.value());
response.sendRedirect(request.getContextPath() + "/");
}
};
}
// Called during init only
@Bean
AuthenticationFailureHandler loginFailureHandler() {
ExceptionMappingAuthenticationFailureHandler handler = new ExceptionMappingAuthenticationFailureHandler();
Map<String, String> mapping = new HashMap<>();
mapping.put(DisabledException.class.getName(), "/userdisabled.html");
mapping.put(UsernameNotFoundException.class.getName(), "/login.html?error"); // error flag for use by the Login page
mapping.put(BannedIpAddressException.class.getName(), "/login.html?banned");
handler.setExceptionMappings(mapping);
return handler;
}
@Autowired
IpAddressAuthProvider ipAddressAuthProvider;
@Autowired
MyAuthProvider myAuthProvider;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(ipAddressAuthProvider);
auth.authenticationProvider(myAuthProvider);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
// List things which don't need to be authenticated
.antMatchers("/public/**", "/index", "/authenticate", "/webjars/**", "/webjars/**/**", "/xxx",
"/xxx/**",
"/logout", "/loggedout.html", "/login.html", "/login.css", "/css/login.css", "/userdisabled.html", "login.html",
"/forgotPassword.html").permitAll()
// Things which need an admin role
.antMatchers("/admin.html").hasAuthority(Authority.ADMIN.getAuthority())
// and these things do require authentication before use
.antMatchers("/topic/**", "/queue/**", "/socket", "/success").authenticated().anyRequest()
.authenticated()
.and()
// Use a Form style login
.formLogin().loginPage("/login.html") // The URL to be displayed with the login form
.loginProcessingUrl("/login") // The URL to process the login request
.authenticationDetailsSource( new ServletAuthenticationDetailsSource() )
.permitAll()
// These are the default names
// .usernameParameter("username")
// .passwordParameter("password")
// On success to go root
// .loginProcessingUrl("/")
// .loginProcessingUrl("/authenticate")
.successHandler(loginSuccessHandler())
.failureHandler(loginFailureHandler())
// .failureForwardUrl("/public/login.html?error=true")
// .failureUrl("/login")
.permitAll().and().logout().logoutSuccessHandler(logoutSuccessHandler()).and().rememberMe()
.userDetailsService(userDetailsService).key("0b2f9fef-29e8-48ed-acf5-c074dba06b3b") // Generated by
// https://www.uuidgenerator.net/
.rememberMeParameter("remember-me") // it is name of checkbox at login page
.rememberMeCookieName("remember-login") // it is name of the cookie
.tokenValiditySeconds((int) Duration.ofDays(config.getLogin().getLifetimeindays()).getSeconds())
.and()
/**
* Applies to User Roles - not to login failures or unauthenticated access
* attempts.
*/
// .exceptionHandling().accessDeniedHandler(accessDeniedHandler()).and()
// .authenticationProvider(authenticationProvider())
;
/** Disabled for local testing */
http.csrf().disable();
/**
* This is solely required to support H2 console viewing in Spring MVC with
* Spring Security
*/
// http.headers().frameOptions().disable();
}
}