Spring Security OAuth2 Database — Bad Credentials Error

I am building a Spring application which uses a database as the Authorisation Service in an OAuth2 configuration.

Here is my SecurityConfig class for Spring Security

public class SecurityConfiguration extends WebSecurityConfigurerAdapter {


@Autowired
private CustomUserDetailsService userDetailsService;

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {

    auth.userDetailsService(userDetailsService)
            .passwordEncoder(getPasswordEncoder());
}


@Override
protected void configure(HttpSecurity http) throws Exception {

    http.csrf().disable();
    http.authorizeRequests()
            .antMatchers("**/secured/**").authenticated()
            .anyRequest().permitAll()
            .and()
            .formLogin().permitAll();
}

private PasswordEncoder getPasswordEncoder() {
    return new PasswordEncoder() {
        @Override
        public String encode(CharSequence charSequence) {
            return charSequence.toString();
        }

        @Override
        public boolean matches(CharSequence charSequence, String s) {
            return true;
        }
    };
}
}

Here is my Repository for my database, which aims to locate users on their email.

@Repository
public interface UsersRepository extends JpaRepository<User, Integer> {
   @Query
   Optional<User> findByEmail(String email);
}

Here is my Service class:

@Service("userDetailsService")
public class CustomUserDetailsService implements UserDetailsService {

@Autowired
private UsersRepository usersRepository;


@Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
    Optional<User> optionalUsers = usersRepository.findByEmail(email);

    optionalUsers
            .orElseThrow(() -> new UsernameNotFoundException("Username not found"));
    return optionalUsers
            .map(CustomUserDetails::new).get();


}
}

When I type an email and password I have on the database it comes back saying

"Bad Credentials"

Can anybody spot anything wrong with my set up?

If I remove the

@PreAuthorise("hasRole('ROLE_admin')")

in the controller which would get rid of the login screen but I wish to have the login screen.

As requested by the comments, here is my database schema. I use H2 to provide an in memory database.

DROP TABLE IF EXISTS 'User'

CREATE TABLE IF NOT EXISTS User (
id INT,
role VARCHAR(5),
title VARCHAR(5),
firstname VARCHAR(20),
lastname VARCHAR(20),
email VARCHAR(50),
password VARCHAR(50),
modified DATETIME,
accessed DATETIME
)

INSERT INTO User VALUES
(
 '1',
 'admin',
 'mr',
 'bob',
 'smith',
 '[email protected]',
 'gobob',
 '1993-10-25 22:10:00',
 '2018-04-09 08:30:00'
 ),
 ....

spring.h2.console.enabled=true
spring.h2.console.path=/h2
# Datasource
spring.datasource.url=jdbc:h2:file:path/to/application/src/main/resources/DATA-DUMP.sql
spring.datasource.username=<user>
spring.datasource.password=<pass>
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.testWhileIdle=true
spring.datasource.validationQuery=SELECT 1
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update
spring.jpa.hibernate.naming-     strategy=org.hibernate.cfg.ImprovedNamingStrategy
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect

I don’t think my H2 is populating my Table it creates:

2018-04-17 13:52:43.523  INFO 4407 --- [           main] o.hibernate.annotations.common.Version   : HCANN000001: Hibernate Commons Annotations {5.0.1.Final}
2018-04-17 13:52:43.583  INFO 4407 --- [           main] org.hibernate.dialect.Dialect            : HHH000400: Using dialect: org.hibernate.dialect.MySQL5Dialect
Hibernate: create table hibernate_sequence (next_val bigint) engine=MyISAM
Hibernate: insert into hibernate_sequence values ( 1 )
Hibernate: create table user (id integer not null, accessed datetime, email varchar(255), firstname varchar(255), lastname varchar(255), modified datetime, password varchar(255), role varchar(255), title varchar(255), primary key (id)) engine=MyISAM
2018-04-17 13:52:43.881  INFO 4407 --- [           main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'

Answer

Although you’re currently getting a Bad Credentials message, you might run into another problem afterward:

@PreAuthorise("hasRole('ROLE_admin')")

Note that hasRole is case sensitive, and it might be possible that the correct role is ROLE_ADMIN. Also, depending on your version of Spring Security, you might need to omit ROLE_ and simply use

@PreAuthorise("hasRole('ADMIN')")

The problem

Like I mentioned in the comments, with your implementation of PasswordEncoder, the password you use to login doesn’t matter as long as the username exists because your implementation’s matches method always return true.

In other words, the problem is likely to be that your repository cannot find any user with the username you’re trying to test.

Your database is most likely empty.

UPDATE

The User table is automatically created by Hibernate after reading all class annotated with @Entity, not because you wrote it in your schema file.

Create a file named data-h2.sql in src/main/resources and move all insertions there, e.g.:

INSERT INTO User VALUES (
  '1',
  'admin',
  'mr',
  'bob',
  'smith',
  '[email protected]',
  'gobob',
  '1993-10-25 22:10:00',
  '2018-04-09 08:30:00'
),
...

See Spring Boot – Loading Initial Data for further details

Leave a Reply

Your email address will not be published. Required fields are marked *