mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-04 01:20:12 +00:00
Use an https callback for OIDC once again. (#3461)
* Use the new WAS callback type and return back to the https callback for OIDC. * Simplify OIDCAuthenticationPresenter now it doesn't need to handle universal links. * Remove old unit tests.
This commit is contained in:
@@ -14,16 +14,6 @@ class OIDCAuthenticationPresenter: NSObject {
|
||||
private let oidcRedirectURL: URL
|
||||
private let presentationAnchor: UIWindow
|
||||
|
||||
/// The data required to complete a request.
|
||||
struct Request {
|
||||
let session: ASWebAuthenticationSession
|
||||
let oidcData: OIDCAuthorizationDataProxy
|
||||
let continuation: CheckedContinuation<Result<UserSessionProtocol, AuthenticationServiceError>, Never>
|
||||
}
|
||||
|
||||
/// The current request in progress. This is a single use value and will be moved on access.
|
||||
@Consumable private var request: Request?
|
||||
|
||||
init(authenticationService: AuthenticationServiceProtocol, oidcRedirectURL: URL, presentationAnchor: UIWindow) {
|
||||
self.authenticationService = authenticationService
|
||||
self.oidcRedirectURL = oidcRedirectURL
|
||||
@@ -33,74 +23,35 @@ class OIDCAuthenticationPresenter: NSObject {
|
||||
|
||||
/// Presents a web authentication session for the supplied data.
|
||||
func authenticate(using oidcData: OIDCAuthorizationDataProxy) async -> Result<UserSessionProtocol, AuthenticationServiceError> {
|
||||
await withCheckedContinuation { continuation in
|
||||
let session = ASWebAuthenticationSession(url: oidcData.url,
|
||||
callbackURLScheme: oidcRedirectURL.scheme) { [weak self] url, error in
|
||||
// This closure won't be called if the scheme is https, see handleUniversalLinkCallback for more info.
|
||||
guard let self else { return }
|
||||
|
||||
guard let url else {
|
||||
// Check for user cancellation to avoid showing an alert in that instance.
|
||||
if let nsError = error as? NSError,
|
||||
nsError.domain == ASWebAuthenticationSessionErrorDomain,
|
||||
nsError.code == ASWebAuthenticationSessionError.canceledLogin.rawValue {
|
||||
self.completeAuthentication(throwing: .oidcError(.userCancellation))
|
||||
return
|
||||
}
|
||||
|
||||
self.completeAuthentication(throwing: .oidcError(.unknown))
|
||||
return
|
||||
}
|
||||
|
||||
completeAuthentication(callbackURL: url)
|
||||
let (url, error) = await withCheckedContinuation { continuation in
|
||||
let session = ASWebAuthenticationSession(url: oidcData.url, callback: .oidcRedirectURL(oidcRedirectURL)) { url, error in
|
||||
continuation.resume(returning: (url, error))
|
||||
}
|
||||
|
||||
session.prefersEphemeralWebBrowserSession = false
|
||||
session.presentationContextProvider = self
|
||||
|
||||
request = Request(session: session, oidcData: oidcData, continuation: continuation)
|
||||
|
||||
session.start()
|
||||
}
|
||||
}
|
||||
|
||||
/// This method will be used if the `appSettings.oidcRedirectURL`'s scheme is `https`.
|
||||
/// When using a custom scheme, the redirect will be handled by the web auth session's closure.
|
||||
func handleUniversalLinkCallback(_ url: URL) {
|
||||
completeAuthentication(callbackURL: url)
|
||||
}
|
||||
|
||||
/// Completes the authentication by exchanging the callback URL for a user session.
|
||||
private func completeAuthentication(callbackURL: URL) {
|
||||
guard let request else {
|
||||
MXLog.error("Failed to complete authentication. Missing request.")
|
||||
return
|
||||
}
|
||||
|
||||
if callbackURL.scheme?.starts(with: "http") == true {
|
||||
request.session.cancel()
|
||||
}
|
||||
|
||||
Task {
|
||||
switch await authenticationService.loginWithOIDCCallback(callbackURL, data: request.oidcData) {
|
||||
case .success(let userSession):
|
||||
request.continuation.resume(returning: .success(userSession))
|
||||
case .failure(let error):
|
||||
request.continuation.resume(returning: .failure(error))
|
||||
guard let url else {
|
||||
// Check for user cancellation to avoid showing an alert in that instance.
|
||||
if let nsError = error as? NSError,
|
||||
nsError.domain == ASWebAuthenticationSessionErrorDomain,
|
||||
nsError.code == ASWebAuthenticationSessionError.canceledLogin.rawValue {
|
||||
await authenticationService.abortOIDCLogin(data: oidcData)
|
||||
return .failure(.oidcError(.userCancellation))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Aborts the authentication with the supplied error.
|
||||
private func completeAuthentication(throwing error: AuthenticationServiceError) {
|
||||
guard let request else {
|
||||
MXLog.error("Failed to throw authentication error. Missing request.")
|
||||
return
|
||||
|
||||
await authenticationService.abortOIDCLogin(data: oidcData)
|
||||
return .failure(.oidcError(.unknown))
|
||||
}
|
||||
|
||||
Task {
|
||||
await authenticationService.abortOIDCLogin(data: request.oidcData)
|
||||
request.continuation.resume(returning: .failure(error))
|
||||
switch await authenticationService.loginWithOIDCCallback(url, data: oidcData) {
|
||||
case .success(let userSession):
|
||||
return .success(userSession)
|
||||
case .failure(let error):
|
||||
return .failure(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -110,3 +61,15 @@ class OIDCAuthenticationPresenter: NSObject {
|
||||
extension OIDCAuthenticationPresenter: ASWebAuthenticationPresentationContextProviding {
|
||||
func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor { presentationAnchor }
|
||||
}
|
||||
|
||||
extension ASWebAuthenticationSession.Callback {
|
||||
static func oidcRedirectURL(_ url: URL) -> Self {
|
||||
if url.scheme == "https", let host = url.host() {
|
||||
.https(host: host, path: url.path())
|
||||
} else if let scheme = url.scheme {
|
||||
.customScheme(scheme)
|
||||
} else {
|
||||
fatalError("Invalid OIDC redirect URL: \(url)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-9
@@ -85,15 +85,6 @@ final class SoftLogoutScreenCoordinator: CoordinatorProtocol {
|
||||
AnyView(SoftLogoutScreen(context: viewModel.context))
|
||||
}
|
||||
|
||||
func handleOIDCRedirectURL(_ url: URL) {
|
||||
guard let oidcPresenter else {
|
||||
MXLog.error("Failed to find an OIDC request in progress.")
|
||||
return
|
||||
}
|
||||
|
||||
oidcPresenter.handleUniversalLinkCallback(url)
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private static let loadingIndicatorIdentifier = "\(SoftLogoutScreenCoordinator.self)-Loading"
|
||||
|
||||
Reference in New Issue
Block a user