From a307d869d45463484e40b62ba054a6187a313806 Mon Sep 17 00:00:00 2001 From: Alex Nachbaur Date: Mon, 12 Aug 2024 13:33:38 -0700 Subject: [PATCH 01/20] Update minimum Swift, Xcode, and platform versions --- OktaAuthFoundation.podspec | 20 +- OktaDirectAuth.podspec | 20 +- OktaOAuth2.podspec | 20 +- OktaWebAuthenticationUI.podspec | 12 +- Package.swift | 9 +- README.md | 13 +- .../AuthFoundation/JWT/Enums/JWTClaim.swift | 2 +- .../JWT/Internal/JWK+Extensions.swift | 1 - .../AuthFoundation/JWT/JWK+Verification.swift | 2 +- .../Migrators/OIDCLegacyMigrator.swift | 2 +- .../AuthFoundation/Network/APIRequest.swift | 4 - .../Internal/String+AuthFoundation.swift | 4 +- .../AuthFoundation/OAuth2/OAuth2Client.swift | 2 - .../Internal/Keychain+Extensions.swift | 13 +- .../Security/Internal/KeychainProtocol.swift | 2 +- .../AuthFoundation/Security/Keychain.swift | 7 +- .../Security/KeychainError.swift | 2 +- .../Internal/KeychainTokenStorage.swift | 2 +- .../Internal/UserDefaultsTokenStorage.swift | 2 +- .../Token Management/Token.swift | 2 - .../Credential+Extensions.swift | 2 - .../User Management/CredentialSecurity.swift | 2 +- .../Internal/CredentialCoordinatorImpl.swift | 2 +- .../CredentialSecurity+Internal.swift | 2 +- .../Utilities/BackgroundTaskWrapper.swift | 2 +- .../Utilities/Data+Extensions.swift | 2 +- Sources/OktaDirectAuth/DirectAuthFlow.swift | 2 - .../AuthorizationCodeFlow.swift | 2 - .../DeviceAuthorizationFlow.swift | 2 - .../Authentication/JWTAuthorizationFlow.swift | 2 - .../Authentication/ResourceOwnerFlow.swift | 2 - .../Authentication/SessionTokenFlow.swift | 2 - .../Authentication/TokenExchangeFlow.swift | 2 - .../OktaOAuth2/Logout/SessionLogoutFlow.swift | 2 - .../WebAuthentication+Deprecated.swift | 2 - .../AuthenticationServicesProvider.swift | 6 - .../Providers/SafariBrowserProvider.swift | 147 -------------- .../Providers/SafariServicesProvider.swift | 190 ------------------ .../WebAuthentication.swift | 32 +-- .../CredentialRefreshTests.swift | 2 - .../CredentialRevokeTests.swift | 2 - Tests/AuthFoundationTests/ErrorTests.swift | 2 +- Tests/AuthFoundationTests/KeychainTests.swift | 2 +- .../KeychainTokenStorageTests.swift | 2 +- .../OAuth2ClientTests.swift | 4 - .../OIDCLegacyMigratorTests.swift | 2 +- Tests/AuthFoundationTests/TokenTests.swift | 2 - .../UserDefaultsTokenStorageTests.swift | 2 +- Tests/AuthFoundationTests/UserInfoTests.swift | 2 +- .../DirectAuth1FATests.swift | 2 - .../DirectAuth2FATests.swift | 2 - .../AuthorizationCodeFlowSuccessTests.swift | 2 - .../DeviceAuthorizationFlowSuccessTests.swift | 2 - .../JWTAuthorizationFlowTests.swift | 2 +- .../ResourceOwnerFlowTests.swift | 2 - .../SessionLogoutFlowSuccessTests.swift | 2 - .../SessionTokenFlowTests.swift | 2 - .../TokenExchangeFlowTests.swift | 2 +- Tests/TestCommon/MockKeychain.swift | 2 +- Tests/TestCommon/URLSessionMock.swift | 2 - Tests/TestCommon/XCTestCase+Extensions.swift | 2 - .../SafariBrowserProviderTests.swift | 41 ---- .../SafariServicesProviderTests.swift | 94 --------- 63 files changed, 92 insertions(+), 635 deletions(-) delete mode 100644 Sources/WebAuthenticationUI/Providers/SafariBrowserProvider.swift delete mode 100644 Sources/WebAuthenticationUI/Providers/SafariServicesProvider.swift delete mode 100644 Tests/WebAuthenticationUITests/SafariBrowserProviderTests.swift delete mode 100644 Tests/WebAuthenticationUITests/SafariServicesProviderTests.swift diff --git a/OktaAuthFoundation.podspec b/OktaAuthFoundation.podspec index 209c07dfd..aafae183a 100644 --- a/OktaAuthFoundation.podspec +++ b/OktaAuthFoundation.podspec @@ -7,15 +7,17 @@ Pod::Spec.new do |s| Provides the foundation and common features used to authenticate users, managing the lifecycle and storage of tokens and credentials, and provide a base for other Okta SDKs to build upon. DESC s.platforms = { - :ios => "10.0", - :tvos => "10.0", - :watchos => "7.0", - :osx => "10.12" + :ios => "12.0", + :tvos => "12.0", + :visionos => "1.0", + :watchos => "7.0", + :osx => "10.13" } - s.ios.deployment_target = "10.0" - s.tvos.deployment_target = "10.0" - s.watchos.deployment_target = "7.0" - s.osx.deployment_target = "10.12" + s.ios.deployment_target = "12.0" + s.tvos.deployment_target = "12.0" + s.visionos.deployment_target = "1.0" + s.watchos.deployment_target = "7.0" + s.osx.deployment_target = "10.13" s.homepage = "https://github.com/okta/okta-mobile-swift" s.license = { :type => "APACHE2", :file => "LICENSE" } @@ -23,5 +25,5 @@ Provides the foundation and common features used to authenticate users, managing s.source = { :git => "https://github.com/okta/okta-mobile-swift.git", :tag => s.version.to_s } s.source_files = "Sources/AuthFoundation/**/*.swift" s.resource_bundles = { "AuthFoundation" => "Sources/AuthFoundation/Resources/**/*" } - s.swift_version = "5.6" + s.swift_version = "5.9" end diff --git a/OktaDirectAuth.podspec b/OktaDirectAuth.podspec index b00ad842e..612a4642b 100644 --- a/OktaDirectAuth.podspec +++ b/OktaDirectAuth.podspec @@ -6,15 +6,17 @@ Pod::Spec.new do |s| Enables application developers to build native sign in experiences using the Okta Direct Authentication API. DESC s.platforms = { - :ios => "10.0", - :tvos => "10.0", - :watchos => "7.0", - :osx => "10.12" + :ios => "12.0", + :tvos => "12.0", + :visionos => "1.0", + :watchos => "7.0", + :osx => "10.13" } - s.ios.deployment_target = "10.0" - s.tvos.deployment_target = "10.0" - s.watchos.deployment_target = "7.0" - s.osx.deployment_target = "10.12" + s.ios.deployment_target = "12.0" + s.tvos.deployment_target = "12.0" + s.visionos.deployment_target = "1.0" + s.watchos.deployment_target = "7.0" + s.osx.deployment_target = "10.13" s.homepage = "https://github.com/okta/okta-mobile-swift" s.license = { :type => "APACHE2", :file => "LICENSE" } @@ -22,7 +24,7 @@ Enables application developers to build native sign in experiences using the Okt s.source = { :git => "https://github.com/okta/okta-mobile-swift.git", :tag => s.version.to_s } s.source_files = "Sources/OktaDirectAuth/**/*.swift" s.resource_bundles = { "OktaDirectAuth" => "Sources/OktaDirectAuth/Resources/**/*" } - s.swift_version = "5.6" + s.swift_version = "5.9" s.dependency "OktaAuthFoundation", "#{s.version.to_s}" end diff --git a/OktaOAuth2.podspec b/OktaOAuth2.podspec index f730dcda1..7c09c4049 100644 --- a/OktaOAuth2.podspec +++ b/OktaOAuth2.podspec @@ -6,15 +6,17 @@ Pod::Spec.new do |s| Enables application developers to authenticate users utilizing a variety of OAuth2 authentication flows. DESC s.platforms = { - :ios => "10.0", - :tvos => "10.0", - :watchos => "7.0", - :osx => "10.12" + :ios => "12.0", + :tvos => "12.0", + :visionos => "1.0", + :watchos => "7.0", + :osx => "10.13" } - s.ios.deployment_target = "10.0" - s.tvos.deployment_target = "10.0" - s.watchos.deployment_target = "7.0" - s.osx.deployment_target = "10.12" + s.ios.deployment_target = "12.0" + s.tvos.deployment_target = "12.0" + s.visionos.deployment_target = "1.0" + s.watchos.deployment_target = "7.0" + s.osx.deployment_target = "10.13" s.homepage = "https://github.com/okta/okta-mobile-swift" s.license = { :type => "APACHE2", :file => "LICENSE" } @@ -22,7 +24,7 @@ Enables application developers to authenticate users utilizing a variety of OAut s.source = { :git => "https://github.com/okta/okta-mobile-swift.git", :tag => s.version.to_s } s.source_files = "Sources/OktaOAuth2/**/*.swift" s.resource_bundles = { "OktaOAuth2" => "Sources/OktaOAuth2/Resources/**/*" } - s.swift_version = "5.6" + s.swift_version = "5.9" s.dependency "OktaAuthFoundation", "#{s.version.to_s}" end diff --git a/OktaWebAuthenticationUI.podspec b/OktaWebAuthenticationUI.podspec index 0ce762838..4e421b870 100644 --- a/OktaWebAuthenticationUI.podspec +++ b/OktaWebAuthenticationUI.podspec @@ -7,11 +7,13 @@ Pod::Spec.new do |s| Authenticate users using web-based OIDC. DESC s.platforms = { - :ios => "10.0", - :osx => "10.12" + :ios => "12.0", + :visionos => "1.0", + :osx => "10.13" } - s.ios.deployment_target = "10.0" - s.osx.deployment_target = "10.12" + s.ios.deployment_target = "12.0" + s.visionos.deployment_target = "1.0" + s.osx.deployment_target = "10.13" s.homepage = "https://github.com/okta/okta-mobile-swift" s.license = { :type => "APACHE2", :file => "LICENSE" } @@ -19,7 +21,7 @@ Authenticate users using web-based OIDC. s.source = { :git => "https://github.com/okta/okta-mobile-swift.git", :tag => s.version.to_s } s.source_files = "Sources/WebAuthenticationUI/**/*.swift" s.resource_bundles = { "WebAuthenticationUI" => "Sources/WebAuthenticationUI/Resources/**/*" } - s.swift_version = "5.6" + s.swift_version = "5.9" s.dependency "OktaAuthFoundation", "#{s.version.to_s}" s.dependency "OktaOAuth2", "#{s.version.to_s}" diff --git a/Package.swift b/Package.swift index 6e65226b0..d5b63081f 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:5.6 +// swift-tools-version:5.9 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription @@ -7,10 +7,11 @@ var package = Package( name: "AuthFoundation", defaultLocalization: "en", platforms: [ - .iOS(.v10), - .tvOS(.v10), + .iOS(.v12), + .tvOS(.v12), .watchOS(.v7), - .macOS(.v10_12), + .visionOS(.v1), + .macOS(.v10_13), .macCatalyst(.v13) ], products: [ diff --git a/README.md b/README.md index 08a5180de..9203bf360 100644 --- a/README.md +++ b/README.md @@ -384,13 +384,14 @@ Only the last 4 major platform versions are officially supported, unless there a | Platform | Supported | Best-Effort | | ----------- | --------- | ----------- | -| iOS | 12.0 | 10.0 | -| tvOS | 12.0 | 10.0 | -| watchOS | 8.0 | 7.0 | +| iOS | 13.0 | 12.0 | +| tvOS | 13.0 | 12.0 | +| watchOS | 7.0 | 7.0 | +| visionOS | 1.0 | 1.0 | | macCatalyst | 13.0 | 13.0 | -| macOS | 12.0 | 10.12 | +| macOS | 12.0 | 10.13 | -Once a platform version becomes unsupported, dropping support for it will not be considered a breaking change and will be done in a minor release. For example, iOS 12 will cease to be supported when iOS 16 gets released, and might be dropped in a minor release. +Once a platform version becomes unsupported, dropping support for it will not be considered a breaking change and will be done in a minor release. For example, iOS 13 will cease to be supported when iOS 18 gets released, and might be dropped in a minor release. In the case of macOS, the yearly named releases are considered a major platform version for this Policy, regardless of the actual version numbers. @@ -431,7 +432,7 @@ Alternatively, if you wish to run tests within Linux, you can utilize Docker fro ```bash docker run --rm --privileged --interactive --tty \ - --volume "$(pwd):/src" --workdir "/src" swift:5.6.1 \ + --volume "$(pwd):/src" --workdir "/src" swift:latest \ swift test ``` diff --git a/Sources/AuthFoundation/JWT/Enums/JWTClaim.swift b/Sources/AuthFoundation/JWT/Enums/JWTClaim.swift index 51572c766..b21011c47 100644 --- a/Sources/AuthFoundation/JWT/Enums/JWTClaim.swift +++ b/Sources/AuthFoundation/JWT/Enums/JWTClaim.swift @@ -277,7 +277,7 @@ public extension HasClaims where ClaimType == JWTClaim { /// The person's preferred username. var preferredUsername: String? { self[.preferredUsername] } -#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) +#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(visionOS) /// The person's name components, pre-assigned to a PersonNameComponents object. /// /// This property can be used as a convenience to generate a string representation of the user's name, based on the user's current locale. diff --git a/Sources/AuthFoundation/JWT/Internal/JWK+Extensions.swift b/Sources/AuthFoundation/JWT/Internal/JWK+Extensions.swift index e87fcf098..1d747de11 100644 --- a/Sources/AuthFoundation/JWT/Internal/JWK+Extensions.swift +++ b/Sources/AuthFoundation/JWT/Internal/JWK+Extensions.swift @@ -16,7 +16,6 @@ import Foundation import CommonCrypto extension JWK.Algorithm { - @available(iOS 10.0, macCatalyst 13.0, tvOS 10.0, watchOS 3.0, macOS 10.12, *) var secKeyAlgorithm: SecKeyAlgorithm? { switch self { case .rs256: diff --git a/Sources/AuthFoundation/JWT/JWK+Verification.swift b/Sources/AuthFoundation/JWT/JWK+Verification.swift index 306c7eda6..2f5205d49 100644 --- a/Sources/AuthFoundation/JWT/JWK+Verification.swift +++ b/Sources/AuthFoundation/JWT/JWK+Verification.swift @@ -44,7 +44,7 @@ extension JWK { nil) } - #if os(iOS) || os(tvOS) || os(watchOS) + #if os(iOS) || os(tvOS) || os(watchOS) || os(visionOS) if #available(iOS 2.0, macCatalyst 13.0, tvOS 9.0, watchOS 2.0, *) { guard let padding = algorithm.secPadding, let digest = algorithm.digest(data: data) diff --git a/Sources/AuthFoundation/Migration/Migrators/OIDCLegacyMigrator.swift b/Sources/AuthFoundation/Migration/Migrators/OIDCLegacyMigrator.swift index 40f9780fd..a498f03ab 100644 --- a/Sources/AuthFoundation/Migration/Migrators/OIDCLegacyMigrator.swift +++ b/Sources/AuthFoundation/Migration/Migrators/OIDCLegacyMigrator.swift @@ -12,7 +12,7 @@ import Foundation -#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) +#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(visionOS) private let accountIdRegex = try? NSRegularExpression(pattern: "0oa[0-9a-zA-Z]{17}") diff --git a/Sources/AuthFoundation/Network/APIRequest.swift b/Sources/AuthFoundation/Network/APIRequest.swift index 495cff5eb..2dfdf15ed 100644 --- a/Sources/AuthFoundation/Network/APIRequest.swift +++ b/Sources/AuthFoundation/Network/APIRequest.swift @@ -63,7 +63,6 @@ public protocol APIRequest { /// - completion: Completion block invoked with the result. func send(to client: APIClient, parsing context: APIParsingContext?, completion: @escaping(Result, APIClientError>) -> Void) - #if swift(>=5.5.1) /// Asynchronously sends the request to the given ``APIClient``. /// - Parameters: /// - client: ``APIClient`` the request is being sent to. @@ -71,7 +70,6 @@ public protocol APIRequest { /// - Returns: ``APIResponse`` result of the request. @available(iOS 13.0, tvOS 13.0, macOS 10.15, watchOS 6, *) func send(to client: APIClient, parsing context: APIParsingContext?) async throws -> APIResponse - #endif } /// API HTTP request method. @@ -242,7 +240,6 @@ extension APIRequest { } } - #if swift(>=5.5.1) @available(iOS 13.0, tvOS 13.0, macOS 10.15, watchOS 6, *) public func send(to client: APIClient, parsing context: APIParsingContext? = nil) async throws -> APIResponse { try await withCheckedThrowingContinuation { continuation in @@ -251,7 +248,6 @@ extension APIRequest { } } } - #endif } extension APIContentType { diff --git a/Sources/AuthFoundation/Network/Internal/String+AuthFoundation.swift b/Sources/AuthFoundation/Network/Internal/String+AuthFoundation.swift index 7d0bbede1..e9bcb9a69 100644 --- a/Sources/AuthFoundation/Network/Internal/String+AuthFoundation.swift +++ b/Sources/AuthFoundation/Network/Internal/String+AuthFoundation.swift @@ -36,6 +36,8 @@ private let systemName: String = { return "watchOS" #elseif os(tvOS) return "tvOS" + #elseif os(visionOS) + return "visionOS" #elseif os(macOS) return "macOS" #elseif os(Linux) @@ -44,7 +46,7 @@ private let systemName: String = { }() private let systemVersion: String = { - #if os(iOS) || os(tvOS) + #if os(iOS) || os(tvOS) || os(visionOS) return UIDevice.current.systemVersion #elseif os(watchOS) return WKInterfaceDevice.current().systemVersion diff --git a/Sources/AuthFoundation/OAuth2/OAuth2Client.swift b/Sources/AuthFoundation/OAuth2/OAuth2Client.swift index eb2c9a0b1..723ec946a 100644 --- a/Sources/AuthFoundation/OAuth2/OAuth2Client.swift +++ b/Sources/AuthFoundation/OAuth2/OAuth2Client.swift @@ -567,7 +567,6 @@ public final class OAuth2Client { } // swiftlint:enable type_body_length -#if swift(>=5.5.1) @available(iOS 13.0, tvOS 13.0, macOS 10.15, watchOS 6, *) extension OAuth2Client { /// Asynchronously retrieves the org's OpenID configuration. @@ -622,7 +621,6 @@ extension OAuth2Client { } } } -#endif extension OAuth2Client: APIClient { /// Exposes the base URL this authorization server is represented by. diff --git a/Sources/AuthFoundation/Security/Internal/Keychain+Extensions.swift b/Sources/AuthFoundation/Security/Internal/Keychain+Extensions.swift index 237ed7ef5..6e43c82ee 100644 --- a/Sources/AuthFoundation/Security/Internal/Keychain+Extensions.swift +++ b/Sources/AuthFoundation/Security/Internal/Keychain+Extensions.swift @@ -10,7 +10,7 @@ // See the License for the specific language governing permissions and limitations under the License. // -#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) +#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(visionOS) import Foundation @@ -251,6 +251,9 @@ extension Keychain.Search.Result: KeychainGettable, KeychainUpdatable, KeychainD } } +fileprivate let _kSecAttrAccessibleAlways = "dk" as CFString +fileprivate let _kSecAttrAccessibleAlwaysThisDeviceOnly = "dku" as CFString + extension Keychain.Accessibility: RawRepresentable { public typealias RawValue = String @@ -267,9 +270,9 @@ extension Keychain.Accessibility: RawRepresentable { self = .afterFirstUnlock case kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly: self = .afterFirstUnlockThisDeviceOnly - case kSecAttrAccessibleAlways: + case _kSecAttrAccessibleAlways: self = .always - case kSecAttrAccessibleAlwaysThisDeviceOnly: + case _kSecAttrAccessibleAlwaysThisDeviceOnly: self = .alwaysThisDeviceOnly default: return nil @@ -289,9 +292,9 @@ extension Keychain.Accessibility: RawRepresentable { case .afterFirstUnlockThisDeviceOnly: return kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly as String case .always: - return kSecAttrAccessibleAlways as String + return _kSecAttrAccessibleAlways as String case .alwaysThisDeviceOnly: - return kSecAttrAccessibleAlwaysThisDeviceOnly as String + return _kSecAttrAccessibleAlwaysThisDeviceOnly as String } } } diff --git a/Sources/AuthFoundation/Security/Internal/KeychainProtocol.swift b/Sources/AuthFoundation/Security/Internal/KeychainProtocol.swift index 4699fe3b5..89d45bc15 100644 --- a/Sources/AuthFoundation/Security/Internal/KeychainProtocol.swift +++ b/Sources/AuthFoundation/Security/Internal/KeychainProtocol.swift @@ -10,7 +10,7 @@ // See the License for the specific language governing permissions and limitations under the License. // -#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) +#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(visionOS) import Foundation diff --git a/Sources/AuthFoundation/Security/Keychain.swift b/Sources/AuthFoundation/Security/Keychain.swift index cc8c080f1..1946809d5 100644 --- a/Sources/AuthFoundation/Security/Keychain.swift +++ b/Sources/AuthFoundation/Security/Keychain.swift @@ -12,7 +12,7 @@ import Foundation -#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) +#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(visionOS) #if canImport(LocalAuthentication) && !os(tvOS) import LocalAuthentication @@ -199,15 +199,14 @@ public struct Keychain { case afterFirstUnlockThisDeviceOnly /// Requires the device to have a passcode set, and disallows iCloud keychain sharing. - @available(iOS 8.0, *) case whenPasswordSetThisDeviceOnly /// Allows the keychain item to always be accessible. - @available(iOS, introduced: 4.0, deprecated: 12.0, message: "Use an accessibility level that provides some user protection, such as kSecAttrAccessibleAfterFirstUnlock") + @available(*, message: "Use an accessibility level that provides some user protection, such as .afterFirstUnlock") case always /// Allows the keychain item to always be accessible, and disallows iCloud keychain sharing. - @available(iOS, introduced: 4.0, deprecated: 12.0, message: "Use an accessibility level that provides some user protection, such as kSecAttrAccessibleAfterFirstUnlock") + @available(*, message: "Use an accessibility level that provides some user protection, such as .afterFirstUnlock") case alwaysThisDeviceOnly var isSynchronizable: Bool { diff --git a/Sources/AuthFoundation/Security/KeychainError.swift b/Sources/AuthFoundation/Security/KeychainError.swift index 12e18d839..61c2e259a 100644 --- a/Sources/AuthFoundation/Security/KeychainError.swift +++ b/Sources/AuthFoundation/Security/KeychainError.swift @@ -12,7 +12,7 @@ import Foundation -#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) +#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(visionOS) /// Describes errors that may occur when interacting with the keychain. public enum KeychainError: Error { diff --git a/Sources/AuthFoundation/Token Management/Internal/KeychainTokenStorage.swift b/Sources/AuthFoundation/Token Management/Internal/KeychainTokenStorage.swift index 176694e3e..1353eef68 100644 --- a/Sources/AuthFoundation/Token Management/Internal/KeychainTokenStorage.swift +++ b/Sources/AuthFoundation/Token Management/Internal/KeychainTokenStorage.swift @@ -10,7 +10,7 @@ // See the License for the specific language governing permissions and limitations under the License. // -#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) +#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(visionOS) import Foundation diff --git a/Sources/AuthFoundation/Token Management/Internal/UserDefaultsTokenStorage.swift b/Sources/AuthFoundation/Token Management/Internal/UserDefaultsTokenStorage.swift index 866a697ae..a8465215a 100644 --- a/Sources/AuthFoundation/Token Management/Internal/UserDefaultsTokenStorage.swift +++ b/Sources/AuthFoundation/Token Management/Internal/UserDefaultsTokenStorage.swift @@ -12,7 +12,7 @@ import Foundation -#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) +#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(visionOS) #if canImport(LocalAuthentication) && !os(tvOS) import LocalAuthentication #else diff --git a/Sources/AuthFoundation/Token Management/Token.swift b/Sources/AuthFoundation/Token Management/Token.swift index 97a86c8e7..a1310b873 100644 --- a/Sources/AuthFoundation/Token Management/Token.swift +++ b/Sources/AuthFoundation/Token Management/Token.swift @@ -215,7 +215,6 @@ public final class Token: Codable, Equatable, Hashable, JSONClaimContainer, Expi } } -#if swift(>=5.5.1) @available(iOS 13.0, tvOS 13.0, macOS 10.15, watchOS 6, *) extension Token { /// Creates a new Token from a refresh token. @@ -231,7 +230,6 @@ extension Token { } } } -#endif extension Token { enum CodingKeysV1: String, CodingKey, CaseIterable { diff --git a/Sources/AuthFoundation/User Management/Credential+Extensions.swift b/Sources/AuthFoundation/User Management/Credential+Extensions.swift index 496fa4ea7..b0bcdf5da 100644 --- a/Sources/AuthFoundation/User Management/Credential+Extensions.swift +++ b/Sources/AuthFoundation/User Management/Credential+Extensions.swift @@ -38,7 +38,6 @@ extension Notification.Name { public static let credentialRefreshFailed = Notification.Name("com.okta.credential.refresh.failed") } -#if swift(>=5.5.1) @available(iOS 13.0, tvOS 13.0, macOS 10.15, watchOS 6, *) extension Credential { /// Attempt to refresh the token. @@ -114,4 +113,3 @@ extension Credential { } } } -#endif diff --git a/Sources/AuthFoundation/User Management/CredentialSecurity.swift b/Sources/AuthFoundation/User Management/CredentialSecurity.swift index 75aef98bf..c30203c97 100644 --- a/Sources/AuthFoundation/User Management/CredentialSecurity.swift +++ b/Sources/AuthFoundation/User Management/CredentialSecurity.swift @@ -23,7 +23,7 @@ extension Credential { /// /// On Apple platforms, this controls the Keychain security settings for the underlying token's keychain item. public enum Security { - #if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) + #if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(visionOS) /// Defines the accessibility level for a credential. case accessibility(_ option: Keychain.Accessibility) diff --git a/Sources/AuthFoundation/User Management/Internal/CredentialCoordinatorImpl.swift b/Sources/AuthFoundation/User Management/Internal/CredentialCoordinatorImpl.swift index 2abd221dd..b5d2c0ead 100644 --- a/Sources/AuthFoundation/User Management/Internal/CredentialCoordinatorImpl.swift +++ b/Sources/AuthFoundation/User Management/Internal/CredentialCoordinatorImpl.swift @@ -94,7 +94,7 @@ final class CredentialCoordinatorImpl: CredentialCoordinator { } static func defaultTokenStorage() -> TokenStorage { - #if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) + #if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(visionOS) KeychainTokenStorage() #else UserDefaultsTokenStorage() diff --git a/Sources/AuthFoundation/User Management/Internal/CredentialSecurity+Internal.swift b/Sources/AuthFoundation/User Management/Internal/CredentialSecurity+Internal.swift index 2223d1e64..c4f535ceb 100644 --- a/Sources/AuthFoundation/User Management/Internal/CredentialSecurity+Internal.swift +++ b/Sources/AuthFoundation/User Management/Internal/CredentialSecurity+Internal.swift @@ -17,7 +17,7 @@ import LocalAuthentication #endif extension Array where Element == Credential.Security { - #if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) + #if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(visionOS) #if canImport(LocalAuthentication) && !os(tvOS) var context: LAContext? { for case let Credential.Security.context(value) in self { diff --git a/Sources/AuthFoundation/Utilities/BackgroundTaskWrapper.swift b/Sources/AuthFoundation/Utilities/BackgroundTaskWrapper.swift index 839600d1a..500d2a492 100644 --- a/Sources/AuthFoundation/Utilities/BackgroundTaskWrapper.swift +++ b/Sources/AuthFoundation/Utilities/BackgroundTaskWrapper.swift @@ -12,7 +12,7 @@ import Foundation -#if os(iOS) || os(tvOS) || targetEnvironment(macCatalyst) +#if os(iOS) || os(tvOS) || os(visionOS) || targetEnvironment(macCatalyst) import UIKit final class BackgroundTask { diff --git a/Sources/AuthFoundation/Utilities/Data+Extensions.swift b/Sources/AuthFoundation/Utilities/Data+Extensions.swift index e6b5c70f9..2b4c5f60d 100644 --- a/Sources/AuthFoundation/Utilities/Data+Extensions.swift +++ b/Sources/AuthFoundation/Utilities/Data+Extensions.swift @@ -31,7 +31,7 @@ extension Data { /// Produces a SHA256 hash of the supplied data. /// - Returns: SHA256 representation of the data. public func sha256() -> Data? { - #if os(iOS) || os(tvOS) || os(watchOS) || os(macOS) + #if os(iOS) || os(tvOS) || os(watchOS) || os(visionOS) || os(macOS) if #available(iOS 13.0, macCatalyst 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *) { return Data(SHA256.hash(data: self)) } else { diff --git a/Sources/OktaDirectAuth/DirectAuthFlow.swift b/Sources/OktaDirectAuth/DirectAuthFlow.swift index 312064d62..16c991ec6 100644 --- a/Sources/OktaDirectAuth/DirectAuthFlow.swift +++ b/Sources/OktaDirectAuth/DirectAuthFlow.swift @@ -410,7 +410,6 @@ public class DirectAuthenticationFlow: AuthenticationFlow { public let delegateCollection = DelegateCollection() } -#if swift(>=5.5.1) @available(iOS 13.0, tvOS 13.0, macOS 10.15, watchOS 6, *) extension DirectAuthenticationFlow { /// Start user authentication, with the given username login hint and primary factor. @@ -456,7 +455,6 @@ extension DirectAuthenticationFlow { } } } -#endif extension DirectAuthenticationFlow: UsesDelegateCollection { public typealias Delegate = DirectAuthenticationFlowDelegate diff --git a/Sources/OktaOAuth2/Authentication/AuthorizationCodeFlow.swift b/Sources/OktaOAuth2/Authentication/AuthorizationCodeFlow.swift index ef6f4142a..cf15eb7cc 100644 --- a/Sources/OktaOAuth2/Authentication/AuthorizationCodeFlow.swift +++ b/Sources/OktaOAuth2/Authentication/AuthorizationCodeFlow.swift @@ -304,7 +304,6 @@ public class AuthorizationCodeFlow: AuthenticationFlow { public let delegateCollection = DelegateCollection() } -#if swift(>=5.5.1) @available(iOS 13.0, tvOS 13.0, macOS 10.15, watchOS 6, *) extension AuthorizationCodeFlow { /// Asynchronously initiates an authentication flow, with an optional ``Context-swift.struct``, using Swift Concurrency. @@ -344,7 +343,6 @@ extension AuthorizationCodeFlow { } } } -#endif extension AuthorizationCodeFlow: UsesDelegateCollection { public typealias Delegate = AuthorizationCodeFlowDelegate diff --git a/Sources/OktaOAuth2/Authentication/DeviceAuthorizationFlow.swift b/Sources/OktaOAuth2/Authentication/DeviceAuthorizationFlow.swift index 45c751b3f..36c3e4f17 100644 --- a/Sources/OktaOAuth2/Authentication/DeviceAuthorizationFlow.swift +++ b/Sources/OktaOAuth2/Authentication/DeviceAuthorizationFlow.swift @@ -283,7 +283,6 @@ public class DeviceAuthorizationFlow: AuthenticationFlow { } } -#if swift(>=5.5.1) @available(iOS 13.0, tvOS 13.0, macOS 10.15, watchOS 6, *) extension DeviceAuthorizationFlow { /// Asynchronously initiates a device authentication flow. @@ -314,7 +313,6 @@ extension DeviceAuthorizationFlow { } } } -#endif extension DeviceAuthorizationFlow: UsesDelegateCollection { public typealias Delegate = DeviceAuthorizationFlowDelegate diff --git a/Sources/OktaOAuth2/Authentication/JWTAuthorizationFlow.swift b/Sources/OktaOAuth2/Authentication/JWTAuthorizationFlow.swift index 7fbbb1658..6494bee59 100644 --- a/Sources/OktaOAuth2/Authentication/JWTAuthorizationFlow.swift +++ b/Sources/OktaOAuth2/Authentication/JWTAuthorizationFlow.swift @@ -119,7 +119,6 @@ public class JWTAuthorizationFlow: AuthenticationFlow { public let delegateCollection = DelegateCollection() } -#if swift(>=5.5.1) @available(iOS 13.0, tvOS 13.0, macOS 10.15, watchOS 6, *) extension JWTAuthorizationFlow { /// Asynchronously authenticates with a JWT bearer assertion. @@ -134,7 +133,6 @@ extension JWTAuthorizationFlow { } } } -#endif extension JWTAuthorizationFlow: UsesDelegateCollection { public typealias Delegate = AuthenticationDelegate diff --git a/Sources/OktaOAuth2/Authentication/ResourceOwnerFlow.swift b/Sources/OktaOAuth2/Authentication/ResourceOwnerFlow.swift index cef282264..740adfa7f 100644 --- a/Sources/OktaOAuth2/Authentication/ResourceOwnerFlow.swift +++ b/Sources/OktaOAuth2/Authentication/ResourceOwnerFlow.swift @@ -123,7 +123,6 @@ public class ResourceOwnerFlow: AuthenticationFlow { public let delegateCollection = DelegateCollection() } -#if swift(>=5.5.1) @available(iOS 13.0, tvOS 13.0, macOS 10.15, watchOS 6, *) extension ResourceOwnerFlow { /// Asynchronously authenticates with the Resource Owner flow. @@ -137,7 +136,6 @@ extension ResourceOwnerFlow { } } } -#endif extension ResourceOwnerFlow: UsesDelegateCollection { public typealias Delegate = AuthenticationDelegate diff --git a/Sources/OktaOAuth2/Authentication/SessionTokenFlow.swift b/Sources/OktaOAuth2/Authentication/SessionTokenFlow.swift index 46ea98233..6dd7297bd 100644 --- a/Sources/OktaOAuth2/Authentication/SessionTokenFlow.swift +++ b/Sources/OktaOAuth2/Authentication/SessionTokenFlow.swift @@ -174,7 +174,6 @@ public class SessionTokenFlow: AuthenticationFlow { } } -#if swift(>=5.5.1) @available(iOS 13.0, tvOS 13.0, macOS 10.15, watchOS 6, *) extension SessionTokenFlow { /// Asynchronously authenticates with the given session token. @@ -188,7 +187,6 @@ extension SessionTokenFlow { } } } -#endif protocol SessionTokenFlowURLExchange { init(scheme: String) diff --git a/Sources/OktaOAuth2/Authentication/TokenExchangeFlow.swift b/Sources/OktaOAuth2/Authentication/TokenExchangeFlow.swift index e97f5ba35..a9b32db5d 100644 --- a/Sources/OktaOAuth2/Authentication/TokenExchangeFlow.swift +++ b/Sources/OktaOAuth2/Authentication/TokenExchangeFlow.swift @@ -155,7 +155,6 @@ extension TokenExchangeFlow: OAuth2ClientDelegate { } -#if swift(>=5.5.1) @available(iOS 13.0, tvOS 13.0, macOS 10.15, watchOS 6, *) extension TokenExchangeFlow { /// Asynchronously initiates a token exchange flow. @@ -169,7 +168,6 @@ extension TokenExchangeFlow { } } } -#endif extension OAuth2Client { /// Creates a new Token Exchange flow configured to use this OAuth2Client, using the supplied arguments. diff --git a/Sources/OktaOAuth2/Logout/SessionLogoutFlow.swift b/Sources/OktaOAuth2/Logout/SessionLogoutFlow.swift index 428d9d5e2..f8c038c03 100644 --- a/Sources/OktaOAuth2/Logout/SessionLogoutFlow.swift +++ b/Sources/OktaOAuth2/Logout/SessionLogoutFlow.swift @@ -218,7 +218,6 @@ public class SessionLogoutFlow: LogoutFlow { public let delegateCollection = DelegateCollection() } -#if swift(>=5.5.1) @available(iOS 13.0, tvOS 13.0, macOS 10.15, watchOS 6, *) extension SessionLogoutFlow { /// Asynchronously initiates a logout flow, with a required ID Token. @@ -258,7 +257,6 @@ extension SessionLogoutFlow { } } } -#endif extension SessionLogoutFlow: UsesDelegateCollection { public typealias Delegate = SessionLogoutFlowDelegate diff --git a/Sources/WebAuthenticationUI/Extensions/WebAuthentication+Deprecated.swift b/Sources/WebAuthenticationUI/Extensions/WebAuthentication+Deprecated.swift index 358defedb..88c8053ce 100644 --- a/Sources/WebAuthenticationUI/Extensions/WebAuthentication+Deprecated.swift +++ b/Sources/WebAuthenticationUI/Extensions/WebAuthentication+Deprecated.swift @@ -94,7 +94,6 @@ extension WebAuthentication { } } -#if swift(>=5.5.1) @available(iOS 13.0, tvOS 13.0, macOS 10.15, watchOS 6, *) extension WebAuthentication { @available(*, deprecated, renamed: "signIn(from:options:)") @@ -128,4 +127,3 @@ extension WebAuthentication { try await signOut(from: window, token: token, options: options(from: additionalParameters)) } } -#endif diff --git a/Sources/WebAuthenticationUI/Providers/AuthenticationServicesProvider.swift b/Sources/WebAuthenticationUI/Providers/AuthenticationServicesProvider.swift index 035ef9aef..361c98bc8 100644 --- a/Sources/WebAuthenticationUI/Providers/AuthenticationServicesProvider.swift +++ b/Sources/WebAuthenticationUI/Providers/AuthenticationServicesProvider.swift @@ -16,7 +16,6 @@ import OktaOAuth2 #if canImport(AuthenticationServices) import AuthenticationServices -@available(iOS 12.0, macOS 10.15, macCatalyst 13.0, *) protocol AuthenticationServicesProviderSession { init(url URL: URL, callbackURLScheme: String?, completionHandler: @escaping ASWebAuthenticationSession.CompletionHandler) @@ -34,10 +33,8 @@ protocol AuthenticationServicesProviderSession { func cancel() } -@available(iOS 12.0, macOS 10.15, macCatalyst 13.0, *) extension ASWebAuthenticationSession: AuthenticationServicesProviderSession {} -@available(iOS 12.0, macOS 10.15, macCatalyst 13.0, *) class AuthenticationServicesProvider: NSObject, WebAuthenticationProvider { let loginFlow: AuthorizationCodeFlow let logoutFlow: SessionLogoutFlow? @@ -213,7 +210,6 @@ class AuthenticationServicesProvider: NSObject, WebAuthenticationProvider { } } -@available(iOS 12.0, macOS 10.15, *) extension AuthenticationServicesProvider: AuthenticationDelegate, AuthorizationCodeFlowDelegate { func authentication(flow: Flow, shouldAuthenticateUsing url: URL) where Flow: AuthorizationCodeFlow { authenticate(using: url) @@ -228,7 +224,6 @@ extension AuthenticationServicesProvider: AuthenticationDelegate, AuthorizationC } } -@available(iOS 12.0, macOS 10.15, *) extension AuthenticationServicesProvider: SessionLogoutFlowDelegate { func logout(flow: Flow, shouldLogoutUsing url: URL) where Flow: SessionLogoutFlow { logout(using: url) @@ -239,7 +234,6 @@ extension AuthenticationServicesProvider: SessionLogoutFlowDelegate { } } -@available(iOS 12.0, macOS 10.15, macCatalyst 13.0, *) extension AuthenticationServicesProvider: ASWebAuthenticationPresentationContextProviding { func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor { if let anchor = anchor { diff --git a/Sources/WebAuthenticationUI/Providers/SafariBrowserProvider.swift b/Sources/WebAuthenticationUI/Providers/SafariBrowserProvider.swift deleted file mode 100644 index 8bb25ea90..000000000 --- a/Sources/WebAuthenticationUI/Providers/SafariBrowserProvider.swift +++ /dev/null @@ -1,147 +0,0 @@ -// -// Copyright (c) 2022-Present, Okta, Inc. and/or its affiliates. All rights reserved. -// The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (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. -// - -#if os(iOS) - -import Foundation -import OktaOAuth2 -import SafariServices - -@available(iOS, introduced: 9.0, deprecated: 11.0) -final class SafariBrowserProvider: NSObject, WebAuthenticationProvider { - let loginFlow: AuthorizationCodeFlow - let logoutFlow: SessionLogoutFlow? - private(set) weak var delegate: WebAuthenticationProviderDelegate? - - private(set) var safariController: SFSafariViewController? - private let anchor: WebAuthentication.WindowAnchor? - - init(loginFlow: AuthorizationCodeFlow, - logoutFlow: SessionLogoutFlow?, - from window: WebAuthentication.WindowAnchor?, - delegate: WebAuthenticationProviderDelegate) - { - self.loginFlow = loginFlow - self.logoutFlow = logoutFlow - self.anchor = window - self.delegate = delegate - - super.init() - - self.loginFlow.add(delegate: self) - self.logoutFlow?.add(delegate: self) - } - - deinit { - self.loginFlow.remove(delegate: self) - self.logoutFlow?.remove(delegate: self) - } - - func authenticate(using url: URL) { - safariController = SFSafariViewController(url: url) - - guard let safariController = safariController else { return } - - DispatchQueue.main.async { - UIWindow - .topViewController(from: self.anchor?.rootViewController)? - .present(safariController, animated: true) - } - } - - func logout(using url: URL) { - // The process is the same as for authentication - authenticate(using: url) - } - - func received(token: Token) { - defer { safariController = nil } - - guard let delegate = delegate else { return } - delegate.authentication(provider: self, received: token) - } - - func received(error: WebAuthenticationError) { - defer { safariController = nil } - - guard let delegate = delegate else { return } - delegate.authentication(provider: self, received: error) - } - - func received(logoutError: WebAuthenticationError) { - delegate?.authentication(provider: self, received: logoutError) - } - - func start(context: AuthorizationCodeFlow.Context?, additionalParameters: [String: String]?) { - loginFlow.start(with: context, additionalParameters: additionalParameters) { _ in } - } - - func logout(context: SessionLogoutFlow.Context, additionalParameters: [String: String]?) { - guard let logoutFlow = logoutFlow else { - return - } - - // LogoutFlow invokes delegate, so an error is propagated from delegate method - try? logoutFlow.start(with: context, additionalParameters: additionalParameters) { _ in } - } - - func cancel() { - safariController?.dismiss(animated: true) - safariController = nil - } -} - -@available(iOS, introduced: 9.0, deprecated: 11.0) -extension SafariBrowserProvider: AuthorizationCodeFlowDelegate { - func authentication(flow: Flow, shouldAuthenticateUsing url: URL) where Flow: AuthorizationCodeFlow { - authenticate(using: url) - } - - func authentication(flow: Flow, received error: OAuth2Error) { - received(error: .oauth2(error: error)) - } - - func authentication(flow: Flow, received token: Token) { - received(token: token) - } -} - -@available(iOS, introduced: 9.0, deprecated: 11.0) -extension SafariBrowserProvider: SessionLogoutFlowDelegate { - func logout(flow: Flow, shouldLogoutUsing url: URL) where Flow: SessionLogoutFlow { - logout(using: url) - } - - func logout(flow: SessionLogoutFlow, received error: OAuth2Error) { - received(logoutError: .oauth2(error: error)) - } -} - -private extension UIWindow { - static func topViewController(from rootViewController: UIViewController?) -> UIViewController? { - if let navigationController = rootViewController as? UINavigationController { - return topViewController(from: navigationController.visibleViewController) - } - - if let tabBarController = rootViewController as? UITabBarController, - let selected = tabBarController.selectedViewController { - return topViewController(from: selected) - } - - if let presentedViewController = rootViewController?.presentedViewController { - return topViewController(from: presentedViewController) - } - - return rootViewController - } -} -#endif diff --git a/Sources/WebAuthenticationUI/Providers/SafariServicesProvider.swift b/Sources/WebAuthenticationUI/Providers/SafariServicesProvider.swift deleted file mode 100644 index 9f4d4d46c..000000000 --- a/Sources/WebAuthenticationUI/Providers/SafariServicesProvider.swift +++ /dev/null @@ -1,190 +0,0 @@ -// -// Copyright (c) 2021-Present, Okta, Inc. and/or its affiliates. All rights reserved. -// The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (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. -// - -#if os(iOS) && canImport(SafariServices) - -import AuthFoundation -import OktaOAuth2 -import SafariServices - -@available(iOS, introduced: 11.0, deprecated: 12.0) -final class SafariServicesProvider: NSObject, WebAuthenticationProvider { - let loginFlow: AuthorizationCodeFlow - let logoutFlow: SessionLogoutFlow? - private(set) weak var delegate: WebAuthenticationProviderDelegate? - - private(set) var authenticationSession: SFAuthenticationSession? - - init(loginFlow: AuthorizationCodeFlow, - logoutFlow: SessionLogoutFlow?, - delegate: WebAuthenticationProviderDelegate) - { - self.loginFlow = loginFlow - self.logoutFlow = logoutFlow - self.delegate = delegate - - super.init() - - self.loginFlow.add(delegate: self) - self.logoutFlow?.add(delegate: self) - } - - deinit { - self.loginFlow.remove(delegate: self) - self.logoutFlow?.remove(delegate: self) - } - - func start(context: AuthorizationCodeFlow.Context?, additionalParameters: [String: String]?) { - loginFlow.start(with: context, additionalParameters: additionalParameters) { _ in } - } - - func logout(context: SessionLogoutFlow.Context, additionalParameters: [String: String]?) { - // LogoutFlow invokes delegate, so an error is propagated from delegate method - try? logoutFlow?.start(with: context, additionalParameters: additionalParameters) { _ in } - } - - func authenticate(using url: URL) { - authenticationSession = SFAuthenticationSession( - url: url, - callbackURLScheme: loginFlow.redirectUri.scheme, - completionHandler: { [weak self] url, error in - self?.process(url: url, error: error) - }) - - authenticationSession?.start() - } - - func logout(using url: URL) { - guard let logoutFlow = logoutFlow else { - return - } - - authenticationSession = SFAuthenticationSession( - url: url, - callbackURLScheme: logoutFlow.logoutRedirectUri.scheme, - completionHandler: { [weak self] url, error in - self?.processLogout(url: url, error: error) - }) - - authenticationSession?.start() - } - - func process(url: URL?, error: Error?) { - defer { authenticationSession = nil } - - if let error = error { - let nsError = error as NSError - if nsError.domain == SFAuthenticationErrorDomain, - nsError.code == SFAuthenticationError.canceledLogin.rawValue - { - received(error: .userCancelledLogin) - } else if let url = url, - let serverError = try? url.oauth2ServerError(redirectUri: loginFlow.redirectUri) - { - received(error: .serverError(serverError)) - } else { - received(error: .authenticationProviderError(error)) - } - - return - } - - guard let url = url else { - received(error: .genericError(message: "Authentication session returned neither a URL or an error")) - return - } - - do { - try loginFlow.resume(with: url) { _ in } - } catch { - received(error: .authenticationProviderError(error)) - } - } - - func processLogout(url: URL?, error: Error?) { - guard let delegate = delegate else { return } - - if let error = error { - let nsError = error as NSError - if nsError.domain == SFAuthenticationErrorDomain, - nsError.code == SFAuthenticationError.canceledLogin.rawValue - { - received(logoutError: .userCancelledLogin) - } else if let url = url, - let serverError = try? url.oauth2ServerError(redirectUri: logoutFlow?.logoutRedirectUri) - { - received(logoutError: .serverError(serverError)) - } else { - received(logoutError: .authenticationProviderError(error)) - } - - return - } - - guard url != nil else { - received(logoutError: .genericError(message: "Authentication session returned neither a URL or an error on logout")) - return - } - - delegate.logout(provider: self, finished: true) - } - - func received(token: Token) { - guard let delegate = delegate else { return } - - delegate.authentication(provider: self, received: token) - } - - func received(error: WebAuthenticationError) { - guard let delegate = delegate else { return } - - delegate.authentication(provider: self, received: error) - } - - func received(logoutError: WebAuthenticationError) { - guard let delegate = delegate else { return } - - delegate.logout(provider: self, received: logoutError) - } - - func cancel() { - authenticationSession?.cancel() - authenticationSession = nil - } -} - -@available(iOS, introduced: 11.0, deprecated: 12.0) -extension SafariServicesProvider: AuthorizationCodeFlowDelegate { - func authentication(flow: Flow, shouldAuthenticateUsing url: URL) where Flow: AuthorizationCodeFlow { - authenticate(using: url) - } - - func authentication(flow: Flow, received error: OAuth2Error) { - received(error: .oauth2(error: error)) - } - - func authentication(flow: Flow, received token: Token) { - received(token: token) - } -} - -@available(iOS, introduced: 11.0, deprecated: 12.0) -extension SafariServicesProvider: SessionLogoutFlowDelegate { - func logout(flow: Flow, shouldLogoutUsing url: URL) where Flow: SessionLogoutFlow { - logout(using: url) - } - - func logout(flow: SessionLogoutFlow, received error: OAuth2Error) { - received(logoutError: .oauth2(error: error)) - } -} -#endif diff --git a/Sources/WebAuthenticationUI/WebAuthentication.swift b/Sources/WebAuthenticationUI/WebAuthentication.swift index 07fb9d121..61d114316 100644 --- a/Sources/WebAuthenticationUI/WebAuthentication.swift +++ b/Sources/WebAuthenticationUI/WebAuthentication.swift @@ -249,7 +249,7 @@ public class WebAuthentication { provider = nil } - #if os(iOS) + #if os(iOS) || os(visionOS) /// Attempts to resume sign in when the app is launched from a redirect URI. /// /// This is a convenience method that can simplify apps that use a UISceneDelegate. Scene-based applications receive URLs when the `UIWindowSceneDelegate.scene(_:openURLContexts:)` method is called; the set of contexts can be supplied to this method, which will filter out only those URLs that match the URL scheme defined in the client configuration. If no matching URLs are found, the call is ignored. @@ -345,30 +345,10 @@ public class WebAuthentication { from window: WebAuthentication.WindowAnchor?, delegate: WebAuthenticationProviderDelegate) -> WebAuthenticationProvider? { - if #available(iOS 12.0, macOS 10.15, macCatalyst 13.0, *) { - return AuthenticationServicesProvider(loginFlow: loginFlow, - logoutFlow: logoutFlow, - from: window, - delegate: delegate) - } - - #if os(iOS) - if #available(iOS 11.0, *) { - return SafariServicesProvider(loginFlow: loginFlow, - logoutFlow: logoutFlow, - delegate: delegate) - } - - if #available(iOS 10.0, *) { - return SafariBrowserProvider(loginFlow: loginFlow, - logoutFlow: logoutFlow, - from: window, - delegate: delegate) - } - - #endif - - return nil + AuthenticationServicesProvider(loginFlow: loginFlow, + logoutFlow: logoutFlow, + from: window, + delegate: delegate) } /// Initializes a web authentication session using the supplied AuthorizationCodeFlow and optional context. @@ -403,7 +383,6 @@ public class WebAuthentication { var logoutCompletionBlock: ((Result) -> Void)? } -#if swift(>=5.5.1) @available(iOS 13.0, tvOS 13.0, macOS 10.15, watchOS 6, *) extension WebAuthentication { /// Asynchronously initiates authentication from the given window. @@ -461,4 +440,3 @@ extension WebAuthentication { } } #endif -#endif diff --git a/Tests/AuthFoundationTests/CredentialRefreshTests.swift b/Tests/AuthFoundationTests/CredentialRefreshTests.swift index aff3a56ae..90b7f6d89 100644 --- a/Tests/AuthFoundationTests/CredentialRefreshTests.swift +++ b/Tests/AuthFoundationTests/CredentialRefreshTests.swift @@ -344,7 +344,6 @@ final class CredentialRefreshTests: XCTestCase, OAuth2ClientDelegate { XCTAssertEqual(credential.token.refreshToken, "therefreshtoken-3") } - #if swift(>=5.5.1) @available(iOS 13.0, tvOS 13.0, macOS 10.15, watchOS 6, *) func testRefreshAsync() async throws { let credential = try credential(for: Token.simpleMockToken) @@ -377,5 +376,4 @@ final class CredentialRefreshTests: XCTestCase, OAuth2ClientDelegate { try await credential.refreshIfNeeded(graceInterval: 300) } } - #endif } diff --git a/Tests/AuthFoundationTests/CredentialRevokeTests.swift b/Tests/AuthFoundationTests/CredentialRevokeTests.swift index 625c1443e..9cade6167 100644 --- a/Tests/AuthFoundationTests/CredentialRevokeTests.swift +++ b/Tests/AuthFoundationTests/CredentialRevokeTests.swift @@ -220,7 +220,6 @@ final class CredentialTests: XCTestCase { XCTAssertTrue(coordinator.credentialDataSource.hasCredential(for: token)) } - #if swift(>=5.5.1) @available(iOS 13.0, tvOS 13.0, macOS 10.15, watchOS 6, *) func testRevokeFailureAsync() async throws { urlSession.expect("https://example.com/oauth2/default/.well-known/openid-configuration", @@ -275,5 +274,4 @@ final class CredentialTests: XCTestCase { XCTFail() } } - #endif } diff --git a/Tests/AuthFoundationTests/ErrorTests.swift b/Tests/AuthFoundationTests/ErrorTests.swift index d7a8d52ba..0cfd04407 100644 --- a/Tests/AuthFoundationTests/ErrorTests.swift +++ b/Tests/AuthFoundationTests/ErrorTests.swift @@ -93,7 +93,7 @@ final class ErrorTests: XCTestCase { "Nested Error") } - #if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) + #if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(visionOS) func testKeychainError() { XCTAssertNotEqual(KeychainError.cannotGet(code: noErr).errorDescription, "keychain_cannot_get") diff --git a/Tests/AuthFoundationTests/KeychainTests.swift b/Tests/AuthFoundationTests/KeychainTests.swift index 481efdb31..9f6a314d9 100644 --- a/Tests/AuthFoundationTests/KeychainTests.swift +++ b/Tests/AuthFoundationTests/KeychainTests.swift @@ -10,7 +10,7 @@ // See the License for the specific language governing permissions and limitations under the License. // -#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) +#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(visionOS) import XCTest @testable import AuthFoundation diff --git a/Tests/AuthFoundationTests/KeychainTokenStorageTests.swift b/Tests/AuthFoundationTests/KeychainTokenStorageTests.swift index bc7ca8384..a94220aa5 100644 --- a/Tests/AuthFoundationTests/KeychainTokenStorageTests.swift +++ b/Tests/AuthFoundationTests/KeychainTokenStorageTests.swift @@ -10,7 +10,7 @@ // See the License for the specific language governing permissions and limitations under the License. // -#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) +#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(visionOS) import XCTest @testable import AuthFoundation diff --git a/Tests/AuthFoundationTests/OAuth2ClientTests.swift b/Tests/AuthFoundationTests/OAuth2ClientTests.swift index 14b281e44..397e2f27b 100644 --- a/Tests/AuthFoundationTests/OAuth2ClientTests.swift +++ b/Tests/AuthFoundationTests/OAuth2ClientTests.swift @@ -132,7 +132,6 @@ final class OAuth2ClientTests: XCTestCase { "https://example.com/oauth2/v1/authorize") } - #if swift(>=5.5.1) @available(iOS 13.0, tvOS 13.0, macOS 10.15, watchOS 6, *) func testOpenIDConfigurationAsync() async throws { urlSession.expect("https://example.com/.well-known/openid-configuration", @@ -146,7 +145,6 @@ final class OAuth2ClientTests: XCTestCase { "https://example.com/oauth2/v1/authorize") } } - #endif func testJWKS() throws { urlSession.expect("https://example.com/.well-known/openid-configuration", @@ -551,7 +549,6 @@ final class OAuth2ClientTests: XCTestCase { XCTAssertEqual(parameters["client_secret"], "supersecret") } - #if swift(>=5.5.1) @available(iOS 13.0, tvOS 13.0, macOS 10.15, watchOS 6, *) func testRefreshAsync() async throws { urlSession.expect("https://example.com/.well-known/openid-configuration", @@ -574,5 +571,4 @@ final class OAuth2ClientTests: XCTestCase { try await client.revoke(token, type: .accessToken) } - #endif } diff --git a/Tests/AuthFoundationTests/OIDCLegacyMigratorTests.swift b/Tests/AuthFoundationTests/OIDCLegacyMigratorTests.swift index 8ee541538..95ffe6169 100644 --- a/Tests/AuthFoundationTests/OIDCLegacyMigratorTests.swift +++ b/Tests/AuthFoundationTests/OIDCLegacyMigratorTests.swift @@ -14,7 +14,7 @@ import XCTest @testable import TestCommon @testable import AuthFoundation -#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) +#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(visionOS) final class OIDCLegacyMigratorTests: XCTestCase { typealias LegacyOIDC = SDKVersion.Migration.LegacyOIDC diff --git a/Tests/AuthFoundationTests/TokenTests.swift b/Tests/AuthFoundationTests/TokenTests.swift index 7d27f16a8..bfe64d110 100644 --- a/Tests/AuthFoundationTests/TokenTests.swift +++ b/Tests/AuthFoundationTests/TokenTests.swift @@ -245,7 +245,6 @@ final class TokenTests: XCTestCase { XCTAssertEqual(token[.accessToken], "the_access_token") } - #if swift(>=5.5.1) @available(iOS 13.0, tvOS 13.0, macOS 10.15, watchOS 6, *) func testTokenFromRefreshTokenAsync() async throws { let client = try mockClient() @@ -253,7 +252,6 @@ final class TokenTests: XCTestCase { XCTAssertEqual(token.token(of: .accessToken), String.mockAccessToken) XCTAssertNotEqual(token.id, Token.RefreshRequest.placeholderId) } - #endif func mockClient() throws -> OAuth2Client { let urlSession = URLSessionMock() diff --git a/Tests/AuthFoundationTests/UserDefaultsTokenStorageTests.swift b/Tests/AuthFoundationTests/UserDefaultsTokenStorageTests.swift index ae9a04ff2..01b362369 100644 --- a/Tests/AuthFoundationTests/UserDefaultsTokenStorageTests.swift +++ b/Tests/AuthFoundationTests/UserDefaultsTokenStorageTests.swift @@ -10,7 +10,7 @@ // See the License for the specific language governing permissions and limitations under the License. // -#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) +#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(visionOS) import XCTest @testable import AuthFoundation import TestCommon diff --git a/Tests/AuthFoundationTests/UserInfoTests.swift b/Tests/AuthFoundationTests/UserInfoTests.swift index 5ad7a10ad..55783fb7f 100644 --- a/Tests/AuthFoundationTests/UserInfoTests.swift +++ b/Tests/AuthFoundationTests/UserInfoTests.swift @@ -30,7 +30,7 @@ final class UserInfoTests: XCTestCase { XCTAssertTrue(info.emailVerified!) XCTAssertEqual(info.address?["street_address"], "155 Country Lane") - #if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) + #if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(visionOS) if #available(iOS 15, macCatalyst 15, macOS 12.0, tvOS 15, watchOS 8, *) { let formatter = PersonNameComponentsFormatter() formatter.style = .long diff --git a/Tests/OktaDirectAuthTests/DirectAuth1FATests.swift b/Tests/OktaDirectAuthTests/DirectAuth1FATests.swift index 445fba9fb..5b8216692 100644 --- a/Tests/OktaDirectAuthTests/DirectAuth1FATests.swift +++ b/Tests/OktaDirectAuthTests/DirectAuth1FATests.swift @@ -41,7 +41,6 @@ final class DirectAuth1FATests: XCTestCase { Token.resetToDefault() } -#if swift(>=5.5.1) @available(iOS 13.0, tvOS 13.0, macOS 10.15, watchOS 6, *) func testUserAndPassword() async throws { // Ensure the initial state @@ -101,5 +100,4 @@ final class DirectAuth1FATests: XCTestCase { XCTFail("Not expecting continuation status") } } -#endif } diff --git a/Tests/OktaDirectAuthTests/DirectAuth2FATests.swift b/Tests/OktaDirectAuthTests/DirectAuth2FATests.swift index 38bf51517..cd87c31f0 100644 --- a/Tests/OktaDirectAuthTests/DirectAuth2FATests.swift +++ b/Tests/OktaDirectAuthTests/DirectAuth2FATests.swift @@ -41,7 +41,6 @@ final class DirectAuth2FATests: XCTestCase { Token.resetToDefault() } -#if swift(>=5.5.1) @available(iOS 13.0, tvOS 13.0, macOS 10.15, watchOS 6, *) func testUserPasswordAndOOB() async throws { // Ensure the initial state @@ -72,5 +71,4 @@ final class DirectAuth2FATests: XCTestCase { } XCTAssertFalse(flow.isAuthenticating) } -#endif } diff --git a/Tests/OktaOAuth2Tests/AuthorizationCodeFlowSuccessTests.swift b/Tests/OktaOAuth2Tests/AuthorizationCodeFlowSuccessTests.swift index 2efe79642..a1549aa19 100644 --- a/Tests/OktaOAuth2Tests/AuthorizationCodeFlowSuccessTests.swift +++ b/Tests/OktaOAuth2Tests/AuthorizationCodeFlowSuccessTests.swift @@ -174,7 +174,6 @@ final class AuthorizationCodeFlowSuccessTests: XCTestCase { XCTAssertNotNil(token) } - #if swift(>=5.5.1) @available(iOS 13.0, tvOS 13.0, macOS 10.15, watchOS 6, *) func testWithAsync() async throws { // Ensure the initial state @@ -199,7 +198,6 @@ final class AuthorizationCodeFlowSuccessTests: XCTestCase { XCTAssertFalse(flow.isAuthenticating) XCTAssertNotNil(token) } - #endif func testAuthorizationCodeFromURL() throws { typealias RedirectError = AuthorizationCodeFlow.RedirectError diff --git a/Tests/OktaOAuth2Tests/DeviceAuthorizationFlowSuccessTests.swift b/Tests/OktaOAuth2Tests/DeviceAuthorizationFlowSuccessTests.swift index 5c7a83cdd..e63a2b03b 100644 --- a/Tests/OktaOAuth2Tests/DeviceAuthorizationFlowSuccessTests.swift +++ b/Tests/OktaOAuth2Tests/DeviceAuthorizationFlowSuccessTests.swift @@ -139,7 +139,6 @@ final class DeviceAuthorizationFlowSuccessTests: XCTestCase { XCTAssertNotNil(token) } - #if swift(>=5.5.1) @available(iOS 13.0, tvOS 13.0, macOS 10.15, watchOS 6, *) func testWithAsync() async throws { // Ensure the initial state @@ -161,7 +160,6 @@ final class DeviceAuthorizationFlowSuccessTests: XCTestCase { XCTAssertFalse(flow.isAuthenticating) XCTAssertNotNil(token) } - #endif func testContextResponse() throws { let data = data(for: """ diff --git a/Tests/OktaOAuth2Tests/JWTAuthorizationFlowTests.swift b/Tests/OktaOAuth2Tests/JWTAuthorizationFlowTests.swift index 242784334..8f011b568 100644 --- a/Tests/OktaOAuth2Tests/JWTAuthorizationFlowTests.swift +++ b/Tests/OktaOAuth2Tests/JWTAuthorizationFlowTests.swift @@ -143,7 +143,7 @@ final class JWTAuthorizationFlowTests: XCTestCase { XCTAssertEqual(request.bodyString, "assertion=\(JWT.mockIDToken)&client_id=clientId&grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&scope=profile+openid") } -#if swift(>=5.5.1) && !os(Linux) +#if !os(Linux) @available(iOS 13.0, tvOS 13.0, macOS 10.15, watchOS 6, *) func testAsyncAuthenticationSucceeded() async throws { XCTAssertFalse(flow.isAuthenticating) diff --git a/Tests/OktaOAuth2Tests/ResourceOwnerFlowTests.swift b/Tests/OktaOAuth2Tests/ResourceOwnerFlowTests.swift index 86c8363ba..c60f03696 100644 --- a/Tests/OktaOAuth2Tests/ResourceOwnerFlowTests.swift +++ b/Tests/OktaOAuth2Tests/ResourceOwnerFlowTests.swift @@ -117,7 +117,6 @@ final class ResourceOwnerFlowSuccessTests: XCTestCase { XCTAssertNotNil(token) } - #if swift(>=5.5.1) @available(iOS 13.0, tvOS 13.0, macOS 10.15, watchOS 6, *) func testWithAsync() async throws { // Ensure the initial state @@ -129,5 +128,4 @@ final class ResourceOwnerFlowSuccessTests: XCTestCase { XCTAssertFalse(flow.isAuthenticating) XCTAssertNotNil(token) } - #endif } diff --git a/Tests/OktaOAuth2Tests/SessionLogoutFlowSuccessTests.swift b/Tests/OktaOAuth2Tests/SessionLogoutFlowSuccessTests.swift index 66884a58e..a3122d2c2 100644 --- a/Tests/OktaOAuth2Tests/SessionLogoutFlowSuccessTests.swift +++ b/Tests/OktaOAuth2Tests/SessionLogoutFlowSuccessTests.swift @@ -148,7 +148,6 @@ final class SessionLogoutFlowSuccessTests: XCTestCase { wait(for: [resumeExpection], timeout: 1) } - #if swift(>=5.5.1) @available(iOS 13.0, tvOS 13.0, macOS 10.15, watchOS 6, *) func testWithAsync() async throws { XCTAssertNil(flow.context) @@ -166,5 +165,4 @@ final class SessionLogoutFlowSuccessTests: XCTestCase { &state=\(state) """) } - #endif } diff --git a/Tests/OktaOAuth2Tests/SessionTokenFlowTests.swift b/Tests/OktaOAuth2Tests/SessionTokenFlowTests.swift index 7810454b3..7b47f9e75 100644 --- a/Tests/OktaOAuth2Tests/SessionTokenFlowTests.swift +++ b/Tests/OktaOAuth2Tests/SessionTokenFlowTests.swift @@ -126,7 +126,6 @@ final class SessionTokenFlowSuccessTests: XCTestCase { XCTAssertNotNil(token) } - #if swift(>=5.5.1) @available(iOS 13.0, tvOS 13.0, macOS 10.15, watchOS 6, *) func testWithAsync() async throws { // Ensure the initial state @@ -140,5 +139,4 @@ final class SessionTokenFlowSuccessTests: XCTestCase { XCTAssertFalse(flow.isAuthenticating) XCTAssertNotNil(token) } - #endif } diff --git a/Tests/OktaOAuth2Tests/TokenExchangeFlowTests.swift b/Tests/OktaOAuth2Tests/TokenExchangeFlowTests.swift index cf2833747..105025a9b 100644 --- a/Tests/OktaOAuth2Tests/TokenExchangeFlowTests.swift +++ b/Tests/OktaOAuth2Tests/TokenExchangeFlowTests.swift @@ -142,7 +142,7 @@ final class TokenExchangeFlowTests: XCTestCase { XCTAssertEqual(request.bodyString, "actor_token=secret&actor_token_type=urn:x-oath:params:oauth:token-type:device-secret&audience=api:%2F%2Fdefault&client_id=clientId&grant_type=urn:ietf:params:oauth:grant-type:token-exchange&scope=profile+openid+device_sso&subject_token=id_token&subject_token_type=urn:ietf:params:oauth:token-type:id_token") } -#if swift(>=5.5.1) && !os(Linux) +#if !os(Linux) @available(iOS 13.0, tvOS 13.0, macOS 10.15, watchOS 6, *) func testAsyncAuthenticationSucceeded() async throws { XCTAssertFalse(flow.isAuthenticating) diff --git a/Tests/TestCommon/MockKeychain.swift b/Tests/TestCommon/MockKeychain.swift index 28178e70e..8dce2edaa 100644 --- a/Tests/TestCommon/MockKeychain.swift +++ b/Tests/TestCommon/MockKeychain.swift @@ -10,7 +10,7 @@ // See the License for the specific language governing permissions and limitations under the License. // -#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) +#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(visionOS) import Foundation @testable import AuthFoundation diff --git a/Tests/TestCommon/URLSessionMock.swift b/Tests/TestCommon/URLSessionMock.swift index 958ba798f..92e00739e 100644 --- a/Tests/TestCommon/URLSessionMock.swift +++ b/Tests/TestCommon/URLSessionMock.swift @@ -96,7 +96,6 @@ class URLSessionMock: URLSessionProtocol { completionHandler: completionHandler) } - #if swift(>=5.5.1) @available(iOS 13.0, tvOS 13.0, macOS 10.15, watchOS 6, *) func data(for request: URLRequest, delegate: URLSessionTaskDelegate?) async throws -> (Data, URLResponse) { requests.append(request) @@ -116,7 +115,6 @@ class URLSessionMock: URLSessionProtocol { throw APIClientError.unknown } } - #endif } class URLSessionDataTaskMock: URLSessionDataTaskProtocol { diff --git a/Tests/TestCommon/XCTestCase+Extensions.swift b/Tests/TestCommon/XCTestCase+Extensions.swift index b2f3dc649..463731b25 100644 --- a/Tests/TestCommon/XCTestCase+Extensions.swift +++ b/Tests/TestCommon/XCTestCase+Extensions.swift @@ -76,7 +76,6 @@ public extension XCTestCase { return try decoder.decode(T.self, from: jsonData) } - #if swift(>=5.5.1) @available(iOS 13.0, tvOS 13.0, macOS 10.15, watchOS 6, *) func perform(queueCount: Int = 5, iterationCount: Int = 10, _ block: @escaping () async throws -> Void) rethrows { let queues: [DispatchQueue] = (0.. Date: Tue, 13 Aug 2024 16:30:47 -0700 Subject: [PATCH 02/20] Reintroduce support for Linux --- .github/workflows/tests.yaml | 5 +- Package.swift | 2 +- README.md | 2 +- .../Internal/String+AuthFoundation.swift | 2 +- .../AuthFoundation/OAuth2/Configuration.swift | 4 +- .../AuthFoundation/OAuth2/OAuth2Client.swift | 4 +- .../Internal/UserDefaultsTokenStorage.swift | 2 - .../User Management/Credential.swift | 2 +- .../Internal/CredentialCoordinatorImpl.swift | 8 +- .../AuthFoundation/Utilities/JSONValue.swift | 10 +- Sources/AuthFoundation/Utilities/Lock.swift | 104 ++++++++++++++++++ .../Utilities/TimeCoordinator.swift | 6 +- .../Utilities/URL+InternalExtensions.swift | 33 ++++++ .../AuthFoundation/Utilities/UnsafeLock.swift | 41 ------- .../Authentication/SessionTokenFlow.swift | 4 + .../WebAuthentication+Deprecated.swift | 2 + .../Internal/Bundle+WebAuthenticationUI.swift | 2 + .../Internal/Options+Extensions.swift | 2 + Sources/WebAuthenticationUI/Version.swift | 2 + .../AuthFoundationTests/APIClientTests.swift | 4 + Tests/AuthFoundationTests/APIRetryTests.swift | 4 + .../DefaultTimeCoordinatorTests.swift | 4 + .../OAuth2ClientTests.swift | 4 + Tests/OktaDirectAuthTests/ErrorTests.swift | 18 +-- Tests/TestCommon/MockApiClient.swift | 4 + Tests/TestCommon/MockApiRequest.swift | 4 + Tests/TestCommon/URLRequest+Extensions.swift | 4 + Tests/TestCommon/XCTestCase+Extensions.swift | 2 +- 28 files changed, 214 insertions(+), 71 deletions(-) create mode 100644 Sources/AuthFoundation/Utilities/Lock.swift create mode 100644 Sources/AuthFoundation/Utilities/URL+InternalExtensions.swift delete mode 100644 Sources/AuthFoundation/Utilities/UnsafeLock.swift diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 96c11b1d6..e3eb1e87a 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -29,7 +29,10 @@ env: jobs: SwiftBuild: name: Swift Unit Tests - runs-on: macos-latest-large + strategy: + matrix: + os: [macos-latest-large, ubuntu-latest] + runs-on: ${{ matrix.os }} timeout-minutes: 10 steps: - name: Get swift version diff --git a/Package.swift b/Package.swift index d5b63081f..48fc333ce 100644 --- a/Package.swift +++ b/Package.swift @@ -11,7 +11,7 @@ var package = Package( .tvOS(.v12), .watchOS(.v7), .visionOS(.v1), - .macOS(.v10_13), + .macOS(.v10_15), .macCatalyst(.v13) ], products: [ diff --git a/README.md b/README.md index 9203bf360..8a0be51c1 100644 --- a/README.md +++ b/README.md @@ -389,7 +389,7 @@ Only the last 4 major platform versions are officially supported, unless there a | watchOS | 7.0 | 7.0 | | visionOS | 1.0 | 1.0 | | macCatalyst | 13.0 | 13.0 | -| macOS | 12.0 | 10.13 | +| macOS | 12.0 | 10.15 | Once a platform version becomes unsupported, dropping support for it will not be considered a breaking change and will be done in a minor release. For example, iOS 13 will cease to be supported when iOS 18 gets released, and might be dropped in a minor release. diff --git a/Sources/AuthFoundation/Network/Internal/String+AuthFoundation.swift b/Sources/AuthFoundation/Network/Internal/String+AuthFoundation.swift index e9bcb9a69..c951d0bfc 100644 --- a/Sources/AuthFoundation/Network/Internal/String+AuthFoundation.swift +++ b/Sources/AuthFoundation/Network/Internal/String+AuthFoundation.swift @@ -77,7 +77,7 @@ public final class SDKVersion: Sendable { /// The calculated user agent string that will be included in outgoing network requests. public private(set) static var userAgent: String = "" - private static let lock = UnfairLock() + private static let lock = Lock() fileprivate static var sdkVersions: [SDKVersion] = [] /// Register a new SDK library component to be added to the ``userAgent`` value. diff --git a/Sources/AuthFoundation/OAuth2/Configuration.swift b/Sources/AuthFoundation/OAuth2/Configuration.swift index b43a4ee9a..28b82ada1 100644 --- a/Sources/AuthFoundation/OAuth2/Configuration.swift +++ b/Sources/AuthFoundation/OAuth2/Configuration.swift @@ -49,11 +49,11 @@ extension OAuth2Client { // Ensure the base URL contains a trailing slash in its path, so request paths can be safely appended. if !relativeURL.lastPathComponent.isEmpty { - relativeURL.appendPathComponent("") + relativeURL = relativeURL.appendingComponent("") } self.baseURL = baseURL - self.discoveryURL = discoveryURL ?? relativeURL.appendingPathComponent(".well-known/openid-configuration") + self.discoveryURL = discoveryURL ?? relativeURL.appendingComponent(".well-known/openid-configuration") self.clientId = clientId self.scopes = scopes self.authentication = authentication diff --git a/Sources/AuthFoundation/OAuth2/OAuth2Client.swift b/Sources/AuthFoundation/OAuth2/OAuth2Client.swift index 723ec946a..abb910dd1 100644 --- a/Sources/AuthFoundation/OAuth2/OAuth2Client.swift +++ b/Sources/AuthFoundation/OAuth2/OAuth2Client.swift @@ -543,14 +543,14 @@ public final class OAuth2Client { // MARK: Private properties / methods private let delegates = DelegateCollection() - private let refreshLock = UnfairLock() + private let refreshLock = Lock() private(set) lazy var refreshQueue: DispatchQueue = { DispatchQueue(label: "com.okta.refreshQueue.\(baseURL.host ?? "unknown")", qos: .userInitiated, attributes: .concurrent) }() - private let configurationLock = UnfairLock() + private let configurationLock = Lock() private lazy var configurationQueue: DispatchQueue = { DispatchQueue(label: "com.okta.configurationQueue.\(baseURL.host ?? "unknown")", qos: .userInitiated, diff --git a/Sources/AuthFoundation/Token Management/Internal/UserDefaultsTokenStorage.swift b/Sources/AuthFoundation/Token Management/Internal/UserDefaultsTokenStorage.swift index a8465215a..6bb46c391 100644 --- a/Sources/AuthFoundation/Token Management/Internal/UserDefaultsTokenStorage.swift +++ b/Sources/AuthFoundation/Token Management/Internal/UserDefaultsTokenStorage.swift @@ -12,7 +12,6 @@ import Foundation -#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(visionOS) #if canImport(LocalAuthentication) && !os(tvOS) import LocalAuthentication #else @@ -161,4 +160,3 @@ final class UserDefaultsTokenStorage: TokenStorage { userDefaults.synchronize() } } -#endif diff --git a/Sources/AuthFoundation/User Management/Credential.swift b/Sources/AuthFoundation/User Management/Credential.swift index 05aa18466..1e8348617 100644 --- a/Sources/AuthFoundation/User Management/Credential.swift +++ b/Sources/AuthFoundation/User Management/Credential.swift @@ -357,7 +357,7 @@ public final class Credential: Equatable, OAuth2ClientDelegate { } tokenObserver = NotificationCenter.default.addObserver(forName: .tokenRefreshFailed, - object: token, + object: nil, queue: nil) { [weak self] notification in guard let self = self, token == self.token diff --git a/Sources/AuthFoundation/User Management/Internal/CredentialCoordinatorImpl.swift b/Sources/AuthFoundation/User Management/Internal/CredentialCoordinatorImpl.swift index b5d2c0ead..2b0fbe521 100644 --- a/Sources/AuthFoundation/User Management/Internal/CredentialCoordinatorImpl.swift +++ b/Sources/AuthFoundation/User Management/Internal/CredentialCoordinatorImpl.swift @@ -94,11 +94,11 @@ final class CredentialCoordinatorImpl: CredentialCoordinator { } static func defaultTokenStorage() -> TokenStorage { - #if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(visionOS) - KeychainTokenStorage() - #else + #if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(visionOS) + KeychainTokenStorage() + #else UserDefaultsTokenStorage() - #endif + #endif } static func defaultCredentialDataSource() -> CredentialDataSource { diff --git a/Sources/AuthFoundation/Utilities/JSONValue.swift b/Sources/AuthFoundation/Utilities/JSONValue.swift index 173a45db5..74f1ef741 100644 --- a/Sources/AuthFoundation/Utilities/JSONValue.swift +++ b/Sources/AuthFoundation/Utilities/JSONValue.swift @@ -251,13 +251,13 @@ extension JSON: Codable { fileprivate extension NSNumber { var isFloatingPoint: Bool { - let type = CFNumberGetType(self as CFNumber) - switch type { - case .floatType, .float32Type, .float64Type, .cgFloatType, .doubleType: + if strcmp(objCType, "f") == 0 || + strcmp(objCType, "d") == 0 + { return true - default: - return false } + + return false } } diff --git a/Sources/AuthFoundation/Utilities/Lock.swift b/Sources/AuthFoundation/Utilities/Lock.swift new file mode 100644 index 000000000..aa277ae2a --- /dev/null +++ b/Sources/AuthFoundation/Utilities/Lock.swift @@ -0,0 +1,104 @@ +// +// Copyright (c) 2023-Present, Okta, Inc. and/or its affiliates. All rights reserved. +// The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (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 + +#if canImport(Darwin) +import Darwin +#elseif canImport(Glibc) +import Glibc +#elseif canImport(Musl) +import Musl +#elseif canImport(Bionic) +import Bionic +#else +#error("Unsupported platform") +#endif + +// **Note:** It would be preferable to use OSAllocatedUnfairLock for this, but this would mean dropping support for older OS versions. While this approach is safe, OSAllocatedUnfairLock provides more features we might need in the future. +// +// If the minimum supported version of this SDK is to increase in the future, this class should be removed and replaced with OSAllocatedUnfairLock. +final class Lock: NSLocking { + #if canImport(Darwin) + private typealias LockType = os_unfair_lock + #elseif canImport(Glibc) || canImport(Musl) || canImport(Bionic) + private typealias LockType = pthread_mutex_t + #else + #error("Unsupported platform") + #endif + + private let _lock: UnsafeMutablePointer = { + let result = UnsafeMutablePointer.allocate(capacity: 1) + + #if canImport(Darwin) + result.initialize(to: os_unfair_lock()) + #elseif canImport(Glibc) || canImport(Musl) || canImport(Bionic) + let status = pthread_mutex_init(result, nil) + precondition(status == 0, "pthread_mutex_init failed") + #else + #error("Unsupported platform") + #endif + + return result + }() + + deinit { + #if canImport(Glibc) || canImport(Musl) || canImport(Bionic) + let status = pthread_mutex_destroy(_lock) + precondition(status == 0, "pthread_mutex_destroy failed") + #endif + _lock.deinitialize(count: 1) + _lock.deallocate() + } + + func lock() { + #if canImport(Darwin) + os_unfair_lock_lock(_lock) + #elseif canImport(Glibc) || canImport(Musl) || canImport(Bionic) + let status = pthread_mutex_lock(_lock) + precondition(status == 0, "pthread_mutex_lock failed") + #else + #error("Unsupported platform") + #endif + } + + func tryLock() -> Bool { + #if canImport(Darwin) + return os_unfair_lock_trylock(_lock) + #elseif canImport(Glibc) || canImport(Musl) || canImport(Bionic) + return pthread_mutex_trylock(_lock) == 0 + #else + #error("Unsupported platform") + #endif + } + + func unlock() { + #if canImport(Darwin) + os_unfair_lock_unlock(_lock) + #elseif canImport(Glibc) || canImport(Musl) || canImport(Bionic) + let status = pthread_mutex_unlock(_lock) + precondition(status == 0, "pthread_mutex_unlock failed") + #else + #error("Unsupported platform") + #endif + } + + #if !canImport(Darwin) + func withLock(_ body: () throws -> T) rethrows -> T { + self.lock() + defer { + self.unlock() + } + return try body() + } + #endif +} \ No newline at end of file diff --git a/Sources/AuthFoundation/Utilities/TimeCoordinator.swift b/Sources/AuthFoundation/Utilities/TimeCoordinator.swift index 3cbcdc51b..c7090a5c6 100644 --- a/Sources/AuthFoundation/Utilities/TimeCoordinator.swift +++ b/Sources/AuthFoundation/Utilities/TimeCoordinator.swift @@ -12,6 +12,10 @@ import Foundation +#if os(Linux) +import FoundationNetworking +#endif + /// Protocol used to return dates and times coordinated against trusted sources. /// /// This can be used to customize the behavior of how dates and times are calculated, when used on devices that may have skewed or incorrect clocks. @@ -53,7 +57,7 @@ class DefaultTimeCoordinator: TimeCoordinator, OAuth2ClientDelegate { Date.coordinator = DefaultTimeCoordinator() } - private let lock = UnfairLock() + private let lock = Lock() private var _offset: TimeInterval private(set) var offset: TimeInterval { get { lock.withLock { _offset } } diff --git a/Sources/AuthFoundation/Utilities/URL+InternalExtensions.swift b/Sources/AuthFoundation/Utilities/URL+InternalExtensions.swift new file mode 100644 index 000000000..37c5510d8 --- /dev/null +++ b/Sources/AuthFoundation/Utilities/URL+InternalExtensions.swift @@ -0,0 +1,33 @@ +// +// Copyright (c) 2024-Present, Okta, Inc. and/or its affiliates. All rights reserved. +// The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (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 + +extension URL { + @inlinable + // Workaround to address a known bug with URL.appendingPathComponent on Linux. + // https://github.com/apple/swift-corelibs-foundation/issues/4849 + func appendingComponent(_ component: String) -> URL { + #if os(Linux) + var components = URLComponents(url: self, resolvingAgainstBaseURL: true)! + if !components.path.hasSuffix("/") { + components.path.append("/") + } + components.path.append(component) + return components.url! + #else + var result = self + result.appendPathComponent(component) + return result + #endif + } +} diff --git a/Sources/AuthFoundation/Utilities/UnsafeLock.swift b/Sources/AuthFoundation/Utilities/UnsafeLock.swift deleted file mode 100644 index f6c09b52b..000000000 --- a/Sources/AuthFoundation/Utilities/UnsafeLock.swift +++ /dev/null @@ -1,41 +0,0 @@ -// -// Copyright (c) 2023-Present, Okta, Inc. and/or its affiliates. All rights reserved. -// The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (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 - -// **Note:** It would be preferable to use OSAllocatedUnfairLock for this, but this would mean dropping support for older OS versions. While this approach is safe, OSAllocatedUnfairLock provides more features we might need in the future. -// -// If the minimum supported version of this SDK is to increase in the future, this class should be removed and replaced with OSAllocatedUnfairLock. -final class UnfairLock: NSLocking { - private let _lock: UnsafeMutablePointer = { - let result = UnsafeMutablePointer.allocate(capacity: 1) - result.initialize(to: os_unfair_lock()) - return result - }() - - deinit { - _lock.deinitialize(count: 1) - _lock.deallocate() - } - - func lock() { - os_unfair_lock_lock(_lock) - } - - func tryLock() -> Bool { - os_unfair_lock_trylock(_lock) - } - - func unlock() { - os_unfair_lock_unlock(_lock) - } -} diff --git a/Sources/OktaOAuth2/Authentication/SessionTokenFlow.swift b/Sources/OktaOAuth2/Authentication/SessionTokenFlow.swift index 6dd7297bd..4edab0680 100644 --- a/Sources/OktaOAuth2/Authentication/SessionTokenFlow.swift +++ b/Sources/OktaOAuth2/Authentication/SessionTokenFlow.swift @@ -13,6 +13,10 @@ import Foundation import AuthFoundation +#if os(Linux) +import FoundationNetworking +#endif + /// An authentication flow class that exchanges a Session Token for access tokens. /// /// This flow is typically used in conjunction with the [classic Okta native authentication library](https://github.com/okta/okta-auth-swift). For native authentication using the Okta Identity Engine (OIE), please use the [Okta IDX library](https://github.com/okta/okta-idx-swift). diff --git a/Sources/WebAuthenticationUI/Extensions/WebAuthentication+Deprecated.swift b/Sources/WebAuthenticationUI/Extensions/WebAuthentication+Deprecated.swift index 88c8053ce..0abdba03b 100644 --- a/Sources/WebAuthenticationUI/Extensions/WebAuthentication+Deprecated.swift +++ b/Sources/WebAuthenticationUI/Extensions/WebAuthentication+Deprecated.swift @@ -13,6 +13,7 @@ import Foundation // TODO: Remove on the next major release. +#if canImport(UIKit) || canImport(AppKit) extension WebAuthentication { @available(*, deprecated, renamed: "signIn(from:options:completion:)") public final func signIn(from window: WindowAnchor?, @@ -127,3 +128,4 @@ extension WebAuthentication { try await signOut(from: window, token: token, options: options(from: additionalParameters)) } } +#endif \ No newline at end of file diff --git a/Sources/WebAuthenticationUI/Internal/Bundle+WebAuthenticationUI.swift b/Sources/WebAuthenticationUI/Internal/Bundle+WebAuthenticationUI.swift index 264092c74..105dba361 100644 --- a/Sources/WebAuthenticationUI/Internal/Bundle+WebAuthenticationUI.swift +++ b/Sources/WebAuthenticationUI/Internal/Bundle+WebAuthenticationUI.swift @@ -12,6 +12,7 @@ import Foundation +#if canImport(UIKit) || canImport(AppKit) #if !SWIFT_PACKAGE private let sharedLocalizationBundle: Bundle = { Bundle(for: WebAuthentication.self) @@ -27,3 +28,4 @@ extension Bundle { #endif } } +#endif \ No newline at end of file diff --git a/Sources/WebAuthenticationUI/Internal/Options+Extensions.swift b/Sources/WebAuthenticationUI/Internal/Options+Extensions.swift index 709a9ee4d..630db255e 100644 --- a/Sources/WebAuthenticationUI/Internal/Options+Extensions.swift +++ b/Sources/WebAuthenticationUI/Internal/Options+Extensions.swift @@ -13,6 +13,7 @@ import Foundation import OktaOAuth2 +#if canImport(UIKit) || canImport(AppKit) extension WebAuthentication.Option { var queryItems: [String: String] { switch self { @@ -81,3 +82,4 @@ extension Collection where Element == WebAuthentication.Option { return .init(state: state, maxAge: maxAge) } } +#endif \ No newline at end of file diff --git a/Sources/WebAuthenticationUI/Version.swift b/Sources/WebAuthenticationUI/Version.swift index c0dd288d5..115e12158 100644 --- a/Sources/WebAuthenticationUI/Version.swift +++ b/Sources/WebAuthenticationUI/Version.swift @@ -13,7 +13,9 @@ import Foundation import AuthFoundation +#if canImport(UIKit) || canImport(AppKit) // swiftlint:disable identifier_name @_documentation(visibility: private) public let Version = SDKVersion(sdk: "okta-webauthenticationui-swift", version: "1.8.2") // swiftlint:enable identifier_name +#endif \ No newline at end of file diff --git a/Tests/AuthFoundationTests/APIClientTests.swift b/Tests/AuthFoundationTests/APIClientTests.swift index bb3491a8f..ea423f6e4 100644 --- a/Tests/AuthFoundationTests/APIClientTests.swift +++ b/Tests/AuthFoundationTests/APIClientTests.swift @@ -14,6 +14,10 @@ import XCTest @testable import AuthFoundation @testable import TestCommon +#if os(Linux) +import FoundationNetworking +#endif + struct MockApiParsingContext: APIParsingContext { var codingUserInfo: [CodingUserInfoKey : Any]? diff --git a/Tests/AuthFoundationTests/APIRetryTests.swift b/Tests/AuthFoundationTests/APIRetryTests.swift index 8a9162021..688454d5a 100644 --- a/Tests/AuthFoundationTests/APIRetryTests.swift +++ b/Tests/AuthFoundationTests/APIRetryTests.swift @@ -14,6 +14,10 @@ import XCTest @testable import AuthFoundation @testable import TestCommon +#if os(Linux) +import FoundationNetworking +#endif + class APIRetryDelegateRecorder: APIClientDelegate { var response: APIRetry? private(set) var requests: [URLRequest] = [] diff --git a/Tests/AuthFoundationTests/DefaultTimeCoordinatorTests.swift b/Tests/AuthFoundationTests/DefaultTimeCoordinatorTests.swift index 518ee7e65..c043e4ca9 100644 --- a/Tests/AuthFoundationTests/DefaultTimeCoordinatorTests.swift +++ b/Tests/AuthFoundationTests/DefaultTimeCoordinatorTests.swift @@ -14,6 +14,10 @@ import XCTest @testable import AuthFoundation @testable import TestCommon +#if os(Linux) +import FoundationNetworking +#endif + final class DefaultTimeCoordinatorTests: XCTestCase { var coordinator: DefaultTimeCoordinator! var client: MockApiClient! diff --git a/Tests/AuthFoundationTests/OAuth2ClientTests.swift b/Tests/AuthFoundationTests/OAuth2ClientTests.swift index 397e2f27b..e19c038d1 100644 --- a/Tests/AuthFoundationTests/OAuth2ClientTests.swift +++ b/Tests/AuthFoundationTests/OAuth2ClientTests.swift @@ -2,6 +2,10 @@ import XCTest @testable import TestCommon @testable import AuthFoundation +#if os(Linux) +import FoundationNetworking +#endif + final class OAuth2ClientTests: XCTestCase { let issuer = URL(string: "https://example.com")! let redirectUri = URL(string: "com.example:/callback")! diff --git a/Tests/OktaDirectAuthTests/ErrorTests.swift b/Tests/OktaDirectAuthTests/ErrorTests.swift index c848b9174..873bb701c 100644 --- a/Tests/OktaDirectAuthTests/ErrorTests.swift +++ b/Tests/OktaDirectAuthTests/ErrorTests.swift @@ -50,18 +50,10 @@ final class ErrorTests: XCTestCase { XCTAssertEqual(DirectAuthenticationFlowError(OAuth2Error.network(error: .invalidRequestData)), .network(error: .invalidRequestData)) - // Ensure a generic error embedded in OAuth2Error becomes the appropriate error type - XCTAssertEqual(DirectAuthenticationFlowError(OAuth2Error.error(KeychainError.invalidFormat)), - .other(error: KeychainError.invalidFormat)) - // Ensure a APIClientError becomes the appropriate type XCTAssertEqual(DirectAuthenticationFlowError(APIClientError.invalidRequestData), .network(error: .invalidRequestData)) - // Ensure a generic error in APIClientError becomes the appropriate type - XCTAssertEqual(DirectAuthenticationFlowError(APIClientError.serverError(KeychainError.invalidFormat)), - .other(error: KeychainError.invalidFormat)) - // Ensure an OAUth2ServerError becomes a .server(error:) let serverError = try defaultJSONDecoder.decode(OAuth2ServerError.self, from: """ { @@ -71,5 +63,15 @@ final class ErrorTests: XCTestCase { """.data(using: .utf8)!) XCTAssertEqual(DirectAuthenticationFlowError(APIClientError.serverError(serverError)), .server(error: serverError)) + + #if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(visionOS) + // Ensure a generic error embedded in OAuth2Error becomes the appropriate error type + XCTAssertEqual(DirectAuthenticationFlowError(OAuth2Error.error(KeychainError.invalidFormat)), + .other(error: KeychainError.invalidFormat)) + + // Ensure a generic error in APIClientError becomes the appropriate type + XCTAssertEqual(DirectAuthenticationFlowError(APIClientError.serverError(KeychainError.invalidFormat)), + .other(error: KeychainError.invalidFormat)) + #endif } } diff --git a/Tests/TestCommon/MockApiClient.swift b/Tests/TestCommon/MockApiClient.swift index de1f68af7..c0680ece5 100644 --- a/Tests/TestCommon/MockApiClient.swift +++ b/Tests/TestCommon/MockApiClient.swift @@ -13,6 +13,10 @@ import Foundation @testable import AuthFoundation +#if os(Linux) +import FoundationNetworking +#endif + class MockApiClient: APIClient { var baseURL: URL var session: URLSessionProtocol diff --git a/Tests/TestCommon/MockApiRequest.swift b/Tests/TestCommon/MockApiRequest.swift index 5b5fcc07a..c496dcc34 100644 --- a/Tests/TestCommon/MockApiRequest.swift +++ b/Tests/TestCommon/MockApiRequest.swift @@ -13,6 +13,10 @@ import Foundation @testable import AuthFoundation +#if os(Linux) +import FoundationNetworking +#endif + struct MockApiRequest: APIRequest { var url: URL var cachePolicy: URLRequest.CachePolicy diff --git a/Tests/TestCommon/URLRequest+Extensions.swift b/Tests/TestCommon/URLRequest+Extensions.swift index fd32511e0..f7c99d3b7 100644 --- a/Tests/TestCommon/URLRequest+Extensions.swift +++ b/Tests/TestCommon/URLRequest+Extensions.swift @@ -12,6 +12,10 @@ import Foundation +#if os(Linux) +import FoundationNetworking +#endif + extension URLRequest { var bodyString: String? { guard let body = httpBody else { return nil } diff --git a/Tests/TestCommon/XCTestCase+Extensions.swift b/Tests/TestCommon/XCTestCase+Extensions.swift index 463731b25..d89732773 100644 --- a/Tests/TestCommon/XCTestCase+Extensions.swift +++ b/Tests/TestCommon/XCTestCase+Extensions.swift @@ -85,8 +85,8 @@ public extension XCTestCase { let group = DispatchGroup() for queue in queues { for _ in 0.. Date: Wed, 14 Aug 2024 18:56:20 -0700 Subject: [PATCH 03/20] Update lint violations --- Sources/AuthFoundation/Utilities/URL+InternalExtensions.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Sources/AuthFoundation/Utilities/URL+InternalExtensions.swift b/Sources/AuthFoundation/Utilities/URL+InternalExtensions.swift index 37c5510d8..588c86dff 100644 --- a/Sources/AuthFoundation/Utilities/URL+InternalExtensions.swift +++ b/Sources/AuthFoundation/Utilities/URL+InternalExtensions.swift @@ -13,10 +13,11 @@ import Foundation extension URL { - @inlinable // Workaround to address a known bug with URL.appendingPathComponent on Linux. // https://github.com/apple/swift-corelibs-foundation/issues/4849 + @inlinable func appendingComponent(_ component: String) -> URL { + // swiftlint:disable force_unwrapping #if os(Linux) var components = URLComponents(url: self, resolvingAgainstBaseURL: true)! if !components.path.hasSuffix("/") { @@ -29,5 +30,6 @@ extension URL { result.appendPathComponent(component) return result #endif + // swiftlint:enable force_unwrapping } } From f62a5cf4f491a7322a5bfb2de704b7fafc80896c Mon Sep 17 00:00:00 2001 From: Alex Nachbaur Date: Wed, 14 Aug 2024 19:07:50 -0700 Subject: [PATCH 04/20] CI runner updates --- .github/workflows/tests.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index e3eb1e87a..21744ea3b 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -21,10 +21,10 @@ on: - 'Tests/**/*.swift' env: - DEVELOPER_DIR: /Applications/Xcode_15.3.app/Contents/Developer + DEVELOPER_DIR: /Applications/Xcode_15.4.app/Contents/Developer NSUnbufferedIO: YES - iOS_DESTINATION: "platform=iOS Simulator,OS=17.4,name=iPhone 15 Pro Max" - tvOS_DESTINATION: "platform=tvOS Simulator,OS=17.4,name=Apple TV" + iOS_DESTINATION: "platform=iOS Simulator,OS=17.5,name=iPhone 15 Pro Max" + tvOS_DESTINATION: "platform=tvOS Simulator,OS=17.5,name=Apple TV" jobs: SwiftBuild: @@ -45,7 +45,7 @@ jobs: Cocoapods: name: CocoaPods Build - runs-on: macos-latest-large + runs-on: macos-latest-xlarge # Running on xlarge to use arm64 chipset timeout-minutes: 10 needs: - SwiftBuild From 56a083e5c07f4d3e8f6ada697a7a89d452bdc44a Mon Sep 17 00:00:00 2001 From: Alex Nachbaur Date: Thu, 15 Aug 2024 10:08:28 -0700 Subject: [PATCH 05/20] Upgrade security scan resource class to work around hanging CI jobs --- .circleci/config.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index 6cd2230f2..b882ddc4a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -236,6 +236,7 @@ workflows: jobs: - general-platform-helpers/job-semgrep-scan: name: semgrep-scan + resource-class: medium context: - static-analysis From e593c8ea37fa09eefde9a9622f8dfa472f0631d7 Mon Sep 17 00:00:00 2001 From: Alex Nachbaur Date: Thu, 15 Aug 2024 10:45:33 -0700 Subject: [PATCH 06/20] Ensure we test multiple swift versions --- .github/workflows/tests.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 21744ea3b..1bee90411 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -32,9 +32,13 @@ jobs: strategy: matrix: os: [macos-latest-large, ubuntu-latest] + swift_version: ["5.9", "5.10"] runs-on: ${{ matrix.os }} timeout-minutes: 10 steps: + - uses: swift-actions/setup-swift@v2 + with: + swift-version: ${{ matrix.swift_version }} - name: Get swift version run: swift --version - uses: actions/checkout@master From 55f44d29dc194af6439fe0bb18e12e6f4b4c6d71 Mon Sep 17 00:00:00 2001 From: Alex Nachbaur Date: Thu, 15 Aug 2024 11:15:41 -0700 Subject: [PATCH 07/20] Matrix test the Xcode unit tests across device types --- .github/workflows/tests.yaml | 65 +++++++++++++++++------------------- 1 file changed, 31 insertions(+), 34 deletions(-) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 1bee90411..79addf7b4 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -23,8 +23,6 @@ on: env: DEVELOPER_DIR: /Applications/Xcode_15.4.app/Contents/Developer NSUnbufferedIO: YES - iOS_DESTINATION: "platform=iOS Simulator,OS=17.5,name=iPhone 15 Pro Max" - tvOS_DESTINATION: "platform=tvOS Simulator,OS=17.5,name=Apple TV" jobs: SwiftBuild: @@ -68,6 +66,13 @@ jobs: XcodeBuild: name: Xcode Unit Tests runs-on: macos-latest-large + strategy: + matrix: + destination: + - "platform=iOS Simulator,OS=16.4,name=iPhone 14 Pro Max" + - "platform=iOS Simulator,OS=17.5,name=iPhone 15 Pro Max" + - "platform=tvOS Simulator,OS=17.5,name=Apple TV" + - "platform:macOS,name=My Mac" timeout-minutes: 25 steps: - uses: actions/checkout@master @@ -78,61 +83,53 @@ jobs: -derivedDataPath ../Build/DerivedData \ -clonedSourcePackagesDirPath ../Build/ClonedSources \ -scheme AuthFoundation \ - -sdk iphonesimulator \ - -destination "$iOS_DESTINATION" 2>&1 - - name: Build OktaDirectAuth - run: | - set -o pipefail && xcodebuild build \ - -derivedDataPath ../Build/DerivedData \ - -clonedSourcePackagesDirPath ../Build/ClonedSources \ - -scheme OktaDirectAuth \ - -sdk iphonesimulator \ - -destination "$iOS_DESTINATION" 2>&1 - - name: Build OktaOAuth2 + -destination "${{ matrix.destination }}" 2>&1 + - name: Test AuthFoundation run: | - set -o pipefail && xcodebuild build \ + set -o pipefail && xcodebuild test \ -derivedDataPath ../Build/DerivedData \ -clonedSourcePackagesDirPath ../Build/ClonedSources \ - -scheme OktaOAuth2 \ - -sdk iphonesimulator \ - -destination "$iOS_DESTINATION" 2>&1 - - name: Build WebAuthenticationUI + -scheme AuthFoundation \ + -destination "${{ matrix.destination }}" 2>&1 + - name: Build OktaDirectAuth run: | set -o pipefail && xcodebuild build \ -derivedDataPath ../Build/DerivedData \ -clonedSourcePackagesDirPath ../Build/ClonedSources \ - -scheme WebAuthenticationUI \ - -sdk iphonesimulator \ - -destination "$iOS_DESTINATION" 2>&1 - - name: Test AuthFoundation + -scheme OktaDirectAuth \ + -destination "${{ matrix.destination }}" 2>&1 + - name: Test OktaDirectAuth run: | set -o pipefail && xcodebuild test \ -derivedDataPath ../Build/DerivedData \ -clonedSourcePackagesDirPath ../Build/ClonedSources \ - -scheme AuthFoundation \ - -sdk iphonesimulator \ - -destination "$iOS_DESTINATION" 2>&1 - - name: Test OktaDirectAuth + -scheme OktaDirectAuth \ + -destination "${{ matrix.destination }}" 2>&1 + - name: Build OktaOAuth2 run: | - set -o pipefail && xcodebuild test \ + set -o pipefail && xcodebuild build \ -derivedDataPath ../Build/DerivedData \ -clonedSourcePackagesDirPath ../Build/ClonedSources \ - -scheme OktaDirectAuth \ - -sdk iphonesimulator \ - -destination "$iOS_DESTINATION" 2>&1 + -scheme OktaOAuth2 \ + -destination "${{ matrix.destination }}" 2>&1 - name: Test OktaOAuth2 run: | set -o pipefail && xcodebuild test \ -derivedDataPath ../Build/DerivedData \ -clonedSourcePackagesDirPath ../Build/ClonedSources \ -scheme OktaOAuth2 \ - -sdk iphonesimulator \ - -destination "$iOS_DESTINATION" 2>&1 + -destination "${{ matrix.destination }}" 2>&1 + - name: Build WebAuthenticationUI + run: | + set -o pipefail && xcodebuild build \ + -derivedDataPath ../Build/DerivedData \ + -clonedSourcePackagesDirPath ../Build/ClonedSources \ + -scheme WebAuthenticationUI \ + -destination "${{ matrix.destination }}" 2>&1 - name: Test WebAuthenticationUI run: | set -o pipefail && xcodebuild test \ -derivedDataPath ../Build/DerivedData \ -clonedSourcePackagesDirPath ../Build/ClonedSources \ -scheme WebAuthenticationUI \ - -sdk iphonesimulator \ - -destination "$iOS_DESTINATION" 2>&1 + -destination "${{ matrix.destination }}" 2>&1 From 40c6b96cbc3318fe0eca912f67379111d89ca8be Mon Sep 17 00:00:00 2001 From: Alex Nachbaur Date: Thu, 15 Aug 2024 11:16:49 -0700 Subject: [PATCH 08/20] Fix syntax error for macOS platform destionation --- .github/workflows/tests.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 79addf7b4..424f194a0 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -72,7 +72,7 @@ jobs: - "platform=iOS Simulator,OS=16.4,name=iPhone 14 Pro Max" - "platform=iOS Simulator,OS=17.5,name=iPhone 15 Pro Max" - "platform=tvOS Simulator,OS=17.5,name=Apple TV" - - "platform:macOS,name=My Mac" + - "platform=macOS,name=My Mac" timeout-minutes: 25 steps: - uses: actions/checkout@master From 57897bbb6340b99c5ca52ef9186124ad877fac6d Mon Sep 17 00:00:00 2001 From: Alex Nachbaur Date: Thu, 15 Aug 2024 11:40:39 -0700 Subject: [PATCH 09/20] Skip WebAuthenticationUI on unsupported platforms --- .github/workflows/tests.yaml | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 424f194a0..0c8996667 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -69,12 +69,21 @@ jobs: strategy: matrix: destination: - - "platform=iOS Simulator,OS=16.4,name=iPhone 14 Pro Max" - - "platform=iOS Simulator,OS=17.5,name=iPhone 15 Pro Max" - - "platform=tvOS Simulator,OS=17.5,name=Apple TV" - - "platform=macOS,name=My Mac" + - "platform=iOS Simulator,OS=16.4,name=iPhone 14 Pro Max" + - "platform=iOS Simulator,OS=17.5,name=iPhone 15 Pro Max" + - "platform=tvOS Simulator,OS=17.5,name=Apple TV" + - "platform=watchOS Simulator,OS=10.5,name=Apple Watch Series 7 (45mm)" + - "platform=macOS,name=My Mac" timeout-minutes: 25 steps: + - name: Set test variables + id: set-variable + run: | + if [ ${{ contains(matrix.destination, 'tvOS') || contains(matrix.destination, 'watchOS') }} ]; then + echo "WebAuthenticationUI is unsupported on this platform" + echo "{WebAuthenticationUIUnsupported}=true" >> $GITHUB_ENV + fi + shell: bash - uses: actions/checkout@master - name: Build AuthFoundation run: | @@ -120,6 +129,7 @@ jobs: -scheme OktaOAuth2 \ -destination "${{ matrix.destination }}" 2>&1 - name: Build WebAuthenticationUI + if: env.WebAuthenticationUIUnsupported != 'true' run: | set -o pipefail && xcodebuild build \ -derivedDataPath ../Build/DerivedData \ @@ -127,6 +137,7 @@ jobs: -scheme WebAuthenticationUI \ -destination "${{ matrix.destination }}" 2>&1 - name: Test WebAuthenticationUI + if: env.WebAuthenticationUIUnsupported != 'true' run: | set -o pipefail && xcodebuild test \ -derivedDataPath ../Build/DerivedData \ From c666e052476ea0cf621fc262ae41d7415b6f877e Mon Sep 17 00:00:00 2001 From: Alex Nachbaur Date: Thu, 15 Aug 2024 11:42:08 -0700 Subject: [PATCH 10/20] Fix syntax --- .github/workflows/tests.yaml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 0c8996667..12add59c3 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -77,13 +77,13 @@ jobs: timeout-minutes: 25 steps: - name: Set test variables - id: set-variable - run: | - if [ ${{ contains(matrix.destination, 'tvOS') || contains(matrix.destination, 'watchOS') }} ]; then - echo "WebAuthenticationUI is unsupported on this platform" - echo "{WebAuthenticationUIUnsupported}=true" >> $GITHUB_ENV - fi - shell: bash + id: set-variable + run: | + if [ ${{ contains(matrix.destination, 'tvOS') || contains(matrix.destination, 'watchOS') }} ]; then + echo "WebAuthenticationUI is unsupported on this platform" + echo "{WebAuthenticationUIUnsupported}=true" >> $GITHUB_ENV + fi + shell: bash - uses: actions/checkout@master - name: Build AuthFoundation run: | From e76f423a230b394ae993f272616d724a1864a425 Mon Sep 17 00:00:00 2001 From: Alex Nachbaur Date: Thu, 15 Aug 2024 12:21:24 -0700 Subject: [PATCH 11/20] Introduce vision pro unit tests --- .github/workflows/tests.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 12add59c3..ef75bd82d 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -65,13 +65,13 @@ jobs: XcodeBuild: name: Xcode Unit Tests - runs-on: macos-latest-large + runs-on: macos-latest-xlarge strategy: matrix: destination: - "platform=iOS Simulator,OS=16.4,name=iPhone 14 Pro Max" - "platform=iOS Simulator,OS=17.5,name=iPhone 15 Pro Max" - - "platform=tvOS Simulator,OS=17.5,name=Apple TV" + - "platform=visionOS Simulator,OS=1.2,name=Apple Vision Pro" - "platform=watchOS Simulator,OS=10.5,name=Apple Watch Series 7 (45mm)" - "platform=macOS,name=My Mac" timeout-minutes: 25 From 6c3b3687c7e6e464fc8bf79cd9e88fdb68f3c91c Mon Sep 17 00:00:00 2001 From: Alex Nachbaur Date: Thu, 15 Aug 2024 12:41:08 -0700 Subject: [PATCH 12/20] Update matrix jobs to support downstream job generation --- .github/workflows/tests.yaml | 46 +++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index ef75bd82d..1c3e8c372 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -63,9 +63,9 @@ jobs: #- name: OktaWebAuthenticationUI.podspec # run: pod lib lint --allow-warnings OktaWebAuthenticationUI.podspec - XcodeBuild: - name: Xcode Unit Tests - runs-on: macos-latest-xlarge + XcodeBuildMatrix: + name: Setup Xcode Unit Tests + runs-on: ubuntu-latest strategy: matrix: destination: @@ -74,16 +74,30 @@ jobs: - "platform=visionOS Simulator,OS=1.2,name=Apple Vision Pro" - "platform=watchOS Simulator,OS=10.5,name=Apple Watch Series 7 (45mm)" - "platform=macOS,name=My Mac" - timeout-minutes: 25 steps: + - outputs: + skipWebAuthenticationUI: ${{ steps.variables.outputs.skipWebAuthenticationUI }} + destination: ${{ matrix.destination }} - name: Set test variables - id: set-variable + id: variables run: | if [ ${{ contains(matrix.destination, 'tvOS') || contains(matrix.destination, 'watchOS') }} ]; then + echo "skipWebAuthenticationUI=true" >> "$GITHUB_OUTPUT" echo "WebAuthenticationUI is unsupported on this platform" - echo "{WebAuthenticationUIUnsupported}=true" >> $GITHUB_ENV + else + echo "skipWebAuthenticationUI=false" >> "$GITHUB_OUTPUT" fi shell: bash + + XcodeBuild: + name: Xcode Unit Tests + runs-on: macos-latest-xlarge + needs: XcodeBuildMatrix + - env: + DESTINATION: ${{needs.XcodeBuildMatrix.outputs.destination}} + SKIP_WEBAUTHENTICATIONUI: ${{needs.XcodeBuildMatrix.outputs.skipWebAuthenticationUI}} + timeout-minutes: 25 + steps: - uses: actions/checkout@master - name: Build AuthFoundation run: | @@ -92,55 +106,55 @@ jobs: -derivedDataPath ../Build/DerivedData \ -clonedSourcePackagesDirPath ../Build/ClonedSources \ -scheme AuthFoundation \ - -destination "${{ matrix.destination }}" 2>&1 + -destination "$DESTINATION" 2>&1 - name: Test AuthFoundation run: | set -o pipefail && xcodebuild test \ -derivedDataPath ../Build/DerivedData \ -clonedSourcePackagesDirPath ../Build/ClonedSources \ -scheme AuthFoundation \ - -destination "${{ matrix.destination }}" 2>&1 + -destination "$DESTINATION" 2>&1 - name: Build OktaDirectAuth run: | set -o pipefail && xcodebuild build \ -derivedDataPath ../Build/DerivedData \ -clonedSourcePackagesDirPath ../Build/ClonedSources \ -scheme OktaDirectAuth \ - -destination "${{ matrix.destination }}" 2>&1 + -destination "$DESTINATION" 2>&1 - name: Test OktaDirectAuth run: | set -o pipefail && xcodebuild test \ -derivedDataPath ../Build/DerivedData \ -clonedSourcePackagesDirPath ../Build/ClonedSources \ -scheme OktaDirectAuth \ - -destination "${{ matrix.destination }}" 2>&1 + -destination "$DESTINATION" 2>&1 - name: Build OktaOAuth2 run: | set -o pipefail && xcodebuild build \ -derivedDataPath ../Build/DerivedData \ -clonedSourcePackagesDirPath ../Build/ClonedSources \ -scheme OktaOAuth2 \ - -destination "${{ matrix.destination }}" 2>&1 + -destination "$DESTINATION" 2>&1 - name: Test OktaOAuth2 run: | set -o pipefail && xcodebuild test \ -derivedDataPath ../Build/DerivedData \ -clonedSourcePackagesDirPath ../Build/ClonedSources \ -scheme OktaOAuth2 \ - -destination "${{ matrix.destination }}" 2>&1 + -destination "$DESTINATION" 2>&1 - name: Build WebAuthenticationUI - if: env.WebAuthenticationUIUnsupported != 'true' + if: env.SKIP_WEBAUTHENTICATIONUI == 'true' run: | set -o pipefail && xcodebuild build \ -derivedDataPath ../Build/DerivedData \ -clonedSourcePackagesDirPath ../Build/ClonedSources \ -scheme WebAuthenticationUI \ - -destination "${{ matrix.destination }}" 2>&1 + -destination "$DESTINATION" 2>&1 - name: Test WebAuthenticationUI - if: env.WebAuthenticationUIUnsupported != 'true' + if: env.SKIP_WEBAUTHENTICATIONUI == 'true' run: | set -o pipefail && xcodebuild test \ -derivedDataPath ../Build/DerivedData \ -clonedSourcePackagesDirPath ../Build/ClonedSources \ -scheme WebAuthenticationUI \ - -destination "${{ matrix.destination }}" 2>&1 + -destination "$DESTINATION" 2>&1 From de18177050353d13be396312c7fdb5780cf12107 Mon Sep 17 00:00:00 2001 From: Alex Nachbaur Date: Thu, 15 Aug 2024 12:58:59 -0700 Subject: [PATCH 13/20] Fix another indentation problem --- .github/workflows/tests.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 1c3e8c372..838f5a801 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -94,8 +94,8 @@ jobs: runs-on: macos-latest-xlarge needs: XcodeBuildMatrix - env: - DESTINATION: ${{needs.XcodeBuildMatrix.outputs.destination}} - SKIP_WEBAUTHENTICATIONUI: ${{needs.XcodeBuildMatrix.outputs.skipWebAuthenticationUI}} + DESTINATION: ${{needs.XcodeBuildMatrix.outputs.destination}} + SKIP_WEBAUTHENTICATIONUI: ${{needs.XcodeBuildMatrix.outputs.skipWebAuthenticationUI}} timeout-minutes: 25 steps: - uses: actions/checkout@master From 0da97c44be8bc4cc99f4d10453ef90ad4b2f49f0 Mon Sep 17 00:00:00 2001 From: Alex Nachbaur Date: Thu, 15 Aug 2024 13:14:38 -0700 Subject: [PATCH 14/20] Fix silly yaml syntax errors --- .github/workflows/documentation.yaml | 8 ++++---- .github/workflows/tests.yaml | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/documentation.yaml b/.github/workflows/documentation.yaml index 250fb89d8..25c623ff9 100644 --- a/.github/workflows/documentation.yaml +++ b/.github/workflows/documentation.yaml @@ -61,22 +61,22 @@ jobs: zip -r ~/Build/$(basename "$archive").zip $(basename "$archive") done - name: Upload AuthFoundation DocC Archive - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: AuthFoundation.doccarchive.zip path: ~/Build/AuthFoundation.doccarchive.zip - name: Upload OktaDirectAuth DocC Archive - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: OktaDirectAuth.doccarchive.zip path: ~/Build/OktaDirectAuth.doccarchive.zip - name: Upload OktaOAuth2 DocC Archive - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: OktaOAuth2.doccarchive.zip path: ~/Build/OktaOAuth2.doccarchive.zip - name: Upload WebAuthenticationUI DocC Archive - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: WebAuthenticationUI.doccarchive.zip path: ~/Build/WebAuthenticationUI.doccarchive.zip diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 838f5a801..fac589b4e 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -74,10 +74,10 @@ jobs: - "platform=visionOS Simulator,OS=1.2,name=Apple Vision Pro" - "platform=watchOS Simulator,OS=10.5,name=Apple Watch Series 7 (45mm)" - "platform=macOS,name=My Mac" + outputs: + skipWebAuthenticationUI: ${{ steps.variables.outputs.skipWebAuthenticationUI }} + destination: ${{ matrix.destination }} steps: - - outputs: - skipWebAuthenticationUI: ${{ steps.variables.outputs.skipWebAuthenticationUI }} - destination: ${{ matrix.destination }} - name: Set test variables id: variables run: | @@ -93,7 +93,7 @@ jobs: name: Xcode Unit Tests runs-on: macos-latest-xlarge needs: XcodeBuildMatrix - - env: + env: DESTINATION: ${{needs.XcodeBuildMatrix.outputs.destination}} SKIP_WEBAUTHENTICATIONUI: ${{needs.XcodeBuildMatrix.outputs.skipWebAuthenticationUI}} timeout-minutes: 25 From 89563b016abb029cf29206a2377c8c37bfd400aa Mon Sep 17 00:00:00 2001 From: Alex Nachbaur Date: Thu, 15 Aug 2024 13:15:40 -0700 Subject: [PATCH 15/20] Make Cocoapods build run in parallel --- .github/workflows/tests.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index fac589b4e..ba1f6dfe8 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -49,8 +49,6 @@ jobs: name: CocoaPods Build runs-on: macos-latest-xlarge # Running on xlarge to use arm64 chipset timeout-minutes: 10 - needs: - - SwiftBuild steps: - uses: actions/checkout@master - name: OktaAuthFoundation.podspec From 927d58a2f853bf13f51b39287b0d552bfcdcbfbe Mon Sep 17 00:00:00 2001 From: Alex Nachbaur Date: Thu, 15 Aug 2024 14:10:31 -0700 Subject: [PATCH 16/20] Remap matrix job to not rely on downstreams --- .github/workflows/tests.yaml | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index ba1f6dfe8..20a81481a 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -49,6 +49,8 @@ jobs: name: CocoaPods Build runs-on: macos-latest-xlarge # Running on xlarge to use arm64 chipset timeout-minutes: 10 + needs: + - SwiftBuild steps: - uses: actions/checkout@master - name: OktaAuthFoundation.podspec @@ -61,9 +63,10 @@ jobs: #- name: OktaWebAuthenticationUI.podspec # run: pod lib lint --allow-warnings OktaWebAuthenticationUI.podspec - XcodeBuildMatrix: - name: Setup Xcode Unit Tests - runs-on: ubuntu-latest + XcodeBuild: + name: Xcode Unit Tests + runs-on: macos-latest-xlarge + needs: XcodeBuildMatrix strategy: matrix: destination: @@ -72,30 +75,17 @@ jobs: - "platform=visionOS Simulator,OS=1.2,name=Apple Vision Pro" - "platform=watchOS Simulator,OS=10.5,name=Apple Watch Series 7 (45mm)" - "platform=macOS,name=My Mac" - outputs: - skipWebAuthenticationUI: ${{ steps.variables.outputs.skipWebAuthenticationUI }} - destination: ${{ matrix.destination }} + timeout-minutes: 25 steps: - name: Set test variables - id: variables run: | + echo "DESTINATION=${{matrix.destination}}" >> "$GITHUB_ENV" if [ ${{ contains(matrix.destination, 'tvOS') || contains(matrix.destination, 'watchOS') }} ]; then - echo "skipWebAuthenticationUI=true" >> "$GITHUB_OUTPUT" + echo "SKIP_WEBAUTHENTICATIONUI=true" >> "$GITHUB_ENV" echo "WebAuthenticationUI is unsupported on this platform" else - echo "skipWebAuthenticationUI=false" >> "$GITHUB_OUTPUT" + echo "SKIP_WEBAUTHENTICATIONUI=false" >> "$GITHUB_ENV" fi - shell: bash - - XcodeBuild: - name: Xcode Unit Tests - runs-on: macos-latest-xlarge - needs: XcodeBuildMatrix - env: - DESTINATION: ${{needs.XcodeBuildMatrix.outputs.destination}} - SKIP_WEBAUTHENTICATIONUI: ${{needs.XcodeBuildMatrix.outputs.skipWebAuthenticationUI}} - timeout-minutes: 25 - steps: - uses: actions/checkout@master - name: Build AuthFoundation run: | From 4345f2fac71fad8a3069c6a67e9cf99c3b9609ab Mon Sep 17 00:00:00 2001 From: Alex Nachbaur Date: Thu, 15 Aug 2024 14:11:33 -0700 Subject: [PATCH 17/20] Fix another syntax error --- .github/workflows/tests.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 20a81481a..dd619d022 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -66,7 +66,6 @@ jobs: XcodeBuild: name: Xcode Unit Tests runs-on: macos-latest-xlarge - needs: XcodeBuildMatrix strategy: matrix: destination: From 7055703d64f508b6aa7d72f306a2b4ccc907afba Mon Sep 17 00:00:00 2001 From: Alex Nachbaur Date: Thu, 15 Aug 2024 15:27:44 -0700 Subject: [PATCH 18/20] Another attempt to skip webauth UI --- .github/workflows/tests.yaml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index dd619d022..f5180480d 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -86,6 +86,8 @@ jobs: echo "SKIP_WEBAUTHENTICATIONUI=false" >> "$GITHUB_ENV" fi - uses: actions/checkout@master + - name: Check environment variables + run: env - name: Build AuthFoundation run: | set -o pipefail @@ -130,7 +132,7 @@ jobs: -scheme OktaOAuth2 \ -destination "$DESTINATION" 2>&1 - name: Build WebAuthenticationUI - if: env.SKIP_WEBAUTHENTICATIONUI == 'true' + if: env.SKIP_WEBAUTHENTICATIONUI != 'false' run: | set -o pipefail && xcodebuild build \ -derivedDataPath ../Build/DerivedData \ @@ -138,7 +140,7 @@ jobs: -scheme WebAuthenticationUI \ -destination "$DESTINATION" 2>&1 - name: Test WebAuthenticationUI - if: env.SKIP_WEBAUTHENTICATIONUI == 'true' + if: env.SKIP_WEBAUTHENTICATIONUI != 'false' run: | set -o pipefail && xcodebuild test \ -derivedDataPath ../Build/DerivedData \ From e933af30b149ef36cd7385b7d311c0d9c2b1ebaf Mon Sep 17 00:00:00 2001 From: Alex Nachbaur Date: Thu, 15 Aug 2024 15:37:30 -0700 Subject: [PATCH 19/20] Tweak logic for skipping webauth --- .github/workflows/tests.yaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index f5180480d..70cde1479 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -71,6 +71,7 @@ jobs: destination: - "platform=iOS Simulator,OS=16.4,name=iPhone 14 Pro Max" - "platform=iOS Simulator,OS=17.5,name=iPhone 15 Pro Max" + - "platform=tvOS Simulator,OS=17.5,name=Apple TV" - "platform=visionOS Simulator,OS=1.2,name=Apple Vision Pro" - "platform=watchOS Simulator,OS=10.5,name=Apple Watch Series 7 (45mm)" - "platform=macOS,name=My Mac" @@ -79,7 +80,9 @@ jobs: - name: Set test variables run: | echo "DESTINATION=${{matrix.destination}}" >> "$GITHUB_ENV" - if [ ${{ contains(matrix.destination, 'tvOS') || contains(matrix.destination, 'watchOS') }} ]; then + + destination="${{matrix.destination}}" + if [[ $destination =~ "tvOS" ]] || [[ $destination =~ "watchOS" ]]; then echo "SKIP_WEBAUTHENTICATIONUI=true" >> "$GITHUB_ENV" echo "WebAuthenticationUI is unsupported on this platform" else From 099e739bb1a336f07c54dbc5fc3943cf0bdf2dcf Mon Sep 17 00:00:00 2001 From: Alex Nachbaur Date: Thu, 15 Aug 2024 15:40:02 -0700 Subject: [PATCH 20/20] Fix stupid logic error --- .github/workflows/tests.yaml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 70cde1479..f0ae1add5 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -89,8 +89,6 @@ jobs: echo "SKIP_WEBAUTHENTICATIONUI=false" >> "$GITHUB_ENV" fi - uses: actions/checkout@master - - name: Check environment variables - run: env - name: Build AuthFoundation run: | set -o pipefail @@ -135,7 +133,7 @@ jobs: -scheme OktaOAuth2 \ -destination "$DESTINATION" 2>&1 - name: Build WebAuthenticationUI - if: env.SKIP_WEBAUTHENTICATIONUI != 'false' + if: env.SKIP_WEBAUTHENTICATIONUI != 'true' run: | set -o pipefail && xcodebuild build \ -derivedDataPath ../Build/DerivedData \ @@ -143,7 +141,7 @@ jobs: -scheme WebAuthenticationUI \ -destination "$DESTINATION" 2>&1 - name: Test WebAuthenticationUI - if: env.SKIP_WEBAUTHENTICATIONUI != 'false' + if: env.SKIP_WEBAUTHENTICATIONUI != 'true' run: | set -o pipefail && xcodebuild test \ -derivedDataPath ../Build/DerivedData \