Spring Security 5 - How to implement custom DaoAuthenticationProvider for form login along with OAUTH2 Login

Viewed 45

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)
0 Answers
Related