diff --git a/build.gradle b/build.gradle index ea7614f..7c7384d 100644 --- a/build.gradle +++ b/build.gradle @@ -17,6 +17,7 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter' implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-security' + implementation 'org.springframework.boot:spring-boot-starter-mail' implementation 'io.jsonwebtoken:jjwt:0.9.1' implementation 'org.springframework.security:spring-security-web' implementation 'org.postgresql:postgresql' diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/WebSecurityConfig.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/WebSecurityConfig.java index a8bcb1d..9bbea89 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/WebSecurityConfig.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/WebSecurityConfig.java @@ -54,6 +54,10 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { .permitAll() .antMatchers("/auth/register") .permitAll() + .antMatchers("/register") + .permitAll() + .antMatchers("/register/confirm-account") + .permitAll() . // all other requests need to be authenticated anyRequest() diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/AuthenticationController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/AuthenticationController.java index ed82692..4646bd1 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/AuthenticationController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/AuthenticationController.java @@ -42,13 +42,6 @@ public class AuthenticationController { return new JWTResponse(token); } - @PostMapping("/register") - public User register(@Valid @RequestBody User user) { - user.setPassword(encoder.encode(user.getPassword())); - users.save(user); - return user; - } - @PatchMapping("/update") public User update(@Valid @RequestBody final UserUpdateRequest u, final Principal principal) { final User oldUser = userRepository.findByUsername(principal.getName()); diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/UserAccountController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/UserAccountController.java index 6b16039..b0210e0 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/UserAccountController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/UserAccountController.java @@ -1,16 +1,24 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.controller; import ch.usi.inf.sa4.sanmarinoes.smarthut.Service.EmailSenderService; +import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.OkResponse; +import ch.usi.inf.sa4.sanmarinoes.smarthut.error.DuplicateEmailRegistrationException; +import ch.usi.inf.sa4.sanmarinoes.smarthut.error.EmailTokenNotFoundException; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.ConfirmationToken; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.ConfirmationTokenRepository; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.User; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.UserRepository; +import javax.validation.Valid; +import javax.validation.constraints.NotNull; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.mail.SimpleMailMessage; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.servlet.ModelAndView; @@ -25,6 +33,8 @@ public class UserAccountController { @Autowired private EmailSenderService emailSenderService; + @Autowired private BCryptPasswordEncoder encoder; + @GetMapping public ModelAndView displayRegistration(ModelAndView modelAndView, User user) { modelAndView.addObject("user", user); @@ -33,14 +43,17 @@ public class UserAccountController { } @PostMapping - public ModelAndView registerUser(ModelAndView modelAndView, User user) { - + public OkResponse registerUser(@Valid @RequestBody User user) + throws DuplicateEmailRegistrationException { + System.out.println(user); User existingUser = userRepository.findByEmailIgnoreCase(user.getEmail()); + // Check if an User with the same email already exists if (existingUser != null) { - modelAndView.addObject("message", "This email already exists!"); - modelAndView.setViewName("error"); + throw new DuplicateEmailRegistrationException(); } else { + // encode user's password + user.setPassword(encoder.encode(user.getPassword())); userRepository.save(user); ConfirmationToken confirmationToken = new ConfirmationToken(user); @@ -53,16 +66,28 @@ public class UserAccountController { mailMessage.setFrom("smarthut.sm@gmail.com"); mailMessage.setText( "To confirm your account, please click here : " - + "http://localhost:8082/confirm-account?token=" + + "http://localhost:8080/register/confirm-account?token=" + confirmationToken.getConfirmationToken()); emailSenderService.sendEmail(mailMessage); - modelAndView.addObject("emailId", user.getEmail()); - - modelAndView.setViewName("successfulRegisteration"); + return new OkResponse(); } + } - return modelAndView; + @GetMapping(value = "/confirm-account") + public OkResponse confirmUserAccount(@RequestParam("token") @NotNull String confirmationToken) + throws EmailTokenNotFoundException { + final ConfirmationToken token = + confirmationTokenRepository.findByConfirmationToken(confirmationToken); + + if (token != null) { + final User user = userRepository.findByEmailIgnoreCase(token.getUser().getEmail()); + user.setEnabled(true); + userRepository.save(user); + return new OkResponse(); + } else { + throw new EmailTokenNotFoundException(); + } } } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/OkResponse.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/OkResponse.java new file mode 100644 index 0000000..e3de94e --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/OkResponse.java @@ -0,0 +1,6 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.dto; + +/** A dummy DTO to return when there is no data to return */ +public class OkResponse { + private boolean success = true; +} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/error/DuplicateEmailRegistrationException.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/error/DuplicateEmailRegistrationException.java new file mode 100644 index 0000000..3c37b2b --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/error/DuplicateEmailRegistrationException.java @@ -0,0 +1,11 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.error; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(code = HttpStatus.BAD_REQUEST) +public class DuplicateEmailRegistrationException extends Exception { + public DuplicateEmailRegistrationException() { + super("Email already belonging to another user"); + } +} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/error/EmailTokenNotFoundException.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/error/EmailTokenNotFoundException.java new file mode 100644 index 0000000..b3e38b1 --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/error/EmailTokenNotFoundException.java @@ -0,0 +1,11 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.error; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(code = HttpStatus.BAD_REQUEST) +public class EmailTokenNotFoundException extends Exception { + public EmailTokenNotFoundException() { + super("Email verification token not found in DB"); + } +} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ConfirmationToken.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ConfirmationToken.java index 7f0b71c..f6c86a0 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ConfirmationToken.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ConfirmationToken.java @@ -37,6 +37,9 @@ public class ConfirmationToken { confirmationToken = UUID.randomUUID().toString(); } + /** Constructor for hibernate reflective stuff things whatever */ + public ConfirmationToken() {} + public Long getId() { return id; } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/User.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/User.java index e4ce24e..6c1ff6b 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/User.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/User.java @@ -3,10 +3,10 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.models; import java.util.Set; import javax.persistence.*; import javax.validation.constraints.Email; -import javax.validation.constraints.Min; import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotNull; import javax.validation.constraints.Pattern; +import javax.validation.constraints.Size; /** A user of the Smarthut application */ @Entity(name = "smarthutuser") @@ -33,7 +33,10 @@ public class User { @NotNull @Column(nullable = false) @NotEmpty(message = "Please provide a password") - @Min(value = 6, message = "Your password should be at least 6 characters long") + @Size( + min = 6, + max = 255, + message = "Your password should be at least 6 characters long and up to 255 chars long") private String password; /** @@ -51,6 +54,9 @@ public class User { @OneToMany(mappedBy = "user") private Set rooms; + @Column(nullable = false) + private Boolean isEnabled = false; + public Long getId() { return id; } @@ -95,6 +101,14 @@ public class User { return rooms; } + public Boolean getEnabled() { + return isEnabled; + } + + public void setEnabled(Boolean enabled) { + isEnabled = enabled; + } + @Override public String toString() { return "User{" @@ -103,11 +117,17 @@ public class User { + ", name='" + name + '\'' + + ", username='" + + username + + '\'' + ", password='" + password + '\'' + ", email='" + email - + "\'}"; + + '\'' + + ", isEnabled=" + + isEnabled + + '}'; } } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 30d24cd..9bfe2a7 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -10,4 +10,16 @@ spring.jpa.hibernate.ddl-auto=update spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyJpaCompliantImpl spring.jpa.properties.hibernate.format_sql=true -jwt.secret=thiskeymustbeverylongorthethingcomplainssoiamjustgoingtowritehereabunchofgarbageciaomamma \ No newline at end of file +jwt.secret=thiskeymustbeverylongorthethingcomplainssoiamjustgoingtowritehereabunchofgarbageciaomamma + +spring.mail.test-connection=true +spring.mail.host=smtp.gmail.com +spring.mail.port=587 +spring.mail.properties.mail.smtp.starttls.enable=true +spring.mail.username=smarthut.sm@gmail.com +spring.mail.password=dcadvbagqfkwbfts +spring.mail.properties.mail.smtp.starttls.required=true +spring.mail.properties.mail.smtp.auth=true +spring.mail.properties.mail.smtp.connectiontimeout=5000 +spring.mail.properties.mail.smtp.timeout=5000 +spring.mail.properties.mail.smtp.writetimeout=5000 \ No newline at end of file