mirror of
https://gitlab.opencode.de/bwi/bundesmessenger/clients/bundesmessenger-ios.git
synced 2026-04-23 18:12:44 +02:00
f2277cbd3d
* Implement the Signup event from AuthenticationViewController. Use AuthenticationFlow instead of MXKAuthenticationType. Create new AuthenticationType that aligns with AnalyticsEvent naming. Add additional cases from AnalyticsEvents.
163 lines
6.9 KiB
Swift
163 lines
6.9 KiB
Swift
//
|
|
// Copyright 2020 New Vector Ltd
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
//
|
|
|
|
import Foundation
|
|
import SafariServices
|
|
|
|
@objc protocol SSOAuthenticationPresenterDelegate {
|
|
func ssoAuthenticationPresenterDidCancel(_ presenter: SSOAuthenticationPresenter)
|
|
func ssoAuthenticationPresenter(_ presenter: SSOAuthenticationPresenter, authenticationDidFailWithError error: Error)
|
|
func ssoAuthenticationPresenter(_ presenter: SSOAuthenticationPresenter,
|
|
authenticationSucceededWithToken token: String,
|
|
usingIdentityProvider identityProvider: SSOIdentityProvider?)
|
|
}
|
|
|
|
enum SSOAuthenticationPresenterError: Error {
|
|
case failToLoadAuthenticationURL
|
|
}
|
|
|
|
/// SSOAuthenticationPresenter enables to present single sign-on authentication
|
|
@objcMembers
|
|
final class SSOAuthenticationPresenter: NSObject {
|
|
|
|
// MARK: - Constants
|
|
|
|
// MARK: - Properties
|
|
|
|
private let ssoAuthenticationService: SSOAuthenticationService
|
|
|
|
// MARK: Private
|
|
|
|
private weak var presentingViewController: UIViewController?
|
|
|
|
private var authenticationSession: SSOAuthentificationSessionProtocol?
|
|
private weak var safariViewController: SFSafariViewController?
|
|
|
|
// MARK: Public
|
|
|
|
private(set) var identityProvider: SSOIdentityProvider?
|
|
weak var delegate: SSOAuthenticationPresenterDelegate?
|
|
|
|
// MARK: - Setup
|
|
|
|
init(ssoAuthenticationService: SSOAuthenticationService) {
|
|
self.ssoAuthenticationService = ssoAuthenticationService
|
|
super.init()
|
|
}
|
|
|
|
// MARK: - Public
|
|
|
|
func present(forIdentityProvider identityProvider: SSOIdentityProvider?,
|
|
with transactionId: String,
|
|
from presentingViewController: UIViewController,
|
|
animated: Bool) {
|
|
guard let authenticationURL = self.ssoAuthenticationService.authenticationURL(for: identityProvider?.id, transactionId: transactionId) else {
|
|
self.delegate?.ssoAuthenticationPresenter(self, authenticationDidFailWithError: SSOAuthenticationPresenterError.failToLoadAuthenticationURL)
|
|
return
|
|
}
|
|
|
|
self.identityProvider = identityProvider
|
|
self.presentingViewController = presentingViewController
|
|
|
|
// NOTE: By using SFAuthenticationSession the consent alert show product name instead of display name. Fallback to SFSafariViewController instead in order to not disturb users with "Riot" wording at the moment.
|
|
// (https://stackoverflow.com/questions/49860338/why-does-sfauthenticationsession-consent-alert-show-xcode-project-name-instead-o)
|
|
if #available(iOS 13.0, *) {
|
|
// SFAuthenticationSession and ASWebAuthenticationSession doesn't work with guided access (rdar://48376122)
|
|
if UIAccessibility.isGuidedAccessEnabled {
|
|
self.presentSafariViewController(with: authenticationURL, animated: animated)
|
|
} else {
|
|
self.startAuthenticationSession(with: authenticationURL)
|
|
}
|
|
} else {
|
|
self.presentSafariViewController(with: authenticationURL, animated: animated)
|
|
}
|
|
}
|
|
|
|
func dismiss(animated: Bool, completion: (() -> Void)?) {
|
|
if let safariViewController = self.safariViewController {
|
|
safariViewController.dismiss(animated: animated, completion: completion)
|
|
}
|
|
|
|
self.authenticationSession?.cancel()
|
|
}
|
|
|
|
// MARK: - Private
|
|
|
|
private func presentSafariViewController(with authenticationURL: URL, animated: Bool) {
|
|
guard let presentingViewController = self.presentingViewController else {
|
|
return
|
|
}
|
|
|
|
let safariViewController = SFSafariViewController(url: authenticationURL)
|
|
safariViewController.dismissButtonStyle = .cancel
|
|
safariViewController.delegate = self
|
|
|
|
presentingViewController.present(safariViewController, animated: animated, completion: nil)
|
|
self.safariViewController = safariViewController
|
|
}
|
|
|
|
private func startAuthenticationSession(with authenticationURL: URL) {
|
|
guard let presentingViewController = self.presentingViewController else {
|
|
return
|
|
}
|
|
|
|
let authenticationSession = SSOAuthentificationSession()
|
|
|
|
if let presentingWindow = presentingViewController.view.window {
|
|
let contextProvider = SSOAuthenticationSessionContextProvider(window: presentingWindow)
|
|
authenticationSession.setContextProvider(contextProvider)
|
|
}
|
|
|
|
authenticationSession.authenticate(with: authenticationURL, callbackURLScheme: self.ssoAuthenticationService.callBackURLScheme) { [weak self] (callBackURL, error) in
|
|
guard let self = self else {
|
|
return
|
|
}
|
|
|
|
if let error = error {
|
|
if case SSOAuthentificationSessionError.userCanceled = error {
|
|
self.delegate?.ssoAuthenticationPresenterDidCancel(self)
|
|
} else {
|
|
self.delegate?.ssoAuthenticationPresenter(self, authenticationDidFailWithError: error)
|
|
}
|
|
} else if let successURL = callBackURL {
|
|
if let loginToken = self.ssoAuthenticationService.loginToken(from: successURL) {
|
|
self.delegate?.ssoAuthenticationPresenter(self, authenticationSucceededWithToken: loginToken, usingIdentityProvider: self.identityProvider)
|
|
} else {
|
|
MXLog.debug("SSOAuthenticationPresenter: Login token not found")
|
|
self.delegate?.ssoAuthenticationPresenter(self, authenticationDidFailWithError: SSOAuthenticationServiceError.tokenNotFound)
|
|
}
|
|
}
|
|
}
|
|
|
|
self.authenticationSession = authenticationSession
|
|
}
|
|
}
|
|
|
|
// MARK: - SFSafariViewControllerDelegate
|
|
extension SSOAuthenticationPresenter: SFSafariViewControllerDelegate {
|
|
|
|
func safariViewControllerDidFinish(_ controller: SFSafariViewController) {
|
|
self.delegate?.ssoAuthenticationPresenterDidCancel(self)
|
|
}
|
|
|
|
func safariViewController(_ controller: SFSafariViewController, didCompleteInitialLoad didLoadSuccessfully: Bool) {
|
|
|
|
if !didLoadSuccessfully {
|
|
self.delegate?.ssoAuthenticationPresenter(self, authenticationDidFailWithError: SSOAuthenticationPresenterError.failToLoadAuthenticationURL)
|
|
}
|
|
}
|
|
}
|