I'm developing a Spring boot web application. The problem is in the login scenario. Suppose I have a user registered by the username "Ali". This user can either login with username "Ali" or "ali". The code below represents my spring security config class. It seems while comparing, Spring boot does not check the uppercase lowercase factor, but I want it to be checked.
package nf.something.conf; import nf.something.repo.EventRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.web.servlet.ServletListenerRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.session.SessionRegistry; import org.springframework.security.core.session.SessionRegistryImpl; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.web.AuthenticationEntryPoint; import org.springframework.security.web.authentication.AuthenticationFailureHandler; import org.springframework.security.web.authentication.AuthenticationSuccessHandler; import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler; import org.springframework.security.web.authentication.logout.LogoutSuccessHandler; import org.springframework.security.web.header.writers.StaticHeadersWriter; import org.springframework.security.web.session.HttpSessionEventPublisher; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; import javax.sql.DataSource; /** * Created by reza on 11/12/16. */ @Configuration public class SecurityConf extends WebSecurityConfigurerAdapter { @Autowired private DataSource datasource; @Autowired private EventRepository eventRepository; // Register HttpSessionEventPublisher @Bean public static ServletListenerRegistrationBean httpSessionEventPublisher() { return new ServletListenerRegistrationBean(new HttpSessionEventPublisher()); } @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() // .antMatchers(HttpMethod.POST, "/users/").permitAll() .antMatchers(HttpMethod.GET, "/**").permitAll() .antMatchers(HttpMethod.POST, "/**").permitAll() .antMatchers(HttpMethod.PUT, "/**").permitAll() .antMatchers(HttpMethod.DELETE, "/**").permitAll() .antMatchers("/swagger*").permitAll() //.anyRequest().permitAll() //.and().csrf().disable(); .anyRequest().authenticated() .and().httpBasic() .and().formLogin().successHandler(restAuthenticationSuccessHandler()).failureHandler(restAuthenticationFailureHandler()) .and().logout().logoutSuccessHandler(restLogoutSuccessHandler()) .and().exceptionHandling().authenticationEntryPoint(restAuthenticationEntryPoint()) .and().csrf().disable().cors() //TODO enable csrf when we are ready .and().sessionManagement().maximumSessions(1).maxSessionsPreventsLogin(true).sessionRegistry(sessionRegistry()); http.headers().cacheControl().disable() .addHeaderWriter(new StaticHeadersWriter("WWW-Authenticate","xBasic realm=\"fake\"")); } @Bean public SessionRegistry sessionRegistry() { SessionRegistry sessionRegistry = new SessionRegistryImpl(); return sessionRegistry; } @Bean public WebMvcConfigurer corsConfigurer() { return new WebMvcConfigurerAdapter() { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**").allowedOrigins("*").allowedMethods("PUT", "POST", "GET", "DELETE", "HEAD"); } }; } @SuppressWarnings("SpringJavaAutowiringInspection") @Autowired public void configureGlobal(AuthenticationManagerBuilder auth, UserDetailsService userDetailsService) throws Exception { /*auth .jdbcAuthentication().usersByUsernameQuery("Select username,password, 'true' as enabled from Users where username=?") .authoritiesByUsernameQuery("select username, authority from authorities where username=?") .dataSource(datasource).passwordEncoder(new BCryptPasswordEncoder());*/ auth.userDetailsService(userDetailsService) .passwordEncoder(new BCryptPasswordEncoder()); } @Bean public AuthenticationEntryPoint restAuthenticationEntryPoint() { return new RestAuthenticationEntryPoint(); } @Bean public AuthenticationFailureHandler restAuthenticationFailureHandler() { return new SimpleUrlAuthenticationFailureHandler(); } @Bean public AuthenticationSuccessHandler restAuthenticationSuccessHandler() { return new RESTAuthenticationSuccessHandler(eventRepository); } @Bean public LogoutSuccessHandler restLogoutSuccessHandler() { return new RESTLogoutSuccessHandler(eventRepository); } }
I have also implemented equals
method in User
class:
@Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof User)) return false; User user = (User) o; if (!getUsername().equals(user.getUsername())) return false; if (getName() != null ? !getName().equals(user.getName()) : user.getName() != null) return false; if (getFamily() != null ? !getFamily().equals(user.getFamily()) : user.getFamily() != null) return false; if (getPassword() != null ? !getPassword().equals(user.getPassword()) : user.getPassword() != null) return false; return getMobilePhone() != null ? getMobilePhone().equals(user.getMobilePhone()) : user.getMobilePhone() == null; }
As of Spring Security version 5.7. 1, the default username is user and the password is randomly generated and displayed in the console (e.g. 8e557245-73e2-4286-969a-ff57fe326336 ). Ryan H. Ryan H.
can you please try to alter the column of username :
ALTER TABLE USERS MODIFY username VARCHAR(50) BINARY
As @dur stated in comments, I checked these queries in my database:
Select username, password, 'true' as enabled
from Users
where username = 'Ali'
Select username, password, 'true' as enabled
from Users
where username = 'ali'
and both of them returned same results. So I changed the username
column of my user
table collation as follows (the previous collation was utf8_general_ci
):
SET FOREIGN_KEY_CHECKS=0;
ALTER TABLE `mydb`.`user`
CHANGE `username` `username` VARCHAR(50) CHARSET utf8 COLLATE utf8_bin NOT NULL;
SET FOREIGN_KEY_CHECKS=1;
Now column username
would be checked case sensitive.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With