mirror of
https://gitlab.linphone.org/BC/public/linphone-iphone.git
synced 2026-01-17 11:08:06 +00:00
Merge branch 'master'
This commit is contained in:
commit
8e3bd3b5ab
11 changed files with 423 additions and 6 deletions
|
|
@ -35,8 +35,14 @@
|
|||
66FBFC492B83BD2400BC6AB1 /* ConfigExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66C491F82B24D25A00CEA16D /* ConfigExtension.swift */; };
|
||||
66FBFC4A2B83BD3300BC6AB1 /* FileUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66C491FE2B24D4AC00CEA16D /* FileUtils.swift */; };
|
||||
66FBFC4B2B83BD7B00BC6AB1 /* CoreExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66C491FA2B24D32600CEA16D /* CoreExtension.swift */; };
|
||||
C60E8F192C0F649200A06DB8 /* UIApplicationExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C60E8F182C0F649200A06DB8 /* UIApplicationExtension.swift */; };
|
||||
C67586AE2C09F23C002E77BF /* URLExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C67586AD2C09F23C002E77BF /* URLExtension.swift */; };
|
||||
C67586B02C09F247002E77BF /* URIHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = C67586AF2C09F247002E77BF /* URIHandler.swift */; };
|
||||
C67586B52C09F617002E77BF /* SingleSignOnManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C67586B22C09F617002E77BF /* SingleSignOnManager.swift */; };
|
||||
C6A5A9412C10B5D50070FEA4 /* EncodableExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6A5A9402C10B5D50070FEA4 /* EncodableExtension.swift */; };
|
||||
C6A5A9432C10B5ED0070FEA4 /* DecodableExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6A5A9422C10B5ED0070FEA4 /* DecodableExtension.swift */; };
|
||||
C6A5A9452C10B6270070FEA4 /* OIDAuthStateExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6A5A9442C10B6270070FEA4 /* OIDAuthStateExtension.swift */; };
|
||||
C6A5A9482C10B6A30070FEA4 /* AuthState.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6A5A9472C10B6A30070FEA4 /* AuthState.swift */; };
|
||||
D706BA822ADD72D100278F45 /* DeviceRotationViewModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = D706BA812ADD72D100278F45 /* DeviceRotationViewModifier.swift */; };
|
||||
D70959F12B8DF3EC0014AC0B /* ConversationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D70959F02B8DF3EC0014AC0B /* ConversationModel.swift */; };
|
||||
D70A26EE2B7CF60B006CC8FC /* ConversationsListBottomSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = D70A26ED2B7CF60B006CC8FC /* ConversationsListBottomSheet.swift */; };
|
||||
|
|
@ -194,8 +200,14 @@
|
|||
66E56BCB2BA9A1E0006CE56F /* MeetingsListItemModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeetingsListItemModel.swift; sourceTree = "<group>"; };
|
||||
66E56BCD2BA9A1F8006CE56F /* MeetingModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeetingModel.swift; sourceTree = "<group>"; };
|
||||
66F626B12BCEBB86003E2DEC /* AddParticipantsFragment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddParticipantsFragment.swift; sourceTree = "<group>"; };
|
||||
C60E8F182C0F649200A06DB8 /* UIApplicationExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIApplicationExtension.swift; sourceTree = "<group>"; };
|
||||
C67586AD2C09F23C002E77BF /* URLExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URLExtension.swift; sourceTree = "<group>"; };
|
||||
C67586AF2C09F247002E77BF /* URIHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URIHandler.swift; sourceTree = "<group>"; };
|
||||
C67586B22C09F617002E77BF /* SingleSignOnManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SingleSignOnManager.swift; sourceTree = "<group>"; };
|
||||
C6A5A9402C10B5D50070FEA4 /* EncodableExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EncodableExtension.swift; sourceTree = "<group>"; };
|
||||
C6A5A9422C10B5ED0070FEA4 /* DecodableExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DecodableExtension.swift; sourceTree = "<group>"; };
|
||||
C6A5A9442C10B6270070FEA4 /* OIDAuthStateExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OIDAuthStateExtension.swift; sourceTree = "<group>"; };
|
||||
C6A5A9472C10B6A30070FEA4 /* AuthState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthState.swift; sourceTree = "<group>"; };
|
||||
D706BA812ADD72D100278F45 /* DeviceRotationViewModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceRotationViewModifier.swift; sourceTree = "<group>"; };
|
||||
D70959F02B8DF3EC0014AC0B /* ConversationModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationModel.swift; sourceTree = "<group>"; };
|
||||
D70A26ED2B7CF60B006CC8FC /* ConversationsListBottomSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationsListBottomSheet.swift; sourceTree = "<group>"; };
|
||||
|
|
@ -353,6 +365,9 @@
|
|||
D76005F52B0798B00054B79A /* IntExtension.swift */,
|
||||
D717071F2AC5989C0037746F /* TextExtension.swift */,
|
||||
D71A0E182B485ADF0002C6CD /* ViewExtension.swift */,
|
||||
C60E8F182C0F649200A06DB8 /* UIApplicationExtension.swift */,
|
||||
C6A5A9402C10B5D50070FEA4 /* EncodableExtension.swift */,
|
||||
C6A5A9422C10B5ED0070FEA4 /* DecodableExtension.swift */,
|
||||
);
|
||||
path = Extensions;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -406,6 +421,16 @@
|
|||
path = Pods;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
C6A5A9462C10B64A0070FEA4 /* SingleSignOn */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
C6A5A9442C10B6270070FEA4 /* OIDAuthStateExtension.swift */,
|
||||
C67586B22C09F617002E77BF /* SingleSignOnManager.swift */,
|
||||
C6A5A9472C10B6A30070FEA4 /* AuthState.swift */,
|
||||
);
|
||||
path = SingleSignOn;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D70959EF2B8DF33B0014AC0B /* Model */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
|
@ -432,6 +457,7 @@
|
|||
D7B99E9A2B29F7C200BE7BF2 /* ActivityIndicator.swift */,
|
||||
D7173EBD2B7A5C0A00BCC481 /* LinphoneUtils.swift */,
|
||||
C67586AF2C09F247002E77BF /* URIHandler.swift */,
|
||||
C6A5A9462C10B64A0070FEA4 /* SingleSignOn */,
|
||||
);
|
||||
path = Utils;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -997,11 +1023,15 @@
|
|||
66E50A492BD12B2300AD61CA /* MeetingsView.swift in Sources */,
|
||||
D719ABCF2ABC779A00B41C10 /* AccountLoginViewModel.swift in Sources */,
|
||||
D717630D2BD7BD0E00464097 /* ParticipantsListFragment.swift in Sources */,
|
||||
C6A5A9452C10B6270070FEA4 /* OIDAuthStateExtension.swift in Sources */,
|
||||
D732A90F2B04C3B400DB42BA /* HistoryFragment.swift in Sources */,
|
||||
D79622342B1DFE600037EACD /* DialerBottomSheet.swift in Sources */,
|
||||
C67586B02C09F247002E77BF /* URIHandler.swift in Sources */,
|
||||
C60E8F192C0F649200A06DB8 /* UIApplicationExtension.swift in Sources */,
|
||||
D78290BB2ADD40B2004AA85C /* ContactViewModel.swift in Sources */,
|
||||
C67586B52C09F617002E77BF /* SingleSignOnManager.swift in Sources */,
|
||||
D7F4D9CB2B5FD27200CDCD76 /* CallsListFragment.swift in Sources */,
|
||||
C6A5A9482C10B6A30070FEA4 /* AuthState.swift in Sources */,
|
||||
D72992392ADD7F68003AF125 /* HistoryContactFragment.swift in Sources */,
|
||||
D70A26F02B7D02E6006CC8FC /* ConversationViewModel.swift in Sources */,
|
||||
6613A0AE2BAEB7DF008923A4 /* MeetingFragment.swift in Sources */,
|
||||
|
|
@ -1041,6 +1071,7 @@
|
|||
6613A0B42BAEBE3F008923A4 /* MeetingViewModel.swift in Sources */,
|
||||
D7173EBE2B7A5C0A00BCC481 /* LinphoneUtils.swift in Sources */,
|
||||
66C492012B24DB6900CEA16D /* Log.swift in Sources */,
|
||||
C6A5A9432C10B5ED0070FEA4 /* DecodableExtension.swift in Sources */,
|
||||
D714035B2BE11E00004BD8CA /* CallMediaEncryptionModel.swift in Sources */,
|
||||
6613A0B62BAEBE5C008923A4 /* ScheduleMeetingViewModel.swift in Sources */,
|
||||
D748BF2C2ACD82D2004844EB /* ThirdPartySipAccountLoginFragment.swift in Sources */,
|
||||
|
|
@ -1075,6 +1106,7 @@
|
|||
D7DA67642ACCB31700E95002 /* ProfileModeFragment.swift in Sources */,
|
||||
D7CEE03D2B7A23B200FD79B7 /* ConversationsListFragment.swift in Sources */,
|
||||
D74C9CFC2ACACF370021626A /* WelcomePage3Fragment.swift in Sources */,
|
||||
C6A5A9412C10B5D50070FEA4 /* EncodableExtension.swift in Sources */,
|
||||
D719ABCC2ABC769C00B41C10 /* AssistantView.swift in Sources */,
|
||||
D78E062C2BEA69BC00CE3783 /* CallStatisticsSheetBottomSheet.swift in Sources */,
|
||||
D7C365082AEFAB7F00FE6142 /* ContactListBottomSheet.swift in Sources */,
|
||||
|
|
|
|||
|
|
@ -45,6 +45,8 @@ final class CoreContext: ObservableObject {
|
|||
private var mIterateSuscription: AnyCancellable?
|
||||
private var mCoreSuscriptions = Set<AnyCancellable?>()
|
||||
|
||||
var bearerAuthInfoPendingPasswordUpdate: AuthInfo? = nil
|
||||
|
||||
let monitor = NWPathMonitor()
|
||||
|
||||
private var mCorePushIncomingDelegate: CoreDelegate!
|
||||
|
|
@ -263,6 +265,19 @@ final class CoreContext: ObservableObject {
|
|||
}
|
||||
})
|
||||
|
||||
self.mCoreSuscriptions.insert(self.mCore.publisher?.onAuthenticationRequested?.postOnCoreQueue { (cbValue: (_: Core, authInfo: AuthInfo, method: AuthMethod)) in
|
||||
let authInfo = cbValue.authInfo
|
||||
guard let username = authInfo.username, let server = authInfo.authorizationServer, !server.isEmpty else {
|
||||
Log.error("Authentication requested but either username [\(String(describing: authInfo.username))], domain [\(String(describing: authInfo.domain))] or server [\(String(describing: authInfo.authorizationServer))] is nil or empty!")
|
||||
return
|
||||
}
|
||||
if cbValue.method == .Bearer {
|
||||
Log.info("Authentication requested method is Bearer, starting Single Sign On activity with server URL \(server) and username \(username)")
|
||||
self.bearerAuthInfoPendingPasswordUpdate = cbValue.authInfo
|
||||
SingleSignOnManager.shared.setUp(ssoUrl: server, user: username)
|
||||
}
|
||||
})
|
||||
|
||||
self.mIterateSuscription = Timer.publish(every: 0.02, on: .main, in: .common)
|
||||
.autoconnect()
|
||||
.receive(on: coreQueue)
|
||||
|
|
|
|||
|
|
@ -84,6 +84,16 @@
|
|||
<string>tel</string>
|
||||
</array>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Editor</string>
|
||||
<key>CFBundleURLName</key>
|
||||
<string>org.linphone.phone</string>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>org.linphone</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
<key>ITSAppUsesNonExemptEncryption</key>
|
||||
<true/>
|
||||
|
|
|
|||
28
Linphone/Utils/Extensions/DecodableExtension.swift
Normal file
28
Linphone/Utils/Extensions/DecodableExtension.swift
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2020 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linhome
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import Foundation
|
||||
|
||||
extension Decodable {
|
||||
init?(dictionary: [String: Any]) {
|
||||
guard let data = try? JSONSerialization.data(withJSONObject: dictionary) else { return nil }
|
||||
guard let object = try? JSONDecoder().decode(Self.self, from: data) else { return nil }
|
||||
self = object
|
||||
}
|
||||
}
|
||||
27
Linphone/Utils/Extensions/EncodableExtension.swift
Normal file
27
Linphone/Utils/Extensions/EncodableExtension.swift
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2020 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linhome
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import Foundation
|
||||
|
||||
extension Encodable {
|
||||
var asDictionary: [String: Any]? {
|
||||
guard let data = try? JSONEncoder().encode(self) else { return nil }
|
||||
return try? JSONSerialization.jsonObject(with: data) as? [String: Any]
|
||||
}
|
||||
}
|
||||
38
Linphone/Utils/Extensions/UIApplicationExtension.swift
Normal file
38
Linphone/Utils/Extensions/UIApplicationExtension.swift
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2020 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linhome
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
extension UIApplication {
|
||||
class func getTopMostViewController() -> UIViewController? {
|
||||
if let scenes = UIApplication.shared.connectedScenes.first as? UIWindowScene {
|
||||
let keyWindow = scenes.windows.filter {$0.isKeyWindow}.first
|
||||
if var topController = keyWindow?.rootViewController {
|
||||
while let presentedViewController = topController.presentedViewController {
|
||||
topController = presentedViewController
|
||||
}
|
||||
return topController
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
44
Linphone/Utils/SingleSignOn/AuthState.swift
Normal file
44
Linphone/Utils/SingleSignOn/AuthState.swift
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2023 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linphone-iphone
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import Foundation
|
||||
import AppAuth
|
||||
|
||||
class AuthState: Encodable, Decodable {
|
||||
var accessToken: String?
|
||||
var refreshToken: String?
|
||||
var tokenEndpointUri: String?
|
||||
var accessTokenExpirationTime: Date?
|
||||
var isAuthorized: Bool
|
||||
|
||||
init(oidAuthState: OIDAuthState) {
|
||||
accessToken = oidAuthState.lastTokenResponse?.accessToken
|
||||
refreshToken = oidAuthState.refreshToken
|
||||
tokenEndpointUri = oidAuthState.lastTokenResponse?.request.configuration.tokenEndpoint.absoluteString
|
||||
accessTokenExpirationTime = oidAuthState.getAccessTokenExpirationTime()
|
||||
isAuthorized = oidAuthState.isAuthorized
|
||||
}
|
||||
|
||||
func update(tokenResponse: OIDTokenResponse) {
|
||||
accessToken = tokenResponse.accessToken
|
||||
refreshToken = tokenResponse.refreshToken
|
||||
tokenEndpointUri = tokenResponse.request.configuration.tokenEndpoint.absoluteString
|
||||
accessTokenExpirationTime = tokenResponse.accessTokenExpirationDate
|
||||
}
|
||||
}
|
||||
36
Linphone/Utils/SingleSignOn/OIDAuthStateExtension.swift
Normal file
36
Linphone/Utils/SingleSignOn/OIDAuthStateExtension.swift
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2020 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linhome
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import Foundation
|
||||
import AppAuth
|
||||
|
||||
extension OIDAuthState {
|
||||
public func getAccessTokenExpirationTime() -> Date? {
|
||||
if authorizationError != nil {
|
||||
return nil
|
||||
}
|
||||
if lastTokenResponse?.accessToken != nil {
|
||||
return lastTokenResponse?.accessTokenExpirationDate
|
||||
}
|
||||
if lastAuthorizationResponse.accessToken != nil {
|
||||
return lastAuthorizationResponse.accessTokenExpirationDate
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
178
Linphone/Utils/SingleSignOn/SingleSignOnManager.swift
Normal file
178
Linphone/Utils/SingleSignOn/SingleSignOnManager.swift
Normal file
|
|
@ -0,0 +1,178 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2023 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linphone-iphone
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import Foundation
|
||||
import linphonesw
|
||||
import AppAuth
|
||||
|
||||
class SingleSignOnManager {
|
||||
|
||||
static let shared = SingleSignOnManager()
|
||||
|
||||
private let TAG = "[SSO]"
|
||||
private let clientId = "linphone"
|
||||
private let userDefaultSSOKey = "sso-authstate"
|
||||
let ssoRedirectUri = URL(string: "org.linphone:/openidcallback")!
|
||||
private var singleSignOnUrl = ""
|
||||
private var username: String = ""
|
||||
private var authState: AuthState?
|
||||
private var authService: OIDAuthorizationService?
|
||||
var currentAuthorizationFlow: OIDExternalUserAgentSession?
|
||||
|
||||
func persistedAuthState() -> AuthState? {
|
||||
if let persistentAuthState = UserDefaults.standard.object(forKey: userDefaultSSOKey), let fromDictionary = persistentAuthState as? [String: Any] {
|
||||
return AuthState(dictionary: fromDictionary)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func persistAuthState() {
|
||||
if let authState = authState {
|
||||
UserDefaults.standard.set(authState.asDictionary, forKey: userDefaultSSOKey)
|
||||
}
|
||||
}
|
||||
|
||||
func setUp(ssoUrl: String, user: String = "") {
|
||||
singleSignOnUrl = ssoUrl
|
||||
username = user
|
||||
Log.info("\(TAG) Setting up SSO environment for username \(username) and URL \(singleSignOnUrl)")
|
||||
authState = persistedAuthState()
|
||||
updateTokenInfo()
|
||||
}
|
||||
|
||||
private func updateTokenInfo() {
|
||||
Log.info("\(TAG) Updating token info")
|
||||
if authState?.isAuthorized == true {
|
||||
Log.info("\(TAG) User is already authenticated!")
|
||||
if let expiration = authState?.accessTokenExpirationTime {
|
||||
if expiration < Date() {
|
||||
Log.warn("\(TAG) Access token is expired")
|
||||
performRefreshToken()
|
||||
} else {
|
||||
Log.info("\(TAG) Access token valid, expires \(expiration)")
|
||||
storeTokensInAuthInfo()
|
||||
}
|
||||
} else {
|
||||
Log.warn("\(TAG) Access token expiration info not available")
|
||||
singleSignOn()
|
||||
}
|
||||
} else {
|
||||
Log.warn("\(TAG) User isn't authenticated yet")
|
||||
singleSignOn()
|
||||
}
|
||||
}
|
||||
|
||||
private func performRefreshToken() {
|
||||
Log.info("\(TAG) Refreshing token")
|
||||
if let issuer = URL(string: singleSignOnUrl) {
|
||||
OIDAuthorizationService.discoverConfiguration(forIssuer: issuer) { configuration, error in
|
||||
guard let configuration = configuration, let refreshToken = self.authState?.refreshToken else {
|
||||
Log.error("\(self.TAG) Error retrieving discovery document: \(error?.localizedDescription ?? "Unknown error")")
|
||||
return
|
||||
}
|
||||
let request = OIDTokenRequest(
|
||||
configuration: configuration,
|
||||
grantType: OIDGrantTypeRefreshToken,
|
||||
authorizationCode: nil,
|
||||
redirectURL: nil,
|
||||
clientID: self.clientId,
|
||||
clientSecret: nil,
|
||||
scope: nil,
|
||||
refreshToken: refreshToken,
|
||||
codeVerifier: nil,
|
||||
additionalParameters: nil)
|
||||
|
||||
OIDAuthorizationService.perform(request) { tokenResponse, error in
|
||||
if error != nil {
|
||||
Log.error("\(self.TAG) Error occured refreshing token \(String(describing: error))")
|
||||
self.authState = nil
|
||||
self.singleSignOn()
|
||||
return
|
||||
}
|
||||
if let tokenResponse = tokenResponse, tokenResponse.accessToken != nil {
|
||||
Log.info("\(self.TAG) Refreshed token \(String(describing: tokenResponse.accessToken))")
|
||||
self.authState?.update(tokenResponse: tokenResponse)
|
||||
self.storeTokensInAuthInfo()
|
||||
} else {
|
||||
Log.info("\(self.TAG) refresh token response or access token is empty")
|
||||
self.authState = nil
|
||||
self.singleSignOn()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func singleSignOn() {
|
||||
if let issuer = URL(string: singleSignOnUrl) {
|
||||
OIDAuthorizationService.discoverConfiguration(forIssuer: issuer) { configuration, error in
|
||||
guard let configuration = configuration else {
|
||||
Log.error("\(self.TAG) Error retrieving discovery document: \(error?.localizedDescription ?? "Unknown error")")
|
||||
return
|
||||
}
|
||||
|
||||
let request = OIDAuthorizationRequest(configuration: configuration,
|
||||
clientId: self.clientId,
|
||||
scopes: ["offline_access"],
|
||||
redirectURL: self.ssoRedirectUri,
|
||||
responseType: OIDResponseTypeCode,
|
||||
additionalParameters: ["login_hint": self.username])
|
||||
|
||||
Log.info("\(self.TAG) Initiating authorization request with scope: \(request.scope ?? "nil")")
|
||||
if let viewController = UIApplication.getTopMostViewController() {
|
||||
self.currentAuthorizationFlow =
|
||||
OIDAuthState.authState(byPresenting: request, presenting: viewController) { authState, error in
|
||||
if let authState = authState {
|
||||
self.authState = AuthState(oidAuthState: authState)
|
||||
self.persistAuthState()
|
||||
Log.info("\(self.TAG) Got authorization tokens. Access token: " +
|
||||
"\(authState.lastTokenResponse?.accessToken ?? "nil")")
|
||||
self.storeTokensInAuthInfo()
|
||||
} else {
|
||||
Log.info("\(self.TAG) Authorization error: \(error?.localizedDescription ?? "Unknown error")")
|
||||
self.authState = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func storeTokensInAuthInfo() {
|
||||
CoreContext.shared.doOnCoreQueue { core in
|
||||
if let expire = self.authState?.accessTokenExpirationTime?.timeIntervalSince1970,
|
||||
let accessToken = self.authState?.accessToken,
|
||||
let lAccessToken = try?Factory.Instance.createBearerToken(token: accessToken, expirationTime: Int(expire)),
|
||||
let refreshToken = self.authState?.refreshToken,
|
||||
let lRefreshToken = try?Factory.Instance.createBearerToken(token: refreshToken, expirationTime: Int(expire)),
|
||||
let authInfo = CoreContext.shared.bearerAuthInfoPendingPasswordUpdate {
|
||||
authInfo.accessToken = lAccessToken
|
||||
authInfo.refreshToken = lRefreshToken
|
||||
authInfo.tokenEndpointUri = self.authState?.tokenEndpointUri
|
||||
authInfo.clientId = self.clientId
|
||||
core.addAuthInfo(info: authInfo)
|
||||
Log.info("\(self.TAG) Auth info added username=\(self.username) access token=\(accessToken) refresh token=\(refreshToken) expire=\(expire)")
|
||||
core.refreshRegisters()
|
||||
} else {
|
||||
Log.warn("\(self.TAG) Unable to store SSO details in auth info")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -27,12 +27,12 @@ class URIHandler {
|
|||
private static let callSchemes = ["sip", "sip-linphone", "linphone-sip", "tel"]
|
||||
private static let secureCallSchemes = ["sips", "sips-linphone", "linphone-sips"]
|
||||
private static let configurationSchemes = ["linphone-config"]
|
||||
|
||||
private static var uriHandlerCoreDelegate: CoreDelegateStub? = nil
|
||||
|
||||
private static var uriHandlerCoreDelegate: CoreDelegateStub?
|
||||
|
||||
static func addCoreDelegate() {
|
||||
uriHandlerCoreDelegate = CoreDelegateStub(
|
||||
onCallStateChanged: { (core: Core, call: Call, state: Call.State, message: String) in
|
||||
onCallStateChanged: { (_: Core, _: Call, state: Call.State, _: String) in
|
||||
if state == .Error {
|
||||
toast("Failed_uri_handler_call_failed")
|
||||
CoreContext.shared.removeCoreDelegateStub(delegate: uriHandlerCoreDelegate!)
|
||||
|
|
@ -41,7 +41,7 @@ class URIHandler {
|
|||
CoreContext.shared.removeCoreDelegateStub(delegate: uriHandlerCoreDelegate!)
|
||||
}
|
||||
},
|
||||
onConfiguringStatus: { (core:Core, state:ConfiguringState, status: String) in
|
||||
onConfiguringStatus: { (_: Core, state: ConfiguringState, _: String) in
|
||||
if state == .Failed {
|
||||
toast("Failed_uri_handler_config_failed")
|
||||
CoreContext.shared.removeCoreDelegateStub(delegate: uriHandlerCoreDelegate!)
|
||||
|
|
@ -54,7 +54,6 @@ class URIHandler {
|
|||
CoreContext.shared.addCoreDelegateStub(delegate: uriHandlerCoreDelegate!)
|
||||
}
|
||||
|
||||
|
||||
static func handleURL(url: URL) {
|
||||
Log.info("[URIHandler] handleURL: \(url)")
|
||||
if let scheme = url.scheme {
|
||||
|
|
@ -64,6 +63,8 @@ class URIHandler {
|
|||
initiateCall(url: url, withScheme: "sip")
|
||||
} else if configurationSchemes.contains(scheme) {
|
||||
initiateConfiguration(url: url)
|
||||
} else if scheme == SingleSignOnManager.shared.ssoRedirectUri.scheme {
|
||||
continueSSO(url: url)
|
||||
} else {
|
||||
Log.error("[URIHandler] unhandled URL \(url) (check Info.plist)")
|
||||
}
|
||||
|
|
@ -107,10 +108,17 @@ class URIHandler {
|
|||
}
|
||||
}
|
||||
|
||||
private static func continueSSO(url: URL) {
|
||||
if let authorizationFlow = SingleSignOnManager.shared.currentAuthorizationFlow,
|
||||
authorizationFlow.resumeExternalUserAgentFlow(with: url) {
|
||||
SingleSignOnManager.shared.currentAuthorizationFlow = nil
|
||||
}
|
||||
}
|
||||
|
||||
private static func autoRemoteProvisioningOnConfigUriHandler() -> Bool {
|
||||
return Config.get().getBool(section: "app", key: "auto_apply_provisioning_config_uri_handler", defaultValue: true)
|
||||
}
|
||||
|
||||
|
||||
private static func toast(_ message: String) {
|
||||
DispatchQueue.main.async {
|
||||
ToastViewModel.shared.toastMessage = message
|
||||
|
|
|
|||
1
Podfile
1
Podfile
|
|
@ -26,6 +26,7 @@ target 'Linphone' do
|
|||
|
||||
# Pods for Linphone
|
||||
pod 'SwiftLint'
|
||||
pod 'AppAuth'
|
||||
basic_pods
|
||||
|
||||
end
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue