Login errors in spring boot: Encoded password does not look like BCrypt - spring

I ran my spring boot project in idea, register, then I have the problem when I login. It redirected to the "localhost:8080/login?error" and has the following in idea console
Encoded password does not look like BCrypt
I've searched the answer in stackoverflow and saw this the link. But It seems to be useless to me because my configure extends WebSecurityConfigurerAdapter not AuthorizationServerConfigurerAdapter. My configure class is
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private WorkersRepository workersRepository;
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/submit").access("hasRole('WORKER')")
.anyRequest().permitAll()
.and()
.formLogin()
.loginPage("/login")
.and()
.logout()
.logoutSuccessUrl("/")
.and()
.rememberMe()
.tokenValiditySeconds(4838400)
.key("workerKey");
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(new UserDetailsService() {
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Worker worker = workersRepository.findByUsername(username);
return workersRepository.findByUsername(username);
}
}).passwordEncoder(new BCryptPasswordEncoder()).and()
.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
.withUser("admin").password("123456").roles("ADMIN","WORKER");
}
}
My Worker class is
#Entity
public class Worker implements UserDetails {
private static final long serialversionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#NotNull
#Size(min = 5, max = 16, message = "{username.size}")
private String username;
#NotNull
#Size(min = 2, max = 30, message = "{firstName.size}")
private String firstname;
#NotNull
#Size(min = 2, max = 30, message = "{lastName.size")
private String lastname;
#NotNull
#Size(min = 5, max = 25,message = "{password.size}")
private String password;
#NotNull
#Size(min = 2, max = 30, message = "{profession,size}")
private String profession;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getFirstname() {
return firstname;
}
public void setFirstname(String firstname) {
this.firstname = firstname;
}
public String getLastname() {
return lastname;
}
public void setLastname(String lastname) {
this.lastname = lastname;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getProfession() {
return profession;
}
public void setProfession(String profession) {
this.profession = profession;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
//UserDetails methods
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return Arrays.asList(new SimpleGrantedAuthority("WORKER"));
}
#Override
public boolean isAccountNonExpired() {
return true;
}
#Override
public boolean isAccountNonLocked() {
return true;
}
#Override
public boolean isCredentialsNonExpired() {
return true;
}
#Override
public boolean isEnabled() {
return true;
}
}
My WorkersRepository is
package com.rieunity.workinghours;
import org.springframework.data.jpa.repository.JpaRepository;
public interface WorkersRepository extends JpaRepository<Worker, String> {
Worker findByUsername(String username);
}
I did not login with user admin, I registered a new user in register.html and succeeded. Then I login in login page and failed with the error:
Encoded password does not look like BCrypt
Did I miss something?

I've solved the problem. Since I encoded the password by using BCryptPasswordEncoder, I should store the password in this form. Hence the solution is adding
String encodedPassword = new BCryptPasswordEncoder().encode(worker.getPassword());
worker.setPassword(encodedPassword);
into the "/register" post request
#RequestMapping(value = "/register", method = RequestMethod.POST)
public String registrationProcessing(#Valid Worker worker, Errors errors, RedirectAttributes model) {
if(errors.hasErrors()) {
return "registerForm";
};
String encodedPassword = new BCryptPasswordEncoder().encode(worker.getPassword());
worker.setPassword(encodedPassword);
workersRepository.save(worker);
model.addAttribute("username", worker.getUsername());
model.addFlashAttribute("worker", worker);
return "redirect:/";
}

The password field for a BCrypt should be at least 60 character because the result hash has 60 char.
#Size(min = 5, max = 60,message = "{password.size}")
private String password;

I had a same issue and solution is simple , first open online Bcrypt ecrypter site in browser :
https://www.dailycred.com/article/bcrypt-calculator
and first try in here.Java is use 12 number of rounds in Brcypt as default.You must use 12 ! not another number.

Related

Spring Security 5.7 - How to return custom UserDetails

I've seen a lot of examples where a user creates a custom UserDetailsService in order to override the loadUserByUsername method and return a custom implementation of a UserDetails object.
This was done previously with sth like this
#Override
public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
Now with the new version I'm confused on how to do this
I created a Bean and used the JdbcUserDetailsManager, I can configure my custom queries for users and authorities tables
#Bean
public UserDetailsManager userDetailsManager(DataSource dataSource) {
String usersByUsernameQuery = "select username, password, enabled from tbl_users where username = ?";
String authsByUserQuery = "select username, authority from tbl_authorities where username = ?";
JdbcUserDetailsManager userDetailsManager = new JdbcUserDetailsManager(dataSource);
userDetailsManager.setUsersByUsernameQuery(usersByUsernameQuery);
userDetailsManager.setAuthoritiesByUsernameQuery(authsByUserQuery);
return userDetailsManager;
}
but how to return a custom UserDetails object with an extra field, e.g. an email with the new version?
OK after many tries what I did was to remove completely JdbcUserDetailsManager stuff from my custom SecurityConfig class and I created a custom UserDetailsService and custom UserDetails class and it worked.
So security config class had no code regarding the authentication of the users.
I was very confused because I thought that somehow I had to create a #Bean inside the config class, implement the authentication myself and in general that all this authentication code had to be done inside the config class, but it worked with this approach.
#Service
public class MyCustomUserDetailsService implements UserDetailsService {
#Autowired
UserRepository userRepository;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username);
if (user == null) {
throw new UsernameNotFoundException("User Not Found with username: " + username);
}
return MyUserDetails.build(user);
}
}
And the details class
public class MyUserDetails implements UserDetails {
private String username;
private String firstName;
private String lastName;
#JsonIgnore
private String password;
private Collection<? extends GrantedAuthority> authorities;
public MyUserDetails(String username, String firstName, String lastName, String password,
Collection<? extends GrantedAuthority> authorities) {
this.username = username;
this.firstName = firstName;
this.lastName = lastName;
this.password = password;
this.authorities = authorities;
}
public static MyUserDetails build(User user) {
List<GrantedAuthority> authorities = user.getRoles().stream()
.map(role -> new SimpleGrantedAuthority(role.getAuthority()))
.collect(Collectors.toList());
return new MyUserDetails(
user.getUsername(),
user.getFirstName(),
user.getLastName(),
user.getPassword(),
authorities);
}
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorities;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
#Override
public String getPassword() {
return password;
}
#Override
public String getUsername() {
return username;
}
#Override
public boolean isAccountNonExpired() {
return true;
}
#Override
public boolean isAccountNonLocked() {
return true;
}
#Override
public boolean isCredentialsNonExpired() {
return true;
}
#Override
public boolean isEnabled() {
return true;
}
#Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
MyUserDetails user = (MyUserDetails) o;
return Objects.equals(username, user.username);
}
}
Also check Spring Security Architecture

Basic Auth Spring security with enum Roles and Permissions always return 401

i am new to Spring Security, i just have a User with enum Role and enum permissions, i wanted to have a basic auth using postman and to test it , but i always get 401 status code.
I am not sure what is the problem exactly because no errors i receive or no exeption occured but all i know is that i can not log in with basic auth using postman perhaps my configuration is not perfect or UserDetails and UserDetailsServices are not like they should be or maybe capturing the authorities in UserDetails is not working at all.
or maybe my password is not encoded in database and that's why the authentication can not pass.
My ApplicationSecurityConfig:
`#Configuration
#EnableWebSecurity
public class ApplicationSecurityConfig extends WebSecurityConfigurerAdapter {
//private final PasswordEncoder passwordEncoder;
private final ApplicationUserDetailsService applicationUserDetailsService;
#Autowired
public ApplicationSecurityConfig(PasswordEncoder passwordEncoder,
ApplicationUserDetailsService applicationUserDetailsService) {
// this.passwordEncoder = passwordEncoder;
this.applicationUserDetailsService = applicationUserDetailsService;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/","/index","/css/*","/js/*") .permitAll()
//MEMBER
.antMatchers("/api/**").hasAnyRole(
ApplicationUserRole.SUPER_ADMIN.name(),
ApplicationUserRole.ADMIN.name(),
ApplicationUserRole.MEMBER.name()
)
.antMatchers(HttpMethod.GET,"/api/**").hasAnyAuthority(
ApplicationUserPermissions.SUPER_ADMIN_READ.name(),
ApplicationUserPermissions.ADMIN_READ.name(),
ApplicationUserPermissions.MEMBER_READ.name()
)
//ADMIN
.antMatchers("/admin/api/**").hasAnyRole(ApplicationUserRole.ADMIN.name(),ApplicationUserRole.SUPER_ADMIN.name())
.antMatchers(HttpMethod.POST,"/admin/api/**").hasAnyAuthority(
ApplicationUserPermissions.SUPER_ADMIN_WRITE.name(),
ApplicationUserPermissions.ADMIN_WRITE.name()
)
.antMatchers(HttpMethod.PUT,"/admin/api/**").hasAnyAuthority(
ApplicationUserPermissions.SUPER_ADMIN_WRITE.name(),
ApplicationUserPermissions.ADMIN_WRITE.name()
)
.antMatchers(HttpMethod.PATCH,"/admin/api/**").hasAnyAuthority(
ApplicationUserPermissions.SUPER_ADMIN_WRITE.name(),
ApplicationUserPermissions.ADMIN_WRITE.name()
)
.antMatchers(HttpMethod.DELETE,"/admin/api/**").hasAnyAuthority(
ApplicationUserPermissions.SUPER_ADMIN_WRITE.name(),
ApplicationUserPermissions.ADMIN_WRITE.name()
)
//SUPER_ADMIN
.antMatchers("/super/admin/api/**").hasAnyRole(
ApplicationUserRole.SUPER_ADMIN.name()
)
.antMatchers(HttpMethod.POST,"/super/admin/api/**").hasAuthority(
ApplicationUserPermissions.SUPER_ADMIN_WRITE.name()
)
.antMatchers(HttpMethod.PUT,"/super/admin/api/**").hasAuthority(
ApplicationUserPermissions.SUPER_ADMIN_WRITE.name()
)
.antMatchers(HttpMethod.PATCH,"/super/admin/api/**").hasAuthority(
ApplicationUserPermissions.SUPER_ADMIN_WRITE.name()
)
.antMatchers(HttpMethod.DELETE,"/super/admin/api/**").hasAuthority(
ApplicationUserPermissions.SUPER_ADMIN_WRITE.name()
)
.anyRequest()
.authenticated()
.and()
.httpBasic();
}
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(applicationUserDetailsService);
}`
ApplicationUserRole:
package com.github.workTimeMangementGithub.security;
import com.google.common.collect.Sets; import
org.springframework.security.core.GrantedAuthority; import
org.springframework.security.core.authority.SimpleGrantedAuthority;
import java.util.Set; import java.util.stream.Collectors;
public enum ApplicationUserRole {
SUPER_ADMIN(Sets.newHashSet(ApplicationUserPermissions.SUPER_ADMIN_READ,ApplicationUserPermissions.SUPER_ADMIN_WRITE)),
ADMIN(Sets.newHashSet(ApplicationUserPermissions.ADMIN_READ,ApplicationUserPermissions.ADMIN_WRITE)),
MEMBER(Sets.newHashSet(ApplicationUserPermissions.MEMBER_READ,ApplicationUserPermissions.MEMBER_WRITE));
private final Set<ApplicationUserPermissions> permissions;
ApplicationUserRole(Set<ApplicationUserPermissions> permissions) {
this.permissions = permissions;
}
public Set<ApplicationUserPermissions> getPermissions() {
return permissions;
}
public Set<GrantedAuthority> getGrantedAuthorities() {
Set<GrantedAuthority> permissions = getPermissions().stream().map(permission-> new
SimpleGrantedAuthority(permission.getPermission())).collect(Collectors.toSet());
permissions.add(new SimpleGrantedAuthority("ROLE_"+this.name()));
return permissions;
}
}
Here i have implemented User Role for Role Based Auth and i connect them with their permissions
My ApplicationUserPermissions
public enum ApplicationUserPermissions {
SUPER_ADMIN_WRITE("super_admin:write"),
SUPER_ADMIN_READ("super_admin:read"),
ADMIN_WRITE("admin:write"),
ADMIN_READ("admin:read"),
MEMBER_WRITE("member:write"),
MEMBER_READ("member:read");
private final String permission;
ApplicationUserPermissions(String permission) {
this.permission = permission;
}
public String getPermission() {
return permission;
}
}
Here i Created the permissions for every User Role to determine all permissions and privileges for each role.
My ApplicationUserDetailsService
import java.util.Optional;
#Service
#Slf4j
public class ApplicationUserDetailsService implements UserDetailsService {
private final UserRepository userRepository;
#Autowired
public ApplicationUserDetailsService(UserRepository userRepository) {
this.userRepository = userRepository;
}
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Optional<User> user = Optional.of(userRepository.findUserByUsername(username));
if(user.get() != null){
UserDTO userDto = UserMapper.toDTO(user.get());
log.info("User Found "+ userDto.getUsername());
}else {
log.warn("User NOT Found ");
}
user.orElseThrow(() -> new UsernameNotFoundException("Not found: " + username));
return new ApplicationUserDetails(user.get());
}
}
Here i have implemented ApplicationUserDetailsService and called the method loadUserByUsername with handling UserNotFoundException in case the user is not found.
My ApplicationUserDetails:
#Slf4j
public class ApplicationUserDetails implements UserDetails {
private List<? extends GrantedAuthority> grantedAuthorities;
private String username;
private String password;
private boolean isAccountNonExpired;
private boolean isAccountNonLocked;
private boolean isCredentialsNonExpired;
private boolean isEnabled;
public ApplicationUserDetails(List<? extends GrantedAuthority> grantedAuthorities, String username, String password, boolean isAccountNonExpired, boolean isAccountNonLocked, boolean isCredentialsNonExpired, boolean isEnabled) {
this.grantedAuthorities = grantedAuthorities;
this.username = username;
this.password = password;
this.isAccountNonExpired = isAccountNonExpired;
this.isAccountNonLocked = isAccountNonLocked;
this.isCredentialsNonExpired = isCredentialsNonExpired;
this.isEnabled = isEnabled;
}
public ApplicationUserDetails(User user) {
List<? extends GrantedAuthority> authorities = new ArrayList<>(ApplicationUserRole.ADMIN.getGrantedAuthorities());
this.grantedAuthorities = authorities;
log.warn("authorities "+authorities);
this.username = user.getUsername();
this.password = user.getPassword();
this.isAccountNonExpired = true;
this.isAccountNonLocked = true;
this.isCredentialsNonExpired = true;
this.isEnabled = true;
}
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return grantedAuthorities;
}
#Override
public String getPassword() {
return password;
}
#Override
public String getUsername() {
return username;
}
#Override
public boolean isAccountNonExpired() {
return isAccountNonExpired;
}
#Override
public boolean isAccountNonLocked() {
return isAccountNonLocked;
}
#Override
public boolean isCredentialsNonExpired() {
return isCredentialsNonExpired;
}
#Override
public boolean isEnabled() {
return isEnabled;
}
Here i have implemented ApplicationUserDetails and override some methods.
My problem is that i can not authenticate using basic auth via Postman.
Here a screen capture of the users of the database:
I am trying to find out what is wrong with my code , i follow many tutorials but no full example of working with enum Roles and permissions with JPA authentication , i spend a lot of time and i still don't know what is wrong exactly with my code.
The logger Slf4j is no showing the authenticated user in console and i don't know why.
Postman:
Spring Boot log Captures:
Any help will be so appreciated.

Spring Security method security not working: PreAuthorize allowing all users instead of limited users

I am trying to implement method level security using spring security. I have annotated 2 separate methods with the #PreAuthorize annotation. In this example, I have 2 users ADMIN and USER. And I have restricted 2 methods both to each of the users. When I try logging in as USER I am able to access both the endpoint restricted to USER (getSomeTextForUser()) as well as to ADMIN(getSomeTextForAdmin()). So this is definitely not right and after viewing multiple tutorials I have not seen the error in my ways.
Expected behavior: person logged in as USER should get an error when trying to access the endpoint /test/admin since it calls getSomeTextForAdmin(). And the similar behavior should happen for the admin when calling /test/user since it calls getSomeTextForUser().
Main class
#SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
My controller class
#RestController
public class UserController {
#GetMapping("/")
public String home() {
return ("<h1> Welcome </h1>");
}
#GetMapping("/test/admin")
public String test() {
return getSomeTextForAdmin();
}
#GetMapping("/test/user")
public String test2() {
return getSomeTextForUser();
}
#PreAuthorize("hasRole('ROLE_ADMIN')")
public String getSomeTextForAdmin() {
return "For Admin Only!";
}
#PreAuthorize("hasRole('ROLE_USER')")
public String getSomeTextForUser() {
return "For User Only!";
}
}
The security configuration where I've enabled the prePost feature
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
UserDetailsService userDetailsService;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/test").hasAnyRole("ADMIN", "USER")
.antMatchers("/").permitAll()
.and().formLogin();
#Bean
public PasswordEncoder getPasswordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
}
My User details service where I've just placed some default users in memory on startup for testing.
#Repository
public class UserRepositoryImpl implements UserRepository {
Map<String, User> users = new HashMap<>();
public UserRepositoryImpl() {
createDefaultUsers();
}
#Override
public Optional<User> findByUserName(String userName) {
return Optional.of(users.get(userName));
}
private void createDefaultUsers() {
users.put("admin", new User("admin", "pass", "ADMIN"));
users.put("user", new User("user", "pass", "USER"));
}
}
MyUserDetails is here
public class MyUserDetails implements UserDetails {
private final String userName;
private final String password;
private final List<GrantedAuthority> authorities;
public MyUserDetails(User user) {
this.userName = user.getUserName();
this.password = user.getPassword();
this.authorities = Arrays.stream(user.getRoles().split(","))
.map(SimpleGrantedAuthority::new)
.collect(Collectors.toList());
}
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorities;
}
#Override
public String getPassword() {
return password;
}
#Override
public String getUsername() {
return userName;
}
#Override
public boolean isAccountNonExpired() {
return true;
}
#Override
public boolean isAccountNonLocked() {
return true;
}
#Override
public boolean isCredentialsNonExpired() {
return true;
}
#Override
public boolean isEnabled() {
return true;
}
}
And the user class itself
#Entity
#Table(name = "User")
public class User {
public User(String userName, String password, String roles) {
this.userName = userName;
this.password = password;
this.roles = roles;
}
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public boolean isActive() {
return active;
}
public void setActive(boolean active) {
this.active = active;
}
public String getRoles() {
return roles;
}
public void setRoles(String roles) {
this.roles = roles;
}
private String userName;
private String password;
private boolean active;
private String roles;
}
First of all: why do you need this line in your configuration?
.antMatchers("/test").hasAnyRole("ADMIN", "USER")
You don't even have /test endpoint in your controller.
Second thing:
#RestController
public class UserController {
#GetMapping("/")
public String home() {
return ("<h1> Welcome </h1>");
}
#GetMapping("/test/admin")
public String test() {
return getSomeTextForAdmin();
}
#GetMapping("/test/user")
public String test2() {
return getSomeTextForUser();
}
#PreAuthorize("hasRole('ROLE_ADMIN')")
public String getSomeTextForAdmin() {
return "For Admin Only!";
}
#PreAuthorize("hasRole('ROLE_USER')")
public String getSomeTextForUser() {
return "For User Only!";
}
}
It shows you don't understand what Spring Proxy is. Unless you learn it, soon or later you will fall into problems.
I really encourge you to read about it but for now one takeaway to remember:
Annotated methods must be called from different class. In your case you call annotated methods from the same class and Spring doesn't care about any annotation.
You should use somtehing like this:
#Service
public class UserService {
#PreAuthorize("hasRole('ROLE_ADMIN')")
public String getSomeTextForAdmin() {
return "For Admin Only!";
}
#PreAuthorize("hasRole('ROLE_USER')")
public String getSomeTextForUser() {
return "For User Only!";
}
}
#RestController
public class UserController {
#Autowired
private UserService userService;
#GetMapping("/")
public String home() {
return ("<h1> Welcome </h1>");
}
#GetMapping("/test/admin")
public String test() {
return userService.getSomeTextForAdmin();
}
#GetMapping("/test/user")
public String test2() {
return userService.getSomeTextForUser();
}
}

Spring Security and JWT in spring boot application

I am struggling a lot in understanding the concepts of spring security. I referred few examples online and tried to implement that in my project. But it is not working and I am not understanding why.
My WebConfig class is,
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private JwtAuthenticationEntryPoint unauthorizedHandler;
#Autowired
private UserDetailsService userDetailsService;
#Autowired
public void configureAuthentication( AuthenticationManagerBuilder authenticationManagerBuilder ) throws Exception
{
authenticationManagerBuilder.userDetailsService(this.userDetailsService);
}
#Bean
public JwtAuthenticationTokenFilter authenticationTokenFilterBean() throws Exception
{
return new JwtAuthenticationTokenFilter();
}
#Override
protected void configure( HttpSecurity httpSecurity ) throws Exception
{
httpSecurity
// we don't need CSRF because our token is invulnerable
.csrf().disable()
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
// don't create session
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests()
//.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
// allow anonymous resource requests
.antMatchers(HttpMethod.GET, "/", "/*.html", "/favicon.ico", "/**/*.html", "/**/*.css", "/**/*.js")
.permitAll().antMatchers("/login").permitAll().anyRequest().authenticated();
// Custom JWT based security filter
httpSecurity.addFilterBefore(authenticationTokenFilterBean(),
UsernamePasswordAuthenticationFilter.class);
// disable page caching
httpSecurity.headers().cacheControl();
}
}
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
#Autowired
private UserDetailsService userDetailsService;
#Autowired
private JwtTokenUtil jwtTokenUtil;
#Override
protected void doFilterInternal( HttpServletRequest request, HttpServletResponse response, FilterChain chain )
throws ServletException, IOException
{
final String requestHeader = "Authorization";
String username = null;
String authToken = null;
if( requestHeader != null && requestHeader.startsWith("Bearer ") )
{
authToken = requestHeader.substring(7);
try
{
username = jwtTokenUtil.getUsernameFromToken(authToken);
}
catch( IllegalArgumentException e )
{
logger.error("an error occured during getting username from token", e);
}
}
else
{
logger.warn("couldn't find bearer string, will ignore the header");
}
logger.info("checking authentication for user " + username);
if( username != null && SecurityContextHolder.getContext().getAuthentication() == null )
{
// It is not compelling necessary to load the use details from the database. You could also store the information
// in the token and read it from it. It's up to you ;)
UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);
if( jwtTokenUtil.validateToken(authToken, userDetails) )
{
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
logger.info("authenticated user " + username + ", setting security context");
SecurityContextHolder.getContext().setAuthentication(authentication);
}
}
chain.doFilter(request, response);
}
}
Implementation of Spring-securities UserDetailsService
#Component
public class JwtUserDetailsServiceImpl implements UserDetailsService {
#Autowired
private UserModelRepository userModelRepository;
#Override
public UserDetails loadUserByUsername( String username ) throws
UsernameNotFoundException
{
Optional<UserModel> userModelOptional =
userModelRepository.findByMobileNumberAndIsActiveTrue(username);
if( !userModelOptional.isPresent() )
{
throw new UsernameNotFoundException(String.format("No user
found with username '%s'.", username));
}
else
{
return JwtUserFactory.create(userModelOptional.get());
}
}
}
Implementation of UserDetails
public class JwtUser implements UserDetails {
private final Long id;
private final String username;
private final String firstname;
private final String lastname;
private final String password;
private final String email;
private final boolean enabled;
private final Date lastPasswordResetDate;
public JwtUser( Long id, String username, String firstname, String lastname, String email, String password,
boolean enabled, Date lastPasswordResetDate )
{
this.id = id;
this.username = username;
this.firstname = firstname;
this.lastname = lastname;
this.email = email;
this.password = password;
this.enabled = enabled;
this.lastPasswordResetDate = lastPasswordResetDate;
}
#JsonIgnore
public Long getId()
{
return id;
}
#Override
public String getUsername()
{
return username;
}
#JsonIgnore
#Override
public boolean isAccountNonExpired()
{
return true;
}
#JsonIgnore
#Override
public boolean isAccountNonLocked()
{
return true;
}
#JsonIgnore
#Override
public boolean isCredentialsNonExpired()
{
return true;
}
public String getFirstname()
{
return firstname;
}
public String getLastname()
{
return lastname;
}
public String getEmail()
{
return email;
}
#JsonIgnore
#Override
public String getPassword()
{
return password;
}
#Override
public Collection<? extends GrantedAuthority> getAuthorities()
{
return Collections.emptyList();
}
#Override
public boolean isEnabled()
{
return enabled;
}
#JsonIgnore
public Date getLastPasswordResetDate()
{
return lastPasswordResetDate;
}
}
#Component
public class JwtTokenUtil {
static final String CLAIM_KEY_USERNAME = "sub";
static final String CLAIM_KEY_AUDIENCE = "aud";
static final String CLAIM_KEY_CREATED = "iat";
static final String AUDIENCE_UNKNOWN = "unknown";
static final String AUDIENCE_WEB = "web";
static final String AUDIENCE_MOBILE = "mobile";
static final String AUDIENCE_TABLET = "tablet";
private static final long serialVersionUID = -3301605591108950415L;
#Autowired
private TimeProvider timeProvider;
private String secret = "MySecret";
private Long expiration = 1508610600000l;
public String getUsernameFromToken( String token )
{
return getClaimFromToken(token, Claims::getSubject);
}
public Date getIssuedAtDateFromToken( String token )
{
return getClaimFromToken(token, Claims::getIssuedAt);
}
public Date getExpirationDateFromToken( String token )
{
return getClaimFromToken(token, Claims::getExpiration);
}
public String getAudienceFromToken( String token )
{
return getClaimFromToken(token, Claims::getAudience);
}
public <T> T getClaimFromToken( String token, Function<Claims, T> claimsResolver )
{
final Claims claims = getAllClaimsFromToken(token);
return claimsResolver.apply(claims);
}
private Claims getAllClaimsFromToken( String token )
{
return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
}
private Boolean isTokenExpired( String token )
{
final Date expiration = getExpirationDateFromToken(token);
return expiration.before(timeProvider.now());
}
private Boolean isCreatedBeforeLastPasswordReset( Date created, Date lastPasswordReset )
{
return (lastPasswordReset != null && created.before(lastPasswordReset));
}
private String generateAudience( Device device )
{
String audience = AUDIENCE_UNKNOWN;
if( device.isNormal() )
{
audience = AUDIENCE_WEB;
}
else if( device.isTablet() )
{
audience = AUDIENCE_TABLET;
}
else if( device.isMobile() )
{
audience = AUDIENCE_MOBILE;
}
return audience;
}
private Boolean ignoreTokenExpiration( String token )
{
String audience = getAudienceFromToken(token);
return (AUDIENCE_TABLET.equals(audience) || AUDIENCE_MOBILE.equals(audience));
}
public String generateToken( UserDetails userDetails, Device device )
{
Map<String, Object> claims = new HashMap<>();
return doGenerateToken(claims, userDetails.getUsername(), generateAudience(device));
}
private String doGenerateToken( Map<String, Object> claims, String subject, String audience )
{
final Date createdDate = timeProvider.now();
final Date expirationDate = new Date(createdDate.getTime() + expiration * 1000);
System.out.println("doGenerateToken " + createdDate);
return Jwts.builder().setClaims(claims).setSubject(subject).setAudience(audience).setIssuedAt(createdDate)
.setExpiration(expirationDate).signWith(SignatureAlgorithm.HS512, secret).compact();
}
public Boolean canTokenBeRefreshed( String token, Date lastPasswordReset )
{
final Date created = getIssuedAtDateFromToken(token);
return !isCreatedBeforeLastPasswordReset(created, lastPasswordReset)
&& (!isTokenExpired(token) || ignoreTokenExpiration(token));
}
public String refreshToken( String token )
{
final Claims claims = getAllClaimsFromToken(token);
claims.setIssuedAt(timeProvider.now());
return doRefreshToken(claims);
}
public String doRefreshToken( Claims claims )
{
return Jwts.builder().setClaims(claims).signWith(SignatureAlgorithm.HS512, secret).compact();
}
public Boolean validateToken( String token, UserDetails userDetails )
{
JwtUser user = (JwtUser) userDetails;
final String username = getUsernameFromToken(token);
final Date created = getIssuedAtDateFromToken(token);
//final Date expiration = getExpirationDateFromToken(token);
return (username.equals(user.getUsername()) && !isTokenExpired(token)
&& !isCreatedBeforeLastPasswordReset(created, user.getLastPasswordResetDate()));
}
}
And the rest controller,
#RestController
public class AuthenticationRestController {
private String tokenHeader = "Authorization";
#Autowired
private AuthenticationManager authenticationManager;
#Autowired
private JwtTokenUtil jwtTokenUtil;
#Autowired
private UserDetailsService userDetailsService;
#RequestMapping( value = "login", method = RequestMethod.POST )
public ResponseEntity<?> createAuthenticationToken( #RequestBody JwtAuthenticationRequest authenticationRequest,
Device device ) throws AuthenticationException
{
// Perform the security
final Authentication authentication = authenticationManager
.authenticate(new UsernamePasswordAuthenticationToken(authenticationRequest.getUsername(),
authenticationRequest.getPassword()));
SecurityContextHolder.getContext().setAuthentication(authentication);
// Reload password post-security so we can generate token
final UserDetails userDetails = userDetailsService.loadUserByUsername(authenticationRequest.getUsername());
final String token = jwtTokenUtil.generateToken(userDetails, device);
// Return the token
return ResponseEntity.ok(new JwtAuthenticationResponse(token));
}
}
In postman I am hitting http://localhost:8080/login and I am passing username and password. In my case both username and password is the users mobile number which I stored the same as mobile number in database too. But it is showing Bad credentials. I am not understanding what is going wrong. Please help me.

Spring boot jpa hibernate not persisting data

I am trying to persist data to database using spring boot - jpa - hibernate.
This is my application.properties:
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/BlurAdmin
spring.datasource.username=blurAdmin
spring.datasource.password =mypassword
spring.datasource.testWhileIdle = true
spring.datasource.validationQuery = SELECT 1
c3p0.acquireIncrement=2
c3p0.minPoolSize=10
c3p0.maxPoolSize=20
c3p0.maxIdleTime=5000
c3p0.maxStatementsPerConnection=50
c3p0.idle_test_period=30000
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect
spring.jpa.show-sql=false
spring.jpa.hibernate.ddl-auto=update
This is HibernateConfiguration.java:
#Configuration
public class HibernateConfiguration {
#Bean
public HibernateJpaSessionFactoryBean sessionFactory(EntityManagerFactory emf) {
HibernateJpaSessionFactoryBean factory = new HibernateJpaSessionFactoryBean();
factory.setEntityManagerFactory(emf);
return factory;
}
}
This is my Model: There is a warning beside #Entity saying :
The project doesn't contain persistant unit
#Entity
#Table(name = "BlurAdminUsers")
public class User implements Serializable{
public static final String ROLE_USER = "ROLE_USER";
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private String username;
private String email;
private String password;
private String role;
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
protected User(){
}
public User(String username,String email,String password){
this.username = username;
this.password = password;
this.email = email;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
This is Repository:
#Transactional
public interface UsersRepository extends JpaRepository<User, Long> {
List<User> findByEmail(String email);
List<User> findByUsername(String username);
}
This is my aop class where I am trying to persist data:
#Component
public class Signup {
private DataValidation dataValidation;
private Message message;
private UsersRepository repository;
#Autowired
public Signup(UsersRepository repository) {
dataValidation = new DataValidation();
this.repository = repository;
}
#Around("execution(* com.ghewareunigps.vts.ui.web.controllers.SignupController.signup(..)) && args(user,..)")
public Message validateAndSignup(ProceedingJoinPoint joinPoint, User user) throws Throwable {
List<User> usersWithEmail = repository.findByEmail(user.getEmail());
List<User> usersWithUsername = repository.findByUsername(user.getUsername()) ;
user.setRole(Roles.ROLE_USER);
if (dataValidation.validate(user.getUsername(), user.getEmail(), user.getPassword())) {
if(usersWithEmail.isEmpty() && usersWithUsername.isEmpty()){
message = (Message) joinPoint.proceed();
try{
repository.save(user);
}catch(Exception ex){
System.out.println(ex);
}
}
else{
message = new Message(false,"Sorry user with email or username already exists");
}
} else {
message = new Message(false, " please recheck your credentials");
}
return message;
}
}
There's no exceptions being thrown and I have added all the dependencies. Can some please tell me where I am going wrong?

Resources