0

I'm trying to populate the database with a hashed password and then log in to my application, by matching the data I'm submitting through my log in form, just like how a typical hashed password is suppose to work. I'm using spring security and spring boot, and so far I know that the log in form is working because I get the error Encoded password does not look like BCrypt. And I know that when I'm submitting the user to the database it's not working because I just see a plain string in the password column in the database. I'm really not sure where I'm going wrong here.

Here's my User object

package com.example.objects;

import java.util.HashSet;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Version;

import com.example.security.PasswordCrypto;
import com.example.security.RoleEnum;

@Entity
@Table(name = "users")
public class User {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;

@Version
private Long version;

@Column(name = "username")
private String username;

@Column(name = "password")
private String password;

@Column(name = "email")
private String email;

@Column(name = "termsOfService")
private Boolean termsOfService;

@OneToMany(mappedBy = "user")
private Set<UserRole> roles;

@OneToMany(mappedBy = "user", fetch = FetchType.LAZY)
private Set<QuestionAnswerSet> questionAnswerSet;


public static User createUser(String username, String email, String password) {
    User user = new User();

    user.username = username;
    user.email = email;
    user.password = PasswordCrypto.getInstance().encrypt(password);

    if(user.roles == null) {
        user.roles = new HashSet<UserRole>();
    }

    //create a new user with basic user privileges
    user.roles.add(
            new UserRole(
                    RoleEnum.USER.toString(),
                    user
            ));

    return user;
}

public Long getId() {
    return id;
}

public void setId(Long id) {
    this.id = id;
}

public Long getVersion() {
    return version;
}

public void setVersion(Long version) {
    this.version = version;
}

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 String getEmail() {
    return email;
}

public void setEmail(String email) {
    this.email = email;
}

public Boolean getTermsOfService() {
    return termsOfService;
}

public void setTermsOfService(Boolean termsOfService) {
    this.termsOfService = termsOfService;
}

public Set<QuestionAnswerSet> getQuestionAnswerSet() {
    return questionAnswerSet;
}

public void setQuestionAnswerSet(Set<QuestionAnswerSet> questionAnswerSet) {
    this.questionAnswerSet = questionAnswerSet;
}

public Set<UserRole> getRoles() {
    return roles;
}

public void setRoles(Set<UserRole> roles) {
    this.roles = roles;
}
}

Here's my Security Config

package com.example.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.csrf.CsrfTokenRepository;
import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    private static PasswordEncoder encoder;

    @Autowired
    private UserDetailsService customUserDetailsService;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf()
        .csrfTokenRepository(csrfTokenRepository());

        http
        .authorizeRequests()
            .antMatchers("/","/home","/register", "/result").permitAll()
            .anyRequest().authenticated();

        http
        .formLogin()
             .loginPage("/login")
                .permitAll()
                .and()
             .logout()
                .permitAll();

    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(customUserDetailsService)
                .passwordEncoder(passwordEncoder());
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        if(encoder == null) {
            encoder = new BCryptPasswordEncoder();
        }

        return encoder;
    }

    private CsrfTokenRepository csrfTokenRepository() 
    { 
        HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository(); 
        repository.setSessionAttributeName("_csrf");
        return repository; 
    }
}

My user detail service

package com.example.service;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.transaction.Transactional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import com.example.dao.UserDao;
import com.example.objects.UserRole;

@Service
@Qualifier("customUserDetailsService")
public class CustomUserDetailsService implements UserDetailsService {

    @Autowired
    private UserDao userDao;

    @Transactional
    @Override
    public UserDetails loadUserByUsername(final String username)
            throws UsernameNotFoundException {

        com.example.objects.User user = userDao.findByUsername(username);
        List<GrantedAuthority> authorities = buildUserAuthority(user.getRoles());

        return buildUserForAuthentication(user, authorities);

    }

    private User buildUserForAuthentication(com.example.objects.User user,
                                            List<GrantedAuthority> authorities) {
        return new User(user.getUsername(), user.getPassword(), authorities);
    }

    private List<GrantedAuthority> buildUserAuthority(Set<UserRole> userRoles) {

        Set<GrantedAuthority> setAuths = new HashSet<GrantedAuthority>();

        // Build user's authorities
        for (UserRole userRole : userRoles) {
            setAuths.add(new SimpleGrantedAuthority(userRole.getRoleName()));
        }

        return new ArrayList<GrantedAuthority>(setAuths);
    }
}

And PasswordCrypto

package com.example.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;

public class PasswordCrypto {

    @Autowired
    private PasswordEncoder passwordEncoder;

    private static PasswordCrypto instance;

    public static PasswordCrypto getInstance() {
        if(instance == null) {
            instance = new PasswordCrypto();
        }

        return instance;
    }

    public String encrypt(String str) {
        return passwordEncoder.encode(str);
    }
}

If anyone knows what I'm doing wrong and could help me out, that would be awesome, also let me know if I need to show anymore code. Thanks in advance.

dochsner
  • 249
  • 2
  • 8
  • 25

2 Answers2

0

Use encoder to user repository like this :

public class UserRepositoryService implements UserService {
    private PasswordEncoder passwordEncoder;

    private UserRepository repository;

    @Autowired
    public UserRepositoryService(PasswordEncoder passwordEncoder,
            UserRepository repository) {
        this.passwordEncoder = passwordEncoder;
        this.repository = repository;
    }

    private boolean emailExist(String email) {
        User user = repository.findByEmail(email);
        if (user != null) {
            return true;
        }
        return false;
    }

    private String encodePassword(RegistrationForm dto) {
        String encodedPassword = null;
        if (dto.isNormalRegistration()) {
            encodedPassword = passwordEncoder.encode(dto.getPassword());
        }

        return encodedPassword;
    }

    @Transactional
    @Override
    public User registerNewUserAccount(RegistrationForm userAccountData)
            throws DuplicateEmailException {
        if (emailExist(userAccountData.getEmail())) {
            LOGGER.debug("Email: {} exists. Throwing exception.",
                    userAccountData.getEmail());
            throw new DuplicateEmailException("The email address: "
                    + userAccountData.getEmail() + " is already in use.");
        }
        String encodedPassword = encodePassword(userAccountData);

        User.Builder user = User.getBuilder().email(userAccountData.getEmail())
                .firstName(userAccountData.getFirstName())
                .lastName(userAccountData.getLastName())
                .password(encodedPassword)
                .background(userAccountData.getBackground())
                .purpose(userAccountData.getPurpose());

        if (userAccountData.isSocialSignIn()) {
            user.signInProvider(userAccountData.getSignInProvider());
        }
        User registered = user.build();
        return repository.save(registered);
    }
}

For morre info, check out this repo

https://bitbucket.org/sulab/biobranch/src/992791aa706d0016de8634ebb6347a81fe952c24/src/main/java/org/scripps/branch/entity/User.java?at=default&fileviewer=file-view-default

  • Thanks, but I actually only had one little problem and that was that I needed to add this line of code in my userController right above the user.save method `user.setPassword(new BCryptPasswordEncoder().encode(user.getPassword()));` – dochsner Nov 03 '15 at 02:15
0

My problem was that I needed to add user.setPassword(new BCryptPasswordEncoder().encode(user.getPassword())); in my UserController Post method right before I saved the user

dochsner
  • 249
  • 2
  • 8
  • 25