From 350755a8395435797c24aec97affe0f5b5a89665 Mon Sep 17 00:00:00 2001 From: George Bafaloukas Date: Fri, 31 May 2024 12:29:00 +0100 Subject: [PATCH 1/5] Adding extra FRSecurityConfiguration property on the FRURLProtocol class to allow respecting SSLPinning in conjunction with Token or Auth Policies --- FRAuth/FRAuth/Network/FRURLProtocol.swift | 52 +++++++++++++++++++---- 1 file changed, 43 insertions(+), 9 deletions(-) diff --git a/FRAuth/FRAuth/Network/FRURLProtocol.swift b/FRAuth/FRAuth/Network/FRURLProtocol.swift index 08e36bb90..64618777 100644 --- a/FRAuth/FRAuth/Network/FRURLProtocol.swift +++ b/FRAuth/FRAuth/Network/FRURLProtocol.swift @@ -10,6 +10,7 @@ import Foundation +import FRCore @objc public class FRURLProtocol: URLProtocol { @@ -20,6 +21,8 @@ import Foundation /// AuthorizationPolicy for URLProtocol @objc public static var authorizationPolicy: AuthorizationPolicy? + @objc public static var frSecurityConfiguration: FRSecurityConfiguration? + // MARK: - Private Property /// Constant String key of FRURLProtocol indication @@ -386,24 +389,55 @@ extension FRURLProtocol: URLSessionDataDelegate { } - /// URLSessionDataDelegate method for Authentication Challenge + /// URLSessionDelegate method for Authentication Challenge /// /// - Parameters: /// - session: URLSession /// - challenge: URLAuthenticationChallenge /// - completionHandler: Completion callback public func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { - let protectionSpace = challenge.protectionSpace - let sender = challenge.sender + if let frSecurityConfiguration = FRURLProtocol.frSecurityConfiguration { + frSecurityConfiguration.validateSessionAuthChallenge(session: session, challenge: challenge, completionHandler: completionHandler) + } else { + let protectionSpace = challenge.protectionSpace + let sender = challenge.sender - if protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust { - if let serverTrust = protectionSpace.serverTrust { - let credential = URLCredential(trust: serverTrust) - sender?.use(credential, for: challenge) - completionHandler(.useCredential, credential) - return + if protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust { + if let serverTrust = protectionSpace.serverTrust { + let credential = URLCredential(trust: serverTrust) + sender?.use(credential, for: challenge) + completionHandler(.useCredential, credential) + return + } + } + } + + } + + /// URLSessionTaskDelegate method for Authentication Challenge + /// + /// - Parameters: + /// - session: URLSession + /// - task: URLSessionTask + /// - challenge: URLAuthenticationChallenge + /// - completionHandler: Completion callback + public func urlSession(_ session: URLSession, task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { + if let frSecurityConfiguration = FRURLProtocol.frSecurityConfiguration { + frSecurityConfiguration.validateTaskAuthChallenge(session: session, task: task, challenge: challenge, completionHandler: completionHandler) + } else { + let protectionSpace = challenge.protectionSpace + let sender = challenge.sender + + if protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust { + if let serverTrust = protectionSpace.serverTrust { + let credential = URLCredential(trust: serverTrust) + sender?.use(credential, for: challenge) + completionHandler(.useCredential, credential) + return + } } } + } From c6ac6275d3c3266b7fb832c412c6f8b844afe6e6 Mon Sep 17 00:00:00 2001 From: George Bafaloukas Date: Mon, 3 Jun 2024 11:24:27 +0100 Subject: [PATCH 2/5] Making FRURLProtocol an open class --- FRAuth/FRAuth/Network/FRURLProtocol.swift | 28 +++++++++++------------ 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/FRAuth/FRAuth/Network/FRURLProtocol.swift b/FRAuth/FRAuth/Network/FRURLProtocol.swift index 64618777..01bb21cc 100644 --- a/FRAuth/FRAuth/Network/FRURLProtocol.swift +++ b/FRAuth/FRAuth/Network/FRURLProtocol.swift @@ -1,8 +1,8 @@ -// +// // FRURLProtocol2.swift // FRAuth // -// Copyright (c) 2020 ForgeRock. All rights reserved. +// Copyright (c) 2020-2024 ForgeRock. All rights reserved. // // This software may be modified and distributed under the terms // of the MIT license. See the LICENSE file for details. @@ -12,7 +12,7 @@ import Foundation import FRCore -@objc public class FRURLProtocol: URLProtocol { +@objc open class FRURLProtocol: URLProtocol { // MARK: - Public Property @@ -134,7 +134,7 @@ import FRCore self.sessionTask?.resume() return } - + FRURLProtocol.setProperty(true, forKey: Constants.FRURLProtocolHandled, in: mutableRequest) session?.dataTask(with: mutableRequest as URLRequest, completionHandler: { (data, response, error) in if let returnData = data { @@ -201,7 +201,7 @@ import FRCore extension FRURLProtocol: URLSessionDataDelegate { - + /// URLSessionDataDelegate method for receiving data /// /// - Parameters: @@ -217,7 +217,7 @@ extension FRURLProtocol: URLSessionDataDelegate { self.responseData = data } } - + /// URLSessionDataDelegate method for receiving response /// @@ -232,7 +232,7 @@ extension FRURLProtocol: URLSessionDataDelegate { completionHandler(.allow) } - + /// URLSessionDataDelegate method to notify completion of the request /// /// In this delegation method, FRURLProtocol will validate the result of the request with given ValidatedURLs, RefreshTokenPolicy, and maximum retry attempt, and perform token refresh if necessary @@ -320,7 +320,7 @@ extension FRURLProtocol: URLSessionDataDelegate { } } - + if shouldRetry { self.responseData = nil self.client?.urlProtocol(self, didLoad: Data()) @@ -337,7 +337,7 @@ extension FRURLProtocol: URLSessionDataDelegate { self.completeRequest(error: error) } } - + /// URLSessionDataDelegate method for HTTP Redirection /// @@ -376,7 +376,7 @@ extension FRURLProtocol: URLSessionDataDelegate { client?.urlProtocol(self, wasRedirectedTo: request, redirectResponse: response) completionHandler(request) } - + /// URLSessionDataDelegate method for invalidating the current request with an error /// @@ -387,7 +387,7 @@ extension FRURLProtocol: URLSessionDataDelegate { guard let error = error else { return } client?.urlProtocol(self, didFailWithError: error) } - + /// URLSessionDelegate method for Authentication Challenge /// @@ -401,7 +401,7 @@ extension FRURLProtocol: URLSessionDataDelegate { } else { let protectionSpace = challenge.protectionSpace let sender = challenge.sender - + if protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust { if let serverTrust = protectionSpace.serverTrust { let credential = URLCredential(trust: serverTrust) @@ -427,7 +427,7 @@ extension FRURLProtocol: URLSessionDataDelegate { } else { let protectionSpace = challenge.protectionSpace let sender = challenge.sender - + if protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust { if let serverTrust = protectionSpace.serverTrust { let credential = URLCredential(trust: serverTrust) @@ -439,7 +439,7 @@ extension FRURLProtocol: URLSessionDataDelegate { } } - + /// URLSessionDataDelegate method /// From 08582b3b8ab2aa6e2ec8e7fbac965ba491f11afc Mon Sep 17 00:00:00 2001 From: George Bafaloukas Date: Mon, 3 Jun 2024 16:28:34 +0100 Subject: [PATCH 3/5] Adding challenge handling for non trust challenges --- FRAuth/FRAuth/Network/FRURLProtocol.swift | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/FRAuth/FRAuth/Network/FRURLProtocol.swift b/FRAuth/FRAuth/Network/FRURLProtocol.swift index 01bb21cc..9c292826 100644 --- a/FRAuth/FRAuth/Network/FRURLProtocol.swift +++ b/FRAuth/FRAuth/Network/FRURLProtocol.swift @@ -409,6 +409,9 @@ extension FRURLProtocol: URLSessionDataDelegate { completionHandler(.useCredential, credential) return } + } else { + completionHandler(.performDefaultHandling, nil) + return } } @@ -435,6 +438,9 @@ extension FRURLProtocol: URLSessionDataDelegate { completionHandler(.useCredential, credential) return } + } else { + completionHandler(.performDefaultHandling, nil) + return } } From 703ff9052728577d30c76313d71fde16fcf3fced Mon Sep 17 00:00:00 2001 From: George Bafaloukas Date: Tue, 4 Jun 2024 15:43:41 +0100 Subject: [PATCH 4/5] Added doc and example for the FRExample app --- FRAuth/FRAuth/Network/FRURLProtocol.swift | 4 ++-- .../xcshareddata/swiftpm/Package.resolved | 7 ++++--- .../FRExample/FRExample/ViewController.swift | 14 ++++++++++++++ 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/FRAuth/FRAuth/Network/FRURLProtocol.swift b/FRAuth/FRAuth/Network/FRURLProtocol.swift index 9c292826..619e0c4d 100644 --- a/FRAuth/FRAuth/Network/FRURLProtocol.swift +++ b/FRAuth/FRAuth/Network/FRURLProtocol.swift @@ -20,7 +20,7 @@ import FRCore @objc public static var tokenManagementPolicy: TokenManagementPolicy? /// AuthorizationPolicy for URLProtocol @objc public static var authorizationPolicy: AuthorizationPolicy? - + /// FRSecurityConfiguration for URLProtocol - Used for SSL Pinning @objc public static var frSecurityConfiguration: FRSecurityConfiguration? // MARK: - Private Property @@ -424,7 +424,7 @@ extension FRURLProtocol: URLSessionDataDelegate { /// - task: URLSessionTask /// - challenge: URLAuthenticationChallenge /// - completionHandler: Completion callback - public func urlSession(_ session: URLSession, task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { + public func urlSession(_ session: URLSession, task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { if let frSecurityConfiguration = FRURLProtocol.frSecurityConfiguration { frSecurityConfiguration.validateTaskAuthChallenge(session: session, task: task, challenge: challenge, completionHandler: completionHandler) } else { diff --git a/SampleApps/FRExample.xcworkspace/xcshareddata/swiftpm/Package.resolved b/SampleApps/FRExample.xcworkspace/xcshareddata/swiftpm/Package.resolved index 2a995953..25b3c460 100644 --- a/SampleApps/FRExample.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/SampleApps/FRExample.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,4 +1,5 @@ { + "originHash" : "4b224c9b3814ec281d0a9ebedbf13f7006658641db6a159b927b4e018e4bf76f", "pins" : [ { "identity" : "appauth-ios", @@ -59,10 +60,10 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/pingidentity/pingone-signals-sdk-ios", "state" : { - "revision" : "88951ad71c37853fb86cee0bf48cf447ded5b268", - "version" : "5.2.3" + "revision" : "59fde21ecebaaf1b20046e79f55f05f4beb7a74d", + "version" : "5.2.7" } } ], - "version" : 2 + "version" : 3 } diff --git a/SampleApps/FRExample/FRExample/ViewController.swift b/SampleApps/FRExample/FRExample/ViewController.swift index 2aeca0b4..a3e9ec5d 100644 --- a/SampleApps/FRExample/FRExample/ViewController.swift +++ b/SampleApps/FRExample/FRExample/ViewController.swift @@ -174,6 +174,20 @@ class ViewController: UIViewController, ErrorAlertShowing { config.protocolClasses = [FRURLProtocol.self] self.urlSession = URLSession(configuration: config) + // Configure FRSecurityConfiguration to set SSL Pinning on the FRURLProtocol + // This needs to be set up if using Authroization or Token Policies with FRURLProtocol + // and want to force SSL Pinning on those endpoints. + // Make sure to add the Key Hashes of the certificates that correspont to the URLs + // set on the `FRURLProtocol.tokenManagementPolicy` & `FRURLProtocol.authorizationPolicy` + + var sslPinningKeyHashes: [String] = [] + //sslPinningKeyHashes = ["Key1", "Key2"] --> Add Key hashes and uncomment to enable + + if(!sslPinningKeyHashes.isEmpty) { + let frSecurityConfiguration = FRSecurityConfiguration(hashes: sslPinningKeyHashes) + FRURLProtocol.frSecurityConfiguration = frSecurityConfiguration + } + // - MARK: FRUI Customize Cell example // Comment out below code to demonstrate FRUI customization // CallbackTableViewCellFactory.shared.registerCallbackTableViewCell(callbackType: "NameCallback", cellClass: CustomNameCallbackCell.self, nibName: "CustomNameCallbackCell") From f8bf9a318b2ef7a768699d642fdbb1c973e15996 Mon Sep 17 00:00:00 2001 From: Stoyan Petrov Date: Tue, 4 Jun 2024 10:04:52 -0700 Subject: [PATCH 5/5] Revert changes in package.resolved to previous version until we update the pipeline to use Xcode 15. --- .../xcshareddata/swiftpm/Package.resolved | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/SampleApps/FRExample.xcworkspace/xcshareddata/swiftpm/Package.resolved b/SampleApps/FRExample.xcworkspace/xcshareddata/swiftpm/Package.resolved index 25b3c460..2a995953 100644 --- a/SampleApps/FRExample.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/SampleApps/FRExample.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,5 +1,4 @@ { - "originHash" : "4b224c9b3814ec281d0a9ebedbf13f7006658641db6a159b927b4e018e4bf76f", "pins" : [ { "identity" : "appauth-ios", @@ -60,10 +59,10 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/pingidentity/pingone-signals-sdk-ios", "state" : { - "revision" : "59fde21ecebaaf1b20046e79f55f05f4beb7a74d", - "version" : "5.2.7" + "revision" : "88951ad71c37853fb86cee0bf48cf447ded5b268", + "version" : "5.2.3" } } ], - "version" : 3 + "version" : 2 }