1
0
mirror of https://github.com/Stirling-Tools/Stirling-PDF.git synced 2024-11-14 11:30:12 +01:00

Fix: Failed authentication #1704 (#1708)

* Fix: Failed authentication #1704

* Update account.html
This commit is contained in:
Ludy 2024-08-19 16:02:40 +02:00 committed by GitHub
parent 6c9a4e8acc
commit 81e2a77e57
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 42 additions and 28 deletions

View File

@ -2,6 +2,8 @@ package stirling.software.SPDF.config.security;
import java.io.IOException; import java.io.IOException;
import java.util.List; 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.Autowired;
import org.springframework.beans.factory.annotation.Qualifier; 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.http.HttpStatus;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException; 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.context.SecurityContextHolder;
import org.springframework.security.core.session.SessionInformation; import org.springframework.security.core.session.SessionInformation;
import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetails;
@ -22,6 +25,7 @@ import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import stirling.software.SPDF.config.security.session.SessionPersistentRegistry; import stirling.software.SPDF.config.security.session.SessionPersistentRegistry;
import stirling.software.SPDF.model.ApiKeyAuthenticationToken; import stirling.software.SPDF.model.ApiKeyAuthenticationToken;
import stirling.software.SPDF.model.User;
@Component @Component
public class UserAuthenticationFilter extends OncePerRequestFilter { public class UserAuthenticationFilter extends OncePerRequestFilter {
@ -54,15 +58,20 @@ public class UserAuthenticationFilter extends OncePerRequestFilter {
try { try {
// Use API key to authenticate. This requires you to have an authentication // Use API key to authenticate. This requires you to have an authentication
// provider for API keys. // provider for API keys.
UserDetails userDetails = userService.loadUserByApiKey(apiKey); Optional<User> user = userService.loadUserByApiKey(apiKey);
if (userDetails == null) { if (!user.isPresent()) {
response.setStatus(HttpStatus.UNAUTHORIZED.value()); response.setStatus(HttpStatus.UNAUTHORIZED.value());
response.getWriter().write("Invalid API Key."); response.getWriter().write("Invalid API Key.");
return; return;
} }
authentication = List<SimpleGrantedAuthority> authorities =
new ApiKeyAuthenticationToken( user.get().getAuthorities().stream()
userDetails, apiKey, userDetails.getAuthorities()); .map(
authority ->
new SimpleGrantedAuthority(
authority.getAuthority()))
.collect(Collectors.toList());
authentication = new ApiKeyAuthenticationToken(user.get(), apiKey, authorities);
SecurityContextHolder.getContext().setAuthentication(authentication); SecurityContextHolder.getContext().setAuthentication(authentication);
} catch (AuthenticationException e) { } catch (AuthenticationException e) {
// If API key authentication fails, deny the request // If API key authentication fails, deny the request

View File

@ -22,6 +22,7 @@ import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.core.user.OAuth2User; import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.DatabaseBackupInterface; import stirling.software.SPDF.config.DatabaseBackupInterface;
import stirling.software.SPDF.config.security.session.SessionPersistentRegistry; import stirling.software.SPDF.config.security.session.SessionPersistentRegistry;
import stirling.software.SPDF.controller.api.pipeline.UserServiceInterface; import stirling.software.SPDF.controller.api.pipeline.UserServiceInterface;
@ -65,8 +66,8 @@ public class UserService implements UserServiceInterface {
} }
public Authentication getAuthentication(String apiKey) { public Authentication getAuthentication(String apiKey) {
User user = getUserByApiKey(apiKey); Optional<User> user = getUserByApiKey(apiKey);
if (user == null) { if (!user.isPresent()) {
throw new UsernameNotFoundException("API key is not valid"); throw new UsernameNotFoundException("API key is not valid");
} }
@ -74,7 +75,7 @@ public class UserService implements UserServiceInterface {
return new UsernamePasswordAuthenticationToken( return new UsernamePasswordAuthenticationToken(
user, // principal (typically the user) user, // principal (typically the user)
null, // credentials (we don't expose the password or API key here) 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; String apiKey;
do { do {
apiKey = UUID.randomUUID().toString(); apiKey = UUID.randomUUID().toString();
} while (userRepository.findByApiKey(apiKey) != null); // Ensure uniqueness } while (userRepository.findByApiKey(apiKey).isPresent()); // Ensure uniqueness
return apiKey; return apiKey;
} }
public User addApiKeyToUser(String username) { public User addApiKeyToUser(String username) {
User user = Optional<User> user = findByUsernameIgnoreCase(username);
findByUsernameIgnoreCase(username) if (user.isPresent()) {
.orElseThrow(() -> new UsernameNotFoundException("User not found")); user.get().setApiKey(generateApiKey());
return userRepository.save(user.get());
user.setApiKey(generateApiKey()); }
return userRepository.save(user); throw new UsernameNotFoundException("User not found");
} }
public User refreshApiKeyForUser(String username) { public User refreshApiKeyForUser(String username) {
@ -114,21 +115,18 @@ public class UserService implements UserServiceInterface {
} }
public boolean isValidApiKey(String apiKey) { public boolean isValidApiKey(String apiKey) {
return userRepository.findByApiKey(apiKey) != null; return userRepository.findByApiKey(apiKey).isPresent();
} }
public User getUserByApiKey(String apiKey) { public Optional<User> getUserByApiKey(String apiKey) {
return userRepository.findByApiKey(apiKey); return userRepository.findByApiKey(apiKey);
} }
public UserDetails loadUserByApiKey(String apiKey) { public Optional<User> loadUserByApiKey(String apiKey) {
User user = userRepository.findByApiKey(apiKey); Optional<User> user = userRepository.findByApiKey(apiKey);
if (user != null) {
// Convert your User entity to a UserDetails object with authorities if (user.isPresent()) {
return new org.springframework.security.core.userdetails.User( return user;
user.getUsername(),
user.getPassword(), // you might not need this for API key auth
getAuthorities(user));
} }
return null; // or throw an exception return null; // or throw an exception
} }

View File

@ -1,5 +1,7 @@
package stirling.software.SPDF.model; package stirling.software.SPDF.model;
import java.io.Serializable;
import jakarta.persistence.Column; import jakarta.persistence.Column;
import jakarta.persistence.Entity; import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue; import jakarta.persistence.GeneratedValue;
@ -11,7 +13,9 @@ import jakarta.persistence.Table;
@Entity @Entity
@Table(name = "authorities") @Table(name = "authorities")
public class Authority { public class Authority implements Serializable {
private static final long serialVersionUID = 1L;
public Authority() {} public Authority() {}

View File

@ -1,5 +1,6 @@
package stirling.software.SPDF.model; package stirling.software.SPDF.model;
import java.io.Serializable;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map; import java.util.Map;
@ -23,7 +24,9 @@ import jakarta.persistence.Table;
@Entity @Entity
@Table(name = "users") @Table(name = "users")
public class User { public class User implements Serializable {
private static final long serialVersionUID = 1L;
@Id @Id
@GeneratedValue(strategy = GenerationType.IDENTITY) @GeneratedValue(strategy = GenerationType.IDENTITY)

View File

@ -13,5 +13,5 @@ public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByUsername(String username); Optional<User> findByUsername(String username);
User findByApiKey(String apiKey); Optional<User> findByApiKey(String apiKey);
} }