change user and pass

This commit is contained in:
Anthony Stirling 2023-08-15 00:39:13 +01:00
parent d7307665b3
commit 86f71ffb93
10 changed files with 125 additions and 34 deletions

View file

@ -20,9 +20,9 @@ public class InitialSetup {
if(initialUsername != null && initialPassword != null) { if(initialUsername != null && initialPassword != null) {
userService.saveUser(initialUsername, initialPassword, Role.ADMIN.getRoleId()); userService.saveUser(initialUsername, initialPassword, Role.ADMIN.getRoleId());
} }
// else { else {
// userService.saveUser("admin", "password", Role.ADMIN.getRoleId()); userService.saveUser("admin", "password", Role.ADMIN.getRoleId());
// } }
} }
} }
} }

View file

@ -134,7 +134,7 @@ public class UserService {
} }
public boolean usernameExists(String username) { public boolean usernameExists(String username) {
return userRepository.findByUsername(username) != null; return userRepository.findByUsername(username).isPresent();
} }
public boolean hasUsers() { public boolean hasUsers() {
@ -158,5 +158,21 @@ public class UserService {
} }
} }
public Optional<User> findByUsername(String username) {
return userRepository.findByUsername(username);
}
public void changeUsername(User user, String newUsername) {
user.setUsername(newUsername);
userRepository.save(user);
}
public void changePassword(User user, String newPassword) {
user.setPassword(passwordEncoder.encode(newPassword));
userRepository.save(user);
}
public boolean isPasswordCorrect(User user, String currentPassword) {
return passwordEncoder.matches(currentPassword, user.getPassword());
}
} }

View file

@ -3,6 +3,7 @@ package stirling.software.SPDF.controller.api;
import java.security.Principal; import java.security.Principal;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
@ -17,8 +18,11 @@ import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestParam;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import stirling.software.SPDF.config.security.UserService; import stirling.software.SPDF.config.security.UserService;
import stirling.software.SPDF.model.User; import stirling.software.SPDF.model.User;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
@Controller @Controller
public class UserController { public class UserController {
@ -26,6 +30,9 @@ public class UserController {
@Autowired @Autowired
private UserService userService; private UserService userService;
@Autowired
private PasswordEncoder passwordEncoder;
@PostMapping("/register") @PostMapping("/register")
public String register(@RequestParam String username, @RequestParam String password, Model model) { public String register(@RequestParam String username, @RequestParam String password, Model model) {
if(userService.usernameExists(username)) { if(userService.usernameExists(username)) {
@ -37,6 +44,59 @@ public class UserController {
return "redirect:/login?registered=true"; return "redirect:/login?registered=true";
} }
@PostMapping("/change-username")
public ResponseEntity<String> changeUsername(Principal principal, @RequestParam String currentPassword, @RequestParam String newUsername, HttpServletRequest request, HttpServletResponse response) {
if (principal == null) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).body("User not authenticated.");
}
Optional<User> userOpt = userService.findByUsername(principal.getName());
if(userOpt == null || userOpt.isEmpty()) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("User not found.");
}
User user = userOpt.get();
if(!userService.isPasswordCorrect(user, currentPassword)) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).body("Current password is incorrect.");
}
if(userService.usernameExists(newUsername)) {
return ResponseEntity.status(HttpStatus.CONFLICT).body("New username already exists.");
}
userService.changeUsername(user, newUsername);
// Logout using Spring's utility
new SecurityContextLogoutHandler().logout(request, response, null);
return ResponseEntity.ok("Username updated successfully.");
}
@PostMapping("/change-password")
public ResponseEntity<String> changePassword(Principal principal, @RequestParam String currentPassword, @RequestParam String newPassword, HttpServletRequest request, HttpServletResponse response) {
if (principal == null) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).body("User not authenticated.");
}
Optional<User> userOpt = userService.findByUsername(principal.getName());
if(userOpt == null || userOpt.isEmpty()) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("User not found.");
}
User user = userOpt.get();
if(!userService.isPasswordCorrect(user, currentPassword)) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).body("Current password is incorrect.");
}
userService.changePassword(user, passwordEncoder.encode(newPassword));
// Logout using Spring's utility
new SecurityContextLogoutHandler().logout(request, response, null);
return ResponseEntity.ok("Password updated successfully.");
}
@PostMapping("/updateUserSettings") @PostMapping("/updateUserSettings")
public String updateUserSettings(HttpServletRequest request, Principal principal) { public String updateUserSettings(HttpServletRequest request, Principal principal) {

View file

@ -33,7 +33,7 @@ public class Authority {
private String authority; private String authority;
@ManyToOne @ManyToOne
@JoinColumn(name = "username") @JoinColumn(name = "user_id")
private User user; private User user;
public Long getId() { public Long getId() {

View file

@ -9,6 +9,8 @@ import jakarta.persistence.Column;
import jakarta.persistence.ElementCollection; import jakarta.persistence.ElementCollection;
import jakarta.persistence.Entity; import jakarta.persistence.Entity;
import jakarta.persistence.FetchType; import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id; import jakarta.persistence.Id;
import jakarta.persistence.MapKeyColumn; import jakarta.persistence.MapKeyColumn;
import jakarta.persistence.OneToMany; import jakarta.persistence.OneToMany;
@ -21,8 +23,12 @@ import java.util.HashSet;
@Table(name = "users") @Table(name = "users")
public class User { public class User {
@Id @Id
@Column(name = "username") @GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "user_id")
private Long id;
@Column(name = "username", unique = true)
private String username; private String username;
@Column(name = "password") @Column(name = "password")
@ -40,11 +46,19 @@ public class User {
@ElementCollection @ElementCollection
@MapKeyColumn(name = "setting_key") @MapKeyColumn(name = "setting_key")
@Column(name = "setting_value") @Column(name = "setting_value")
@CollectionTable(name = "user_settings", joinColumns = @JoinColumn(name = "username")) @CollectionTable(name = "user_settings", joinColumns = @JoinColumn(name = "user_id"))
private Map<String, String> settings = new HashMap<>(); // Key-value pairs of settings. private Map<String, String> settings = new HashMap<>(); // Key-value pairs of settings.
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getApiKey() { public String getApiKey() {
return apiKey; return apiKey;
} }

View file

@ -16,9 +16,9 @@ server.error.include-stacktrace=always
server.error.include-exception=true server.error.include-exception=true
server.error.include-message=always server.error.include-message=always
#logging.level.org.springframework.web=DEBUG logging.level.org.springframework.web=DEBUG
#logging.level.org.springframework=DEBUG logging.level.org.springframework=DEBUG
#logging.level.org.springframework.security=DEBUG logging.level.org.springframework.security=DEBUG
login.enabled=true login.enabled=true

View file

@ -56,8 +56,8 @@ settings.downloadOption.3=Download file
settings.zipThreshold=Zip files when the number of downloaded files exceeds settings.zipThreshold=Zip files when the number of downloaded files exceeds
settings.accountSettings=Account Settings settings.accountSettings=Account Settings
settings.adminSettings=Admin - View/Add Users settings.adminSettings=Admin Settings- View and Add Users
settings.userSettings=User Settings settings.userControlSettings=User Control Settings
settings.changeUsername=New Username settings.changeUsername=New Username
settings.changeUsernameButton=Change Username settings.changeUsernameButton=Change Username
settings.password=Confirmation Password settings.password=Confirmation Password

View file

@ -20,6 +20,7 @@
<!-- At the top of the user settings --> <!-- At the top of the user settings -->
<h3 class="text-center">Welcome <span th:text="${username}">User</span>!</h3> <h3 class="text-center">Welcome <span th:text="${username}">User</span>!</h3>
<!-- Change Username Form --> <!-- Change Username Form -->
<h4>Change username?</h4> <h4>Change username?</h4>
<form action="/change-username" method="post"> <form action="/change-username" method="post">
@ -28,8 +29,8 @@
<input type="text" class="form-control" name="newUsername" id="newUsername" placeholder="New Username"> <input type="text" class="form-control" name="newUsername" id="newUsername" placeholder="New Username">
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="password" th:text="#{settings.password}">Password</label> <label for="currentPassword" th:text="#{settings.password}">Password</label>
<input type="password" class="form-control" name="password" id="password" placeholder="Password"> <input type="password" class="form-control" name="currentPassword" id="currentPassword" placeholder="Password">
</div> </div>
<div class="form-group"> <div class="form-group">
<button type="submit" class="btn btn-primary" th:text="#{settings.changeUsernameButton}">Change Username</button> <button type="submit" class="btn btn-primary" th:text="#{settings.changeUsernameButton}">Change Username</button>
@ -42,8 +43,8 @@
<h4>Change Password?</h4> <h4>Change Password?</h4>
<form action="/change-password" method="post"> <form action="/change-password" method="post">
<div class="form-group"> <div class="form-group">
<label for="oldPassword" th:text="#{settings.oldPassword}">Old Password</label> <label for="currentPassword" th:text="#{settings.oldPassword}">Old Password</label>
<input type="password" class="form-control" name="oldPassword" id="oldPassword" placeholder="Old Password"> <input type="password" class="form-control" name="currentPassword" id="currentPassword" placeholder="Old Password">
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="newPassword" th:text="#{settings.newPassword}">New Password</label> <label for="newPassword" th:text="#{settings.newPassword}">New Password</label>
@ -177,13 +178,9 @@
</table> </table>
<div class="buttons-container mt-3 text-center"> <div class="buttons-container mt-3 text-center">
<button id="syncToBrowser" class="btn btn-primary btn-sm">Sync Account to Web Browser</button> <button id="syncToBrowser" class="btn btn-primary btn-sm">Sync Account -> Browser</button>
<button id="syncToAccount" class="btn btn-secondary btn-sm">Sync Web Browser to Account</button> <button id="syncToAccount" class="btn btn-secondary btn-sm">Sync Account <- Browser</button>
</div> </div>
<a th:if="${role == 'ROLE_ADMIN'}" href="addUsers" target="_blank">
<button type="button" class="btn btn-sm btn-outline-primary" th:text="#{settings.adminSettings}">Admin Settings</button>
</a>
</div> </div>
@ -276,11 +273,15 @@
<!-- Sign Out Button -->
<div class="form-group mt-4"> <div class="form-group mt-4">
<a href="/logout"> <a href="/logout">
<button type="button" class="btn btn-danger" th:text="#{settings.signOut}">Sign Out</button> <button type="button" class="btn btn-danger" th:text="#{settings.signOut}">Sign Out</button>
</a> </a>
<a th:if="${role == 'ROLE_ADMIN'}" href="addUsers" target="_blank">
<button type="button" class="btn btn-info" th:text="#{settings.adminSettings}">Admin Settings</button>
</a>
</div> </div>
</div> </div>

View file

@ -14,11 +14,8 @@
<div class="col-md-8"> <div class="col-md-8">
<!-- User Settings Title --> <!-- User Settings Title -->
<h2 class="text-center" th:text="#{settings.accountSettings}">User Settings</h2> <h2 class="text-center" th:text="#{settings.userControlSettings}">User Control Settings</h2>
<hr>
<!-- At the top of the user settings -->
<h3 class="text-center">Welcome <span th:text="${username}">User</span>!</h3>

View file

@ -339,11 +339,14 @@
</div> </div>
</div> </div>
<a href="account" target="_blank"> <div th:if="${@loginEnabled}">
<button type="button" class="btn btn-sm btn-outline-primary" th:text="#{settings.accountSettings}">Account Settings</button> <a href="account" target="_blank">
</a> <button type="button" class="btn btn-sm btn-outline-primary" th:text="#{settings.accountSettings}">Account Settings</button>
</a>
<a href="/logout">
<button type="button" class="btn btn-danger" th:text="#{settings.signOut}">Sign Out</button>
</a>
</div>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal" th:text="#{close}"></button> <button type="button" class="btn btn-secondary" data-dismiss="modal" th:text="#{close}"></button>