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