Files
iOS/Sources/Shared/API/mTLS/ClientCertificateSessionDelegate.swift
Bruno Pantaleão Gonçalves 831b534bed mTLS for REST api (#4389)
<!-- Thank you for submitting a Pull Request and helping to improve Home
Assistant. Please complete the following sections to help the processing
and review of your changes. Please do not delete anything from this
template. -->

## Summary
<!-- Provide a brief summary of the changes you have made and most
importantly what they aim to achieve -->
This PR works in combination with
https://github.com/home-assistant/HAKit/pull/96 to provide the missing
certificate evaluation when executing commands through the rest API
while using mTLS

## Screenshots
<!-- If this is a user-facing change not in the frontend, please include
screenshots in light and dark mode. -->

## Link to pull request in Documentation repository
<!-- Pull requests that add, change or remove functionality must have a
corresponding pull request in the Companion App Documentation repository
(https://github.com/home-assistant/companion.home-assistant). Please add
the number of this pull request after the "#" -->
Documentation: home-assistant/companion.home-assistant#

## Any other notes
<!-- If there is any other information of note, like if this Pull
Request is part of a bigger change, please include it here. -->

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-02-26 14:27:36 +01:00

51 lines
2.0 KiB
Swift

import Alamofire
import Foundation
#if !os(watchOS)
/// Custom SessionDelegate that handles client certificate authentication (mTLS)
public class ClientCertificateSessionDelegate: SessionDelegate {
private let server: Server
public init(server: Server) {
self.server = server
super.init()
}
override public func urlSession(
_ session: URLSession,
task: URLSessionTask,
didReceive challenge: URLAuthenticationChallenge,
completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void
) {
// Handle client certificate challenge
if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodClientCertificate {
handleClientCertificateChallenge(challenge, completionHandler: completionHandler)
return
}
// Let parent handle other challenges (server trust, etc.)
super.urlSession(session, task: task, didReceive: challenge, completionHandler: completionHandler)
}
private func handleClientCertificateChallenge(
_ challenge: URLAuthenticationChallenge,
completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void
) {
guard let clientCertificate = server.info.connection.clientCertificate else {
Current.Log.warning("[mTLS] Client certificate requested but none configured for server")
completionHandler(.performDefaultHandling, nil)
return
}
do {
let credential = try ClientCertificateManager.shared.urlCredential(for: clientCertificate)
Current.Log.info("[mTLS] Using client certificate: \(clientCertificate.displayName)")
completionHandler(.useCredential, credential)
} catch {
Current.Log.error("[mTLS] Failed to get credential for client certificate: \(error)")
completionHandler(.cancelAuthenticationChallenge, nil)
}
}
}
#endif