Guchelkaben
Guchelkaben

Reputation: 1275

Spring Boot Security sends 404 although credentials are correct - cant resolve redirect path

I got a simple problem for you guys. I face the problem that I always get a 404 response if I implement Spring Security in my Spring Boot application.

I debugged through the entire code and I just find out that the redirect path is always "/" and not the called URL.

For example

call localhost:8080/user/login/ 
-> Spring Security check given credentials
-> they are correct 
-> resolve given path
-> SOMETHING STANGES HAPPENS HERE (Refer to figure (1))
-> resolve path to "/" and not "/user/login/" 
-> Therefore I get the response 404 NOT FOUND because it returns the wrong path

Debugged mode -- determineTargetUrl -> this.targetUrlParameter is not set and therefore the targetUrl will be "/" and not the real targetUrl "/user/login/" . The code is shown in figure (1).

figure(1) Spring Secutiry class - AbstractAuthenticationTargetUrlRequestHandler enter image description here

My Code with Spring Security

WebSecurityConfig

@EnableWebSecurity

public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
            .cors()
            .disable()
            .csrf()
            .disable()
            .authorizeRequests()
            .antMatchers(HttpMethod.POST, "/user/login/").permitAll()
            .antMatchers(HttpMethod.GET, "/user/secret/**").permitAll()
            .and()
            .addFilterBefore(new JWTLoginFilter("/user/login/", authenticationManager()), UsernamePasswordAuthenticationFilter.class)
            .addFilterBefore(new JWTAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
}

}

JWTLoginFilter

public class JWTLoginFilter extends AbstractAuthenticationProcessingFilter {

public JWTLoginFilter(String url, AuthenticationManager authManager) {
    super(new AntPathRequestMatcher(url));
    setAuthenticationManager(authManager);
}

@Override
public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse res) throws AuthenticationException, IOException, ServletException {
    User user = new ObjectMapper().readValue(req.getInputStream(), User.class);

    Optional<User> dbUser = SpringContextBridge.services().getUserRepository().findUserByEmail(user.getEmail());

    dbUser.ifPresent(us -> user.setPassword(SecretGenerator.generateSha256(user.getPassword(), us.getSecret())));

    return getAuthenticationManager()
            .authenticate(new UsernamePasswordAuthenticationToken(user.getEmail(), user.getPassword(), Collections.emptyList())
            );
}

}

JWTAuthenticationFilter

public class JWTAuthenticationFilter extends GenericFilterBean {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
    Authentication authentication = TokenAuthenticationService.getAuthentication((HttpServletRequest) request);

    SecurityContextHolder.getContext().setAuthentication(authentication);
    filterChain.doFilter(request, response);
}

}

UserDetailsServiceImpl

@Service
public class UserDetailsServiceImpl implements UserDetailsService {

private UserRepository userRepository;

@Autowired
public void setUserRepository(UserRepository userRepository) {
    this.userRepository = userRepository;
}

@Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
    Optional<User> user = userRepository.findUserByEmail(email);

    if (!user.isPresent()) {
        throw new UserNotFoundException("User with email: " + email + " not found");
    }
    return new org.springframework.security.core.userdetails.User(user.get().getEmail(), user.get().getPassword(), Collections.emptyList());
}

}

Maybe someone can help me!

Upvotes: 1

Views: 1120

Answers (1)

David Romao
David Romao

Reputation: 90

I had a similar problem and the solution that worked for me was to override the successfulAuthentication method of AbstractAuthenticationProcessingFilter like this

override fun successfulAuthentication(request: HttpServletRequest, response: HttpServletResponse, chain: FilterChain, authResult: Authentication?) {
    logger.info("Successful Authentication for user ${authResult?.principal}")
    SecurityContextHolder.getContext().authentication = authResult
    chain.doFilter(request, response)
}

Note: the example is in kotlin

Upvotes: 1

Related Questions