2024-01-03 17:59:04 +00:00
|
|
|
package stirling.software.SPDF.config.security;
|
|
|
|
|
2024-09-05 22:24:38 +05:30
|
|
|
import java.io.IOException;
|
2025-01-06 18:58:26 +00:00
|
|
|
import java.sql.SQLException;
|
2024-09-05 22:24:38 +05:30
|
|
|
import java.util.*;
|
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
2024-05-12 19:58:34 +02:00
|
|
|
import org.springframework.context.MessageSource;
|
|
|
|
import org.springframework.context.i18n.LocaleContextHolder;
|
2024-01-03 17:59:04 +00:00
|
|
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
|
|
|
import org.springframework.security.core.Authentication;
|
|
|
|
import org.springframework.security.core.GrantedAuthority;
|
|
|
|
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
2024-09-13 16:42:38 +01:00
|
|
|
import org.springframework.security.core.context.SecurityContextHolder;
|
2024-08-16 12:57:37 +02:00
|
|
|
import org.springframework.security.core.session.SessionInformation;
|
2024-01-03 17:59:04 +00:00
|
|
|
import org.springframework.security.core.userdetails.UserDetails;
|
|
|
|
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
|
|
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
2024-08-16 12:57:37 +02:00
|
|
|
import org.springframework.security.oauth2.core.user.OAuth2User;
|
2024-01-03 17:59:04 +00:00
|
|
|
import org.springframework.stereotype.Service;
|
2024-11-29 15:11:59 +00:00
|
|
|
import org.springframework.transaction.annotation.Transactional;
|
2024-09-05 22:24:38 +05:30
|
|
|
|
2024-11-11 12:55:46 +01:00
|
|
|
import lombok.extern.slf4j.Slf4j;
|
2025-01-06 18:58:26 +00:00
|
|
|
import stirling.software.SPDF.config.interfaces.DatabaseInterface;
|
2024-10-20 13:30:58 +02:00
|
|
|
import stirling.software.SPDF.config.security.saml2.CustomSaml2AuthenticatedPrincipal;
|
2024-08-16 12:57:37 +02:00
|
|
|
import stirling.software.SPDF.config.security.session.SessionPersistentRegistry;
|
2024-01-03 17:59:04 +00:00
|
|
|
import stirling.software.SPDF.controller.api.pipeline.UserServiceInterface;
|
2024-12-24 09:52:53 +00:00
|
|
|
import stirling.software.SPDF.model.*;
|
2025-01-06 18:58:26 +00:00
|
|
|
import stirling.software.SPDF.model.provider.UnsupportedProviderException;
|
2024-05-02 14:52:50 -06:00
|
|
|
import stirling.software.SPDF.repository.AuthorityRepository;
|
2024-01-03 17:59:04 +00:00
|
|
|
import stirling.software.SPDF.repository.UserRepository;
|
|
|
|
|
|
|
|
@Service
|
2024-11-11 12:55:46 +01:00
|
|
|
@Slf4j
|
2024-01-03 17:59:04 +00:00
|
|
|
public class UserService implements UserServiceInterface {
|
|
|
|
|
2024-12-24 09:52:53 +00:00
|
|
|
private final UserRepository userRepository;
|
2024-01-03 17:59:04 +00:00
|
|
|
|
2024-12-24 09:52:53 +00:00
|
|
|
private final AuthorityRepository authorityRepository;
|
2024-05-02 14:52:50 -06:00
|
|
|
|
2024-12-24 09:52:53 +00:00
|
|
|
private final PasswordEncoder passwordEncoder;
|
2024-01-03 17:59:04 +00:00
|
|
|
|
2024-12-24 09:52:53 +00:00
|
|
|
private final MessageSource messageSource;
|
2024-05-12 19:58:34 +02:00
|
|
|
|
2024-12-24 09:52:53 +00:00
|
|
|
private final SessionPersistentRegistry sessionRegistry;
|
2024-08-16 12:57:37 +02:00
|
|
|
|
2025-01-06 18:58:26 +00:00
|
|
|
private final DatabaseInterface databaseService;
|
2024-07-05 21:48:33 +02:00
|
|
|
|
2024-12-24 09:52:53 +00:00
|
|
|
private final ApplicationProperties applicationProperties;
|
|
|
|
|
|
|
|
public UserService(
|
|
|
|
UserRepository userRepository,
|
|
|
|
AuthorityRepository authorityRepository,
|
|
|
|
PasswordEncoder passwordEncoder,
|
|
|
|
MessageSource messageSource,
|
|
|
|
SessionPersistentRegistry sessionRegistry,
|
2025-01-06 18:58:26 +00:00
|
|
|
DatabaseInterface databaseService,
|
2024-12-24 09:52:53 +00:00
|
|
|
ApplicationProperties applicationProperties) {
|
|
|
|
this.userRepository = userRepository;
|
|
|
|
this.authorityRepository = authorityRepository;
|
|
|
|
this.passwordEncoder = passwordEncoder;
|
|
|
|
this.messageSource = messageSource;
|
|
|
|
this.sessionRegistry = sessionRegistry;
|
2025-01-06 18:58:26 +00:00
|
|
|
this.databaseService = databaseService;
|
2024-12-24 09:52:53 +00:00
|
|
|
this.applicationProperties = applicationProperties;
|
|
|
|
}
|
2024-11-11 12:55:46 +01:00
|
|
|
|
2024-11-29 15:11:59 +00:00
|
|
|
@Transactional
|
|
|
|
public void migrateOauth2ToSSO() {
|
|
|
|
userRepository
|
|
|
|
.findByAuthenticationTypeIgnoreCase("OAUTH2")
|
|
|
|
.forEach(
|
|
|
|
user -> {
|
|
|
|
user.setAuthenticationType(AuthenticationType.SSO);
|
|
|
|
userRepository.save(user);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2024-04-29 15:01:22 -06:00
|
|
|
// Handle OAUTH2 login and user auto creation.
|
2024-11-29 15:11:59 +00:00
|
|
|
public boolean processSSOPostLogin(String username, boolean autoCreateUser)
|
2025-01-06 18:58:26 +00:00
|
|
|
throws IllegalArgumentException, SQLException, UnsupportedProviderException {
|
2024-05-18 23:47:05 +02:00
|
|
|
if (!isUsernameValid(username)) {
|
2024-05-12 19:58:34 +02:00
|
|
|
return false;
|
|
|
|
}
|
2024-08-16 12:57:37 +02:00
|
|
|
Optional<User> existingUser = findByUsernameIgnoreCase(username);
|
2024-05-18 23:47:05 +02:00
|
|
|
if (existingUser.isPresent()) {
|
2024-04-29 15:01:22 -06:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (autoCreateUser) {
|
2024-11-29 15:11:59 +00:00
|
|
|
saveUser(username, AuthenticationType.SSO);
|
2024-04-29 15:01:22 -06:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2024-01-03 17:59:04 +00:00
|
|
|
public Authentication getAuthentication(String apiKey) {
|
2024-08-19 16:02:40 +02:00
|
|
|
Optional<User> user = getUserByApiKey(apiKey);
|
|
|
|
if (!user.isPresent()) {
|
2024-01-03 17:59:04 +00:00
|
|
|
throw new UsernameNotFoundException("API key is not valid");
|
|
|
|
}
|
|
|
|
// Convert the user into an Authentication object
|
2024-12-24 09:52:53 +00:00
|
|
|
return new UsernamePasswordAuthenticationToken( // principal (typically the user)
|
|
|
|
user, // credentials (we don't expose the password or API key here)
|
|
|
|
null, // user's authorities (roles/permissions)
|
|
|
|
getAuthorities(user.get()));
|
2024-01-03 17:59:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private Collection<? extends GrantedAuthority> getAuthorities(User user) {
|
|
|
|
// Convert each Authority object into a SimpleGrantedAuthority object.
|
|
|
|
return user.getAuthorities().stream()
|
|
|
|
.map((Authority authority) -> new SimpleGrantedAuthority(authority.getAuthority()))
|
|
|
|
.collect(Collectors.toList());
|
|
|
|
}
|
|
|
|
|
|
|
|
private String generateApiKey() {
|
|
|
|
String apiKey;
|
|
|
|
do {
|
|
|
|
apiKey = UUID.randomUUID().toString();
|
2024-12-24 09:52:53 +00:00
|
|
|
} while ( // Ensure uniqueness
|
|
|
|
userRepository.findByApiKey(apiKey).isPresent());
|
2024-01-03 17:59:04 +00:00
|
|
|
return apiKey;
|
|
|
|
}
|
|
|
|
|
|
|
|
public User addApiKeyToUser(String username) {
|
2024-08-19 16:02:40 +02:00
|
|
|
Optional<User> user = findByUsernameIgnoreCase(username);
|
|
|
|
if (user.isPresent()) {
|
|
|
|
user.get().setApiKey(generateApiKey());
|
|
|
|
return userRepository.save(user.get());
|
|
|
|
}
|
|
|
|
throw new UsernameNotFoundException("User not found");
|
2024-01-03 17:59:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public User refreshApiKeyForUser(String username) {
|
2024-12-24 09:52:53 +00:00
|
|
|
// reuse the add API key method for refreshing
|
|
|
|
return addApiKeyToUser(username);
|
2024-01-03 17:59:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public String getApiKeyForUser(String username) {
|
|
|
|
User user =
|
2024-08-16 12:57:37 +02:00
|
|
|
findByUsernameIgnoreCase(username)
|
2024-01-03 17:59:04 +00:00
|
|
|
.orElseThrow(() -> new UsernameNotFoundException("User not found"));
|
|
|
|
return user.getApiKey();
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean isValidApiKey(String apiKey) {
|
2024-08-19 16:02:40 +02:00
|
|
|
return userRepository.findByApiKey(apiKey).isPresent();
|
2024-01-03 17:59:04 +00:00
|
|
|
}
|
|
|
|
|
2024-08-19 16:02:40 +02:00
|
|
|
public Optional<User> getUserByApiKey(String apiKey) {
|
2024-01-03 17:59:04 +00:00
|
|
|
return userRepository.findByApiKey(apiKey);
|
|
|
|
}
|
|
|
|
|
2024-08-19 16:02:40 +02:00
|
|
|
public Optional<User> loadUserByApiKey(String apiKey) {
|
|
|
|
Optional<User> user = userRepository.findByApiKey(apiKey);
|
|
|
|
if (user.isPresent()) {
|
|
|
|
return user;
|
2024-01-03 17:59:04 +00:00
|
|
|
}
|
2024-12-24 09:52:53 +00:00
|
|
|
// or throw an exception
|
|
|
|
return null;
|
2024-01-03 17:59:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public boolean validateApiKeyForUser(String username, String apiKey) {
|
2024-08-16 12:57:37 +02:00
|
|
|
Optional<User> userOpt = findByUsernameIgnoreCase(username);
|
2024-05-18 23:47:05 +02:00
|
|
|
return userOpt.isPresent() && apiKey.equals(userOpt.get().getApiKey());
|
2024-01-03 17:59:04 +00:00
|
|
|
}
|
|
|
|
|
2024-05-12 19:58:34 +02:00
|
|
|
public void saveUser(String username, AuthenticationType authenticationType)
|
2025-01-06 18:58:26 +00:00
|
|
|
throws IllegalArgumentException, SQLException, UnsupportedProviderException {
|
2024-08-16 12:57:37 +02:00
|
|
|
saveUser(username, authenticationType, Role.USER.getRoleId());
|
|
|
|
}
|
|
|
|
|
|
|
|
public void saveUser(String username, AuthenticationType authenticationType, String role)
|
2025-01-06 18:58:26 +00:00
|
|
|
throws IllegalArgumentException, SQLException, UnsupportedProviderException {
|
2024-05-18 23:47:05 +02:00
|
|
|
if (!isUsernameValid(username)) {
|
|
|
|
throw new IllegalArgumentException(getInvalidUsernameMessage());
|
|
|
|
}
|
2024-01-03 17:59:04 +00:00
|
|
|
User user = new User();
|
2024-05-18 23:47:05 +02:00
|
|
|
user.setUsername(username);
|
2024-05-12 19:58:34 +02:00
|
|
|
user.setEnabled(true);
|
|
|
|
user.setFirstLogin(false);
|
2024-08-16 12:57:37 +02:00
|
|
|
user.addAuthority(new Authority(role, user));
|
2024-05-12 19:58:34 +02:00
|
|
|
user.setAuthenticationType(authenticationType);
|
|
|
|
userRepository.save(user);
|
2025-01-06 18:58:26 +00:00
|
|
|
databaseService.exportDatabase();
|
2024-05-12 19:58:34 +02:00
|
|
|
}
|
|
|
|
|
2024-07-05 21:48:33 +02:00
|
|
|
public void saveUser(String username, String password)
|
2025-01-06 18:58:26 +00:00
|
|
|
throws IllegalArgumentException, SQLException, UnsupportedProviderException {
|
2024-05-18 23:47:05 +02:00
|
|
|
if (!isUsernameValid(username)) {
|
|
|
|
throw new IllegalArgumentException(getInvalidUsernameMessage());
|
|
|
|
}
|
2024-05-12 19:58:34 +02:00
|
|
|
User user = new User();
|
2024-05-18 23:47:05 +02:00
|
|
|
user.setUsername(username);
|
2024-01-03 17:59:04 +00:00
|
|
|
user.setPassword(passwordEncoder.encode(password));
|
|
|
|
user.setEnabled(true);
|
2024-05-12 19:58:34 +02:00
|
|
|
user.setAuthenticationType(AuthenticationType.WEB);
|
2024-01-03 17:59:04 +00:00
|
|
|
userRepository.save(user);
|
2025-01-06 18:58:26 +00:00
|
|
|
databaseService.exportDatabase();
|
2024-01-03 17:59:04 +00:00
|
|
|
}
|
|
|
|
|
2024-05-12 19:58:34 +02:00
|
|
|
public void saveUser(String username, String password, String role, boolean firstLogin)
|
2025-01-06 18:58:26 +00:00
|
|
|
throws IllegalArgumentException, SQLException, UnsupportedProviderException {
|
2024-05-18 23:47:05 +02:00
|
|
|
if (!isUsernameValid(username)) {
|
|
|
|
throw new IllegalArgumentException(getInvalidUsernameMessage());
|
|
|
|
}
|
2024-01-03 17:59:04 +00:00
|
|
|
User user = new User();
|
2024-05-18 23:47:05 +02:00
|
|
|
user.setUsername(username);
|
2024-01-03 17:59:04 +00:00
|
|
|
user.setPassword(passwordEncoder.encode(password));
|
|
|
|
user.addAuthority(new Authority(role, user));
|
|
|
|
user.setEnabled(true);
|
2024-05-12 19:58:34 +02:00
|
|
|
user.setAuthenticationType(AuthenticationType.WEB);
|
2024-01-03 17:59:04 +00:00
|
|
|
user.setFirstLogin(firstLogin);
|
|
|
|
userRepository.save(user);
|
2025-01-06 18:58:26 +00:00
|
|
|
databaseService.exportDatabase();
|
2024-01-03 17:59:04 +00:00
|
|
|
}
|
|
|
|
|
2024-05-12 19:58:34 +02:00
|
|
|
public void saveUser(String username, String password, String role)
|
2025-01-06 18:58:26 +00:00
|
|
|
throws IllegalArgumentException, SQLException, UnsupportedProviderException {
|
2024-05-18 23:47:05 +02:00
|
|
|
saveUser(username, password, role, false);
|
2024-01-03 17:59:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public void deleteUser(String username) {
|
2024-08-16 12:57:37 +02:00
|
|
|
Optional<User> userOpt = findByUsernameIgnoreCase(username);
|
2024-01-03 17:59:04 +00:00
|
|
|
if (userOpt.isPresent()) {
|
|
|
|
for (Authority authority : userOpt.get().getAuthorities()) {
|
|
|
|
if (authority.getAuthority().equals(Role.INTERNAL_API_USER.getRoleId())) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
userRepository.delete(userOpt.get());
|
|
|
|
}
|
2024-08-16 12:57:37 +02:00
|
|
|
invalidateUserSessions(username);
|
2024-01-03 17:59:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public boolean usernameExists(String username) {
|
2024-08-16 12:57:37 +02:00
|
|
|
return findByUsername(username).isPresent();
|
2024-01-03 17:59:04 +00:00
|
|
|
}
|
|
|
|
|
2024-04-14 23:07:03 +02:00
|
|
|
public boolean usernameExistsIgnoreCase(String username) {
|
2024-08-16 12:57:37 +02:00
|
|
|
return findByUsernameIgnoreCase(username).isPresent();
|
2024-04-14 23:07:03 +02:00
|
|
|
}
|
|
|
|
|
2024-01-03 17:59:04 +00:00
|
|
|
public boolean hasUsers() {
|
2024-05-19 10:52:11 +02:00
|
|
|
long userCount = userRepository.count();
|
2024-08-16 12:57:37 +02:00
|
|
|
if (findByUsernameIgnoreCase(Role.INTERNAL_API_USER.getRoleId()).isPresent()) {
|
2024-05-19 10:52:11 +02:00
|
|
|
userCount -= 1;
|
|
|
|
}
|
|
|
|
return userCount > 0;
|
2024-01-03 17:59:04 +00:00
|
|
|
}
|
|
|
|
|
2024-07-05 21:48:33 +02:00
|
|
|
public void updateUserSettings(String username, Map<String, String> updates)
|
2025-01-06 18:58:26 +00:00
|
|
|
throws SQLException, UnsupportedProviderException {
|
2024-08-23 23:37:45 +03:00
|
|
|
Optional<User> userOpt = findByUsernameIgnoreCaseWithSettings(username);
|
2024-01-03 17:59:04 +00:00
|
|
|
if (userOpt.isPresent()) {
|
|
|
|
User user = userOpt.get();
|
|
|
|
Map<String, String> settingsMap = user.getSettings();
|
|
|
|
if (settingsMap == null) {
|
2024-05-18 23:47:05 +02:00
|
|
|
settingsMap = new HashMap<>();
|
2024-01-03 17:59:04 +00:00
|
|
|
}
|
|
|
|
settingsMap.clear();
|
|
|
|
settingsMap.putAll(updates);
|
|
|
|
user.setSettings(settingsMap);
|
|
|
|
userRepository.save(user);
|
2025-01-06 18:58:26 +00:00
|
|
|
databaseService.exportDatabase();
|
2024-01-03 17:59:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public Optional<User> findByUsername(String username) {
|
|
|
|
return userRepository.findByUsername(username);
|
|
|
|
}
|
|
|
|
|
2024-03-13 23:09:16 +01:00
|
|
|
public Optional<User> findByUsernameIgnoreCase(String username) {
|
|
|
|
return userRepository.findByUsernameIgnoreCase(username);
|
|
|
|
}
|
|
|
|
|
2024-08-23 23:37:45 +03:00
|
|
|
public Optional<User> findByUsernameIgnoreCaseWithSettings(String username) {
|
|
|
|
return userRepository.findByUsernameIgnoreCaseWithSettings(username);
|
|
|
|
}
|
|
|
|
|
2024-05-02 14:52:50 -06:00
|
|
|
public Authority findRole(User user) {
|
|
|
|
return authorityRepository.findByUserId(user.getId());
|
|
|
|
}
|
|
|
|
|
2024-07-05 21:48:33 +02:00
|
|
|
public void changeUsername(User user, String newUsername)
|
2025-01-06 18:58:26 +00:00
|
|
|
throws IllegalArgumentException,
|
|
|
|
IOException,
|
|
|
|
SQLException,
|
|
|
|
UnsupportedProviderException {
|
2024-05-18 23:47:05 +02:00
|
|
|
if (!isUsernameValid(newUsername)) {
|
|
|
|
throw new IllegalArgumentException(getInvalidUsernameMessage());
|
|
|
|
}
|
|
|
|
user.setUsername(newUsername);
|
2024-01-03 17:59:04 +00:00
|
|
|
userRepository.save(user);
|
2025-01-06 18:58:26 +00:00
|
|
|
databaseService.exportDatabase();
|
2024-01-03 17:59:04 +00:00
|
|
|
}
|
|
|
|
|
2025-01-06 18:58:26 +00:00
|
|
|
public void changePassword(User user, String newPassword)
|
|
|
|
throws SQLException, UnsupportedProviderException {
|
2024-01-03 17:59:04 +00:00
|
|
|
user.setPassword(passwordEncoder.encode(newPassword));
|
|
|
|
userRepository.save(user);
|
2025-01-06 18:58:26 +00:00
|
|
|
databaseService.exportDatabase();
|
2024-01-03 17:59:04 +00:00
|
|
|
}
|
|
|
|
|
2025-01-06 18:58:26 +00:00
|
|
|
public void changeFirstUse(User user, boolean firstUse)
|
|
|
|
throws SQLException, UnsupportedProviderException {
|
2024-01-03 17:59:04 +00:00
|
|
|
user.setFirstLogin(firstUse);
|
|
|
|
userRepository.save(user);
|
2025-01-06 18:58:26 +00:00
|
|
|
databaseService.exportDatabase();
|
2024-01-03 17:59:04 +00:00
|
|
|
}
|
|
|
|
|
2025-01-06 18:58:26 +00:00
|
|
|
public void changeRole(User user, String newRole)
|
|
|
|
throws SQLException, UnsupportedProviderException {
|
2024-05-02 14:52:50 -06:00
|
|
|
Authority userAuthority = this.findRole(user);
|
|
|
|
userAuthority.setAuthority(newRole);
|
|
|
|
authorityRepository.save(userAuthority);
|
2025-01-06 18:58:26 +00:00
|
|
|
databaseService.exportDatabase();
|
2024-08-16 12:57:37 +02:00
|
|
|
}
|
|
|
|
|
2025-01-06 18:58:26 +00:00
|
|
|
public void changeUserEnabled(User user, Boolean enbeled)
|
|
|
|
throws SQLException, UnsupportedProviderException {
|
2024-08-16 12:57:37 +02:00
|
|
|
user.setEnabled(enbeled);
|
|
|
|
userRepository.save(user);
|
2025-01-06 18:58:26 +00:00
|
|
|
databaseService.exportDatabase();
|
2024-05-02 14:52:50 -06:00
|
|
|
}
|
|
|
|
|
2024-01-03 17:59:04 +00:00
|
|
|
public boolean isPasswordCorrect(User user, String currentPassword) {
|
|
|
|
return passwordEncoder.matches(currentPassword, user.getPassword());
|
|
|
|
}
|
2024-03-13 23:09:16 +01:00
|
|
|
|
|
|
|
public boolean isUsernameValid(String username) {
|
2024-05-12 19:58:34 +02:00
|
|
|
// Checks whether the simple username is formatted correctly
|
2025-01-12 16:30:17 +01:00
|
|
|
// Regular expression for user name: Min. 3 characters, max. 50 characters
|
2024-05-12 19:58:34 +02:00
|
|
|
boolean isValidSimpleUsername =
|
2025-01-12 16:30:17 +01:00
|
|
|
username.matches("^[a-zA-Z0-9](?!.*[-@._+]{2,})[a-zA-Z0-9@._+-]{1,48}[a-zA-Z0-9]$");
|
|
|
|
|
2024-05-12 19:58:34 +02:00
|
|
|
// Checks whether the email address is formatted correctly
|
2025-01-12 16:30:17 +01:00
|
|
|
// Regular expression for email addresses: Max. 320 characters, with RFC-like validation
|
2024-05-12 19:58:34 +02:00
|
|
|
boolean isValidEmail =
|
|
|
|
username.matches(
|
2025-01-12 16:30:17 +01:00
|
|
|
"^(?=.{1,320}$)(?=.{1,64}@)[A-Za-z0-9](?:[A-Za-z0-9_.+-]*[A-Za-z0-9])?@[^-][A-Za-z0-9-]+(?:\\\\.[A-Za-z0-9-]+)*(?:\\\\.[A-Za-z]{2,})$");
|
|
|
|
|
2024-11-15 10:36:59 +01:00
|
|
|
List<String> notAllowedUserList = new ArrayList<>();
|
|
|
|
notAllowedUserList.add("ALL_USERS".toLowerCase());
|
|
|
|
boolean notAllowedUser = notAllowedUserList.contains(username.toLowerCase());
|
|
|
|
return (isValidSimpleUsername || isValidEmail) && !notAllowedUser;
|
2024-05-12 19:58:34 +02:00
|
|
|
}
|
|
|
|
|
2024-05-18 23:47:05 +02:00
|
|
|
private String getInvalidUsernameMessage() {
|
|
|
|
return messageSource.getMessage(
|
|
|
|
"invalidUsernameMessage", null, LocaleContextHolder.getLocale());
|
2024-05-12 19:58:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public boolean hasPassword(String username) {
|
2024-08-16 12:57:37 +02:00
|
|
|
Optional<User> user = findByUsernameIgnoreCase(username);
|
2024-05-18 23:47:05 +02:00
|
|
|
return user.isPresent() && user.get().hasPassword();
|
2024-05-12 19:58:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public boolean isAuthenticationTypeByUsername(
|
|
|
|
String username, AuthenticationType authenticationType) {
|
2024-08-16 12:57:37 +02:00
|
|
|
Optional<User> user = findByUsernameIgnoreCase(username);
|
2024-05-18 23:47:05 +02:00
|
|
|
return user.isPresent()
|
|
|
|
&& authenticationType.name().equalsIgnoreCase(user.get().getAuthenticationType());
|
2024-03-13 23:09:16 +01:00
|
|
|
}
|
2024-08-16 12:57:37 +02:00
|
|
|
|
|
|
|
public boolean isUserDisabled(String username) {
|
|
|
|
Optional<User> userOpt = findByUsernameIgnoreCase(username);
|
|
|
|
return userOpt.map(user -> !user.isEnabled()).orElse(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void invalidateUserSessions(String username) {
|
|
|
|
String usernameP = "";
|
|
|
|
for (Object principal : sessionRegistry.getAllPrincipals()) {
|
|
|
|
for (SessionInformation sessionsInformation :
|
|
|
|
sessionRegistry.getAllSessions(principal, false)) {
|
|
|
|
if (principal instanceof UserDetails) {
|
|
|
|
UserDetails userDetails = (UserDetails) principal;
|
|
|
|
usernameP = userDetails.getUsername();
|
|
|
|
} else if (principal instanceof OAuth2User) {
|
|
|
|
OAuth2User oAuth2User = (OAuth2User) principal;
|
|
|
|
usernameP = oAuth2User.getName();
|
2024-10-20 13:30:58 +02:00
|
|
|
} else if (principal instanceof CustomSaml2AuthenticatedPrincipal) {
|
|
|
|
CustomSaml2AuthenticatedPrincipal saml2User =
|
|
|
|
(CustomSaml2AuthenticatedPrincipal) principal;
|
|
|
|
usernameP = saml2User.getName();
|
2024-08-16 12:57:37 +02:00
|
|
|
} else if (principal instanceof String) {
|
|
|
|
usernameP = (String) principal;
|
|
|
|
}
|
|
|
|
if (usernameP.equalsIgnoreCase(username)) {
|
|
|
|
sessionRegistry.expireSession(sessionsInformation.getSessionId());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-09-13 16:42:38 +01:00
|
|
|
|
|
|
|
public String getCurrentUsername() {
|
|
|
|
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
|
|
|
if (principal instanceof UserDetails) {
|
|
|
|
return ((UserDetails) principal).getUsername();
|
2024-11-11 12:55:46 +01:00
|
|
|
} else if (principal instanceof OAuth2User) {
|
|
|
|
return ((OAuth2User) principal)
|
|
|
|
.getAttribute(
|
|
|
|
applicationProperties.getSecurity().getOauth2().getUseAsUsername());
|
|
|
|
} else if (principal instanceof CustomSaml2AuthenticatedPrincipal) {
|
|
|
|
return ((CustomSaml2AuthenticatedPrincipal) principal).getName();
|
|
|
|
} else if (principal instanceof String) {
|
|
|
|
return (String) principal;
|
2024-09-13 16:42:38 +01:00
|
|
|
} else {
|
|
|
|
return principal.toString();
|
|
|
|
}
|
|
|
|
}
|
2024-10-22 00:42:17 +01:00
|
|
|
|
2024-12-10 20:39:24 +00:00
|
|
|
@Transactional
|
2025-01-06 18:58:26 +00:00
|
|
|
public void syncCustomApiUser(String customApiKey)
|
|
|
|
throws SQLException, UnsupportedProviderException {
|
2024-12-10 20:39:24 +00:00
|
|
|
if (customApiKey == null || customApiKey.trim().length() == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
String username = "CUSTOM_API_USER";
|
|
|
|
Optional<User> existingUser = findByUsernameIgnoreCase(username);
|
|
|
|
if (!existingUser.isPresent()) {
|
|
|
|
// Create new user with API role
|
|
|
|
User user = new User();
|
|
|
|
user.setUsername(username);
|
|
|
|
user.setPassword(UUID.randomUUID().toString());
|
|
|
|
user.setEnabled(true);
|
|
|
|
user.setFirstLogin(false);
|
|
|
|
user.setAuthenticationType(AuthenticationType.WEB);
|
|
|
|
user.setApiKey(customApiKey);
|
|
|
|
user.addAuthority(new Authority(Role.INTERNAL_API_USER.getRoleId(), user));
|
|
|
|
userRepository.save(user);
|
2025-01-06 18:58:26 +00:00
|
|
|
databaseService.exportDatabase();
|
2024-12-10 20:39:24 +00:00
|
|
|
} else {
|
|
|
|
// Update API key if it has changed
|
|
|
|
User user = existingUser.get();
|
|
|
|
if (!customApiKey.equals(user.getApiKey())) {
|
|
|
|
user.setApiKey(customApiKey);
|
|
|
|
userRepository.save(user);
|
2025-01-06 18:58:26 +00:00
|
|
|
databaseService.exportDatabase();
|
2024-12-10 20:39:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-10-23 07:17:40 -04:00
|
|
|
@Override
|
|
|
|
public long getTotalUsersCount() {
|
|
|
|
return userRepository.count();
|
|
|
|
}
|
2024-01-03 17:59:04 +00:00
|
|
|
}
|