I am trying to implement form login along with social login in latest Spring 5 security.
Below is my security Config:
package security.spring5login;
import java.io.IOException;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import security.spring5login.conf.CustomAuthProvider;
import security.spring5login.conf.CustomOAuth2User;
import security.spring5login.conf.CustomOAuth2UserService;
import security.spring5login.conf.CustomUserDetailService;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private CustomOAuth2UserService oauth2UserService;
@Bean
public DaoAuthenticationProvider authProvider() throws Exception {
CustomAuthProvider authProvider = new CustomAuthProvider();
authProvider.setUserDetailsService(userDetailsService());
authProvider.setPasswordEncoder(NoOpPasswordEncoder.getInstance());
return authProvider;
}
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.csrf().disable()
// .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
// .and()
.authorizeHttpRequests()
.mvcMatchers("/favicon.ico", "/signup", "/signup/**", "/assets", "/assets/**", "/cdn.jsdelivr.net",
"/cdn.jsdelivr.net/**", "/login", "/login/**", "/login/oauth2/code/google", "/oauth2",
"/oauth2/**")
.permitAll().anyRequest().authenticated().and().formLogin(form -> form.loginPage("/login").permitAll())
.authenticationManager(new ProviderManager(List.of(authProvider()))).oauth2Login().loginPage("/login")
.userInfoEndpoint().userService(oauth2UserService).and()
.successHandler(new AuthenticationSuccessHandler() {
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
logger.info("authentication::::: {}", authentication.toString());
CustomOAuth2User oauthUser = (CustomOAuth2User) authentication.getPrincipal();
// userService.processOAuthPostLogin(oauthUser.getEmail());
response.sendRedirect("/");
}
}).and().logout().logoutUrl("/").deleteCookies("JSESSIONID").invalidateHttpSession(true);
;
return http.build();
}
@Bean
public UserDetailsService userDetailsService() {
return new CustomUserDetailService();
}
@Bean
public PasswordEncoder passwordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
}
Below is my CustomOAuth2UserService:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService;
import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.stereotype.Service;
@Service
public class CustomOAuth2UserService extends DefaultOAuth2UserService {
Logger logger = LoggerFactory.getLogger(getClass());
@Override
public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
logger.info("OAuth2UserRequest:::::: {}",userRequest.toString());
OAuth2User user = super.loadUser(userRequest);
return new CustomOAuth2User(user);
}
}
CustomOAuth2User::
import java.util.Collection;
import java.util.Map;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.oauth2.core.user.OAuth2User;
public class CustomOAuth2User implements OAuth2User {
private OAuth2User oauth2User;
public CustomOAuth2User(OAuth2User oauth2User) {
this.oauth2User = oauth2User;
}
@Override
public Map<String, Object> getAttributes() {
return oauth2User.getAttributes();
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return oauth2User.getAuthorities();
}
@Override
public String getName() {
return oauth2User.getAttribute("name");
}
public String getEmail() {
return oauth2User.<String>getAttribute("email");
}
}
CustomAuthProvider:::
import java.util.Optional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import security.spring5login.exception.BadPasswordException;
import security.spring5login.model.AuthUser;
import security.spring5login.repository.AuthUserRepo;
public class CustomAuthProvider extends DaoAuthenticationProvider {
Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private AuthUserRepo authUserRepo;
@Override
public Authentication authenticate(final Authentication authentication) throws AuthenticationException {
System.err.println("authenticate");
logger.info("CustomAuthProvider authentication ::::: {} ", authentication);
logger.info("CustomAuthProvider authentication.getPrincipal() ::::: {} ",
authentication.getPrincipal().toString());
final String name = authentication.getName();
logger.info("CustomAuthenticationProvider ::::: " + authentication.getCredentials().toString());
final String password = authentication.getCredentials().toString();
logger.info("CustomAuthenticationProvider password ::::: " + password);
if ((name == null || name.trim().equalsIgnoreCase(""))) {
throw new BadCredentialsException("Please enter a username");
}
if(password == null || password.trim().equalsIgnoreCase("")) {
throw new BadCredentialsException("Please enter a password");
}
Optional<AuthUser> authUser = authUserRepo.findByEmail(name);
if (authUser.isEmpty()) {
throw new BadCredentialsException("Invalid username");
}
if (authentication.getCredentials() == null) {
throw new BadPasswordException("Password is null");
}
final Authentication result = super.authenticate(authentication);
return new UsernamePasswordAuthenticationToken(authUser.get(), result.getCredentials().toString(),
result.getAuthorities());
}
@Override
public boolean supports(Class<?> authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
}
CustomUserDetailService::::
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
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.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import security.spring5login.model.AuthUser;
import security.spring5login.repository.AuthUserRepo;
@Service
public class CustomUserDetailService implements UserDetailsService {
Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
AuthUserRepo authUserRepo;
@Autowired
PasswordEncoder passwordEncoder;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// TODO Auto-generated method stub
System.err.println("eeee");
logger.info("CustomUserDetailService -> UserName :::: {}", username);
Optional<AuthUser> savedUser = authUserRepo.findByEmail(username);
if (savedUser.isEmpty()) {
throw new UsernameNotFoundException("No user found with username: " + username);
}
logger.info("CustomUserDetailService password ::::: " + savedUser.get().getPassword());
return new org.springframework.security.core.userdetails.User(savedUser.get().getEmail(),
passwordEncoder.encode(savedUser.get().getPassword()), true, true, true, true, getAuthorities());
}
private Collection<? extends GrantedAuthority> getAuthorities() {
// TODO Auto-generated method stub
final List<GrantedAuthority> authorities = new ArrayList<>();
List<String> roles = Arrays.asList("Associate", "Manager");
for (String string : roles) {
authorities.add(new SimpleGrantedAuthority(string));
}
return authorities;
}
}
I am getting an exception:
M 19-Sept-2022 02:21:38.120 [http-nio-8080-exec-6] TRACE [org.springframework.security.oauth2.client.web.OAuth2LoginAuthenticationFilter:346] - Failed to process authentication request
org.springframework.security.authentication.ProviderNotFoundException: No AuthenticationProvider found for org.springframework.security.oauth2.client.authentication.OAuth2LoginAuthenticationToken
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:234)
at org.springframework.security.oauth2.client.web.OAuth2LoginAuthenticationFilter.attemptAuthentication(OAuth2LoginAuthenticationFilter.java:195)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:227)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:217)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
at org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectFilter.doFilterInternal(OAuth2AuthorizationRequestRedirectFilter.java:178)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:103)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:89)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90)
at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75)