JAVA-8360 Split or move spring-5-security module

This commit is contained in:
anuragkumawat 2022-04-05 14:08:25 +05:30
parent 9759513bf9
commit bacd580822
33 changed files with 883 additions and 842 deletions

View File

@ -4,7 +4,6 @@ This module contains articles about Spring Security 5
## Relevant articles: ## Relevant articles:
- [Extra Login Fields with Spring Security](https://www.baeldung.com/spring-security-extra-login-fields)
- [A Custom Spring SecurityConfigurer](https://www.baeldung.com/spring-security-custom-configurer) - [A Custom Spring SecurityConfigurer](https://www.baeldung.com/spring-security-custom-configurer)
- [New Password Storage In Spring Security 5](https://www.baeldung.com/spring-security-5-password-storage) - [New Password Storage In Spring Security 5](https://www.baeldung.com/spring-security-5-password-storage)
- [Default Password Encoder in Spring Security 5](https://www.baeldung.com/spring-security-5-default-password-encoder) - [Default Password Encoder in Spring Security 5](https://www.baeldung.com/spring-security-5-default-password-encoder)

View File

@ -12,6 +12,7 @@ The "Learn Spring Security" Classes: http://github.learnspringsecurity.com
- [Spring Security Customize the 403 Forbidden/Access Denied Page](https://www.baeldung.com/spring-security-custom-access-denied-page) - [Spring Security Customize the 403 Forbidden/Access Denied Page](https://www.baeldung.com/spring-security-custom-access-denied-page)
- [Spring Security Redirect to the Previous URL After Login](https://www.baeldung.com/spring-security-redirect-login) - [Spring Security Redirect to the Previous URL After Login](https://www.baeldung.com/spring-security-redirect-login)
- [Spring Security Custom AuthenticationFailureHandler](https://www.baeldung.com/spring-security-custom-authentication-failure-handler) - [Spring Security Custom AuthenticationFailureHandler](https://www.baeldung.com/spring-security-custom-authentication-failure-handler)
- [Extra Login Fields with Spring Security](https://www.baeldung.com/spring-security-extra-login-fields)
### Build the Project ### Build the Project
``` ```

View File

@ -16,6 +16,26 @@
</parent> </parent>
<dependencies> <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity5</artifactId>
<version>${thymeleaf-extras-springsecurity5.version}</version>
</dependency>
<!-- Spring Security --> <!-- Spring Security -->
<dependency> <dependency>
<groupId>org.springframework.security</groupId> <groupId>org.springframework.security</groupId>
@ -98,6 +118,12 @@
<scope>runtime</scope> <scope>runtime</scope>
</dependency> </dependency>
<!-- test scoped --> <!-- test scoped -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>${spring-boot.version}</version>
<scope>test</scope>
</dependency>
<dependency> <dependency>
<groupId>org.springframework</groupId> <groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId> <artifactId>spring-test</artifactId>
@ -110,6 +136,11 @@
<version>${spring-security.version}</version> <version>${spring-security.version}</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${commons-lang3.version}</version>
</dependency>
</dependencies> </dependencies>
<build> <build>
@ -153,6 +184,9 @@
<properties> <properties>
<!-- Maven plugins --> <!-- Maven plugins -->
<cargo-maven3-plugin.version>1.9.9</cargo-maven3-plugin.version> <cargo-maven3-plugin.version>1.9.9</cargo-maven3-plugin.version>
<spring-boot.version>2.6.4</spring-boot.version>
<thymeleaf-extras-springsecurity5.version>3.0.4.RELEASE</thymeleaf-extras-springsecurity5.version>
<commons-lang3.version>3.11</commons-lang3.version>
</properties> </properties>
</project> </project>

View File

@ -1,50 +1,50 @@
package com.baeldung.loginextrafieldscustom; package com.baeldung.loginextrafieldscustom;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import org.springframework.security.authentication.AuthenticationServiceException; import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
public class CustomAuthenticationFilter extends UsernamePasswordAuthenticationFilter { public class CustomAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
public static final String SPRING_SECURITY_FORM_DOMAIN_KEY = "domain"; public static final String SPRING_SECURITY_FORM_DOMAIN_KEY = "domain";
@Override @Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException { throws AuthenticationException {
if (!request.getMethod().equals("POST")) { if (!request.getMethod().equals("POST")) {
throw new AuthenticationServiceException("Authentication method not supported: " throw new AuthenticationServiceException("Authentication method not supported: "
+ request.getMethod()); + request.getMethod());
} }
CustomAuthenticationToken authRequest = getAuthRequest(request); CustomAuthenticationToken authRequest = getAuthRequest(request);
setDetails(request, authRequest); setDetails(request, authRequest);
return this.getAuthenticationManager().authenticate(authRequest); return this.getAuthenticationManager().authenticate(authRequest);
} }
private CustomAuthenticationToken getAuthRequest(HttpServletRequest request) { private CustomAuthenticationToken getAuthRequest(HttpServletRequest request) {
String username = obtainUsername(request); String username = obtainUsername(request);
String password = obtainPassword(request); String password = obtainPassword(request);
String domain = obtainDomain(request); String domain = obtainDomain(request);
if (username == null) { if (username == null) {
username = ""; username = "";
} }
if (password == null) { if (password == null) {
password = ""; password = "";
} }
if (domain == null) { if (domain == null) {
domain = ""; domain = "";
} }
return new CustomAuthenticationToken(username, password, domain); return new CustomAuthenticationToken(username, password, domain);
} }
private String obtainDomain(HttpServletRequest request) { private String obtainDomain(HttpServletRequest request) {
return request.getParameter(SPRING_SECURITY_FORM_DOMAIN_KEY); return request.getParameter(SPRING_SECURITY_FORM_DOMAIN_KEY);
} }
} }

View File

@ -1,28 +1,28 @@
package com.baeldung.loginextrafieldscustom; package com.baeldung.loginextrafieldscustom;
import java.util.Collection; import java.util.Collection;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.GrantedAuthority;
public class CustomAuthenticationToken extends UsernamePasswordAuthenticationToken { public class CustomAuthenticationToken extends UsernamePasswordAuthenticationToken {
private String domain; private String domain;
public CustomAuthenticationToken(Object principal, Object credentials, String domain) { public CustomAuthenticationToken(Object principal, Object credentials, String domain) {
super(principal, credentials); super(principal, credentials);
this.domain = domain; this.domain = domain;
super.setAuthenticated(false); super.setAuthenticated(false);
} }
public CustomAuthenticationToken(Object principal, Object credentials, String domain, public CustomAuthenticationToken(Object principal, Object credentials, String domain,
Collection<? extends GrantedAuthority> authorities) { Collection<? extends GrantedAuthority> authorities) {
super(principal, credentials, authorities); super(principal, credentials, authorities);
this.domain = domain; this.domain = domain;
super.setAuthenticated(true); // must use super, as we override super.setAuthenticated(true); // must use super, as we override
} }
public String getDomain() { public String getDomain() {
return this.domain; return this.domain;
} }
} }

View File

@ -1,92 +1,92 @@
package com.baeldung.loginextrafieldscustom; package com.baeldung.loginextrafieldscustom;
import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.InternalAuthenticationServiceException; import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider; import org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider;
import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.util.Assert; import org.springframework.util.Assert;
public class CustomUserDetailsAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider { public class CustomUserDetailsAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
/** /**
* The plaintext password used to perform * The plaintext password used to perform
* PasswordEncoder#matches(CharSequence, String)} on when the user is * PasswordEncoder#matches(CharSequence, String)} on when the user is
* not found to avoid SEC-2056. * not found to avoid SEC-2056.
*/ */
private static final String USER_NOT_FOUND_PASSWORD = "userNotFoundPassword"; private static final String USER_NOT_FOUND_PASSWORD = "userNotFoundPassword";
private PasswordEncoder passwordEncoder; private PasswordEncoder passwordEncoder;
private CustomUserDetailsService userDetailsService; private CustomUserDetailsService userDetailsService;
/** /**
* The password used to perform * The password used to perform
* {@link PasswordEncoder#matches(CharSequence, String)} on when the user is * {@link PasswordEncoder#matches(CharSequence, String)} on when the user is
* not found to avoid SEC-2056. This is necessary, because some * not found to avoid SEC-2056. This is necessary, because some
* {@link PasswordEncoder} implementations will short circuit if the password is not * {@link PasswordEncoder} implementations will short circuit if the password is not
* in a valid format. * in a valid format.
*/ */
private String userNotFoundEncodedPassword; private String userNotFoundEncodedPassword;
public CustomUserDetailsAuthenticationProvider(PasswordEncoder passwordEncoder, CustomUserDetailsService userDetailsService) { public CustomUserDetailsAuthenticationProvider(PasswordEncoder passwordEncoder, CustomUserDetailsService userDetailsService) {
this.passwordEncoder = passwordEncoder; this.passwordEncoder = passwordEncoder;
this.userDetailsService = userDetailsService; this.userDetailsService = userDetailsService;
} }
@Override @Override
protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication)
throws AuthenticationException { throws AuthenticationException {
if (authentication.getCredentials() == null) { if (authentication.getCredentials() == null) {
logger.debug("Authentication failed: no credentials provided"); logger.debug("Authentication failed: no credentials provided");
throw new BadCredentialsException( throw new BadCredentialsException(
messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials")); messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
} }
String presentedPassword = authentication.getCredentials() String presentedPassword = authentication.getCredentials()
.toString(); .toString();
if (!passwordEncoder.matches(presentedPassword, userDetails.getPassword())) { if (!passwordEncoder.matches(presentedPassword, userDetails.getPassword())) {
logger.debug("Authentication failed: password does not match stored value"); logger.debug("Authentication failed: password does not match stored value");
throw new BadCredentialsException( throw new BadCredentialsException(
messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials")); messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
} }
} }
@Override @Override
protected void doAfterPropertiesSet() throws Exception { protected void doAfterPropertiesSet() throws Exception {
Assert.notNull(this.userDetailsService, "A UserDetailsService must be set"); Assert.notNull(this.userDetailsService, "A UserDetailsService must be set");
this.userNotFoundEncodedPassword = this.passwordEncoder.encode(USER_NOT_FOUND_PASSWORD); this.userNotFoundEncodedPassword = this.passwordEncoder.encode(USER_NOT_FOUND_PASSWORD);
} }
@Override @Override
protected UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) protected UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication)
throws AuthenticationException { throws AuthenticationException {
CustomAuthenticationToken auth = (CustomAuthenticationToken) authentication; CustomAuthenticationToken auth = (CustomAuthenticationToken) authentication;
UserDetails loadedUser; UserDetails loadedUser;
try { try {
loadedUser = this.userDetailsService.loadUserByUsernameAndDomain(auth.getPrincipal() loadedUser = this.userDetailsService.loadUserByUsernameAndDomain(auth.getPrincipal()
.toString(), auth.getDomain()); .toString(), auth.getDomain());
} catch (UsernameNotFoundException notFound) { } catch (UsernameNotFoundException notFound) {
if (authentication.getCredentials() != null) { if (authentication.getCredentials() != null) {
String presentedPassword = authentication.getCredentials() String presentedPassword = authentication.getCredentials()
.toString(); .toString();
passwordEncoder.matches(presentedPassword, userNotFoundEncodedPassword); passwordEncoder.matches(presentedPassword, userNotFoundEncodedPassword);
} }
throw notFound; throw notFound;
} catch (Exception repositoryProblem) { } catch (Exception repositoryProblem) {
throw new InternalAuthenticationServiceException(repositoryProblem.getMessage(), repositoryProblem); throw new InternalAuthenticationServiceException(repositoryProblem.getMessage(), repositoryProblem);
} }
if (loadedUser == null) { if (loadedUser == null) {
throw new InternalAuthenticationServiceException("UserDetailsService returned null, " throw new InternalAuthenticationServiceException("UserDetailsService returned null, "
+ "which is an interface contract violation"); + "which is an interface contract violation");
} }
return loadedUser; return loadedUser;
} }
} }

View File

@ -1,10 +1,10 @@
package com.baeldung.loginextrafieldscustom; package com.baeldung.loginextrafieldscustom;
import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.core.userdetails.UsernameNotFoundException;
public interface CustomUserDetailsService { public interface CustomUserDetailsService {
UserDetails loadUserByUsernameAndDomain(String username, String domain) throws UsernameNotFoundException; UserDetails loadUserByUsernameAndDomain(String username, String domain) throws UsernameNotFoundException;
} }

View File

@ -1,30 +1,30 @@
package com.baeldung.loginextrafieldscustom; package com.baeldung.loginextrafieldscustom;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@Service("userDetailsService") @Service("userDetailsService")
public class CustomUserDetailsServiceImpl implements CustomUserDetailsService { public class CustomUserDetailsServiceImpl implements CustomUserDetailsService {
private UserRepository userRepository; private UserRepository userRepository;
public CustomUserDetailsServiceImpl(UserRepository userRepository) { public CustomUserDetailsServiceImpl(UserRepository userRepository) {
this.userRepository = userRepository; this.userRepository = userRepository;
} }
@Override @Override
public UserDetails loadUserByUsernameAndDomain(String username, String domain) throws UsernameNotFoundException { public UserDetails loadUserByUsernameAndDomain(String username, String domain) throws UsernameNotFoundException {
if (StringUtils.isAnyBlank(username, domain)) { if (StringUtils.isAnyBlank(username, domain)) {
throw new UsernameNotFoundException("Username and domain must be provided"); throw new UsernameNotFoundException("Username and domain must be provided");
} }
User user = userRepository.findUser(username, domain); User user = userRepository.findUser(username, domain);
if (user == null) { if (user == null) {
throw new UsernameNotFoundException( throw new UsernameNotFoundException(
String.format("Username not found for domain, username=%s, domain=%s", String.format("Username not found for domain, username=%s, domain=%s",
username, domain)); username, domain));
} }
return user; return user;
} }
} }

View File

@ -1,33 +1,33 @@
package com.baeldung.loginextrafieldscustom; package com.baeldung.loginextrafieldscustom;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
@Repository("userRepository") @Repository("userRepository")
public class CustomUserRepository implements UserRepository { public class CustomUserRepository implements UserRepository {
private PasswordEncoder passwordEncoder; private PasswordEncoder passwordEncoder;
public CustomUserRepository(PasswordEncoder passwordEncoder) { public CustomUserRepository(PasswordEncoder passwordEncoder) {
this.passwordEncoder = passwordEncoder; this.passwordEncoder = passwordEncoder;
} }
@Override @Override
public User findUser(String username, String domain) { public User findUser(String username, String domain) {
if (StringUtils.isAnyBlank(username, domain)) { if (StringUtils.isAnyBlank(username, domain)) {
return null; return null;
} else { } else {
Collection<? extends GrantedAuthority> authorities = new ArrayList<>(); Collection<? extends GrantedAuthority> authorities = new ArrayList<>();
User user = new User(username, domain, User user = new User(username, domain,
passwordEncoder.encode("secret"), true, passwordEncoder.encode("secret"), true,
true, true, true, authorities); true, true, true, authorities);
return user; return user;
} }
} }
} }

View File

@ -1,63 +1,63 @@
package com.baeldung.loginextrafieldscustom; package com.baeldung.loginextrafieldscustom;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.PropertySource; import org.springframework.context.annotation.PropertySource;
import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity; 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.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler; import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@EnableWebSecurity @EnableWebSecurity
@PropertySource("classpath:/application-extrafields.properties") @PropertySource("classpath:/application-extrafields.properties")
public class SecurityConfig extends WebSecurityConfigurerAdapter { public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired @Autowired
private CustomUserDetailsService userDetailsService; private CustomUserDetailsService userDetailsService;
@Autowired @Autowired
private PasswordEncoder passwordEncoder; private PasswordEncoder passwordEncoder;
@Override @Override
protected void configure(HttpSecurity http) throws Exception { protected void configure(HttpSecurity http) throws Exception {
http http
.addFilterBefore(authenticationFilter(), UsernamePasswordAuthenticationFilter.class) .addFilterBefore(authenticationFilter(), UsernamePasswordAuthenticationFilter.class)
.authorizeRequests() .authorizeRequests()
.antMatchers("/css/**", "/index").permitAll() .antMatchers("/css/**", "/index").permitAll()
.antMatchers("/user/**").authenticated() .antMatchers("/user/**").authenticated()
.and() .and()
.formLogin().loginPage("/login") .formLogin().loginPage("/login")
.and() .and()
.logout() .logout()
.logoutUrl("/logout"); .logoutUrl("/logout");
} }
public CustomAuthenticationFilter authenticationFilter() throws Exception { public CustomAuthenticationFilter authenticationFilter() throws Exception {
CustomAuthenticationFilter filter = new CustomAuthenticationFilter(); CustomAuthenticationFilter filter = new CustomAuthenticationFilter();
filter.setAuthenticationManager(authenticationManagerBean()); filter.setAuthenticationManager(authenticationManagerBean());
filter.setAuthenticationFailureHandler(failureHandler()); filter.setAuthenticationFailureHandler(failureHandler());
return filter; return filter;
} }
@Autowired @Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authProvider()); auth.authenticationProvider(authProvider());
} }
public AuthenticationProvider authProvider() { public AuthenticationProvider authProvider() {
CustomUserDetailsAuthenticationProvider provider CustomUserDetailsAuthenticationProvider provider
= new CustomUserDetailsAuthenticationProvider(passwordEncoder, userDetailsService); = new CustomUserDetailsAuthenticationProvider(passwordEncoder, userDetailsService);
return provider; return provider;
} }
public SimpleUrlAuthenticationFailureHandler failureHandler() { public SimpleUrlAuthenticationFailureHandler failureHandler() {
return new SimpleUrlAuthenticationFailureHandler("/login?error=true"); return new SimpleUrlAuthenticationFailureHandler("/login?error=true");
} }
} }

View File

@ -1,23 +1,23 @@
package com.baeldung.loginextrafieldscustom; package com.baeldung.loginextrafieldscustom;
import java.util.Collection; import java.util.Collection;
import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.GrantedAuthority;
public class User extends org.springframework.security.core.userdetails.User { public class User extends org.springframework.security.core.userdetails.User {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private String domain; private String domain;
public User(String username, String domain, String password, boolean enabled, public User(String username, String domain, String password, boolean enabled,
boolean accountNonExpired, boolean credentialsNonExpired, boolean accountNonExpired, boolean credentialsNonExpired,
boolean accountNonLocked, Collection<? extends GrantedAuthority> authorities) { boolean accountNonLocked, Collection<? extends GrantedAuthority> authorities) {
super(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities); super(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities);
this.domain = domain; this.domain = domain;
} }
public String getDomain() { public String getDomain() {
return domain; return domain;
} }
} }

View File

@ -1,7 +1,7 @@
package com.baeldung.loginextrafieldscustom; package com.baeldung.loginextrafieldscustom;
public interface UserRepository { public interface UserRepository {
public User findUser(String username, String domain); public User findUser(String username, String domain);
} }

View File

@ -1,51 +1,51 @@
package com.baeldung.loginextrafieldscustom; package com.baeldung.loginextrafieldscustom;
import java.util.Optional; import java.util.Optional;
import org.springframework.security.authentication.AnonymousAuthenticationToken; import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.ui.Model; import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
@Controller @Controller
public class WebController { public class WebController {
@RequestMapping("/") @RequestMapping("/")
public String root() { public String root() {
return "redirect:/index"; return "redirect:/index";
} }
@RequestMapping("/index") @RequestMapping("/index")
public String index(Model model) { public String index(Model model) {
getDomain().ifPresent(d -> { getDomain().ifPresent(d -> {
model.addAttribute("domain", d); model.addAttribute("domain", d);
}); });
return "index"; return "index";
} }
@RequestMapping("/user/index") @RequestMapping("/user/index")
public String userIndex(Model model) { public String userIndex(Model model) {
getDomain().ifPresent(d -> { getDomain().ifPresent(d -> {
model.addAttribute("domain", d); model.addAttribute("domain", d);
}); });
return "user/index"; return "user/index";
} }
@RequestMapping("/login") @RequestMapping("/login")
public String login() { public String login() {
return "login"; return "login";
} }
private Optional<String> getDomain() { private Optional<String> getDomain() {
Authentication auth = SecurityContextHolder.getContext() Authentication auth = SecurityContextHolder.getContext()
.getAuthentication(); .getAuthentication();
String domain = null; String domain = null;
if (auth != null && !auth.getClass().equals(AnonymousAuthenticationToken.class)) { if (auth != null && !auth.getClass().equals(AnonymousAuthenticationToken.class)) {
User user = (User) auth.getPrincipal(); User user = (User) auth.getPrincipal();
domain = user.getDomain(); domain = user.getDomain();
} }
return Optional.ofNullable(domain); return Optional.ofNullable(domain);
} }
} }

View File

@ -1,66 +1,66 @@
package com.baeldung.loginextrafieldssimple; package com.baeldung.loginextrafieldssimple;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.PropertySource; import org.springframework.context.annotation.PropertySource;
import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider; import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity; 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.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler; import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@EnableWebSecurity @EnableWebSecurity
@PropertySource("classpath:/application-extrafields.properties") @PropertySource("classpath:/application-extrafields.properties")
public class SecurityConfig extends WebSecurityConfigurerAdapter { public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired @Autowired
private UserDetailsService userDetailsService; private UserDetailsService userDetailsService;
@Autowired @Autowired
private PasswordEncoder passwordEncoder; private PasswordEncoder passwordEncoder;
@Override @Override
protected void configure(HttpSecurity http) throws Exception { protected void configure(HttpSecurity http) throws Exception {
http http
.addFilterBefore(authenticationFilter(), UsernamePasswordAuthenticationFilter.class) .addFilterBefore(authenticationFilter(), UsernamePasswordAuthenticationFilter.class)
.authorizeRequests() .authorizeRequests()
.antMatchers("/css/**", "/index").permitAll() .antMatchers("/css/**", "/index").permitAll()
.antMatchers("/user/**").authenticated() .antMatchers("/user/**").authenticated()
.and() .and()
.formLogin().loginPage("/login") .formLogin().loginPage("/login")
.and() .and()
.logout() .logout()
.logoutUrl("/logout"); .logoutUrl("/logout");
} }
public SimpleAuthenticationFilter authenticationFilter() throws Exception { public SimpleAuthenticationFilter authenticationFilter() throws Exception {
SimpleAuthenticationFilter filter = new SimpleAuthenticationFilter(); SimpleAuthenticationFilter filter = new SimpleAuthenticationFilter();
filter.setAuthenticationManager(authenticationManagerBean()); filter.setAuthenticationManager(authenticationManagerBean());
filter.setAuthenticationFailureHandler(failureHandler()); filter.setAuthenticationFailureHandler(failureHandler());
return filter; return filter;
} }
@Autowired @Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authProvider()); auth.authenticationProvider(authProvider());
} }
public AuthenticationProvider authProvider() { public AuthenticationProvider authProvider() {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider(); DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setUserDetailsService(userDetailsService); provider.setUserDetailsService(userDetailsService);
provider.setPasswordEncoder(passwordEncoder); provider.setPasswordEncoder(passwordEncoder);
return provider; return provider;
} }
public SimpleUrlAuthenticationFailureHandler failureHandler() { public SimpleUrlAuthenticationFailureHandler failureHandler() {
return new SimpleUrlAuthenticationFailureHandler("/login?error=true"); return new SimpleUrlAuthenticationFailureHandler("/login?error=true");
} }
} }

View File

@ -1,54 +1,54 @@
package com.baeldung.loginextrafieldssimple; package com.baeldung.loginextrafieldssimple;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import org.springframework.security.authentication.AuthenticationServiceException; import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
public class SimpleAuthenticationFilter extends UsernamePasswordAuthenticationFilter { public class SimpleAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
public static final String SPRING_SECURITY_FORM_DOMAIN_KEY = "domain"; public static final String SPRING_SECURITY_FORM_DOMAIN_KEY = "domain";
@Override @Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException { throws AuthenticationException {
if (!request.getMethod() if (!request.getMethod()
.equals("POST")) { .equals("POST")) {
throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod()); throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
} }
UsernamePasswordAuthenticationToken authRequest = getAuthRequest(request); UsernamePasswordAuthenticationToken authRequest = getAuthRequest(request);
setDetails(request, authRequest); setDetails(request, authRequest);
return this.getAuthenticationManager() return this.getAuthenticationManager()
.authenticate(authRequest); .authenticate(authRequest);
} }
private UsernamePasswordAuthenticationToken getAuthRequest(HttpServletRequest request) { private UsernamePasswordAuthenticationToken getAuthRequest(HttpServletRequest request) {
String username = obtainUsername(request); String username = obtainUsername(request);
String password = obtainPassword(request); String password = obtainPassword(request);
String domain = obtainDomain(request); String domain = obtainDomain(request);
if (username == null) { if (username == null) {
username = ""; username = "";
} }
if (password == null) { if (password == null) {
password = ""; password = "";
} }
if (domain == null) { if (domain == null) {
domain = ""; domain = "";
} }
String usernameDomain = String.format("%s%s%s", username.trim(), String usernameDomain = String.format("%s%s%s", username.trim(),
String.valueOf(Character.LINE_SEPARATOR), domain); String.valueOf(Character.LINE_SEPARATOR), domain);
return new UsernamePasswordAuthenticationToken(usernameDomain, password); return new UsernamePasswordAuthenticationToken(usernameDomain, password);
} }
private String obtainDomain(HttpServletRequest request) { private String obtainDomain(HttpServletRequest request) {
return request.getParameter(SPRING_SECURITY_FORM_DOMAIN_KEY); return request.getParameter(SPRING_SECURITY_FORM_DOMAIN_KEY);
} }
} }

View File

@ -1,32 +1,32 @@
package com.baeldung.loginextrafieldssimple; package com.baeldung.loginextrafieldssimple;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@Service("userDetailsService") @Service("userDetailsService")
public class SimpleUserDetailsService implements UserDetailsService { public class SimpleUserDetailsService implements UserDetailsService {
private UserRepository userRepository; private UserRepository userRepository;
public SimpleUserDetailsService(UserRepository userRepository) { public SimpleUserDetailsService(UserRepository userRepository) {
this.userRepository = userRepository; this.userRepository = userRepository;
} }
@Override @Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
String[] usernameAndDomain = StringUtils.split(username, String.valueOf(Character.LINE_SEPARATOR)); String[] usernameAndDomain = StringUtils.split(username, String.valueOf(Character.LINE_SEPARATOR));
if (usernameAndDomain == null || usernameAndDomain.length != 2) { if (usernameAndDomain == null || usernameAndDomain.length != 2) {
throw new UsernameNotFoundException("Username and domain must be provided"); throw new UsernameNotFoundException("Username and domain must be provided");
} }
User user = userRepository.findUser(usernameAndDomain[0], usernameAndDomain[1]); User user = userRepository.findUser(usernameAndDomain[0], usernameAndDomain[1]);
if (user == null) { if (user == null) {
throw new UsernameNotFoundException( throw new UsernameNotFoundException(
String.format("Username not found for domain, username=%s, domain=%s", String.format("Username not found for domain, username=%s, domain=%s",
usernameAndDomain[0], usernameAndDomain[1])); usernameAndDomain[0], usernameAndDomain[1]));
} }
return user; return user;
} }
} }

View File

@ -1,33 +1,33 @@
package com.baeldung.loginextrafieldssimple; package com.baeldung.loginextrafieldssimple;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
@Repository("userRepository") @Repository("userRepository")
public class SimpleUserRepository implements UserRepository { public class SimpleUserRepository implements UserRepository {
private PasswordEncoder passwordEncoder; private PasswordEncoder passwordEncoder;
public SimpleUserRepository(PasswordEncoder passwordEncoder) { public SimpleUserRepository(PasswordEncoder passwordEncoder) {
this.passwordEncoder = passwordEncoder; this.passwordEncoder = passwordEncoder;
} }
@Override @Override
public User findUser(String username, String domain) { public User findUser(String username, String domain) {
if (StringUtils.isAnyBlank(username, domain)) { if (StringUtils.isAnyBlank(username, domain)) {
return null; return null;
} else { } else {
Collection<? extends GrantedAuthority> authorities = new ArrayList<>(); Collection<? extends GrantedAuthority> authorities = new ArrayList<>();
User user = new User(username, domain, User user = new User(username, domain,
passwordEncoder.encode("secret"), true, passwordEncoder.encode("secret"), true,
true, true, true, authorities); true, true, true, authorities);
return user; return user;
} }
} }
} }

View File

@ -1,21 +1,21 @@
package com.baeldung.loginextrafieldssimple; package com.baeldung.loginextrafieldssimple;
import java.util.Collection; import java.util.Collection;
import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.GrantedAuthority;
public class User extends org.springframework.security.core.userdetails.User { public class User extends org.springframework.security.core.userdetails.User {
private String domain; private String domain;
public User(String username, String domain, String password, boolean enabled, public User(String username, String domain, String password, boolean enabled,
boolean accountNonExpired, boolean credentialsNonExpired, boolean accountNonExpired, boolean credentialsNonExpired,
boolean accountNonLocked, Collection<? extends GrantedAuthority> authorities) { boolean accountNonLocked, Collection<? extends GrantedAuthority> authorities) {
super(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities); super(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities);
this.domain = domain; this.domain = domain;
} }
public String getDomain() { public String getDomain() {
return domain; return domain;
} }
} }

View File

@ -1,7 +1,7 @@
package com.baeldung.loginextrafieldssimple; package com.baeldung.loginextrafieldssimple;
public interface UserRepository { public interface UserRepository {
public User findUser(String username, String domain); public User findUser(String username, String domain);
} }

View File

@ -1,51 +1,51 @@
package com.baeldung.loginextrafieldssimple; package com.baeldung.loginextrafieldssimple;
import java.util.Optional; import java.util.Optional;
import org.springframework.security.authentication.AnonymousAuthenticationToken; import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.ui.Model; import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
@Controller @Controller
public class WebController { public class WebController {
@RequestMapping("/") @RequestMapping("/")
public String root() { public String root() {
return "redirect:/index"; return "redirect:/index";
} }
@RequestMapping("/index") @RequestMapping("/index")
public String index(Model model) { public String index(Model model) {
getDomain().ifPresent(d -> { getDomain().ifPresent(d -> {
model.addAttribute("domain", d); model.addAttribute("domain", d);
}); });
return "index"; return "index";
} }
@RequestMapping("/user/index") @RequestMapping("/user/index")
public String userIndex(Model model) { public String userIndex(Model model) {
getDomain().ifPresent(d -> { getDomain().ifPresent(d -> {
model.addAttribute("domain", d); model.addAttribute("domain", d);
}); });
return "user/index"; return "user/index";
} }
@RequestMapping("/login") @RequestMapping("/login")
public String login() { public String login() {
return "login"; return "login";
} }
private Optional<String> getDomain() { private Optional<String> getDomain() {
Authentication auth = SecurityContextHolder.getContext() Authentication auth = SecurityContextHolder.getContext()
.getAuthentication(); .getAuthentication();
String domain = null; String domain = null;
if (auth != null && !auth.getClass().equals(AnonymousAuthenticationToken.class)) { if (auth != null && !auth.getClass().equals(AnonymousAuthenticationToken.class)) {
User user = (User) auth.getPrincipal(); User user = (User) auth.getPrincipal();
domain = user.getDomain(); domain = user.getDomain();
} }
return Optional.ofNullable(domain); return Optional.ofNullable(domain);
} }
} }

View File

@ -0,0 +1,7 @@
server.port=8081
logging.level.root=INFO
logging.level.com.baeldung.dsl.ClientErrorLoggingFilter=DEBUG
logging.level.org.springframework.security=DEBUG

View File

@ -1,46 +1,46 @@
package com.baeldung.loginextrafields; package com.baeldung.loginextrafields;
import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity; import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrlPattern; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrlPattern;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.web.FilterChainProxy; import org.springframework.security.web.FilterChainProxy;
import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.WebApplicationContext;
public abstract class AbstractExtraLoginFieldsIntegrationTest { public abstract class AbstractExtraLoginFieldsIntegrationTest {
@Autowired @Autowired
private FilterChainProxy springSecurityFilterChain; private FilterChainProxy springSecurityFilterChain;
@Autowired @Autowired
private WebApplicationContext wac; private WebApplicationContext wac;
protected MockMvc mockMvc; protected MockMvc mockMvc;
@Before @Before
public void setup() { public void setup() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(wac) this.mockMvc = MockMvcBuilders.webAppContextSetup(wac)
.apply(springSecurity(springSecurityFilterChain)) .apply(springSecurity(springSecurityFilterChain))
.build(); .build();
} }
@Test @Test
public void givenRootPathAccess_thenRedirectToIndex() throws Exception { public void givenRootPathAccess_thenRedirectToIndex() throws Exception {
this.mockMvc.perform(get("/")) this.mockMvc.perform(get("/"))
.andExpect(status().is3xxRedirection()) .andExpect(status().is3xxRedirection())
.andExpect(redirectedUrlPattern("/index*")); .andExpect(redirectedUrlPattern("/index*"));
} }
@Test @Test
public void givenSecuredResource_whenAccessUnauthenticated_thenRequiresAuthentication() throws Exception { public void givenSecuredResource_whenAccessUnauthenticated_thenRequiresAuthentication() throws Exception {
this.mockMvc.perform(get("/user/index")) this.mockMvc.perform(get("/user/index"))
.andExpect(status().is3xxRedirection()) .andExpect(status().is3xxRedirection())
.andExpect(redirectedUrlPattern("**/login")); .andExpect(redirectedUrlPattern("**/login"));
} }
} }

View File

@ -1,72 +1,72 @@
package com.baeldung.loginextrafields; package com.baeldung.loginextrafields;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrlPattern; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrlPattern;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.mock.web.MockHttpSession; import org.springframework.mock.web.MockHttpSession;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository; import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
import org.springframework.test.context.junit.jupiter.web.SpringJUnitWebConfig; import org.springframework.test.context.junit.jupiter.web.SpringJUnitWebConfig;
import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MvcResult; import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder; import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import com.baeldung.loginextrafieldscustom.ExtraLoginFieldsApplication; import com.baeldung.loginextrafieldscustom.ExtraLoginFieldsApplication;
import com.baeldung.loginextrafieldscustom.User; import com.baeldung.loginextrafieldscustom.User;
@RunWith(SpringRunner.class) @RunWith(SpringRunner.class)
@SpringJUnitWebConfig @SpringJUnitWebConfig
@SpringBootTest(classes = ExtraLoginFieldsApplication.class) @SpringBootTest(classes = ExtraLoginFieldsApplication.class)
public class LoginFieldsFullIntegrationTest extends AbstractExtraLoginFieldsIntegrationTest { public class LoginFieldsFullIntegrationTest extends AbstractExtraLoginFieldsIntegrationTest {
@Test @Test
public void givenAccessSecuredResource_whenAuthenticated_thenAuthHasExtraFields() throws Exception { public void givenAccessSecuredResource_whenAuthenticated_thenAuthHasExtraFields() throws Exception {
MockHttpServletRequestBuilder securedResourceAccess = get("/user/index"); MockHttpServletRequestBuilder securedResourceAccess = get("/user/index");
MvcResult unauthenticatedResult = mockMvc.perform(securedResourceAccess) MvcResult unauthenticatedResult = mockMvc.perform(securedResourceAccess)
.andExpect(status().is3xxRedirection()) .andExpect(status().is3xxRedirection())
.andReturn(); .andReturn();
MockHttpSession session = (MockHttpSession) unauthenticatedResult.getRequest() MockHttpSession session = (MockHttpSession) unauthenticatedResult.getRequest()
.getSession(); .getSession();
String loginUrl = unauthenticatedResult.getResponse() String loginUrl = unauthenticatedResult.getResponse()
.getRedirectedUrl(); .getRedirectedUrl();
User user = getUser(); User user = getUser();
mockMvc.perform(post(loginUrl) mockMvc.perform(post(loginUrl)
.param("username", user.getUsername()) .param("username", user.getUsername())
.param("password", user.getPassword()) .param("password", user.getPassword())
.param("domain", user.getDomain()) .param("domain", user.getDomain())
.session(session) .session(session)
.with(csrf())) .with(csrf()))
.andExpect(status().is3xxRedirection()) .andExpect(status().is3xxRedirection())
.andExpect(redirectedUrlPattern("**/user/index")) .andExpect(redirectedUrlPattern("**/user/index"))
.andReturn(); .andReturn();
mockMvc.perform(securedResourceAccess.session(session)) mockMvc.perform(securedResourceAccess.session(session))
.andExpect(status().isOk()); .andExpect(status().isOk());
SecurityContext securityContext SecurityContext securityContext
= (SecurityContext) session.getAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY); = (SecurityContext) session.getAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY);
Authentication auth = securityContext.getAuthentication(); Authentication auth = securityContext.getAuthentication();
assertEquals(((User)auth.getPrincipal()).getDomain(), user.getDomain()); assertEquals(((User)auth.getPrincipal()).getDomain(), user.getDomain());
} }
private User getUser() { private User getUser() {
Collection<? extends GrantedAuthority> authorities = new ArrayList<>(); Collection<? extends GrantedAuthority> authorities = new ArrayList<>();
return new User("myusername", "mydomain", "secret", true, true, true, true, authorities); return new User("myusername", "mydomain", "secret", true, true, true, true, authorities);
} }
} }

View File

@ -1,72 +1,72 @@
package com.baeldung.loginextrafields; package com.baeldung.loginextrafields;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrlPattern; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrlPattern;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.mock.web.MockHttpSession; import org.springframework.mock.web.MockHttpSession;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository; import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
import org.springframework.test.context.junit.jupiter.web.SpringJUnitWebConfig; import org.springframework.test.context.junit.jupiter.web.SpringJUnitWebConfig;
import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MvcResult; import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder; import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import com.baeldung.loginextrafieldssimple.ExtraLoginFieldsApplication; import com.baeldung.loginextrafieldssimple.ExtraLoginFieldsApplication;
import com.baeldung.loginextrafieldssimple.User; import com.baeldung.loginextrafieldssimple.User;
@RunWith(SpringRunner.class) @RunWith(SpringRunner.class)
@SpringJUnitWebConfig @SpringJUnitWebConfig
@SpringBootTest(classes = ExtraLoginFieldsApplication.class) @SpringBootTest(classes = ExtraLoginFieldsApplication.class)
public class LoginFieldsSimpleIntegrationTest extends AbstractExtraLoginFieldsIntegrationTest { public class LoginFieldsSimpleIntegrationTest extends AbstractExtraLoginFieldsIntegrationTest {
@Test @Test
public void givenAccessSecuredResource_whenAuthenticated_thenAuthHasExtraFields() throws Exception { public void givenAccessSecuredResource_whenAuthenticated_thenAuthHasExtraFields() throws Exception {
MockHttpServletRequestBuilder securedResourceAccess = get("/user/index"); MockHttpServletRequestBuilder securedResourceAccess = get("/user/index");
MvcResult unauthenticatedResult = mockMvc.perform(securedResourceAccess) MvcResult unauthenticatedResult = mockMvc.perform(securedResourceAccess)
.andExpect(status().is3xxRedirection()) .andExpect(status().is3xxRedirection())
.andReturn(); .andReturn();
MockHttpSession session = (MockHttpSession) unauthenticatedResult.getRequest() MockHttpSession session = (MockHttpSession) unauthenticatedResult.getRequest()
.getSession(); .getSession();
String loginUrl = unauthenticatedResult.getResponse() String loginUrl = unauthenticatedResult.getResponse()
.getRedirectedUrl(); .getRedirectedUrl();
User user = getUser(); User user = getUser();
mockMvc.perform(post(loginUrl) mockMvc.perform(post(loginUrl)
.param("username", user.getUsername()) .param("username", user.getUsername())
.param("password", user.getPassword()) .param("password", user.getPassword())
.param("domain", user.getDomain()) .param("domain", user.getDomain())
.session(session) .session(session)
.with(csrf())) .with(csrf()))
.andExpect(status().is3xxRedirection()) .andExpect(status().is3xxRedirection())
.andExpect(redirectedUrlPattern("**/user/index")) .andExpect(redirectedUrlPattern("**/user/index"))
.andReturn(); .andReturn();
mockMvc.perform(securedResourceAccess.session(session)) mockMvc.perform(securedResourceAccess.session(session))
.andExpect(status().isOk()); .andExpect(status().isOk());
SecurityContext securityContext SecurityContext securityContext
= (SecurityContext) session.getAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY); = (SecurityContext) session.getAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY);
Authentication auth = securityContext.getAuthentication(); Authentication auth = securityContext.getAuthentication();
assertEquals(((User)auth.getPrincipal()).getDomain(), user.getDomain()); assertEquals(((User)auth.getPrincipal()).getDomain(), user.getDomain());
} }
private User getUser() { private User getUser() {
Collection<? extends GrantedAuthority> authorities = new ArrayList<>(); Collection<? extends GrantedAuthority> authorities = new ArrayList<>();
return new User("myusername", "mydomain", "secret", true, true, true, true, authorities); return new User("myusername", "mydomain", "secret", true, true, true, true, authorities);
} }
} }