Change User Roles (#1153)

* Modify user service and controller

* Modify Template

* Add messages

* Fix Username output

* Add tooltip

* Change Role Modify logic

* Add Roles from database to existing users

* Add default select Fillers

* Indent JS

* Add Change Role Related Translations

* Remove unnecessary Whitespace and imports
This commit is contained in:
Sahil Phule
2024-05-02 14:52:50 -06:00
committed by GitHub
parent c622ee915b
commit d7afc574a6
33 changed files with 213 additions and 0 deletions

View File

@@ -15,6 +15,9 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.core.userdetails.UserDetailsService;
@@ -23,6 +26,7 @@ import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.client.registration.ClientRegistration;
import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.security.oauth2.core.user.OAuth2UserAuthority;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@@ -34,9 +38,11 @@ import org.springframework.security.oauth2.client.registration.ClientRegistratio
import jakarta.servlet.http.HttpSession;
import stirling.software.SPDF.model.ApplicationProperties;
import stirling.software.SPDF.model.User;
import stirling.software.SPDF.repository.JPATokenRepositoryImpl;
import java.io.IOException;
import java.util.*;
@Configuration
@EnableWebSecurity()
@@ -182,6 +188,10 @@ public class SecurityConfiguration {
}
}
)
// Add existing Authorities from the database
.userInfoEndpoint( userInfoEndpoint ->
userInfoEndpoint.userAuthoritiesMapper(userAuthoritiesMapper())
)
);
}
} else {
@@ -210,6 +220,38 @@ public class SecurityConfiguration {
.build();
}
/*
This following function is to grant Authorities to the OAUTH2 user from the values stored in the database.
This is required for the internal; 'hasRole()' function to give out the correct role.
*/
@Bean
@ConditionalOnProperty(value = "security.oauth2.enabled" , havingValue = "true", matchIfMissing = false)
GrantedAuthoritiesMapper userAuthoritiesMapper() {
return (authorities) -> {
Set<GrantedAuthority> mappedAuthorities = new HashSet<>();
authorities.forEach(authority -> {
// Add existing OAUTH2 Authorities
mappedAuthorities.add(new SimpleGrantedAuthority(authority.getAuthority()));
// Add Authorities from database for existing user, if user is present.
if (authority instanceof OAuth2UserAuthority oauth2Auth) {
Optional<User> userOpt = userService.findByUsernameIgnoreCase((String)oauth2Auth.getAttributes().get("email"));
if (userOpt.isPresent()) {
User user = userOpt.get();
if (user != null){
mappedAuthorities.add(new SimpleGrantedAuthority(
userService
.findRole(user)
.getAuthority()));
}
}
}
});
return mappedAuthorities;
};
}
@Bean
public IPRateLimitingFilter rateLimitingFilter() {
int maxRequestsPerIp = 1000000; // Example limit TODO add config level

View File

@@ -21,6 +21,7 @@ import stirling.software.SPDF.controller.api.pipeline.UserServiceInterface;
import stirling.software.SPDF.model.Authority;
import stirling.software.SPDF.model.Role;
import stirling.software.SPDF.model.User;
import stirling.software.SPDF.repository.AuthorityRepository;
import stirling.software.SPDF.repository.UserRepository;
@Service
@@ -28,6 +29,8 @@ public class UserService implements UserServiceInterface {
@Autowired private UserRepository userRepository;
@Autowired private AuthorityRepository authorityRepository;
@Autowired private PasswordEncoder passwordEncoder;
// Handle OAUTH2 login and user auto creation.
@@ -202,6 +205,10 @@ public class UserService implements UserServiceInterface {
return userRepository.findByUsernameIgnoreCase(username);
}
public Authority findRole(User user) {
return authorityRepository.findByUserId(user.getId());
}
public void changeUsername(User user, String newUsername) {
user.setUsername(newUsername);
userRepository.save(user);
@@ -217,6 +224,12 @@ public class UserService implements UserServiceInterface {
userRepository.save(user);
}
public void changeRole(User user, String newRole) {
Authority userAuthority = this.findRole(user);
userAuthority.setAuthority(newRole);
authorityRepository.save(userAuthority);
}
public boolean isPasswordCorrect(User user, String currentPassword) {
return passwordEncoder.matches(currentPassword, user.getPassword());
}

View File

@@ -227,6 +227,45 @@ public class UserController {
return new RedirectView("/addUsers"); // Redirect to account page after adding the user
}
@PreAuthorize("hasRole('ROLE_ADMIN')")
@PostMapping("/admin/changeRole")
public RedirectView changeRole(
@RequestParam(name = "username") String username,
@RequestParam(name = "role") String role,
Authentication authentication) {
Optional<User> userOpt = userService.findByUsernameIgnoreCase(username);
if (!userOpt.isPresent()) {
return new RedirectView("/addUsers?messageType=userNotFound");
}
if (!userService.usernameExistsIgnoreCase(username)) {
return new RedirectView("/addUsers?messageType=userNotFound");
}
// Get the currently authenticated username
String currentUsername = authentication.getName();
// Check if the provided username matches the current session's username
if (currentUsername.equalsIgnoreCase(username)) {
return new RedirectView("/addUsers?messageType=downgradeCurrentUser");
}
try {
// Validate the role
Role roleEnum = Role.fromString(role);
if (roleEnum == Role.INTERNAL_API_USER) {
// If the role is INTERNAL_API_USER, reject the request
return new RedirectView("/addUsers?messageType=invalidRole");
}
} catch (IllegalArgumentException e) {
// If the role ID is not valid, redirect with an error message
return new RedirectView("/addUsers?messageType=invalidRole");
}
User user = userOpt.get();
userService.changeRole(user, role);
return new RedirectView("/addUsers"); // Redirect to account page after adding the user
}
@PreAuthorize("hasRole('ROLE_ADMIN')")
@PostMapping("/admin/deleteUser/{username}")
public RedirectView deleteUser(

View File

@@ -9,4 +9,7 @@ import stirling.software.SPDF.model.Authority;
public interface AuthorityRepository extends JpaRepository<Authority, Long> {
// Set<Authority> findByUsername(String username);
Set<Authority> findByUser_Username(String username);
Authority findByUserId(long user_id);
}