Repository doesn't save data to H2 in-memory db - java

Here is my controller method:
// CREATE A USER
#PostMapping("/register")
public String createUser(
#RequestBody User user
) {
if (userService.userExists(user)) {
return "User already exists";
}
userService.saveUser(user);
return "Good job!";
}
UserServiceBean
#Service
public class UserServiceBean {
private UserRepository userRepository;
#Autowired
public UserServiceBean(UserRepository userRepository) {
this.userRepository = userRepository;
}
public User saveUser(User user) {
return userRepository.save(user);
}
public boolean userExists(User user) {
if (userRepository.findByUsername(user.getUsername()) == null) {
return false;
}
return true;
}
And my interface repository:
UserRepository
public interface UserRepository extends CrudRepository<User, Long> {
// TODO: 29.01.17 Create a query to find all todos for logged in user
#Query("select td from User u inner join u.toDoItems td where u = :user")
public Iterable<ToDoItem> findAllToDosForLoggedInUser(#Param("user") User user);
public User findByUsername(String username);
}
And here is my User Entity (getters and setters ommited)
#Entity
#Table (name = "USERS")
public class User extends BaseEntity {
#Column(name = "USERNAME")
private String username;
// TODO: 28.01.17 Find a way to store hashed and salted pws in DB
#Column(name = "PASSWORD")
private String password;
#Column(name = "EMAIL")
private String email;
// user can have many ToDoItems
#OneToMany(cascade = CascadeType.ALL, mappedBy = "user")
private Set<ToDoItem> toDoItems;
// JPA demands empty constructor
public User() {}
public User(String username, String password, String email) {
this.username = username;
this.password = password;
this.email = email;
}
When I shoot JSON at my localhost:8080/register:
{
"username":"ss",
"password":"mkyong.com",
"email":"asdasd#wp.pl"
}
I get response Good job! so it works fine. But when I check my DB at localhost:8080/console it just has Test Table and new User is not added.
I've got my hibernate ddl setup in application.properties set:
# Console to H2 database to check data
spring.h2.console.enabled=true
spring.h2.console.path=/console
spring.jpa.hibernate.ddl-auto=create-drop
So, how do I update my code that it creates table USERS and save created user into that db? I'm going to change my db later on, just using H2 to check if my controllers work fine but it shouldn't matter here.
EDIT:
Here is my RepositoryConfiguration.java:
#Configuration
#EnableAutoConfiguration
#EntityScan(basePackages = {"com.doublemc.domain"})
#EnableJpaRepositories(basePackages = {"com.doublemc.repositories"})
#EnableTransactionManagement
public class RepositoryConfiguration {
}
EDIT2:
When I want to register the same User again (using same JSON) then it gives me "User already exists" resposne so it is already in the db... Why can't I see it then? Maybe I've got H2 somewhere else? Not in the basic /console or different port? How can I check this?

I think you're missing the transactional part of your service. Did you define a transaction manager in your spring context ?
If so, you need to add the annotation #Transactional into your service. For example :
#Service
public class UserServiceBean {
#Transactional
public User saveUser(User user) {
return userRepository.save(user);
}
}

I had to add:
spring.datasource.url=jdbc:h2:~/test
spring.datasource.driver-class-name=org.h2.Driver
to application.properties and it works great now. I just thought I don't need it becasue Spring will auto-configure it for me but apparently it doesn't.

Related

Spring Boot DBRef is null after saving

I have user and role models. Thats look like this:
User:
#Document("user")
#Data
#NoArgsConstructor
#AllArgsConstructor
public class User {
#Id
private String id;
private String name;
private String username;
private String password;
#DBRef
private Collection<Role> roles = new ArrayList<>();
Role:
#Document("role")
#Data
#NoArgsConstructor
#AllArgsConstructor
public class Role {
#Id
private String id;
private String name;
}
And I have besides others those three methods to save user, save role and add role to user, like this:
#Override
public User saveUser(User user) {
log.info("Saving new user {} to the database", user.getName());
return userRepository.save(user);
}
#Override
public Role saveRole(Role role) {
log.info("Saving new role {} to the database", role.getName());
return roleRepository.save(role);
}
#Override
public void addRoleToUser(String username, String roleName) {
log.info("Adding role {} to user {}", roleName, username);
User user = userRepository.findByUsername(username);
Role role = roleRepository.findByName(roleName);
user.getRoles().add(role);
}
Also I have a CommandLineRunner to insert those data
#Bean
CommandLineRunner run(UserService userService) {
return args -> {
userService.saveRole(new Role(null, "ROLE_USER"));
userService.saveRole(new Role(null, "ROLE_ADMIN"));
userService.saveUser(new User(null,"Stefan", "stefanadmin", "stefanadmin", new ArrayList<>()));
userService.saveUser(new User(null,"Marko", "markoadmin", "markoadmin", new ArrayList<>()));
userService.saveUser(new User(null,"Jovan", "jovanobicanuser", "jovanobicanuser", new ArrayList<>()));
userService.addRoleToUser("stefanadmin", "ROLE_ADMIN");
userService.addRoleToUser("stefanadmin", "ROLE_USER");
userService.addRoleToUser("markoadmin", "ROLE_ADMIN");
userService.addRoleToUser("jovanobicanuser", "ROLE_USER");
};
}
And everything works fine except array column roles, its empty.
Its like this in JSON when I try to return all users:
{"id":"6331bda42c1fa17e41079c99","name":"Jovan","username":"jovanobicanuser","password":"jovanobicanuser","roles":[]}]
I'm following some tutorial for this stuff, guy is using MySql while I'm using Mongo, so I think problem is somewhere how I'm trying to connect those two tables.
What can cause problem like this, what I'm missing?

toDoList Rest API: springBoot+H2+springSecutiry

I,m trying to do toDoList Rest API and have some problems with it.
Help me!
I decided to do multiuser project, separate users using basic auth of Spring Security. Here is my Entities: Task.java
#Entity
public class Task {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#NotNull
private String title;
#JsonFormat(pattern = "yyyy-MM-dd")
private LocalDate date;
private boolean status;
#ManyToOne
private User user;
public Task() {};
+Getters and Setters
#Entity
public class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String firstName;
private String lastName;
private String username;
#JsonIgnore
private String password;
#JsonIgnore
private String[] roles;
public User() {};
+Getters and Setter;
Both entity interface extends CrudRepository. Task have #ManyToOne relationship to User.
Java helps me to create bd in h2 according to settings in application.properties
# H2
spring.h2.console.enabled=true
spring.h2.console.path=/h2
# Datasource
spring.datasource.url=jdbc:h2:./data/ToDoList
spring.datasource.username=sa
spring.datasource.password=
spring.datasource.driver-class-name=org.h2.Driver
spring.jpa.show-sql = true
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.H2Dialect
# Hibernate ddl auto (create, create-drop, validate, update)
spring.jpa.hibernate.ddl-auto = update
Problem #1: I can't open h2 console. All crud operations are working well, i tested it it Postman, but i want to have access to console.
Then i implement UserDetailService to grab users attributes:
#Component
public class DetailsService implements UserDetailsService{
#Autowired
private UserRepository users;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = users.findByUsername(username);
if (user == null) {
throw new UsernameNotFoundException(username + " was not found");
}
return new org.springframework.security.core.userdetails.User(
user.getUsername(),
user.getPassword(),
AuthorityUtils.createAuthorityList(user.getRoles())
);
}
}
And configure WebSecurity:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
private DetailsService userDetailsService;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.httpBasic()
.and()
.csrf().disable();
}
}
And here is Problem #2: how to take information about tasks of only one user?
In findAll method for example.
P.S. Sorry for my french (c).
UPD.
Try to grad User's data from SecurityContext. Create new file UserController. And that is works fine. Still have problems with access to H2 Console...
#RestController
#RequestMapping("/api/v1")
public class UserController {
#Autowired
private TaskRepository tasks;
#GetMapping("/tasks")
public List<Task> getAllTasks() {
List<Task> allTasks = tasks.findAll();
List<Task> userTasks = new ArrayList<>();
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
String username = ((UserDetails)principal).getUsername();
for (Task t: allTasks) {
if (t.getUser().getUsername().equals(username)) {
userTasks.add(t);
}
}
return userTasks;
}
}

How to get user id with Spring MVC?

I using the POST method for add Item to the database with Spring MVC. But each Item has field userId, it FOREIGN KEY to users table. Need to know user's id for this. I using Spring security for auth. May be there is a possibility get current user's id with ServletContext or HttpSession, may be spring security save user's id somewhere?
How to identify user which requested to the server with Spring MVC to data in the database?
#PostMapping("/get_all_items/add_item_page/add_item")
public String addItem(#RequestParam(value = "description")
final String description) {
final Item item = new Item();
item.setDescription(description);
item.setAuthorId(/* ??? */);
service.add(item);
return "redirect:get_all_items";
}
Spring security implementation with using UserDetails so all details hidden from me, and I don't know how to intervene in auth process and intercept user's id in the authorysation stage.
#Entity(name = "users")
public class User implements UserDetails {...}
#Autowired
private UserService userService;
#Autowired
private void configureGlobal(AuthenticationManagerBuilder auth)
throws Exception {
auth.userDetailsService(userService);
}
Thank You!
Please try with this approach
Make sure that you have your own User pojo class
#Entity
public class MyUser {
#Id
private Long id;
private String username;
private String password;
private boolean isEnabled;
#ManyToMany
private List<MyAuthority> myAuthorities;
...
}
Also an Authority pojo in order to define the user roles
#Entity
public class MyAuthority {
#Id
private int id;
private String name; .....
Then the user repository, in this example I just declare a method to find by username and get an Optional to validate if the user exists.
public interface MyUserRepository extends CrudRepository<MyUser,Long> {
public Optional<MyUser> findFirstByUsername(String username);
}
Create a user class that extends from org.springframework.security.core.userdetails.User in order to wrap your custom user inside the definition of the spring security user.
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import java.util.Collection;
public class MySpringUser extends User {
private MyUser user;
public MySpringUser(MyUser myUser, Collection<? extends GrantedAuthority> authorities) {
super(myUser.getUsername(), myUser.getPassword(), myUser.isEnabled()
, true, true, true, authorities);
this.setUser(myUser);
}
public MyUser getUser() {
return user;
}
public void setUser(MyUser user) {
this.user = user;
}
}
And now the UserDetailService implementation, there is just one method to implement loadUserByUsername here is where the MyUserRepository is needed, in order to retrieve the user information from the repository by the username.
#Service
public class MyUserService implements UserDetailsService {
#Autowired
MyUserRepository myUserRepository;
#Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
Optional<MyUser> myUser = myUserRepository.findFirstByUsername(s);
return myUser.map( (user) -> {
return new MySpringUser(
user,
user.getMyAuthorities().stream().
map( authority ->
new SimpleGrantedAuthority(authority.getName())).
collect(Collectors.toList()));
}).orElseThrow(() -> new UsernameNotFoundException("user not found"));
}
}
And now you can inject the UserDetailService because its implementation will be injected form MyUserService class.
#Autowired
private UserService userService;
#Autowired
private void configureGlobal(AuthenticationManagerBuilder auth)
throws Exception {
auth.userDetailsService(userService);
}
then with this approach you can inject the Principal object to your controller, and inside the method you can cast the Principal object to MySpringUser, it is because MySpringUser is extended from org.springframework.security.core.userdetails.User and User class implements the UserDetails interface. Of course you can get all the rest of custom fields of the user because its definition is wrapped inside the org.springframework.security.core.userdetails.User class
#PostMapping("/get_all_items/add_item_page/add_item")
public String addItem(#RequestParam(value = "description")
final String description, Principal principal) {
MySpringUser mySpringUser = (MySpringUser)principal;
final Item item = new Item();
item.setDescription(description);
item.setAuthorId(mySpringUser.getUser().getId());
service.add(item);
return "redirect:get_all_items";
}
I have tried many things but the best thing is to create custer User class which extend org.springframework.security.core.userdetails.User
package com.walterwhites.library.model.pojo;
import lombok.Getter;
import lombok.Setter;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import java.util.Collection;
#Getter
#Setter
public class MyUser extends User {
long id;
public MyUser(long id, String username, String password, Collection<? extends GrantedAuthority> authorities) {
super(username, password, authorities);
this.id = id;
}
}
after you can use like below
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
UserDetails client = (UserDetails) auth.getPrincipal();
long id = ((MyUser) client).getId();
Cordially
UserDetails client = (UserDetails) auth.getPrincipal();
long id = ((User) client).getUserId();
System.out.println(id);
I got this error:
java.lang.ClassCastException: com.doc.importexport.implementation.UserPrincipal cannot be cast to com.doc.importexport.model.User

What is the best practice to salt a password with spring security in spring boot?

I'm creating a REST API in java for an online store with Spring Boot, I want to securely store user passwords in the database,
for this I am using BCrypt that comes included with spring security, I use MySQL and JPA-Hibernate for persistence.
And I am implementing it as follows:
This is the user entity:
#Entity
#SelectBeforeUpdate
#DynamicUpdate
#Table (name = "USER")
public class User {
#Id
#GeneratedValue
#Column(name = "USER_ID")
private Long userId;
#Column(name = "ALIAS")
private String alias;
#Column(name = "NAME")
private String name;
#Column(name = "LAST_NAME")
private String lastName;
#Column(name = "TYPE")
private String type;
#Column(name = "PASSWORD")
private String password;
public String getPassword() {
return password;
}
/**
* When adding the password to the user class the setter asks if it is necessary or not to add the salt,
* if this is necessary the method uses the method BCrypt.hashpw (password, salt),
* if it is not necessary to add the salt the string That arrives is added intact
*/
public void setPassword(String password, boolean salt) {
if (salt) {
this.password = BCrypt.hashpw(password, BCrypt.gensalt());
} else {
this.password = password;
}
}
//Setters and Getters and etc.
}
This is the repository of the user class:
#Repository
public interface UserRepository extends JpaRepository<User, Long> {
}
This is the service of the user class:
#Service
public class UserService{
private UserRepository userRepository;
#Autowired
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
public User addEntity(User user) {
//Here we tell the password setter to generate the salt
user.setPassword(user.getPassword(), true);
return userRepository.save(user);
}
public User updateEntity(User user) {
User oldUser = userRepository.findOne(user.getUserId());
/*
*This step is necessary to maintain the same password since if we do not do this
*in the database a null is generated in the password field,
*this happens since the JSON that arrives from the client application does not
*contain the password field, This is because to carry out the modification of
*the password a different procedure has to be performed
*/
user.setPassword(oldUser.getPassword(), false);
return userRepository.save(user);
}
/**
* By means of this method I verify if the password provided by the client application
* is the same as the password that is stored in the database which is already saved with the salt,
* returning a true or false boolean depending on the case
*/
public boolean isPassword(Object password, Long id) {
User user = userRepository.findOne(id);
//To not create an entity that only has a field that says password, I perform this mapping operation
String stringPassword = (String)((Map)password).get("password");
//This method generates boolean
return BCrypt.checkpw(stringPassword, user.getPassword());
}
/**
*This method is used to update the password in the database
*/
public boolean updatePassword(Object passwords, Long id) {
User user = userRepository.findOne(id);
//Here it receive a JSON with two parameters old password and new password, which are transformed into strings
String oldPassword = (String)((Map)passwords).get("oldPassword");
String newPassword = (String)((Map)passwords).get("newPassword");
if (BCrypt.checkpw(oldPassword, user.getPassword())){
//If the old password is the same as the one currently stored in the database then the new password is updated
//in the database for this a new salt is generated
user.setPassword(newPassword, true);
//We use the update method, passing the selected user
updateEntity(user);
//We return a true boolean
return true;
}else {
//If the old password check fails then we return a false boolean
return false;
}
}
//CRUD basic methods omitted because it has no case for the question
}
This is the controller that exposes the API endpoints:
#RestController
#CrossOrigin
#RequestMapping("/api/users")
public class UserController implements{
UserService userService;
#Autowired
public UserController(UserService userService) {
this.userService = userService;
}
#RequestMapping( value = "", method = RequestMethod.POST )
public User addEntity(#RequestBody User user) {
return userService.addEntity(user);
}
#RequestMapping( value = "", method = RequestMethod.PUT )
public User updateEntity(#RequestBody User user) {
return userService.updateEntity(user);
}
#RequestMapping( value = "/{id}/checkPassword", method = RequestMethod.POST )
public boolean isPassword(#PathVariable(value="id") Long id, #RequestBody Object password) {
return userService.isPassword(password, id);
}
#RequestMapping( value = "/{id}/updatePassword", method = RequestMethod.POST )
public boolean updatePassword(#PathVariable(value="id") Long id, #RequestBody Object password) {
return userService.updatePassword(password, id);
}
}
This is where my question comes, my method is working but I feel it is not the best way, I do not feel comfortable changing the password setter I would prefer to keep the standard form of a setter, as in the user service I think there is Opportunity to handle the user and password update differently, so try to use the #DynamicUpdate annotation in the entity but it simply does not work properly since the fields not provided in the update instead of leaving them as they were are saved Like nulls.
What I'm looking for is a better way to handle the security of passwords using Spring Boot.
First of all you would like to have a unique field for each user in your online store (f.e. alias, or email), to use it as an identifier, without exposing id value to the end users.
Also, as I understand, you want to use Spring Security to secure your web application. Spring security uses ROLEs to indicate user authorities (f.e. ROLE_USER, ROLE_ADMIN). So it would be nice to have a field (a list, a separate UserRole entity) to keep track of user roles.
Let's assume, that you added unique constraint to User field alias (private String alias;) and added simple private String role; field. Now you want to set up Spring Security to keep '/shop' and all sub-resources (f.e. '/shop/search') open to everyone, unsecured, resource '/discounts' available only for registered users and resource '/admin' available for administrator only.
To implement it, you need to define several classes. Let's start with implementation of UserDetailsService (needed by Spring Security to get user information):
#Service
public class UserDetailsServiceImpl implements UserDetailsService {
private final UserRepository repository;
#Autowired
public UserDetailsServiceImpl(UserRepository repository) {
this.repository = repository;
}
#Override
public UserDetails loadUserByUsername(String alias) {
User user = repository.findByAlias(alias);
if (user == null) {
//Do something about it :) AFAIK this method must not return null in any case, so an un-/ checked exception might be a good option
throw new RuntimeException(String.format("User, identified by '%s', not found", alias));
}
return new org.springframework.security.core.userdetails.User(
user.getAlias(), user.getPassword(),
AuthorityUtils.createAuthorityList(user.getRole()));
}
}
Then, the main class for configuring Spring Security is one, that extends WebSecurityConfigurerAdapter (the example was taken from the application with a form based authentication, but you can adjust it for your needs):
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsService userDetailsService;
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/shop/**").permitAll()
.antMatchers("/discounts/**").hasRole("USER")
.antMatchers("/admin/**").hasRole("ADMIN")
.and()
.formLogin()
.usernameParameter("alias")
.passwordParameter("password")
.loginPage("/login").failureUrl("/login?error").defaultSuccessUrl("/")
.permitAll()
.and()
.logout()
.logoutUrl("/logout")
.clearAuthentication(true)
.invalidateHttpSession(true)
.deleteCookies("JSESSIONID", "remember-me")
.logoutSuccessUrl("/")
.permitAll();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder());
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
Then, in your UserService you can use something like:
...
#Autowired
private PasswordEncoder passwordEncoder;
public User addEntity(User user) {
...
user.setPassword(passwordEncoder.encode(user.getPassword()))
...
}
All other checks (f.e. for login attempt or for accessing resource) Spring Security will do automatically, according to the configuration. There are many more things to setup and consider, but I hope I was able to explain the overall idea.
EDIT
Define bean as follows within any spring Component or Configuration
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
Then autowire it in your UserService class
#Service
public class UserService {
private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;
#Autowired
public UserService(UserRepository userRepository, PasswordEncoder passwordEncoder) {
this.userRepository = userRepository;
this.passwordEncoder = passwordEncoder;
}
public User addEntity(User user) {
user.setPassword(passwordEncoder.encode(user.getPassword());
return userRepository.save(user);
}
...
public boolean isPassword(Object password, Long id) {
User user = userRepository.findOne(id);
String stringPassword = (String)((Map)password).get("password");
return passwordEncoder.matches(stringPassword, user.getPassword());
}
public boolean updatePassword(Object passwords, Long id) {
User user = userRepository.findOne(id);
String oldPassword = (String)((Map)passwords).get("oldPassword");
String newPassword = (String)((Map)passwords).get("newPassword");
if (!passwordEncoder.matches(oldPassword, newPassword)) {
return false;
}
user.setPassword(passwordEncoder.encode(newPassword));
updateEntity(user);
return true;
}
...
}
After that you can keep simple setter in User class.

SpringBoot JPA throws exception while making post request

Im making a small application where i can save user details using spring-boot. i created the entities and their corresponding repositories. When ever i make a post request to add a user the id of the user object which is null at the point of saving to the data base.This id is auto generated(Auto Increment) in MySQL. From the POST request i get 3 fields which are username,email,password. The User class contains fields id,username,email,password. I've added the annotations
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Integer id;
for the id field. an the constructors are
public User() { }
public User(String username, String email, String password) {
this.username = username;
this.email = email;
this.password = password;
}
This is the error im getting.
The debugging process
my userService class
#Service
public class UserService implements UserServiceInterface {
#Autowired(required = true)
private UserRepository userrepository;
#Override
public User CreateNewUser(User user) {
return userrepository.save(user);
}
}
my userController class
#RestController
public class UserController {
UserService us = new UserService();
#RequestMapping(value ="/user",method = RequestMethod.POST)
public void RegisterUser(
#RequestParam(value="username") String username,
#RequestParam(value="email") String email,
#RequestParam(value="password") String password){
us.CreateNewUser(new User(username,email,password));
}
}
Any reason why i cant POST to save data to database? how to overcome this?
After digging through the code i found out the error. by creating a new instance of UserService us = new UserService(); this is not managed by Spring (Spring doesn't know about it and cannot inject UserRepository - this causes NullPointerException). there of instead of creting new instace it should extends the UserService class in this example.

Categories

Resources