javaspringspring-securityspring-bootpre-authentication

spring security : make a mysql authentication


I have an issue with Spring Security.

I'm trying to make an authentication with a mysql data checking. I'm using AngularJs, Spring Boot and Spring Security.

I have a webservice rest which is called by $http.post(...). When I launch my app, and if I test my webservice with the chrome plugin "Advanced Rest Client" > "http://localhost:8080/check-login"; it works and I receive the code 200:OK.

But if I want to access to my webservice via Chrome with the same URL. A window with authentication opening. I think it is a pre-authentication by Spring Security. But I don't know how to disable it.

It's an issue because when I want to access to the web service with my browser, it said : "http://localhost:8080/check-login 401 unauthaurized"

Edit : this is my code :

HTML :

<form role="form" ng-submit="controller.login()">

    <div class="form-group">
        <label for="username">Username:</label> 
        <input type="text" class="form-control" id="username" name="username" ng-model="controller.credentials.username"/>
    </div>

    <div class="form-group">
        <label for="password">Password:</label> 
        <input type="password" class="form-control" id="password" name="password" ng-model="controller.credentials.password"/>
    </div>

    <button type="submit" class="btn btn-primary">Submit</button>

</form>

JS :

myModule.controller('NavCtrl',function($rootScope, $location, $http){

    var self = this

    var authenticate = function(credentials, callback) {


        var headers = credentials ? {authorization : "Basic " + btoa(credentials.username + ":" + credentials.password)} : {};

        $http.get('user', {headers : headers}).then(
            function(response) {
                if (response.data.name) {
                    $rootScope.authenticated = true;
                } else {
                    $rootScope.authenticated = false;
                }
                callback && callback();
            }, 
            function() {
                $rootScope.authenticated = false;
                callback && callback();
            }
        );

    }

    authenticate();
    self.credentials = {};

    self.login = function() {
        authenticate(self.credentials, function() {
            if ($rootScope.authenticated) {
                $location.path("/");
                self.error = false;
            } else {
                $location.path("/login");
                self.error = true;
            }
        });
    };

});

My Java REST :

@RestController
public class TestRest {

    @RequestMapping("/user")
    public Principal user(Principal user){
        return user;
    }

}

My Java Spring Boot and Security Configuration :

@SpringBootApplication
public class BusinessBootApplication {

    public static void main(String[] args) {
        SpringApplication.run(BusinessBootApplication.class, args);
    }

    @Configuration
    @Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
    protected static class SecurityConfiguration extends WebSecurityConfigurerAdapter{
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
            .httpBasic()
            .and()
            .authorizeRequests()
            .antMatchers("/index.html","/home.html","/login.html","/").permitAll()
            .anyRequest()
            .authenticated()
            .and()
            .addFilterAfter(new CsrfHeaderFilter(), CsrfFilter.class)
            .csrf()
            .csrfTokenRepository(csrfTokenRepository());
        }

        private CsrfTokenRepository csrfTokenRepository() {
            HttpSessionCsrfTokenRepository repo = new HttpSessionCsrfTokenRepository();
            repo.setHeaderName("X-XSRF-TOKEN");
            return repo;
        }
    }
}

And to finish, my Java about UserDetailsService

@Service
public class UserDetailsServiceImpl implements UserDetailsService {

    public UserDao userDao;

    @Autowired
    public UserDetailsServiceImpl(UserDao _userDao) {
        super();
        userDao = _userDao;
    }

    @Override
    public UserDetails loadUserByUsername(String arg0) throws UsernameNotFoundException {

        UserDetailsImpl userDetailsImpl = null;

        User user = userDao.findByLogin(arg0);

        if(user == null){
            throw new UsernameNotFoundException("Login not found");
        } else{
            userDetailsImpl = new UserDetailsImpl(user);
        }

        return userDetailsImpl;
    }

}




public class UserDetailsImpl implements UserDetails {

    /** The Constant serialVersionUID. */
    private static final long serialVersionUID = 1L;

    /** The _username. */
    private String username;

    /** The _password. */
    private String password;

    public UserDetailsImpl(User user) {
        username = user.getLogin();
        password = user.getPwd();
    }

    /**
     * @param password the password to set
     */
    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public String getPassword() {
        // TODO Auto-generated method stub
        return null;
    }

    /**
     * @param username the username to set
     */
    public void setUsername(String username) {
        this.username = username;
    }

    @Override
    public String getUsername() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public boolean isAccountNonExpired() {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public boolean isAccountNonLocked() {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public boolean isEnabled() {
        // TODO Auto-generated method stub
        return false;
    }

}

Do you have an idea ? Thanks


Solution

  • This window is the Basic Authentication window, in your code you are using Basic Authentication (httpBasic) :

    http.httpBasic()
         .and()
         .authorizeRequests()
         .antMatchers("/index.html","/home.html","/login.html","/").permitAll()
         .anyRequest()
         .authenticated()
    

    So you configure your spring security to apply Basic Authentication if you are trying to access protected urls.

    Based on this configuration, Chrome is checking the http request if it contains the Authentication Header (which includes the user credentials), if yes authentication window is not opened, otherwise chrome will open the authentication window to insert username and password.

    To Solve the window issue, you need to handle the Basic Authentication in angularJS code as you wrote in code below (please check if this code is working fine by monitoring the request header in the chrome developer tool)

    var headers = credentials ? {authorization : "Basic " + btoa(credentials.username + ":" + credentials.password)} : {};
    
            $http.get('user', {headers : headers}).then(
                function(response) {
                    if (response.data.name) {
                        $rootScope.authenticated = true;
                    } else {
                        $rootScope.authenticated = false;
                    }
                    callback && callback();
                }, 
                function() {
                    $rootScope.authenticated = false;
                    callback && callback();
                }
            );
    

    Please note: When you are using Advanced Rest Client Tool, you can pass the the Basic authentication header, and if you don't pass this header, authentication window will not be opened.