Reputation: 562
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:
@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();
}
}
@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 );
}
}
@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
Reputation: 97
Remove UserDetailsService bean creation from config file when you are using custom AuthenticationProvider.
Upvotes: 2
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