11

I am trying to setup a REST based web application, where the frontend is using Reactjs and the backend is using Spring Boot. I am also trying to setup a custom authentication provider, and this is where my problems start. When trying to test the login API call, the CustomAuthenticationProvider is never called, and instead the default DaoAuthenticationProvider is used. This causes the login to report "Bad credentials".

I have upload a small sample application to github: spring-boot-auth-demo

To test the login API I use the following curl:

curl -H "Content-Type: application/json" -X POST -d '{"username":"admin","password":"admin"}' http://localhost:8080/api/users/login

The CustomAuthenticationProvider does a simple username/password check and returns an UsernamePasswordAuthenicationToken object.

package no.bluebit.demo;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {

private static final Logger logger =     LoggerFactory.getLogger(CustomAuthenticationProvider.class);

public CustomAuthenticationProvider() {
    logger.info("*** CustomAuthenticationProvider created");
}

@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {

    if(authentication.getName().equals("admin")  && authentication.getCredentials().equals("admin")) {
        List<GrantedAuthority> grantedAuths = new ArrayList<>();
        grantedAuths.add(new SimpleGrantedAuthority("ROLE_USER"));
        grantedAuths.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
        return new UsernamePasswordAuthenticationToken(authentication.getName(), authentication.getCredentials(), grantedAuths);
    } else {
        return null;
    }

}

@Override
public boolean supports(Class<?> authentication) {
    return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);
}

}

The CustomAuthenticationProvider is wired up using the SecurityConfiguration class. When stepping through the code, I can see that the CustomAuthenicationProvider is not in the list of providers used to authenticate the incoming request.

package no.bluebit.demo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    @Autowired
    private CustomAuthenticationProvider customAuthenticationProvider;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
            .authenticationProvider(this.customAuthenticationProvider);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/api/users/login").permitAll()    // Permit access for all to login REST service
                .antMatchers("/").permitAll()                   // Neccessary to permit access to default document
            .anyRequest().authenticated().and()                 // All other requests require authentication
            .httpBasic().and()
            .logout().and()
            .csrf().disable();
    }
}

Why is this not working?

7
  • 1
    Take a look at this: stackoverflow.com/questions/22453550/… Commented Apr 20, 2016 at 13:13
  • 1
    Thank you! The missing @Autowired annotation was the issue. Problem solved! Commented Apr 21, 2016 at 2:18
  • @franDayz maybe add your comment as an answer, so that Håvard Bakke can accept as an answer? Commented Dec 13, 2016 at 9:30
  • @demaniak I just tried but the system converts simple answers to comments... Commented Dec 13, 2016 at 11:19
  • @franDayz just mention, why '@autowired' was required and follow up with the URL then you can add it as a answer :) Commented May 20, 2018 at 2:53

3 Answers 3

0

Try to add on header http this thinks:

Example:

const headers = new HttpHeaders();
headers.set('Access-Control-Allow-Origin', '*');
headers.set('Access-Control-Allow-Methods', 'POST, GET, OPTIONS, DELETE, PUT');
headers.set('Access-Control-Allow-Headers', 'Authorization, Content-Type, Accept, x- 
requested-with, Cache-Control');
headers.set('Content-Type', 'application/json');


this.http.post('http://localhost:8081/loginAngular',
   JSON.stringify({user: 'sdasd', password: 'dasdasd', estado: 'dasdasd', idUsuario: 1, resultado: 'asdasd'}) ,
  {headers: new HttpHeaders().set('Content-Type', 'application/json')}).subscribe(data => {
  console.log(' Data: ' + data);

});

I made this app with spring security and angular! Front: https://github.com/nicobassart/angularforHidra Back: https://github.com/nicobassart/hidra_server

Sign up to request clarification or add additional context in comments.

Comments

-2

Look at the AuthenticationProvider class (respectively it's java doc)

The method authenticate expects to :

 * Performs authentication with the same contract as
 * {@link org.springframework.security.authentication.AuthenticationManager#authenticate(Authentication)}
 * @return a fully authenticated object including credentials. May return
 * <code>null</code> if the <code>AuthenticationProvider</code> is unable to support
 * authentication of the passed <code>Authentication</code> object. In such a case,
 * the next <code>AuthenticationProvider</code> that supports the presented
 * <code>Authentication</code> class will be tried.

If you return null, then the next AuthenticationProvider will be called, which is the defaut one.

I am not sure this is the problem, but this might be something. Try to throw BadCredentialsException, as the AuthenticationManager class tells you to do :

 * <li>A {@link BadCredentialsException} must be thrown if incorrect credentials are
 * presented. Whilst the above exceptions are optional, an
 * <code>AuthenticationManager</code> must <B>always</B> test credentials.</li>

Comments

-2

You have to set the credentials in some other way. Try to see a working example of Username Password token. But your "authenticate" function needs to be the one that sets the credentials.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.