Enhance AuthenticationService with proper error handling

- Add AuthenticationError enum for domain-specific error handling
- Add attemptAutoLogin method for automatic credential-based authentication
- Improve error handling and logging for credential retrieval
- Support 24-hour token expiry validation
This commit is contained in:
David Collado 2025-07-02 23:30:49 +02:00 committed by Peter Steinberger
parent 8f20a0ef26
commit 7975c4b916

View file

@ -218,27 +218,40 @@ final class AuthenticationService: ObservableObject {
/// Attempt automatic login using stored credentials for a server profile /// Attempt automatic login using stored credentials for a server profile
func attemptAutoLogin(profile: ServerProfile) async throws { func attemptAutoLogin(profile: ServerProfile) async throws {
logger.debug("attemptAutoLogin called for profile: \(profile.name) (id: \(profile.id)), isAuthenticated: \(isAuthenticated)")
logger.debug("Profile requiresAuth: \(profile.requiresAuth), username: \(profile.username ?? "nil")")
// Check if we already have valid authentication // Check if we already have valid authentication
if isAuthenticated { if isAuthenticated {
let tokenValid = await verifyToken() let tokenValid = await verifyToken()
if tokenValid { if tokenValid {
logger.info("Already authenticated with valid token") logger.info("Already authenticated with valid token for user: \(currentUser ?? "unknown")")
return return
} else {
logger.warning("Token verification failed, will attempt fresh login")
} }
} }
// Get stored password from keychain // Check if profile requires authentication
guard let password = try? KeychainService.getPassword(for: profile.id) else { if !profile.requiresAuth {
logger.debug("No stored password found for profile: \(profile.name)") logger.debug("Profile does not require authentication, but server requires it - treating as credentials not found")
throw AuthenticationError.credentialsNotFound throw AuthenticationError.credentialsNotFound
} }
// Get stored password from keychain
do {
let password = try KeychainService.getPassword(for: profile.id)
logger.debug("Successfully retrieved password from keychain for profile: \(profile.name)")
logger.debug("Password length: \(password.count) characters")
// Get username from profile or use default // Get username from profile or use default
guard let username = profile.username else { guard let username = profile.username else {
logger.error("No username configured for profile: \(profile.name)") logger.error("No username configured for profile: \(profile.name)")
throw AuthenticationError.credentialsNotFound throw AuthenticationError.credentialsNotFound
} }
logger.debug("Attempting authentication with username: \(username)")
// Attempt authentication with stored credentials // Attempt authentication with stored credentials
do { do {
try await authenticateWithPassword(username: username, password: password) try await authenticateWithPassword(username: username, password: password)
@ -257,6 +270,19 @@ final class AuthenticationService: ObservableObject {
} }
throw AuthenticationError.invalidCredentials throw AuthenticationError.invalidCredentials
} }
} catch let keychainError {
logger.error("Failed to retrieve password from keychain for profile: \(profile.name), error: \(keychainError)")
logger.debug("Looking for keychain item with account: server-\(profile.id)")
if let keychainErr = keychainError as? KeychainService.KeychainError {
switch keychainErr {
case .itemNotFound:
logger.debug("Keychain item not found for profile id: \(profile.id)")
default:
logger.error("Keychain error: \(keychainErr)")
}
}
throw AuthenticationError.credentialsNotFound
}
} }
// MARK: - Private Methods // MARK: - Private Methods