AuthenticationManager.authenticates gives me StackOverflowError

this morning I implemented my own login controller with Spring-Security JWT and it was working perfectly.

Now i tried the same without changing the code (That is what the git repository said) and I am receving a java.lang.StackOverflowError: null when the AuthenticationManager.authenticate the user.

This is the code:

Security Configuration:

@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    RestAuthenticationEntryPoint restAuthenticationEntryPoint;

    @Autowired
    UserRepository userRepository;

    @Bean
    public PasswordEncoder encoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        super.configure(auth);
    }

    @Bean(name = BeanIds.AUTHENTICATION_MANAGER)
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
            .sessionManagement().sessionCreationPolicy( SessionCreationPolicy.STATELESS )
        .and()
        .addFilter( new JwtAuthorizationFilter( authenticationManager(),restAuthenticationEntryPoint,userRepository ) );
        http.exceptionHandling().authenticationEntryPoint( restAuthenticationEntryPoint );
        http.authorizeRequests()
            .antMatchers( HttpMethod.POST,"/Auth/login" ).permitAll()
            .antMatchers( HttpMethod.POST,"/Auth/signup" ).permitAll()
            .anyRequest().authenticated();
    }
}

LoginConroller:

@RestController
@RequestMapping("/Auth")
public class AuthController {

    @Autowired
    private AuthService authService;


    @RequestMapping(value = "/signup", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
    public SignUpDTO signUp(@RequestBody SignUpDTO signUpDTO){
        return authService.signUp( signUpDTO );
    }

    @RequestMapping(value = "/login", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
    public LogedUserDTO login(@RequestBody LoginDTO loginDTO){
        return authService.login( loginDTO );
    }
}

Authentication Service:

@Service
@Transactional
public class AuthServiceImpl implements AuthService {

    private static final String EMAIL_PATTERN =
        "^[_A-Za-z0-9-+]+(.[_A-Za-z0-9-]+)*@" + "[A-Za-z0-9-]+(.[A-Za-z0-9]+)*(.[A-Za-z]{2,})$";

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    @Qualifier(BeanIds.AUTHENTICATION_MANAGER)
    private AuthenticationManager authenticationManagerBean;

    @Override
    public SignUpDTO signUp(SignUpDTO signUpDTO) {

        validateSignUpRequest( signUpDTO );
        User newUser = mapUserFromSignUp( signUpDTO );
        userRepository.save( newUser );
        return signUpDTO;
    }

    public LogedUserDTO login(LoginDTO loginDTO) {

        User user = userRepository.findByEmail( loginDTO.getEmail() );

        if (user == null) {
            throw new LoginSignUpException( AuthErrorCodes.LOGIN_ERROR_USER_NOT_FOUND );
        } else if (user.getPassword() == null) {
            throw new LoginSignUpException( AuthErrorCodes.LOGIN_ERROR_NULL_PASSWORD );
        } else if (!validPassword( loginDTO.getPassword(), user.getPassword() )) {
            throw new LoginSignUpException( AuthErrorCodes.LOGIN_ERROR_WRONG_PASSWORD );
        }

        UsernamePasswordAuthenticationToken authenticationWithToken =
            new UsernamePasswordAuthenticationToken( loginDTO.getEmail(), loginDTO.getPassword(), null );
        Authentication authentication = authenticationManagerBean.authenticate( authenticationWithToken );

        String token = generateToken( user.getEmail() );

        LogedUserDTO logedUserDTO =
            new LogedUserDTO( user.getEmail(), TokenProperties.PREFIX + token, TokenProperties.EXPIRATION_TIME,
                null );

        return logedUserDTO;
    }

It fails here: Authentication authentication = authenticationManagerBean.authenticate( authenticationWithToken );

I swear it was working fine but suddently:

java.lang.StackOverflowError: null
   at org.springframework.aop.framework.AdvisedSupport$MethodCacheKey.equals(AdvisedSupport.java:596) ~[spring-aop-5.1.8.RELEASE.jar:5.1.8.RELEASE]
   at java.util.concurrent.ConcurrentHashMap.get(ConcurrentHashMap.java:940) ~[na:1.8.0_161]
   at org.springframework.aop.framework.AdvisedSupport.getInterceptorsAndDynamicInterceptionAdvice(AdvisedSupport.java:481) ~[spring-aop-5.1.8.RELEASE.jar:5.1.8.RELEASE]
   at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:196) ~[spring-aop-5.1.8.RELEASE.jar:5.1.8.RELEASE]
   at com.sun.proxy.$Proxy110.authenticate(Unknown Source) ~[na:na]
   at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:200) ~[spring-security-core-5.1.5.RELEASE.jar:5.1.5.RELEASE]
   at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$AuthenticationManagerDelegator.authenticate(WebSecurityConfigurerAdapter.java:503) ~[spring-security-config-5.1.5.RELEASE.jar:5.1.5.RELEASE]
   at sun.reflect.GeneratedMethodAccessor57.invoke(Unknown Source) ~[na:na]
   at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_161]
   at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_161]
   at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343) ~[spring-aop-5.1.8.RELEASE.jar:5.1.8.RELEASE]
   at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:205) ~[spring-aop-5.1.8.RELEASE.jar:5.1.8.RELEASE]
   at com.sun.proxy.$Proxy110.authenticate(Unknown Source) ~[na:na]
AND SO ON

I remember that it was perfecty giving me the token back, it's very weird that now it return this error.

If any one could help me I would appreciate it very much because i can not continue with the task

Thanks in advance

I have tried a lot of thing already but i cant find the solution.

Upvotes: 3

Views: 3536

Answers (2)

Tarun Singh
Tarun Singh

Reputation: 97

Remove UserDetailsService bean creation from config file when you are using custom AuthenticationProvider.

Upvotes: 2

giulianopz
giulianopz

Reputation: 350

It's late, but nonetheless I suggest this simple solution to avoid using the UserDetailService, as Gabriel García Garrido asked. Just create your minimal implementation of AuthenticationManager and use it instead of your bean, as you can see in Spring documentation:

    import org.springframework.security.authentication.*;        
    import org.springframework.security.core.*;
    import org.springframework.security.core.authority.SimpleGrantedAuthority;
    import org.springframework.security.core.context.SecurityContextHolder;
        
    public class AuthenticationExample {
          private static AuthenticationManager am = new SampleAuthenticationManager();
        
          public static void main(String[] args) throws Exception {
            BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        
            while(true) {
              System.out.println("Please enter your username:");
              String name = in.readLine();
              System.out.println("Please enter your password:");
              String password = in.readLine();
              try {
                Authentication request = new UsernamePasswordAuthenticationToken(name, password);
                Authentication result = am.authenticate(request);
                //to save user into the session
               SecurityContext sc =  SecurityContextHolder.getContext();
               sc.setAuthentication(result);
               HttpSession session = req.getSession(true);
               session.setAttribute("SPRING_SECURITY_CONTEXT_KEY", sc);
                break;
              } catch(AuthenticationException e) {
                System.out.println("Authentication failed: " + e.getMessage());
              }
            }
            System.out.println("Successfully authenticated. Security context contains: " +
                      SecurityContextHolder.getContext().getAuthentication());
          }
        }
    

public class SampleAuthenticationManager implements AuthenticationManager {
      static final List<GrantedAuthority> AUTHORITIES = new ArrayList<GrantedAuthority>();
    
      static {
        AUTHORITIES.add(new SimpleGrantedAuthority("ROLE_USER"));
      }
    
      public Authentication authenticate(Authentication auth) throws AuthenticationException {
        if (auth.getName().equals(auth.getCredentials())) {
          return new UsernamePasswordAuthenticationToken(auth.getName(),
            auth.getCredentials(), AUTHORITIES);
          }
          throw new BadCredentialsException("Bad Credentials");
      }
    }

Upvotes: 1

Related Questions