From d9bd306f70331eec35c958acca0c9c947ea155b9 Mon Sep 17 00:00:00 2001 From: Mike Nachbaur Date: Tue, 23 Jul 2024 10:44:27 -0700 Subject: [PATCH] Ensure SDKVersion registration locks --- .../Internal/String+AuthFoundation.swift | 40 +++++++++++++------ .../Authentication/ResourceOwnerFlow.swift | 3 +- 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/Sources/AuthFoundation/Network/Internal/String+AuthFoundation.swift b/Sources/AuthFoundation/Network/Internal/String+AuthFoundation.swift index 4451768ef..7d0bbede1 100644 --- a/Sources/AuthFoundation/Network/Internal/String+AuthFoundation.swift +++ b/Sources/AuthFoundation/Network/Internal/String+AuthFoundation.swift @@ -54,31 +54,47 @@ private let systemVersion: String = { #endif }() -public final class SDKVersion { +/// Utility class that allows SDK components to register their name and version for use in HTTP User-Agent values. +/// +/// The Okta Client SDK consists of multiple libraries, each of which may or may not be used within the same application, or at the same time. To allow version information to be sustainably managed, this class can be used to centralize the registration of these SDK versions to report just the components used within an application. +public final class SDKVersion: Sendable { + /// The name of this library component. public let name: String + + /// The version number string of this library component. public let version: String public init(sdk name: String, version: String) { self.name = name self.version = version } - + + /// The formatted display name for this individual library's information. public var displayName: String { "\(name)/\(version)" } + + /// 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() fileprivate static var sdkVersions: [SDKVersion] = [] + + /// Register a new SDK library component to be added to the ``userAgent`` value. + /// > Note: SDK ``name`` values must be unique. If a duplicate SDK version is already added, only the first registered SDK value will be applied. + /// - Parameter sdk: SDK version to add. public static func register(sdk: SDKVersion) { - guard sdkVersions.filter({ $0.name == sdk.name }).isEmpty else { - return + lock.withLock { + guard sdkVersions.filter({ $0.name == sdk.name }).isEmpty else { + return + } + + sdkVersions.append(sdk) + + let sdkVersions = SDKVersion.sdkVersions + .sorted(by: { $0.name < $1.name }) + .map(\.displayName) + .joined(separator: " ") + userAgent = "\(sdkVersions) \(systemName)/\(systemVersion) Device/\(deviceModel)" } - - sdkVersions.append(sdk) - - let sdkVersions = SDKVersion.sdkVersions - .sorted(by: { $0.name < $1.name }) - .map(\.displayName) - .joined(separator: " ") - userAgent = "\(sdkVersions) \(systemName)/\(systemVersion) Device/\(deviceModel)" } } diff --git a/Sources/OktaOAuth2/Authentication/ResourceOwnerFlow.swift b/Sources/OktaOAuth2/Authentication/ResourceOwnerFlow.swift index d45d70d94..f1d2cbd64 100644 --- a/Sources/OktaOAuth2/Authentication/ResourceOwnerFlow.swift +++ b/Sources/OktaOAuth2/Authentication/ResourceOwnerFlow.swift @@ -17,8 +17,7 @@ import AuthFoundation /// /// This simple authentication flow permits a suer to authenticate using a simple username and password. As such, the configuration is straightforward. /// -/// > Important: Resource Owner authentication does not support MFA or other more secure authentication models, and is not recommended for production applications. -@available(*, deprecated, message: "Please use the DirectAuth SDK's DirectAuthenticationFlow class instead") +/// > Important: Resource Owner authentication does not support MFA or other more secure authentication models, and is not recommended for production applications. Please use the DirectAuth SDK's DirectAuthenticationFlow class instead. public class ResourceOwnerFlow: AuthenticationFlow { /// The OAuth2Client this authentication flow will use. public let client: OAuth2Client