Java-Hashed password value is null - spring

Hello I have spent several hours trying to figure out why my hashed password is null. I am trying to use Spring BCryptPasswordEncoder. I have read several documentations, looked at many different examples, and watched videos on how to use this encryptor but I just can't get it to work. Looking at my MYSQL database I know the password field is populated, but the field for hashPassword remains null. Before anyone flips out I know that the plain password should not be stored in the database, but at the moment this is how I know that the password parameter is not null. As far as I know this is not a duplicate question and if so please direct me to right place, because everything I have seen for the hashing category has not been helpful. Below is a snippet of the code I am using if you need more detail please let me know.
#Entity
public class User {
#Id
#GeneratedValue
private int uid;
#NotNull
#Column(unique = true )
private String username;
#NotNull
private String password;
#Column
private String hashedPassword;
private static final BCryptPasswordEncoder encodedPassword = new BCryptPasswordEncoder();
public User(String username, String password) {
this.username = username;
this.password = password;
this.hashedPassword = hashIt(this.password);
}
public User() { }
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getHashedPassword() {
return hashedPassword;
}
public void setHashedPassword(String hashedPassword) {
this.hashedPassword = hashedPassword;
}
public String hashIt(String password) {
return encodedPassword.encode(password);
}
public boolean isCorrectPassword(String password){
return encodedPassword.matches(password,hashedPassword);
}
}

Related

Springboot: What is the best way to search for a List of an entity using more than one of its characteristics

I am developing a web application in spring-boot, where a user can search for users using a search field. The users being searched (which depends on the value typed into the input field) will be queried according to their username, first name and last-name. This is my UserModel :
#Component
#Entity
#Table(name = "Users")
public class User extends DefaultEntity {
#Column(name = "FirstName")
#NotNull(message = "Enter a FirstName")
private String firstName;
#Column(name = "LastName")
#NotBlank(message = "Enter a LastName")
private String lastName;
#Column(unique = true,name = "UserName")
#NotBlank(message = "Enter a UserName")
private String userName;
#Column(unique = true, name = "Email")
#NotBlank(message = "Please enter an Email address")
#Email(message = "Enter a valid Email")
private String email;
#Column(name = "Password")
#NotBlank(message = "Enter a Password")
private String password;
#Enumerated(EnumType.STRING)
#Column(name = "Gender")
private Gender gender;
#Column(name = "Address")
#NotBlank(message = "Please enter your Home Address")
private String address;
#Column(name = "Country")
#NotBlank(message = "Please enter your Country")
private String country;
#Column(name = "Picture")
private String picture;
#Column(unique = true, name = "PhoneNumber") //make this accept only numbers
private String phoneNumber;
#Column(name = "Bio")
private String bio;
#Enumerated(EnumType.STRING)
#Column(name = "OnlineStatus")
private OnlineStatus onlineStatus;
#Enumerated(EnumType.STRING)
#Column(name = "UserType")
private UserType userType;
#Column(name = "Money")
private double money;
//#MapsId()
#OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(name = "playerstats")
private PlayerStats playerStats;
//columnDefinition = "tinyint default false"
#Column(name = "locked",columnDefinition = "BOOL default false")
private Boolean locked;
#Transient
private MultipartFile file;
public String getFirstName() {
return firstName;
}
public User setFirstName(String firstName) {
this.firstName = firstName;
return this;
}
public String getLastName() {
return lastName;
}
public User setLastName(String lastName) {
this.lastName = lastName;
return this;
}
public String getUserName() {
return userName;
}
public User setUserName(String userName) {
this.userName = userName;
return this;
}
public String getEmail() {
return email;
}
public User setEmail(String email) {
this.email = email;
return this;
}
public String getPassword() {
return password;
}
public User setPassword(String password) {
this.password = password;
return this;
}
public Enum.Gender getGender() {
return gender;
}
public User setGender(Enum.Gender gender) {
this.gender = gender;
return this;
}
public String getAddress() {
return address;
}
public User setAddress(String address) {
this.address = address;
return this;
}
public String getCountry() {
return country;
}
public User setCountry(String country) {
this.country = country;
return this;
}
public String getPicture() {
return picture;
}
public User setPicture(String picture) {
this.picture = picture;
return this;
}
public String getBio() {
return bio;
}
public User setBio(String bio) {
this.bio = bio;
return this;
}
public Enum.OnlineStatus getOnlineStatus() {
return onlineStatus;
}
public User setOnlineStatus(Enum.OnlineStatus onlineStatus) {
this.onlineStatus = onlineStatus;
return this;
}
public Enum.UserType getUserType() {
return userType;
}
public User setUserType(Enum.UserType userType) {
this.userType = userType;
return this;
}
public double getMoney() {
return money;
}
public User setMoney(double money) {
this.money = money;
return this;
}
public String getPhoneNumber() {
return phoneNumber;
}
public User setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
return this;
}
public MultipartFile getFile() {
return file;
}
public User setFile(MultipartFile file) {
this.file = file;
return this;
}
public PlayerStats getPlayerStats() {
return playerStats;
}
public User setPlayerStats(PlayerStats playerStats) {
this.playerStats = playerStats;
return this;
}
public Boolean getLocked() {
return locked;
}
public void setLocked(Boolean locked) {
this.locked = locked;
}
}
this is my method for querying the usermodel in my UserRepository :
#Repository
public interface UserRepository extends JpaRepository<User,Long> {
Page<User> findUsersByUserNameContainingOrFirstNameContainingOrLastNameContaining(String UserName, String FirstName, String LastName, Pageable pageable);
}
My question: Is there a better way or more efficient way to achieve querying the user entity ?
As mentioned in the comments, what you're looking for is a fuzzy search. This is not something you can easily do within a database, but there are separate search engines that you can use:
Apache Solr (platform based on Apache Lucene)
ElasticSearch
Hibernate Search (Hibernate integration with Apache Lucene)
...
When using such solution, you'll have to index your entities into your search engine as well. Spring Data can help you with that since there is also a library for Solr.
First of all you need a new class that represents how your entity will look like in Solr. Be aware that you want to "flatten" everything if you would have nested relations:
#Document
public class UserDocument {
#Id
#Indexed("id")
private String id;
#Indexed("firstName")
private String firstName;
#Indexed("lastName")
private String lastName;
#Indexed("userName")
private String userName;
// ...
}
After that, you can write a repository like you're used to with Spring Data:
public interface UserDocumentRepository extends SolrCrudRepository<UserDocument, String> {
#Query("userName:?0 OR firstName:?0 OR lastName:?0")
List<UserDocument> findAll(String searchTerm);
}
After that, you can do something like this:
public User create(User input) {
// Create user in database
documentRepository.save(new UserDocument(input.getFirstName(), input.getLastName(), input.getUserName());
}
And you can query for fuzzy searches by using the repository as well:
documentRepository.findAll("vickz~3");
This will use the query that I just wrote, and will look first firstnames, lastnames or usernames containing vickz. The ~3 at the end is a special syntax to indicate that the name can be 3 characters different from the one I just used (= edit distance).
However, this will return the UserDocument Solr entities. If you want to get the entities, you'll have to look them up as well, which can be done by their username:
List<String> usernames = documentRepository
.findAll("vickz~3")
.stream()
.map(UserDocument::getUserName)
.collect(Collectors.toList());
repository.findByUsername(usernames); // Look in database for users matching those usernames

Spring JPA - Ignore a field only in persistence

I have a field called password which can be received by endpoint. But it cannot be sent back in response or persisted in Database
The class is as follows -
public class ShortURL {
#Pattern(regexp="^(https?|ftp|file)://[-a-zA-Z0-9+&##/%?=~_|!:,.;]*[-a-zA-Z0-9+&##/%=~_|]")
private String url;
#Size(min=8,max=16)
#Transient
private String password = null;
private boolean isPasswordProtected = false;
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public boolean isPasswordProtected() {
return isPasswordProtected;
}
public void setPasswordProtected(boolean isPasswordProtected) {
this.isPasswordProtected = isPasswordProtected;
}
public ShortURL(
#Pattern(regexp = "^(https?|ftp|file)://[-a-zA-Z0-9+&##/%?=~_|!:,.;]*[-a-zA-Z0-9+&##/%=~_|]") String url,
#Size(min = 8, max = 16) String password, boolean isPasswordProtected) {
super();
this.url = url;
this.password = password;
this.isPasswordProtected = isPasswordProtected;
}
#Transient works properly. But adding the #JsonIgnore after #Transient causes problems -
Type definition error: [simple type, class java.lang.String];
nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException:
No fallback setter/field defined for creator property 'password'"
How do I achieve my intentions?
Depends on your Jackson version.
Before version 1.9, you could add #JsonIgnore to the getter of password and add #JsonProperty to the setter of the password field.
Recent versions of Jackson provide READ_ONLY and WRITE_ONLY annotation arguments for #JsonProperty, something like this:
#JsonProperty(access = Access.READ_ONLY)
private String password;
Yes you can use #JsonIgnore to let jackson ignore it during sending the user response but. There are certain best practices you should follow.
Never expose the Entities directly to the endpoint instead its better to have a wrapper i.e DTO that translates your entity to the required response.
For eg. in your case
public class ShortURL {
#Pattern(regexp="^(https?|ftp|file)://[-a-zA-Z0-9+&##/%?=~_|!:,.;]*[-a-zA-Z0-9+&##/%=~_|]")
private String url;
#Size(min=8,max=16)
private String password;
private boolean isPasswordProtected;
}
//here is the dto in which you can create a parameterised constructor and
accordingly invoke it based on the fields you want to set.
public class ShortURLDTO {
private String url;
public ShortURLDTO(String url){
this.url=url
}
}

#JsonProperty/#JsonIgnore not working as expected on write-only property

As suggested here I've tried to use #JsonIgnore and #JsonProperty (from import com.fasterxml.jackson.annotation.*;) on the password and passwordSalt fields of my AppUser.
#Entity
#Table(name = "app_user")
public class AppUser extends AbstractTimestampEntity {
// ..
#JsonIgnore
public String getPassword() {
return password;
}
#JsonProperty
public void setPassword(String password) {
this.password = password;
}
#JsonIgnore
public String getPasswordSalt() {
return passwordSalt;
}
#JsonProperty
public void setPasswordSalt(String passwordSalt) {
this.passwordSalt = passwordSalt;
}
}
However, for some reason the two fields are always null. As I try to "register" a user, the JSON I am sending is not getting de-serialized completely. password is set to null:
What I want to achieve is to be able to receive the user's password in order to store it, but at the same time make sure that the stored (encrypted) password is not being serialized and sent back to the client as well.
What am I doing wrong here?
With Jackson version 2.9.0 the following works for me:
#NoArgsConstructor
#AllArgsConstructor
public class Credentials {
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
#JsonProperty(access = Access.WRITE_ONLY)
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
…and a running test example…
#Test
public void jsonIgnoreSerialization() throws Exception {
ObjectMapper objectMapper = new ObjectMapper();
String serialized = objectMapper.writeValueAsString(new Credentials("user", "pass"));
assertThat(serialized).isEqualTo("{\"username\":\"user\"}");
Credentials credentials = objectMapper.readValue("{\"username\":\"user\",\"password\":\"pass\"}", Credentials.class);
assertThat(credentials.getUsername()).isEqualTo("user");
assertThat(credentials.getPassword()).isEqualTo("pass");
}
For the sake of simplicity the constructors are the ones from Lombok and the assertions come from AssertJ.
Can you give this a try?

why I can't use string as id

I am trying to create a user model with a CrudRepository:
#Entity
public class User {
#Id
#GeneratedValue
private String username;
private String password;
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
public interface UserRepository extends CrudRepository<User, String> {
}
However I got an 500 error every time I call findOne():
#Controller
public class UserController {
#Autowired
private UserRepository users;
#Override
#RequestMapping(value="/register", method=RequestMethod.POST)
public #ResponseBody User register(#RequestBody User userToRegister) {
String username = userToRegister.getUsername();
User user = users.findOne(id);
if (user != null) {
return null;
}
User registeredUser = users.save(userToRegister);
return registeredUser;
}
}
However if I just switch to an long type id instead of username itself then everything works. I think it's common to use string as id. So how to make this work?
I use the embedded hsql database. I didn't wrote any sql code.
The problem is that String username; is annotated with both #Id and #GeneratedValue. #Id means that is should be a primary key, fine it can be a String. But #GeneratedValue means that you want the system to automatically generate a new key when you create a new record. That's easy when the primary key is integer, all databases have a notion of sequence (even if the syntax is not always the same). But if you want String automatically generated keys, you will have do define your own custom generator.
Or if you have no reason for the #GeneratedValue annotation, simply remove it as suggested by Bohuslav Burghardt
Use column annotation like below by putting nullable False.
#Id
#GeneratedValue
#Column(name = "username", nullable = false)
private String username;

Spring Security + JPA user schema

As per Spring documentation if you need to manage spring security via database you should have some standard schema of tables. for example.
create table users(
username varchar(256) not null primary key,
password varchar(256) not null,
enabled boolean not null
);
create table authorities (
username varchar(256) not null,
authority varchar(256) not null,
constraint fk_authorities_users foreign key(username) references users(username)
);
create unique index ix_auth_username on authorities (username,authority);
The problem I am facing is following.
1) Not able to understand how could I achieve such schema of tables using JPA?
I have tried something as follows.
#Entity
#Table(name="USERS")
public class UsersPersistence extends Users implements Serializable{
private static final long serialVersionUID = 1009548075747154488L;
public UsersPersistence() {
super();
}
public UsersPersistence(long id, String userName, String password, boolean enabled) {
super(id, userName,password,enabled);
}
#Id
#GeneratedValue
#Column(name="id")
#Override
public long getId() {
return super.getId();
}
#Column(name="username", nullable=false)
#Override
public String getUserName() {
return super.getUserName();
}
#Column(name="password", nullable=false)
#Override
public String getPassword() {
return super.getPassword();
}
#Column(name="enabled", nullable=false)
#Override
public boolean isEnabled() {
return super.isEnabled();
}
}
This table created as per requirement stated in Spring documentation schema.
Problem in understanding is when i am trying to assign a foreign key on username in authorities table.Since JPA assign the foreign key's via the id of parent table (primary key Table) Or may be i do not know how to assign it.
Following is the JPA class which create problem :-
#Entity
#Table(name="AUTHORITIES")
public class AuthoritiesPersistence extends Authorities implements Serializable{
private static final long serialVersionUID = 1L;
public AuthoritiesPersistence() {
super();
}
public AuthoritiesPersistence(long id, UsersPersistence userName, String authority) {
super(id,userName,authority);
}
#Id
#GeneratedValue
#Column(name="id")
#Override
public long getId() {
return super.getId();
}
#Override
#ManyToOne(cascade=CascadeType.ALL)
#JoinColumn(name="username", nullable=false)
public UsersPersistence getUserName() {
return (UsersPersistence) super.getUserName();
}
#Column(name="authority", nullable=false)
#Override
public String getAuthority() {
return super.getAuthority();
}
}
This table is created successfully but Spring security authentication is not able to recognize the username because JPA uses the foreign key id than the actual user name.
Any help would be appreciable. I am really stuck in creating a foreign key which will be based on the username rather than the id.
Thanks
You only have to stick to the schema given in Spring Security reference docs, when using a default JdbcDaoImpl as UserDetailsService implementation, which is the case if you have the <jdbc-user-service> tag in your security configuration. Even then it is possible to override the default SQL queries it uses to fetch users and authorities (refer to the namespace appendix).
However if you manage user accounts using hibernate, it would make sense to write your own UserDetailsService implementation, instead of trying to create JPA entities that result in the specific schema required by the JdbcDaoImpl.
The documentation states as well:
If your application does use an ORM tool, you might prefer to write a custom UserDetailsService to reuse the mapping files you've probably already created.
There are a couple of ways you could handle this:
You could write your own AuthenticationProvider using Hibernate for
DB access
You could use the <jdbc-user-service> and overwrite the SQL queries as mentioned by #zagyi. (http://static.springsource.org/spring-security/site/docs/current/reference/appendix-namespace.html#nsa-jdbc-user-service)
Or you can create the your schema to fit the standard <jdbc-user-service>
To use the approach you are interested in you have to know that aside from having the fields username, password and enabled spring security expects the username to be a unique identifier. This means that you can use the username property of your entity as Id for your DB and Hibernate.
If you don't want to do this a way of approaching this is to set a table wihch defines the authorites using an ID/Name and the authority. And then to set up the use a jointable to map them to the users.
Some untested examplecode:
Role:
#Entity
#DynamicUpdate
#Table(name ="authorities")
public class Authority{
private String authority;
#Id
#Column(name="authority")
public String getAuthority() {
return authority;
}
User:
#Entity
#DynamicUpdate
#Table(name = "users", uniqueConstraints={ #UniqueConstraint(columnNames={"username"})})
public class User {
private String username;
private List<Authority> authorities;
#Type(type = "numeric_boolean")
private boolean enabled;
#Id
#Column(name="username")
public String getUsername() {
return username;
}
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(
name = "authorities",
joinColumns = #JoinColumn(name = "username"),
inverseJoinColumns = #JoinColumn(name = "rolename")
)
public List<Authority> getauthorities() {
return authorities;
}
#Column(name="ENABLED")
public boolean isEnabled() {
return enabled;
}
When the base is running you can add properties for internal use as u like.
I have figure out the Alternative which is "Configuring the JdbcUserDetailsManager to use custom SQL queries" at least i can create my tables via JPA and Can hope
" users-by-username-query and authorities-by-username-query " would do my work indeed.
To achieve it I have to add following schema .
create table custom_user_authorities (
id bigint identity,
user bigint not null,
authority varchar(256) not null,
);
this schema have id(which will be auto-incremented) which will definitely work for JPA.
I was able to map those tables using the following class definition:
#Entity
#Table(name = "users")
public class User {
#Id
#Column(name = "username")
private String username;
#Column(name = "password")
private String password;
#Column
private boolean enabled;
#Column
private String firstName;
#ElementCollection
#JoinTable(name = "authorities", joinColumns = {#JoinColumn(name = "email")})
#Column(name = "authority")
private Set<String> roles;
public User() {
}
public Serializable getId() {
return username;
}
public String getUsername() {
return username;
}
public String getPassword() {
return password;
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public void setPassword(String password) {
this.password = password;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Set<String> getRoles() {
return roles;
}
public void setRoles(Set<String> roles) {
this.roles = roles;
}
}

Resources