Skip to content
This repository has been archived by the owner on Jan 2, 2023. It is now read-only.

Commit

Permalink
Merge pull request #239 from SCCapstone/152-Springbootmail-user-verif…
Browse files Browse the repository at this point in the history
…ication

152 springbootmail user verification
  • Loading branch information
afrederiksen authored Apr 3, 2022
2 parents 559bb3a + a5d6223 commit 17a2f5f
Show file tree
Hide file tree
Showing 12 changed files with 242 additions and 90 deletions.
10 changes: 10 additions & 0 deletions backend/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,16 @@
<artifactId>modelmapper</artifactId>
<version>2.3.5</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.10</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
<!-- <dependency>-->
<!-- <groupId>org.mockito</groupId>-->
<!-- <artifactId>mockito-core</artifactId>-->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,40 @@

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.data.repository.query.Param;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
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.RestController;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.*;
import recipes.fridger.backend.dto.CreateAuthRequestDTO;
import recipes.fridger.backend.dto.CreateUserDTO;
import recipes.fridger.backend.dto.JwtTokenDTO;
import recipes.fridger.backend.mail.OnRegistrationCompleteEvent;
import recipes.fridger.backend.mail.Utility;
import recipes.fridger.backend.model.User;
import recipes.fridger.backend.security.jwt.JwtUtils;
import recipes.fridger.backend.security.services.UserDetailsImpl;
import recipes.fridger.backend.service.UserService;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

@RestController
@Slf4j
@RequestMapping(path = "/v1/auth")
public class AuthController {

@Autowired
ApplicationEventPublisher eventPublisher;

@Autowired
private UserService userService;

Expand All @@ -40,9 +48,14 @@ public class AuthController {
@Autowired
JwtUtils jwtUtils;

//used to verifiy if user has an account
@PostMapping(path = "/login")
public ResponseEntity<JwtTokenDTO>
authenticateUser(@RequestBody CreateAuthRequestDTO u) {
//TODO add
// if(user.getEnabled()==false)
// -->don't allow

Authentication authentication = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(u.getEmail(), u.getPassword()));

Expand All @@ -62,22 +75,71 @@ public class AuthController {

@PostMapping(path = "/register")
public ResponseEntity<String>
createUser(@RequestBody @Valid CreateUserDTO u) {
createUser(@RequestBody @Valid CreateUserDTO u, HttpServletRequest request) {
// Ensure email is unique
log.info("attempting user create");
if(userService.getUserByEmail(u.getEmail()) != null) {
log.info("already exists user" + u.getEmail());
return ResponseEntity.badRequest().body("Account already exists");
}
try {
log.info("halfway there to user creation");
userService.createUser(u);
//Create user
User registered = userService.registerNewUserAccount(u, request);
log.info("Successful creation of user");

//Send Verification Email To that user
// String siteURL = Utility.getSiteURL(request); //get site for verification email
// userService.createVerificationToken(registered, UUID.randomUUID().toString());
// userService.sendVerificationEmail(registered,siteURL);
// log.info("Sent email to "+u.getEmail());

return ResponseEntity.ok("Created user");
} catch (Exception e) {
log.warn("Unable to create user\n" + e.getMessage());
return ResponseEntity.internalServerError().body(
"Unable to create user\n" + e.getMessage());
}
}

@GetMapping("/verify")
public String verifyUser(@Param("code") String code) {
if (userService.verify(code)) {
return "verify_success";
} else {
return "verify_fail";
}
}

// @PostMapping(path = "/register")
// public ResponseEntity<String>
// createUser(@RequestBody @Valid CreateUserDTO u, HttpServletRequest request, Errors errors) {
// // Ensure email is unique
// log.info("attempting user create");
// if(userService.getUserByEmail(u.getEmail()) != null) {
// log.info("already exists user" + u.getEmail());
// return ResponseEntity.badRequest().body("Account already exists");
// }
// try {
// log.info("Entering User Creation");
// User registered = userService.registerNewUserAccount(u);
//
// String appURL = request.getContextPath();
// eventPublisher.publishEvent(new OnRegistrationCompleteEvent(registered,request.getLocale(),appURL));
//
// log.info("Successful creation of user");
// return ResponseEntity.ok("Created user");
// } catch (Exception e) {
// log.warn("Unable to create user\n" + e.getMessage());
// return ResponseEntity.internalServerError().body(
// "Unable to create user\n" + e.getMessage());
// }
// }

@DeleteMapping(path = "/deleteUserAcct")
public void deleteUser(@RequestBody @Valid String email) {
if(userService.emailExistsPub(email)) {
log.info("user exists at this email: "+email);
userService.deleteUserByEmail(email);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.MessageSource;
import org.springframework.data.repository.query.Param;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.GrantedAuthority;
Expand Down Expand Up @@ -94,47 +95,30 @@ public class UserController {
* USER API
*/

//no verification -> this works and is tested
@PostMapping(path = "/")
public ResponseEntity<String>
createUser(@RequestBody @Valid CreateUserDTO u) {
try {
userService.createUser(u);
log.info("Successful creation of user");
return ResponseEntity.ok("Created user");
} catch (Exception e) {
log.warn("Unable to create user\n" + e.getMessage());
return ResponseEntity.internalServerError().body(
"Unable to create user\n" + e.getMessage());
}
}
@GetMapping("/registrationConfirm")
public String confirmRegistration
(WebRequest request, Model model, @RequestParam("token") String token) {

//account verification of user
@PostMapping("/user/registration")
public ModelAndView registerUserAccount(
@ModelAttribute("user") @Valid CreateUserDTO userDto,
HttpServletRequest request, Errors errors) {
Locale locale = request.getLocale();

try {
User registered = userService.registerNewUserAccount(userDto);
log.info("inside registerUserAccount");

String appUrl = request.getContextPath();
eventPublisher.publishEvent(new OnRegistrationCompleteEvent(registered,
request.getLocale(), appUrl));
} catch (UserAlreadyExistException uaeEx) {
ModelAndView mav = new ModelAndView("registration", "user", userDto);
mav.addObject("message", "An account for that username/email already exists.");
log.info("1st catch");
return mav;

} catch (RuntimeException ex) {
log.info("2nd catch");
return new ModelAndView("emailError", "user", userDto);
VerificationToken verificationToken = userService.getVerificationToken(token);
if (verificationToken == null) {
String message = messages.getMessage("auth.message.invalidToken", null, locale);
model.addAttribute("message", message);
return "redirect:/badUser.html?lang=" + locale.getLanguage();
}

User user = verificationToken.getUser();
Calendar cal = Calendar.getInstance();
if ((verificationToken.getExpiryDate().getTime() - cal.getTime().getTime()) <= 0) {
String messageValue = messages.getMessage("auth.message.expired", null, locale);
model.addAttribute("message", messageValue);
return "redirect:/badUser.html?lang=" + locale.getLanguage();
}

return new ModelAndView("successRegister", "user", userDto);
user.setEnabled(true);
userService.saveRegisteredUser(user);
return "redirect:/login.html?lang=" + request.getLocale().getLanguage();
}

@PreAuthorize("hasAnyRole('USER', 'ADMIN')")
Expand Down Expand Up @@ -211,31 +195,7 @@ public ResponseEntity<String> deleteUser(@PathVariable Long id) {
}
}

@GetMapping("/registrationConfirm")
public String confirmRegistration
(WebRequest request, Model model, @RequestParam("token") String token) {

Locale locale = request.getLocale();

VerificationToken verificationToken = userService.getVerificationToken(token);
if (verificationToken == null) {
String message = messages.getMessage("auth.message.invalidToken", null, locale);
model.addAttribute("message", message);
return "redirect:/badUser.html?lang=" + locale.getLanguage();
}

User user = verificationToken.getUser();
Calendar cal = Calendar.getInstance();
if ((verificationToken.getExpiryDate().getTime() - cal.getTime().getTime()) <= 0) {
String messageValue = messages.getMessage("auth.message.expired", null, locale);
model.addAttribute("message", messageValue);
return "redirect:/badUser.html?lang=" + locale.getLanguage();
}

user.setEnabled(true);
userService.saveRegisteredUser(user);
return "redirect:/login.html?lang=" + request.getLocale().getLanguage();
}

//@PreAuthorization("hasRole('USER') or hasRole(‘ADMIN’)")

Expand Down
4 changes: 4 additions & 0 deletions backend/src/main/java/recipes/fridger/backend/crud/Users.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,8 @@ public interface Users extends CrudRepository<User, Long> {

@Query("select u from User u where (u.email = :email)")
User findByEmailAuth(String email);

@Query("SELECT u FROM User u WHERE u.verificationCode = ?1")
public User findByVerificationCode(String code);

}
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ private void confirmRegistration(OnRegistrationCompleteEvent event) {
userService.createVerificationToken(user, token);

String recipientAddress = user.getEmail();
String subject = "Fridger Registration Confirmation";
String subject = "Fridger New Account Confirmation";
String confirmationUrl
= event.getAppUrl() + "/registrationConfirm.html?token=" + token;
String message = messages.getMessage("message.regSucc", null, event.getLocale());
Expand Down
10 changes: 10 additions & 0 deletions backend/src/main/java/recipes/fridger/backend/mail/Utility.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package recipes.fridger.backend.mail;

import javax.servlet.http.HttpServletRequest;

public class Utility {
public static String getSiteURL(HttpServletRequest request) {
String siteURL = request.getRequestURL().toString();
return siteURL.replace(request.getServletPath(),"");
}
}
3 changes: 3 additions & 0 deletions backend/src/main/java/recipes/fridger/backend/model/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ public class User {
@Column(name = "enabled")
private boolean enabled;

@Column(name = "verification_code", length = 64)
private String verificationCode;

@Size(min = 0, max = 100)
@Column(name = "password")
private String password;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ public class VerificationToken {
public VerificationToken() { //default contructor

}
public VerificationToken(User u, String tokn) {
public VerificationToken(User u, String tok) {
user = u;
token = tokn;
token = tok;
}

private Date calculateExpiryDate(int expiryTimeInMinutes) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,26 @@
import recipes.fridger.backend.model.User;
import recipes.fridger.backend.model.VerificationToken;

import javax.mail.MessagingException;
import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;

public interface UserService {
public void createUser(CreateUserDTO dto);
public void deleteUser(Long id);
public User getUser(Long id);
public void updateUser(Long id, UpdateUserDTO u) throws Exception;

public boolean emailExistsPub(String email);
public boolean isEnabled(String email);
public Iterable<User> getUsersByIdAndEmail(Long id, String email);
public Iterable<User> getUsers(Long userId);
public void testSendEmail(CreateUserDTO dto);
public void sendVerificationEmail(User user, String url) throws MessagingException, UnsupportedEncodingException;
public boolean verify(String verificationCode);
public void deleteUserByEmail(String email);
public User getUserByEmail(String email);
public void saveRegisteredUser(User user);
public void createVerificationToken(User user, String token);
VerificationToken getVerificationToken(String token);
public User registerNewUserAccount(CreateUserDTO dto);
public User registerNewUserAccount(CreateUserDTO dto, HttpServletRequest request) throws MessagingException, UnsupportedEncodingException;
}
Loading

0 comments on commit 17a2f5f

Please sign in to comment.