├── settings.gradle ├── README.md ├── src ├── main │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── jpaservices │ │ │ ├── JPAServicesApplication.java │ │ │ ├── repository │ │ │ └── UserRepository.java │ │ │ ├── exception │ │ │ ├── BadRequestException.java │ │ │ └── ResourceNotFoundException.java │ │ │ ├── service │ │ │ ├── EmailService.java │ │ │ └── UserService.java │ │ │ ├── model │ │ │ ├── AuditModel.java │ │ │ └── User.java │ │ │ └── controller │ │ │ └── UserController.java │ └── resources │ │ └── application.properties └── test │ └── java │ └── com │ └── example │ └── jpaservices │ ├── JPAservicesApplicationTests.java │ └── test │ ├── repository │ └── UserRepositoryTest.java │ ├── controller │ └── UserControllerTest.java │ └── service │ └── UserServiceTest.java ├── .gitignore └── LICENSE /settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | gradlePluginPortal() 4 | } 5 | } 6 | rootProject.name = 'spring-user-reset-services' 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # spring-user-rest-service 2 | Spring Boot User Registration and Login REST Services 3 | 4 | This is server side code. Client side code (Angular) is at https://github.com/wugangca/angular-user-login 5 | 6 | Use `gradle build` to build the code 7 | 8 | Use `java -jar build/libs/spring-user-reset-services-0.0.1-SNAPSHOT.jar` to run the code 9 | -------------------------------------------------------------------------------- /src/main/java/com/example/jpaservices/JPAServicesApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.jpaservices; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class JPAServicesApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(JPAServicesApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/** 6 | !**/src/test/** 7 | 8 | ### STS ### 9 | .apt_generated 10 | .classpath 11 | .factorypath 12 | .project 13 | .settings 14 | .springBeans 15 | .sts4-cache 16 | 17 | ### IntelliJ IDEA ### 18 | .idea 19 | *.iws 20 | *.iml 21 | *.ipr 22 | out/ 23 | 24 | ### NetBeans ### 25 | /nbproject/private/ 26 | /nbbuild/ 27 | /dist/ 28 | /nbdist/ 29 | /.nb-gradle/ 30 | 31 | ### VS Code ### 32 | .vscode/ 33 | -------------------------------------------------------------------------------- /src/main/java/com/example/jpaservices/repository/UserRepository.java: -------------------------------------------------------------------------------- 1 | package com.example.jpaservices.repository; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | import org.springframework.stereotype.Repository; 5 | 6 | import com.example.jpaservices.model.User; 7 | 8 | @Repository 9 | public interface UserRepository extends JpaRepository { 10 | 11 | User findByUsername(String username); 12 | 13 | User findByConfirmationToken(String confirmationToken); 14 | } -------------------------------------------------------------------------------- /src/main/java/com/example/jpaservices/exception/BadRequestException.java: -------------------------------------------------------------------------------- 1 | package com.example.jpaservices.exception; 2 | 3 | 4 | import org.springframework.http.HttpStatus; 5 | import org.springframework.web.bind.annotation.ResponseStatus; 6 | 7 | @ResponseStatus(HttpStatus.BAD_REQUEST) 8 | public class BadRequestException extends RuntimeException { 9 | private static final long serialVersionUID = 1L; 10 | 11 | public BadRequestException (String message) { 12 | super(message); 13 | } 14 | 15 | public BadRequestException(String message, Throwable cause) { 16 | super (message, cause); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/example/jpaservices/service/EmailService.java: -------------------------------------------------------------------------------- 1 | package com.example.jpaservices.service; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.mail.SimpleMailMessage; 5 | import org.springframework.mail.javamail.JavaMailSender; 6 | import org.springframework.scheduling.annotation.Async; 7 | import org.springframework.stereotype.Service; 8 | 9 | @Service 10 | public class EmailService { 11 | @Autowired 12 | private JavaMailSender mailSender; 13 | 14 | @Async 15 | public void sendEmail(SimpleMailMessage email) { 16 | mailSender.send(email); 17 | } 18 | } -------------------------------------------------------------------------------- /src/main/java/com/example/jpaservices/exception/ResourceNotFoundException.java: -------------------------------------------------------------------------------- 1 | package com.example.jpaservices.exception; 2 | 3 | 4 | import org.springframework.http.HttpStatus; 5 | import org.springframework.web.bind.annotation.ResponseStatus; 6 | 7 | @ResponseStatus(HttpStatus.NOT_FOUND) 8 | public class ResourceNotFoundException extends RuntimeException { 9 | private static final long serialVersionUID = 1L; 10 | 11 | public ResourceNotFoundException (String message) { 12 | super(message); 13 | } 14 | 15 | public ResourceNotFoundException(String message, Throwable cause) { 16 | super (message, cause); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/test/java/com/example/jpaservices/JPAservicesApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.jpaservices; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | 5 | import org.junit.Test; 6 | import org.junit.runner.RunWith; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.boot.test.context.SpringBootTest; 9 | import org.springframework.test.context.junit4.SpringRunner; 10 | 11 | import com.example.jpaservices.controller.UserController; 12 | 13 | @RunWith(SpringRunner.class) 14 | @SpringBootTest 15 | public class JPAservicesApplicationTests { 16 | 17 | @Autowired 18 | private UserController userController; 19 | 20 | @Test 21 | public void contextLoads() { 22 | assertThat(userController).isNotNull(); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/example/jpaservices/model/AuditModel.java: -------------------------------------------------------------------------------- 1 | package com.example.jpaservices.model; 2 | 3 | import java.util.Date; 4 | 5 | import javax.persistence.Column; 6 | import javax.persistence.EntityListeners; 7 | import javax.persistence.MappedSuperclass; 8 | import javax.persistence.Temporal; 9 | import javax.persistence.TemporalType; 10 | 11 | import org.springframework.data.annotation.CreatedDate; 12 | import org.springframework.data.annotation.LastModifiedDate; 13 | import org.springframework.data.jpa.domain.support.AuditingEntityListener; 14 | 15 | @MappedSuperclass 16 | @EntityListeners(AuditingEntityListener.class) 17 | 18 | public abstract class AuditModel { 19 | 20 | @Temporal(TemporalType.TIMESTAMP) 21 | @Column( nullable = false, updatable = false) 22 | @CreatedDate 23 | private Date createdAt; 24 | 25 | @Temporal(TemporalType.TIMESTAMP) 26 | @Column(nullable = false) 27 | @LastModifiedDate 28 | private Date updatedAt; 29 | 30 | // Getters and Setters (Omitted for brevity) 31 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 wugangca 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | #https://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/Hibernate_User_Guide.html#configurations-hbmddl 2 | #validate | update | create | create-drop 3 | #spring.jpa.hibernate.ddl-auto=create 4 | 5 | #MySQL 6 | spring.datasource.url=jdbc:mysql://localhost:3306/test 7 | spring.datasource.username=mysql 8 | spring.datasource.password=admin 9 | 10 | #PostgreSQL 11 | #spring.datasource.url=jdbc:postgresql://localhost:5432/test 12 | #spring.datasource.username=postgres 13 | #spring.datasource.password=admin 14 | 15 | #https://exceptionshub.com/disabling-contextual-lob-creation-as-createclob-method-threw-error.html 16 | spring.jpa.properties.hibernate.temp.use_jdbc_metadata_defaults=false 17 | 18 | #SMTP setup 19 | spring.mail.host=smtp.gmail.com 20 | spring.mail.username=donotreply@gmail.com 21 | spring.mail.password=donotreply 22 | spring.mail.port=587 23 | spring.mail.properties.mail.smtp.starttls.enable=true 24 | spring.mail.properties.mail.smtp.auth=true 25 | spring.mail.properties.mail.smtp.starttls.required=true 26 | 27 | #For debugging 28 | spring.jpa.show-sql = true 29 | 30 | #Used in the emails sent to users 31 | webServerUrl=http://localhost:8080 32 | 33 | 34 | -------------------------------------------------------------------------------- /src/test/java/com/example/jpaservices/test/repository/UserRepositoryTest.java: -------------------------------------------------------------------------------- 1 | package com.example.jpaservices.test.repository; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | 5 | import org.junit.Test; 6 | import org.junit.runner.RunWith; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; 9 | import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager; 10 | import org.springframework.data.jpa.repository.config.EnableJpaAuditing; 11 | import org.springframework.test.context.junit4.SpringRunner; 12 | 13 | import com.example.jpaservices.model.User; 14 | import com.example.jpaservices.repository.UserRepository; 15 | 16 | @RunWith(SpringRunner.class) 17 | @DataJpaTest 18 | @EnableJpaAuditing 19 | public class UserRepositoryTest { 20 | 21 | @Autowired 22 | private TestEntityManager entityManager; 23 | 24 | @Autowired 25 | private UserRepository userRepository; 26 | 27 | @Test 28 | public void findByUserNameTest() { 29 | // given 30 | User user = new User(); 31 | user.setUsername("wugan"); 32 | user.setEmail("gang.wu@bhge.com"); 33 | user.setPassword("password"); 34 | user.setRole("ROLE_ADMIN"); 35 | user.setEnabled(true); 36 | 37 | entityManager.persist(user); 38 | entityManager.flush(); 39 | 40 | // when 41 | User found = userRepository.findByUsername(user.getUsername()); 42 | 43 | // then 44 | assertThat(found.getUsername()).isEqualTo(user.getUsername()); 45 | 46 | found = userRepository.findByUsername("N/A"); 47 | assertThat(found).isEqualTo(null); 48 | } 49 | 50 | @Test 51 | public void findByComfirmationTokenTest() { 52 | // given 53 | User user = new User(); 54 | user.setUsername("wugan"); 55 | user.setEmail("gang.wu@bhge.com"); 56 | user.setPassword("password"); 57 | user.setRole("ROLE_USER"); 58 | user.setEnabled(false); 59 | user.setConfirmationToken("token"); 60 | 61 | entityManager.persist(user); 62 | entityManager.flush(); 63 | 64 | // when 65 | User found = userRepository.findByConfirmationToken(user.getConfirmationToken()); 66 | 67 | // then 68 | assertThat(found.getConfirmationToken()).isEqualTo(user.getConfirmationToken()); 69 | 70 | found = userRepository.findByConfirmationToken("N/A"); 71 | assertThat(found).isEqualTo(null); 72 | } 73 | 74 | } -------------------------------------------------------------------------------- /src/main/java/com/example/jpaservices/controller/UserController.java: -------------------------------------------------------------------------------- 1 | package com.example.jpaservices.controller; 2 | 3 | import java.util.List; 4 | 5 | import javax.validation.Valid; 6 | 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.beans.factory.annotation.Value; 9 | import org.springframework.mail.SimpleMailMessage; 10 | import org.springframework.web.bind.annotation.CrossOrigin; 11 | import org.springframework.web.bind.annotation.GetMapping; 12 | import org.springframework.web.bind.annotation.PostMapping; 13 | import org.springframework.web.bind.annotation.RequestBody; 14 | import org.springframework.web.bind.annotation.RequestParam; 15 | import org.springframework.web.bind.annotation.RestController; 16 | 17 | import com.example.jpaservices.model.User; 18 | import com.example.jpaservices.service.EmailService; 19 | import com.example.jpaservices.service.UserService; 20 | 21 | @CrossOrigin(maxAge = 3600) // https://spring.io/guides/gs/rest-service-cors/ 22 | @RestController 23 | public class UserController { 24 | 25 | @Autowired 26 | private UserService userService; 27 | @Autowired 28 | private EmailService emailService; 29 | @Value("${webServerUrl}") 30 | private String webServerUrl; 31 | 32 | @GetMapping(path = "/users") 33 | public List getAllUsers() { 34 | return userService.getAllUsers(); 35 | } 36 | 37 | @PostMapping(path = "/users/register") 38 | public void register(@Valid @RequestBody User user) { 39 | 40 | if (userService.registerUser(user)) { 41 | 42 | SimpleMailMessage registrationEmail = new SimpleMailMessage(); 43 | registrationEmail.setTo(user.getEmail()); 44 | registrationEmail.setSubject("Registration Confirmation"); 45 | registrationEmail.setText("To confirm your e-mail address, please click the link below:\n" + webServerUrl 46 | + "/users/confirm?token=" + user.getConfirmationToken()); 47 | registrationEmail.setFrom("noreply@domain.com"); 48 | 49 | emailService.sendEmail(registrationEmail); 50 | } 51 | } 52 | 53 | @GetMapping(path = "/users/confirm") 54 | public String confirm(@RequestParam("token") String token) { 55 | userService.confirmrUser(token); 56 | return "User confirmed."; 57 | } 58 | 59 | @PostMapping(path = "/users/login") 60 | public User login(@Valid @RequestBody User user) { 61 | return userService.loginUser(user); 62 | } 63 | 64 | @PostMapping(path = "/users/reset") 65 | public void reset(@Valid @RequestBody User user) { 66 | User resetUser = userService.resetUser(user); 67 | if (resetUser != null) { 68 | SimpleMailMessage registrationEmail = new SimpleMailMessage(); 69 | registrationEmail.setTo(user.getEmail()); 70 | registrationEmail.setSubject("Temporary Password Sent From " + webServerUrl); 71 | registrationEmail 72 | .setText("To access your account, please use this temporary password: " + resetUser.getPassword() 73 | + ".\r\nNOTE: This email was sent from an automated system. Please do not reply."); 74 | registrationEmail.setFrom("noreply@domain.com"); 75 | emailService.sendEmail(registrationEmail); 76 | } 77 | } 78 | 79 | @PostMapping(path = "/users/changepwd") 80 | public User changePassword(@Valid @RequestBody User user) { 81 | return userService.changeUserPassword(user); 82 | } 83 | } -------------------------------------------------------------------------------- /src/main/java/com/example/jpaservices/model/User.java: -------------------------------------------------------------------------------- 1 | package com.example.jpaservices.model; 2 | 3 | import javax.persistence.Column; 4 | import javax.persistence.Entity; 5 | import javax.persistence.GeneratedValue; 6 | import javax.persistence.GenerationType; 7 | import javax.persistence.Id; 8 | import javax.persistence.Table; 9 | 10 | @Entity 11 | @Table(name = "users") 12 | public class User extends AuditModel{ 13 | 14 | @Id 15 | @GeneratedValue(strategy = GenerationType.AUTO) 16 | private Integer id; 17 | 18 | @Column(name = "username", nullable = false, unique = true) 19 | private String username; 20 | 21 | @Column(name = "password", nullable = false) 22 | private String password; 23 | 24 | private String firstName; 25 | 26 | private String lastName; 27 | 28 | @Column(name = "email", nullable = false) 29 | private String email; 30 | 31 | @Column(name = "role", nullable = false) 32 | private String role; 33 | 34 | @Column(name = "enabled", nullable = false) 35 | private boolean enabled; 36 | 37 | private String confirmationToken; 38 | 39 | private boolean isTempPassword; 40 | 41 | public User() { 42 | id = 0; 43 | username = ""; 44 | password = ""; 45 | firstName = ""; 46 | lastName = ""; 47 | email = ""; 48 | role = ""; 49 | enabled = false; 50 | confirmationToken = ""; 51 | setTempPassword(false); 52 | } 53 | 54 | public Integer getId() { 55 | return id; 56 | } 57 | 58 | public void setId(Integer id) { 59 | this.id = id; 60 | } 61 | 62 | public String getPassword() { 63 | return password; 64 | } 65 | 66 | public void setPassword(String password) { 67 | this.password = password; 68 | } 69 | 70 | public String getFirstName() { 71 | return firstName; 72 | } 73 | 74 | public void setFirstName(String firstName) { 75 | this.firstName = firstName; 76 | } 77 | 78 | public String getLastName() { 79 | return lastName; 80 | } 81 | 82 | public void setLastName(String lastName) { 83 | this.lastName = lastName; 84 | } 85 | 86 | public String getEmail() { 87 | return email; 88 | } 89 | 90 | public void setEmail(String email) { 91 | this.email = email; 92 | } 93 | 94 | public String getUsername() { 95 | return username; 96 | } 97 | 98 | public void setUsername(String username) { 99 | this.username = username; 100 | } 101 | 102 | public String getRole() { 103 | return role; 104 | } 105 | 106 | public void setRole(String role) { 107 | this.role = role; 108 | } 109 | 110 | public boolean getEnabled() { 111 | return enabled; 112 | } 113 | 114 | public void setEnabled(boolean value) { 115 | this.enabled = value; 116 | } 117 | 118 | public String getConfirmationToken() { 119 | return confirmationToken; 120 | } 121 | 122 | public void setConfirmationToken(String confirmationToken) { 123 | this.confirmationToken = confirmationToken; 124 | } 125 | 126 | public boolean isTempPassword() { 127 | return isTempPassword; 128 | } 129 | 130 | public void setTempPassword(boolean isTempPassword) { 131 | this.isTempPassword = isTempPassword; 132 | } 133 | 134 | @Override 135 | public boolean equals(Object o) { 136 | 137 | if (o == this) { 138 | return true; 139 | } 140 | 141 | if (!(o instanceof User)) { 142 | return false; 143 | } 144 | 145 | User u = (User) o; 146 | 147 | return u.getUsername().equals(this.getUsername()) && u.getEmail().equals(this.getEmail()) 148 | && u.getRole().equals(this.getRole()) && (u.getEnabled() == this.getEnabled()); 149 | } 150 | 151 | } -------------------------------------------------------------------------------- /src/test/java/com/example/jpaservices/test/controller/UserControllerTest.java: -------------------------------------------------------------------------------- 1 | package com.example.jpaservices.test.controller; 2 | 3 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; 4 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; 5 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; 6 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; 7 | 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | import org.hamcrest.Matchers; 12 | import org.junit.Test; 13 | import org.junit.runner.RunWith; 14 | import org.mockito.BDDMockito; 15 | import org.springframework.beans.factory.annotation.Autowired; 16 | import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; 17 | import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; 18 | import org.springframework.boot.test.mock.mockito.MockBean; 19 | import org.springframework.http.MediaType; 20 | import org.springframework.test.context.junit4.SpringRunner; 21 | import org.springframework.test.web.servlet.MockMvc; 22 | 23 | import com.example.jpaservices.controller.UserController; 24 | import com.example.jpaservices.model.User; 25 | import com.example.jpaservices.service.EmailService; 26 | import com.example.jpaservices.service.UserService; 27 | 28 | @RunWith(SpringRunner.class) 29 | @WebMvcTest(UserController.class) 30 | @AutoConfigureMockMvc 31 | public class UserControllerTest { 32 | 33 | @Autowired 34 | private MockMvc mvc; 35 | 36 | @MockBean 37 | private UserService userService; 38 | 39 | @MockBean 40 | private EmailService emailService; 41 | 42 | @Test 43 | public void getAllUsersTest() throws Exception { 44 | List allUsers = new ArrayList(); 45 | User user1 = new User(); 46 | user1.setUsername("Name1"); 47 | user1.setId(1); 48 | allUsers.add(user1); 49 | 50 | User user2 = new User(); 51 | user2.setId(2); 52 | user2.setUsername("Name2"); 53 | allUsers.add(user2); 54 | 55 | BDDMockito.given(userService.getAllUsers()).willReturn(allUsers); 56 | 57 | mvc.perform(get("/users").contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk()) 58 | .andExpect(jsonPath("$", Matchers.hasSize(2))) 59 | .andExpect(jsonPath("$[0].username", Matchers.is(user1.getUsername()))) 60 | .andExpect(jsonPath("$[1].username", Matchers.is(user2.getUsername()))); 61 | } 62 | 63 | @Test 64 | public void registerTest() throws Exception { 65 | 66 | User user1 = new User(); 67 | user1.setUsername("wugan"); 68 | user1.setId(1); 69 | 70 | BDDMockito.given(userService.registerUser(user1)).willReturn(true); 71 | 72 | mvc.perform(post("/users/register") 73 | .content("{\"username\": \"wugan\", \"email\": \"gang.wu@example.com\", \"password\": \"aaa\"}") 74 | .contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk()); 75 | 76 | } 77 | 78 | @Test 79 | public void confirmTest() throws Exception { 80 | String token = "token"; 81 | User user1 = new User(); 82 | user1.setUsername("wugan"); 83 | user1.setId(1); 84 | BDDMockito.given(userService.confirmrUser(token)).willReturn(user1); 85 | mvc.perform(get("/users/confirm?token=\"token\"")).andExpect(status().isOk()); 86 | } 87 | 88 | @Test 89 | public void loginTest() throws Exception { 90 | User user = new User(); 91 | user.setUsername("wugan"); 92 | user.setPassword("wugan"); 93 | 94 | User user1 = new User(); 95 | user1.setUsername("wugan"); 96 | user1.setPassword("wugan"); 97 | user1.setRole("ROLE_ADMIN"); 98 | 99 | BDDMockito.given(userService.loginUser(user)).willReturn(user1); 100 | mvc.perform(post("/users/login").content("{\"username\": \"wugan\", \"password\": \"wugan\"}") 101 | .contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk()) 102 | .andExpect(jsonPath("$.username", Matchers.is(user1.getUsername()))) 103 | .andExpect(jsonPath("$.role", Matchers.is(user1.getRole()))); 104 | 105 | } 106 | 107 | @Test 108 | public void resetTest() throws Exception { 109 | 110 | User user = new User(); 111 | user.setUsername("wugan"); 112 | user.setPassword("wugan"); 113 | 114 | User user1 = new User(); 115 | user1.setUsername("wugan"); 116 | user1.setPassword("wugan"); 117 | user1.setRole("ROLE_ADMIN"); 118 | 119 | BDDMockito.given(userService.resetUser(user)).willReturn(user1); 120 | 121 | mvc.perform(post("/users/reset").content("{\"username\": \"wugan\", \"email\": \"gang.wu@example.com\"}") 122 | .contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk()); 123 | 124 | } 125 | @Test 126 | public void changePasswordTest() throws Exception { 127 | User user = new User(); 128 | user.setUsername("wugan"); 129 | user.setPassword("wugan"); 130 | 131 | User user1 = new User(); 132 | user1.setUsername("wugan"); 133 | user1.setPassword("wugan"); 134 | user1.setRole("ROLE_ADMIN"); 135 | 136 | BDDMockito.given(userService.changeUserPassword(user)).willReturn(user1); 137 | 138 | mvc.perform(post("/users/changepwd").content("{\"username\": \"wugan\", \"email\": \"gang.wu@example.com\"}") 139 | .contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk()); 140 | } 141 | 142 | 143 | } 144 | -------------------------------------------------------------------------------- /src/main/java/com/example/jpaservices/service/UserService.java: -------------------------------------------------------------------------------- 1 | package com.example.jpaservices.service; 2 | 3 | import java.security.SecureRandom; 4 | import java.util.List; 5 | import java.util.Random; 6 | import java.util.UUID; 7 | 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.context.annotation.Bean; 10 | import org.springframework.data.jpa.repository.config.EnableJpaAuditing; 11 | import org.springframework.security.crypto.factory.PasswordEncoderFactories; 12 | import org.springframework.security.crypto.password.PasswordEncoder; 13 | import org.springframework.stereotype.Service; 14 | 15 | import com.example.jpaservices.exception.BadRequestException; 16 | import com.example.jpaservices.model.User; 17 | import com.example.jpaservices.repository.UserRepository; 18 | 19 | @Service 20 | @EnableJpaAuditing 21 | 22 | public class UserService { 23 | 24 | @Bean 25 | public PasswordEncoder passwordEncoder() { 26 | return PasswordEncoderFactories.createDelegatingPasswordEncoder(); 27 | } 28 | 29 | @Autowired 30 | private UserRepository userRepository; 31 | 32 | @Autowired 33 | private PasswordEncoder encoder; 34 | 35 | private static final Random RANDOM = new SecureRandom(); 36 | private static final String ALPHABET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; 37 | 38 | public List getAllUsers() { 39 | List users = userRepository.findAll(); 40 | for (User user : users) { 41 | user.setPassword(""); 42 | } 43 | return users; 44 | } 45 | 46 | public boolean registerUser(User user) { 47 | String password = user.getPassword(); 48 | if (password.isEmpty()) { 49 | throw new BadRequestException("Invalid password."); 50 | } 51 | 52 | String encodedPassword = encoder.encode(password); 53 | user.setPassword(encodedPassword); 54 | if (user.getUsername().isEmpty()) { 55 | user.setUsername(user.getEmail()); 56 | } 57 | 58 | User userExists = userRepository.findByUsername(user.getUsername()); 59 | 60 | if (userExists != null) { 61 | throw new BadRequestException(user.getUsername() + " already registered."); 62 | } 63 | 64 | // Disable user until they click on confirmation link in email 65 | user.setEnabled(false); 66 | user.setRole("ROLE_USER"); 67 | 68 | // Generate random 36-character string token for confirmation link 69 | user.setConfirmationToken(UUID.randomUUID().toString()); 70 | 71 | userRepository.save(user); 72 | 73 | return true; 74 | } 75 | 76 | public User resetUser(User user) { 77 | if (user.getUsername().isEmpty()) { 78 | user.setUsername(user.getEmail()); 79 | } 80 | User userExists = userRepository.findByUsername(user.getUsername()); 81 | 82 | if (userExists == null) { 83 | throw new BadRequestException(user.getUsername() + " is not registered."); 84 | } 85 | 86 | if (userExists.getEmail().isEmpty()) { 87 | throw new BadRequestException(user.getUsername() + " does not have a valid email address."); 88 | } 89 | 90 | String password = generatePassword(10); 91 | String encodedPassword = encoder.encode(password); 92 | userExists.setPassword(encodedPassword); 93 | userExists.setTempPassword(true); 94 | 95 | userRepository.save(userExists); 96 | 97 | // return the user with plain password so that we can send it to the user's email. 98 | userExists.setPassword(password); 99 | 100 | return userExists; 101 | } 102 | 103 | public User changeUserPassword(User user) { 104 | User userExists = userRepository.findByUsername(user.getUsername()); 105 | 106 | if (userExists == null) { 107 | throw new BadRequestException(user.getUsername() + " is not registered."); 108 | } 109 | 110 | String oldPassword = user.getPassword(); 111 | if (!encoder.matches(oldPassword, userExists.getPassword())) { 112 | throw new BadRequestException("Invalid current password."); 113 | } 114 | 115 | if (!userExists.getEnabled()) { 116 | throw new BadRequestException("The user is not enabled."); 117 | } 118 | 119 | String newPassword = user.getConfirmationToken(); 120 | String encodedPassword = encoder.encode(newPassword); 121 | userExists.setPassword(encodedPassword); 122 | userExists.setTempPassword(false); 123 | 124 | userRepository.save(userExists); 125 | 126 | userExists.setPassword(""); 127 | userExists.setId(0); 128 | return userExists; 129 | } 130 | 131 | public User confirmrUser(String token) { 132 | User user = userRepository.findByConfirmationToken(token); 133 | 134 | if (user == null) { 135 | throw new BadRequestException("Invalid token."); 136 | } 137 | // Token found 138 | user.setEnabled(true); 139 | user.setConfirmationToken(""); 140 | 141 | // Save user 142 | userRepository.save(user); 143 | return user; 144 | } 145 | 146 | public User loginUser(User user) { 147 | User userExists = userRepository.findByUsername(user.getUsername()); 148 | 149 | if (userExists == null) { 150 | throw new BadRequestException("Invalid user name."); 151 | } 152 | 153 | String password = user.getPassword(); 154 | if (!encoder.matches(password, userExists.getPassword())) { 155 | throw new BadRequestException("Invalid user name and password combination."); 156 | } 157 | 158 | if (!userExists.getEnabled()) { 159 | throw new BadRequestException("The user is not enabled."); 160 | } 161 | 162 | userExists.setPassword(""); 163 | userExists.setId(0); 164 | return userExists; 165 | } 166 | 167 | public static String generatePassword(int length) { 168 | StringBuilder returnValue = new StringBuilder(length); 169 | for (int i = 0; i < length; i++) { 170 | returnValue.append(ALPHABET.charAt(RANDOM.nextInt(ALPHABET.length()))); 171 | } 172 | return new String(returnValue); 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /src/test/java/com/example/jpaservices/test/service/UserServiceTest.java: -------------------------------------------------------------------------------- 1 | package com.example.jpaservices.test.service; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | import static org.junit.Assert.fail; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | import org.junit.Before; 10 | import org.junit.Test; 11 | import org.junit.runner.RunWith; 12 | import org.mockito.Mockito; 13 | import org.springframework.beans.factory.annotation.Autowired; 14 | import org.springframework.boot.test.context.TestConfiguration; 15 | import org.springframework.boot.test.mock.mockito.MockBean; 16 | import org.springframework.context.annotation.Bean; 17 | import org.springframework.security.crypto.password.PasswordEncoder; 18 | import org.springframework.test.context.junit4.SpringRunner; 19 | 20 | import com.example.jpaservices.exception.BadRequestException; 21 | import com.example.jpaservices.model.User; 22 | import com.example.jpaservices.repository.UserRepository; 23 | import com.example.jpaservices.service.UserService; 24 | 25 | @RunWith(SpringRunner.class) 26 | public class UserServiceTest { 27 | 28 | @TestConfiguration 29 | static class UserServiceTestContextConfiguration { 30 | 31 | @Bean 32 | public UserService userService() { 33 | return new UserService(); 34 | } 35 | } 36 | 37 | @Autowired 38 | private UserService userService; 39 | 40 | @MockBean 41 | private UserRepository userRepository; 42 | 43 | @MockBean 44 | private PasswordEncoder encoder; 45 | 46 | @Before 47 | public void setUp() { 48 | User user = new User(); 49 | user.setId(1); 50 | user.setUsername("wugan"); 51 | user.setEmail("gang.wu@example.com"); 52 | user.setPassword("password"); 53 | user.setRole("ROLE_USER"); 54 | user.setEnabled(false); 55 | user.setConfirmationToken("token"); 56 | 57 | List users = new ArrayList(); 58 | users.add(user); 59 | 60 | User user1 = new User(); 61 | user1.setId(2); 62 | user1.setUsername("wugan1"); 63 | user1.setEmail("gang1.wu@example.com"); 64 | user1.setPassword("password1"); 65 | user1.setRole("ROLE_USER"); 66 | user1.setEnabled(true); 67 | user1.setConfirmationToken(""); 68 | users.add(user1); 69 | 70 | Mockito.when(userRepository.findByUsername(user.getUsername())).thenReturn(user); 71 | Mockito.when(userRepository.findByConfirmationToken(user.getConfirmationToken())).thenReturn(user); 72 | Mockito.when(userRepository.findAll()).thenReturn(users); 73 | Mockito.when(encoder.matches(user.getPassword(), "password")).thenReturn(true); 74 | 75 | Mockito.when(userRepository.findByUsername(user1.getUsername())).thenReturn(user1); 76 | Mockito.when(encoder.encode(user.getPassword())).thenReturn("encoded_password"); 77 | Mockito.when(encoder.matches(user1.getPassword(), "password1")).thenReturn(true); 78 | } 79 | 80 | @Test 81 | public void getAllUsersTest() { 82 | List users = userService.getAllUsers(); 83 | 84 | assertThat(users.size()).isEqualTo(2); 85 | } 86 | 87 | @Test 88 | public void registerUserTest() { 89 | 90 | User user = new User(); 91 | user.setId(1); 92 | user.setUsername("wugang"); 93 | user.setEmail("gang.wu@java.com"); 94 | user.setPassword("password"); 95 | user.setConfirmationToken(""); 96 | user.setEnabled(true); 97 | user.setRole(""); 98 | 99 | boolean result = userService.registerUser(user); 100 | assertThat(result).isEqualTo(true); 101 | assertThat(user.getPassword()).isEqualTo("encoded_password"); 102 | assertThat(user.getRole()).isEqualTo("ROLE_USER"); 103 | assertThat(user.getEnabled()).isEqualTo(false); 104 | assertThat(user.getConfirmationToken()).isNotEmpty(); 105 | 106 | user.setUsername("wugan"); 107 | try { 108 | result = userService.registerUser(user); 109 | fail(); 110 | } catch (BadRequestException e) { 111 | assertThat(e.getMessage()).isEqualTo("wugan already registered."); 112 | } 113 | 114 | user.setUsername("wugang"); 115 | user.setPassword(""); 116 | try { 117 | result = userService.registerUser(user); 118 | fail(); 119 | } catch (BadRequestException e) { 120 | assertThat(e.getMessage()).isEqualTo("Invalid password."); 121 | } 122 | } 123 | 124 | @Test 125 | public void resetUserTest() { 126 | User user = new User(); 127 | user.setId(1); 128 | user.setUsername("wugan"); 129 | 130 | user = userService.resetUser(user); 131 | assertThat(user.getPassword()).isNotEmpty(); 132 | assertThat(user.isTempPassword()).isEqualTo(true); 133 | } 134 | 135 | @Test 136 | public void changeUserPasswordTest() { 137 | User user = new User(); 138 | user.setUsername("wugan1"); 139 | user.setPassword("password1"); 140 | user.setConfirmationToken("newpassword"); 141 | user.setTempPassword(true); 142 | 143 | user = userService.changeUserPassword(user); 144 | assertThat(user.isTempPassword()).isEqualTo(false); 145 | } 146 | 147 | @Test 148 | public void confirmrUserTest() { 149 | User user = userService.confirmrUser("token"); 150 | assertThat(user.getEnabled()).isEqualTo(true); 151 | assertThat(user.getConfirmationToken()).isEmpty(); 152 | } 153 | 154 | @Test 155 | public void loginUserTest() { 156 | User user = new User(); 157 | user.setUsername("wugan1"); 158 | user.setPassword("password1"); 159 | User loginUser = userService.loginUser(user); 160 | 161 | assertThat(loginUser.getEnabled()).isEqualTo(true); 162 | assertThat(loginUser.getConfirmationToken()).isEmpty(); 163 | assertThat(loginUser.getPassword()).isEqualTo(""); 164 | assertThat(loginUser.getEmail()).isEqualTo("gang1.wu@example.com"); 165 | 166 | user.setUsername("wugan"); 167 | user.setPassword("password"); 168 | try { 169 | loginUser = userService.loginUser(user); 170 | fail(); 171 | } catch (BadRequestException e) { 172 | assertThat(e.getMessage()).isEqualTo("The user is not enabled."); 173 | } 174 | 175 | } 176 | } 177 | --------------------------------------------------------------------------------