From 81e2a77e57f884dfae6a772086a1aaba43690abf Mon Sep 17 00:00:00 2001 From: Ludy Date: Mon, 19 Aug 2024 16:02:40 +0200 Subject: [PATCH] Fix: Failed authentication #1704 (#1708) * Fix: Failed authentication #1704 * Update account.html --- .../security/UserAuthenticationFilter.java | 19 +++++++--- .../SPDF/config/security/UserService.java | 38 +++++++++---------- .../software/SPDF/model/Authority.java | 6 ++- .../stirling/software/SPDF/model/User.java | 5 ++- .../SPDF/repository/UserRepository.java | 2 +- 5 files changed, 42 insertions(+), 28 deletions(-) diff --git a/src/main/java/stirling/software/SPDF/config/security/UserAuthenticationFilter.java b/src/main/java/stirling/software/SPDF/config/security/UserAuthenticationFilter.java index 23269477..10de4ea9 100644 --- a/src/main/java/stirling/software/SPDF/config/security/UserAuthenticationFilter.java +++ b/src/main/java/stirling/software/SPDF/config/security/UserAuthenticationFilter.java @@ -2,6 +2,8 @@ package stirling.software.SPDF.config.security; import java.io.IOException; import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -9,6 +11,7 @@ import org.springframework.context.annotation.Lazy; import org.springframework.http.HttpStatus; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; +import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.session.SessionInformation; import org.springframework.security.core.userdetails.UserDetails; @@ -22,6 +25,7 @@ import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import stirling.software.SPDF.config.security.session.SessionPersistentRegistry; import stirling.software.SPDF.model.ApiKeyAuthenticationToken; +import stirling.software.SPDF.model.User; @Component public class UserAuthenticationFilter extends OncePerRequestFilter { @@ -54,15 +58,20 @@ public class UserAuthenticationFilter extends OncePerRequestFilter { try { // Use API key to authenticate. This requires you to have an authentication // provider for API keys. - UserDetails userDetails = userService.loadUserByApiKey(apiKey); - if (userDetails == null) { + Optional user = userService.loadUserByApiKey(apiKey); + if (!user.isPresent()) { response.setStatus(HttpStatus.UNAUTHORIZED.value()); response.getWriter().write("Invalid API Key."); return; } - authentication = - new ApiKeyAuthenticationToken( - userDetails, apiKey, userDetails.getAuthorities()); + List authorities = + user.get().getAuthorities().stream() + .map( + authority -> + new SimpleGrantedAuthority( + authority.getAuthority())) + .collect(Collectors.toList()); + authentication = new ApiKeyAuthenticationToken(user.get(), apiKey, authorities); SecurityContextHolder.getContext().setAuthentication(authentication); } catch (AuthenticationException e) { // If API key authentication fails, deny the request diff --git a/src/main/java/stirling/software/SPDF/config/security/UserService.java b/src/main/java/stirling/software/SPDF/config/security/UserService.java index d20aba8b..7b8c5ff0 100644 --- a/src/main/java/stirling/software/SPDF/config/security/UserService.java +++ b/src/main/java/stirling/software/SPDF/config/security/UserService.java @@ -22,6 +22,7 @@ import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.oauth2.core.user.OAuth2User; import org.springframework.stereotype.Service; +import lombok.extern.slf4j.Slf4j; import stirling.software.SPDF.config.DatabaseBackupInterface; import stirling.software.SPDF.config.security.session.SessionPersistentRegistry; import stirling.software.SPDF.controller.api.pipeline.UserServiceInterface; @@ -65,8 +66,8 @@ public class UserService implements UserServiceInterface { } public Authentication getAuthentication(String apiKey) { - User user = getUserByApiKey(apiKey); - if (user == null) { + Optional user = getUserByApiKey(apiKey); + if (!user.isPresent()) { throw new UsernameNotFoundException("API key is not valid"); } @@ -74,7 +75,7 @@ public class UserService implements UserServiceInterface { return new UsernamePasswordAuthenticationToken( user, // principal (typically the user) null, // credentials (we don't expose the password or API key here) - getAuthorities(user) // user's authorities (roles/permissions) + getAuthorities(user.get()) // user's authorities (roles/permissions) ); } @@ -89,17 +90,17 @@ public class UserService implements UserServiceInterface { String apiKey; do { apiKey = UUID.randomUUID().toString(); - } while (userRepository.findByApiKey(apiKey) != null); // Ensure uniqueness + } while (userRepository.findByApiKey(apiKey).isPresent()); // Ensure uniqueness return apiKey; } public User addApiKeyToUser(String username) { - User user = - findByUsernameIgnoreCase(username) - .orElseThrow(() -> new UsernameNotFoundException("User not found")); - - user.setApiKey(generateApiKey()); - return userRepository.save(user); + Optional user = findByUsernameIgnoreCase(username); + if (user.isPresent()) { + user.get().setApiKey(generateApiKey()); + return userRepository.save(user.get()); + } + throw new UsernameNotFoundException("User not found"); } public User refreshApiKeyForUser(String username) { @@ -114,21 +115,18 @@ public class UserService implements UserServiceInterface { } public boolean isValidApiKey(String apiKey) { - return userRepository.findByApiKey(apiKey) != null; + return userRepository.findByApiKey(apiKey).isPresent(); } - public User getUserByApiKey(String apiKey) { + public Optional getUserByApiKey(String apiKey) { return userRepository.findByApiKey(apiKey); } - public UserDetails loadUserByApiKey(String apiKey) { - User user = userRepository.findByApiKey(apiKey); - if (user != null) { - // Convert your User entity to a UserDetails object with authorities - return new org.springframework.security.core.userdetails.User( - user.getUsername(), - user.getPassword(), // you might not need this for API key auth - getAuthorities(user)); + public Optional loadUserByApiKey(String apiKey) { + Optional user = userRepository.findByApiKey(apiKey); + + if (user.isPresent()) { + return user; } return null; // or throw an exception } diff --git a/src/main/java/stirling/software/SPDF/model/Authority.java b/src/main/java/stirling/software/SPDF/model/Authority.java index 57ba538e..8dd6d6e7 100644 --- a/src/main/java/stirling/software/SPDF/model/Authority.java +++ b/src/main/java/stirling/software/SPDF/model/Authority.java @@ -1,5 +1,7 @@ package stirling.software.SPDF.model; +import java.io.Serializable; + import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; @@ -11,7 +13,9 @@ import jakarta.persistence.Table; @Entity @Table(name = "authorities") -public class Authority { +public class Authority implements Serializable { + + private static final long serialVersionUID = 1L; public Authority() {} diff --git a/src/main/java/stirling/software/SPDF/model/User.java b/src/main/java/stirling/software/SPDF/model/User.java index 0a6ccc70..2dadbe0f 100644 --- a/src/main/java/stirling/software/SPDF/model/User.java +++ b/src/main/java/stirling/software/SPDF/model/User.java @@ -1,5 +1,6 @@ package stirling.software.SPDF.model; +import java.io.Serializable; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -23,7 +24,9 @@ import jakarta.persistence.Table; @Entity @Table(name = "users") -public class User { +public class User implements Serializable { + + private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/src/main/java/stirling/software/SPDF/repository/UserRepository.java b/src/main/java/stirling/software/SPDF/repository/UserRepository.java index cf0c80d1..7a5ccffb 100644 --- a/src/main/java/stirling/software/SPDF/repository/UserRepository.java +++ b/src/main/java/stirling/software/SPDF/repository/UserRepository.java @@ -13,5 +13,5 @@ public interface UserRepository extends JpaRepository { Optional findByUsername(String username); - User findByApiKey(String apiKey); + Optional findByApiKey(String apiKey); }