Skip to content

Commit

Permalink
Merge pull request #170 from ForgeRock/develop
Browse files Browse the repository at this point in the history
ForgeRock iOS SDK 3.4.1 Release
  • Loading branch information
spetrov authored Nov 15, 2022
2 parents 20ebe11 + 3529d16 commit a124cfd
Show file tree
Hide file tree
Showing 27 changed files with 159 additions and 93 deletions.
9 changes: 7 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
# Version 3.4.0
# Version 3.4.1
## [3.4.1]
#### Changed
- Updated legacy encryption algorithm for iOS SE [SDKS-1994]
- Fixed an issue related to push notifications timeout [SDKS-2164]
- Fixed an unexpected error occurring during the decoding of some push notifications [SDKS-2199]

## [3.4.0]
#### Added
- Dynamic SDK Configuration [SDKS-1760]
Expand All @@ -8,7 +14,6 @@
- Fixed build errors on Xcode 14 [SDKS-2073]
- Fixed bug where the `state` parameter value was not verified upon calling the `Authorize` endpoint [SDKS-2077]

# Version 3.3.2
## [3.3.2]
#### Added
- Interface for log management [SDKS-1863]
Expand Down
4 changes: 2 additions & 2 deletions FRAuth.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

Pod::Spec.new do |s|
s.name = 'FRAuth'
s.version = '3.4.0'
s.version = '3.4.1'
s.summary = 'ForgeRock Auth SDK for iOS'
s.description = <<-DESC
FRAuth is a SDK that allows you easily and quickly develop an application with ForgeRock Platform or ForgeRock Identity Cloud. FRAuth SDK provides interfaces and functionalities of user authentication, registration, and identity and access management against ForgeRock solutions.
Expand All @@ -29,5 +29,5 @@ Pod::Spec.new do |s|

base_dir = "FRAuth/FRAuth"
s.source_files = base_dir + '/**/*.swift', base_dir + '/**/*.c', base_dir + '/**/*.h'
s.ios.dependency 'FRCore', '~> 3.4.0'
s.ios.dependency 'FRCore', '~> 3.4.1'
end
4 changes: 2 additions & 2 deletions FRAuth/FRAuth.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -2132,7 +2132,7 @@
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
MARKETING_VERSION = 3.4.0;
MARKETING_VERSION = 3.4.1;
MODULEMAP_FILE = "${PROJECT_DIR}/FRAuth/SharedC/FRAuth.modulemap";
OTHER_CFLAGS = "-DXCODE_FRAMEWORK=1";
PRODUCT_BUNDLE_IDENTIFIER = com.forgerock.ios.FRAuth;
Expand Down Expand Up @@ -2166,7 +2166,7 @@
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
MARKETING_VERSION = 3.4.0;
MARKETING_VERSION = 3.4.1;
MODULEMAP_FILE = "${PROJECT_DIR}/FRAuth/SharedC/FRAuth.modulemap";
OTHER_CFLAGS = "-DXCODE_FRAMEWORK=1";
PRODUCT_BUNDLE_IDENTIFIER = com.forgerock.ios.FRAuth;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// CookieTests.swift
// FRAuthTests
//
// Copyright (c) 2020 ForgeRock. All rights reserved.
// Copyright (c) 2020-2022 ForgeRock. All rights reserved.
//
// This software may be modified and distributed under the terms
// of the MIT license. See the LICENSE file for details.
Expand Down Expand Up @@ -219,7 +219,7 @@ class CookieTests: FRAuthBaseTest {
self.performLogin()
let url = URL(string: "https://openam.example.com")!

let setCookie: [String: String] = ["Set-Cookie":"iPlanetDirectoryPro=token; Expires=Wed, 21 Oct 2022 01:00:00 GMT; Domain=openam.example.com"]
let setCookie: [String: String] = ["Set-Cookie":"iPlanetDirectoryPro=token; Expires=Wed, 21 Oct 2032 01:00:00 GMT; Domain=openam.example.com"]
let cookies = HTTPCookie.cookies(withResponseHeaderFields: setCookie, for: url)

guard let cookie = cookies.first, let frAuth = FRAuth.shared else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// CookieValidationTests.swift
// FRAuthTests
//
// Copyright (c) 2020 ForgeRock. All rights reserved.
// Copyright (c) 2020-2022 ForgeRock. All rights reserved.
//
// This software may be modified and distributed under the terms
// of the MIT license. See the LICENSE file for details.
Expand Down Expand Up @@ -202,7 +202,7 @@ class CookieValidationTests: FRAuthBaseTest {


func test_10_cookie_is_expired_validation_not_expired() {
let setCookie: [String: String] = ["Set-Cookie":"iPlanetDirectoryPro=token; Expires=Wed, 21 Oct 2022 01:00:00 GMT; Domain=openam.example.com"]
let setCookie: [String: String] = ["Set-Cookie":"iPlanetDirectoryPro=token; Expires=Wed, 21 Oct 2032 01:00:00 GMT; Domain=openam.example.com"]
let cookies = HTTPCookie.cookies(withResponseHeaderFields: setCookie, for: URL(string: "https://openam.example.com")!)
guard let cookie = cookies.first else {
XCTFail("Failed to parse Cookies from response header")
Expand Down
4 changes: 2 additions & 2 deletions FRAuthenticator.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

Pod::Spec.new do |s|
s.name = 'FRAuthenticator'
s.version = '3.4.0'
s.version = '3.4.1'
s.summary = 'ForgeRock OTP/Push Authentication SDK for iOS'
s.description = <<-DESC
FRAuthenticator is a SDK that allows you easily and quickly develop an application with ForgeRock Platform for OATH and Push Authentication with AM. FRAuthenticator SDK provides interfaces and functionalities of HMAC-based OTP, Time-based OTP, Push Registration and Authentication with AM.
Expand All @@ -29,5 +29,5 @@ Pod::Spec.new do |s|

base_dir = "FRAuthenticator/FRAuthenticator"
s.source_files = base_dir + '/**/*.swift', base_dir + '/**/*.c', base_dir + '/**/*.h'
s.ios.dependency 'FRCore', '~> 3.4.0'
s.ios.dependency 'FRCore', '~> 3.4.1'
end
4 changes: 2 additions & 2 deletions FRAuthenticator/FRAuthenticator.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -1264,7 +1264,7 @@
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
MARKETING_VERSION = 3.4.0;
MARKETING_VERSION = 3.4.1;
MODULEMAP_FILE = "${PROJECT_DIR}/FRAuthenticator/SharedC/FRAuthenticator.modulemap";
OTHER_CFLAGS = "-DXCODE_FRAMEWORK=1";
PRODUCT_BUNDLE_IDENTIFIER = com.forgerock.ios.FRAuthenticator;
Expand Down Expand Up @@ -1293,7 +1293,7 @@
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
MARKETING_VERSION = 3.4.0;
MARKETING_VERSION = 3.4.1;
MODULEMAP_FILE = "${PROJECT_DIR}/FRAuthenticator/SharedC/FRAuthenticator.modulemap";
OTHER_CFLAGS = "-DXCODE_FRAMEWORK=1";
PRODUCT_BUNDLE_IDENTIFIER = com.forgerock.ios.FRAuthenticator;
Expand Down
4 changes: 2 additions & 2 deletions FRAuthenticator/FRAuthenticator/JWT/FRCompactJWT.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// FRCompactJWT.swift
// FRAuthenticator
//
// Copyright (c) 2020 ForgeRock. All rights reserved.
// Copyright (c) 2020-2022 ForgeRock. All rights reserved.
//
// This software may be modified and distributed under the terms
// of the MIT license. See the LICENSE file for details.
Expand Down Expand Up @@ -117,7 +117,7 @@ struct FRCompactJWT {
throw CryptoError.invalidJWT
}
var payloadStr = String(components[1])
payloadStr = payloadStr.base64Pad()
payloadStr = payloadStr.urlSafeDecoding().base64Pad()

guard let payloadData = Data(base64Encoded: payloadStr),
let payload = try? JSONSerialization.jsonObject(with: payloadData, options: []) as? [String: Any] else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,14 @@ public class PushNotification: NSObject, NSSecureCoding, Codable {
/// Boolean property indicating whether or not current Notification is still pending for approval
public var isPending: Bool {
get {
return self.pending && !self.isExpired
return self.pending
}
}

/// Boolean property indicating whether or not current Notification is expired
public var isExpired: Bool {
get {
return pending && ((Date().timeIntervalSince1970 - (self.timeAdded.timeIntervalSince1970 + self.ttl)) > 0)
return ((Date().timeIntervalSince1970 - (self.timeAdded.timeIntervalSince1970 + self.ttl)) > 0)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// FRCompactJWTTests.swift
// FRAuthenticatorTests
//
// Copyright (c) 2020 ForgeRock. All rights reserved.
// Copyright (c) 2020-2022 ForgeRock. All rights reserved.
//
// This software may be modified and distributed under the terms
// of the MIT license. See the LICENSE file for details.
Expand Down Expand Up @@ -193,4 +193,21 @@ class FRCompactJWTTests: FRABaseTests {
XCTFail("JWT extracting payload with invalid payload segment failed with unexpected error: \(error.localizedDescription)")
}
}

func test_10_extract_payload_with_extra_data() {
let jwt1 = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJwIjoieyAgfSIsImMiOiJ2TGhoaW9FNTIxVlcyYmNsNUM2aktERGp1bXk3Um01d2NwVkpYQllUY2ZFPSIsInQiOiIyMCIsInUiOiI0NkQ2QkUzQi02NTEyLTQ4QTQtODY4Ni1DQUIxQTkxNTZCNDQiLCJpIjoiMTY2Nzk0MDI3NDk0MiIsImsiOiJjaGFsbGVuZ2UiLCJsIjoiWVcxc1ltTnZiMnRwWlQwd01RPT0iLCJtIjoiRGlkIHlvdSB0cnkgdG8gbG9naW4_IiwibiI6IjUwLDYyLDg5In0.GXCMwE1VJTC1zVzLfBcSeiGEfPiY5i13lrtf6Fpwz6w"
let jwt2 = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJwIjoieyAgfSIsImMiOiJqK0NBWlhrUnlRdEdxdHljYmFMc3EwTWtjcFJZbU9SSzRhUzgyQWNlTWNrPSIsInQiOiIyMCIsInUiOiI0NkQ2QkUzQi02NTEyLTQ4QTQtODY4Ni1DQUIxQTkxNTZCNDQiLCJpIjoiMTY2Nzk0MTA5MTMwNiIsImsiOiJkZWZhdWx0IiwibCI6IllXMXNZbU52YjJ0cFpUMHdNUT09IiwibSI6IkRpZCB5b3UgdHJ5IHRvIGxvZ2luPyJ9.L2WjxnumzIgA9gpNN8p7onip0As5Rytb0RuOW8_sDWI"

do {
let payload1 = try FRCompactJWT.extractPayload(jwt: jwt1)
let payload2 = try FRCompactJWT.extractPayload(jwt: jwt2)

XCTAssertEqual(payload1.keys.count, 9)
XCTAssertEqual(payload2.keys.count, 8)

}
catch {
XCTFail("Failed to extract JWT payload: \(error.localizedDescription)")
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ class NotificationTests: FRABaseTests {
func test_07_1_notification_is_pending_with_interval() {
do {
let notification = try PushNotification(messageId: messageId, payload: payload)
XCTAssertFalse(notification.isPending)
XCTAssertTrue(notification.isPending)
XCTAssertFalse(notification.isDenied)
XCTAssertFalse(notification.isApproved)
}
Expand All @@ -195,7 +195,7 @@ class NotificationTests: FRABaseTests {
XCTAssertTrue(notification.isApproved)
XCTAssertFalse(notification.isDenied)
XCTAssertFalse(notification.isPending)
XCTAssertFalse(notification.isExpired)
XCTAssertTrue(notification.isExpired)
}
catch {
XCTFail("Failed with unexpected error: \(error.localizedDescription)")
Expand All @@ -211,7 +211,7 @@ class NotificationTests: FRABaseTests {
XCTAssertTrue(notification.isDenied)
XCTAssertFalse(notification.isPending)
XCTAssertFalse(notification.isApproved)
XCTAssertFalse(notification.isExpired)
XCTAssertTrue(notification.isExpired)
}
catch {
XCTFail("Failed with unexpected error: \(error.localizedDescription)")
Expand Down Expand Up @@ -249,6 +249,19 @@ class NotificationTests: FRABaseTests {
}
}

func test_09_2_notification_is_not_expired() {
do {
let notification = try PushNotification(messageId: messageId, payload: payload)
XCTAssertTrue(notification.isExpired)
let calendar = Calendar.current
let future = calendar.date(byAdding: .minute, value: 1, to: Date())
notification.timeAdded = future!
XCTAssertFalse(notification.isExpired)
}
catch {
XCTFail("Failed with unexpected error: \(error.localizedDescription)")
}
}

func test_10_notification_archive_obj() {
do {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
//

import XCTest
@testable import FRCore
@testable import FRAuthenticator

class PushNotificationAuthenticationTests: FRABaseTests {
Expand Down Expand Up @@ -292,6 +293,9 @@ class PushNotificationAuthenticationTests: FRABaseTests {


func test_07_push_notification_expired() {

self.loadMockResponses(["AM_Push_Authentication_Fail"])

let qrCode = URL(string: "pushauth://push/forgerock:pushdemouser1?a=aHR0cDovL29wZW5hbS5leGFtcGxlLmNvbTo4MDgxL29wZW5hbS9qc29uL3B1c2gvc25zL21lc3NhZ2U_X2FjdGlvbj1hdXRoZW50aWNhdGU&b=519387&r=aHR0cDovL29wZW5hbS5leGFtcGxlLmNvbTo4MDgxL29wZW5hbS9qc29uL3B1c2gvc25zL21lc3NhZ2U_X2FjdGlvbj1yZWdpc3Rlcg&s=O9JHEGfOsaZqc5JT0DHM5hYFA8jofohw5vAP0EpG4JU&c=75OQ3FXmzV99TPf0ihevFfB0s43XsxQ747sY6BopgME&l=YW1sYmNvb2tpZT0wMQ&m=REGISTER:fe6311ab-013e-4599-9c0e-4c4e2525199b1588721418483&issuer=Rm9yZ2VSb2NrU2FuZGJveA")!

do {
Expand All @@ -315,11 +319,11 @@ class PushNotificationAuthenticationTests: FRABaseTests {
ex.fulfill()
}) { (error) in
switch error {
case PushNotificationError.notificationInvalidStatus:
case NetworkError.apiRequestFailure(_, _, _):
break
default:
XCTFail("Push authentication is expected to failed with PushNotificationError.notificationInvalidStatus for expired status, but failed with different reason: \(error.localizedDescription)")
break
XCTFail("Push authentication is expected to failed for expired status, but failed with different reason: \(error.localizedDescription)")
break
}
ex.fulfill()
}
Expand Down
2 changes: 1 addition & 1 deletion FRCore.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

Pod::Spec.new do |s|
s.name = 'FRCore'
s.version = '3.4.0'
s.version = '3.4.1'
s.summary = 'ForgeRock Core SDK for iOS'
s.description = <<-DESC
FRCore is a SDK that allows you to consume some of core functionalities and security features built for FRAuth SDK.
Expand Down
4 changes: 2 additions & 2 deletions FRCore/FRCore.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -768,7 +768,7 @@
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
MARKETING_VERSION = 3.4.0;
MARKETING_VERSION = 3.4.1;
PRODUCT_BUNDLE_IDENTIFIER = com.forgerock.ios.FRCore;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SKIP_INSTALL = YES;
Expand All @@ -795,7 +795,7 @@
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
MARKETING_VERSION = 3.4.0;
MARKETING_VERSION = 3.4.1;
PRODUCT_BUNDLE_IDENTIFIER = com.forgerock.ios.FRCore;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SKIP_INSTALL = YES;
Expand Down
30 changes: 19 additions & 11 deletions FRCore/FRCore/Keychain/SecuredKey.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// SecuredKey.swift
// FRCore
//
// Copyright (c) 2020 - 2021 ForgeRock. All rights reserved.
// Copyright (c) 2020 - 2022 ForgeRock. All rights reserved.
//
// This software may be modified and distributed under the terms
// of the MIT license. See the LICENSE file for details.
Expand All @@ -22,7 +22,7 @@ public struct SecuredKey {
/// Public Key of SecuredKey
fileprivate var publicKey: SecKey
/// Algorithm to be used for encryption/decryption using SecuredKey
fileprivate let algorithm: SecKeyAlgorithm = .eciesEncryptionCofactorX963SHA256AESGCM
fileprivate let oldAlgorithm: SecKeyAlgorithm = .eciesEncryptionCofactorX963SHA256AESGCM

/// Validates whether SecuredKey using Secure Enclave is available on the device or not
public static func isAvailable() -> Bool {
Expand Down Expand Up @@ -161,15 +161,15 @@ public struct SecuredKey {

/// Encrypts Data object using SecuredKey object
/// - Parameter data: Encrypted Data object
public func encrypt(data: Data) -> Data? {
public func encrypt(data: Data, secAlgorithm: SecKeyAlgorithm = .eciesEncryptionCofactorVariableIVX963SHA256AESGCM) -> Data? {

guard SecKeyIsAlgorithmSupported(publicKey, .encrypt, algorithm) else {
Log.e("\(algorithm) is not supported on the device.")
guard SecKeyIsAlgorithmSupported(publicKey, .encrypt, secAlgorithm) else {
Log.e("\(secAlgorithm) is not supported on the device.")
return nil
}

var error: Unmanaged<CFError>?
let encryptedData = SecKeyCreateEncryptedData(publicKey, algorithm, data as CFData, &error) as Data?
let encryptedData = SecKeyCreateEncryptedData(publicKey, secAlgorithm, data as CFData, &error) as Data?
if let error = error {
Log.e("Failed to encrypt data: \(error)")
}
Expand All @@ -180,17 +180,25 @@ public struct SecuredKey {

/// Decrypts Data object using SecuredKey object
/// - Parameter data: Decrypted Data object
public func decrypt(data: Data) -> Data? {
public func decrypt(data: Data, secAlgorithm: SecKeyAlgorithm = .eciesEncryptionCofactorVariableIVX963SHA256AESGCM) -> Data? {

guard SecKeyIsAlgorithmSupported(privateKey, .decrypt, algorithm) else {
Log.e("\(algorithm) is not supported on the device.")
guard SecKeyIsAlgorithmSupported(privateKey, .decrypt, secAlgorithm) else {
Log.e("\(secAlgorithm) is not supported on the device.")
return nil
}

var error: Unmanaged<CFError>?
let decryptedData = SecKeyCreateDecryptedData(privateKey, algorithm, data as CFData, &error) as Data?
let decryptedData = SecKeyCreateDecryptedData(privateKey, secAlgorithm, data as CFData, &error) as Data?
if let error = error {
Log.e("Failed to decrypt data: \(error)")
Log.e("Failed to decrypt data - attempting Legacy Algorithm: \(error)")
var decryptError: Unmanaged<CFError>?
let decryptedData = SecKeyCreateDecryptedData(privateKey, oldAlgorithm, data as CFData, &decryptError) as Data?
if let decryptError = decryptError {
Log.e("Failed to decrypt data: \(decryptError)")
} else {
return decryptedData
}

}
return decryptedData
}
Expand Down
2 changes: 1 addition & 1 deletion FRCore/FRCore/Log/Log.swift
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ public class Log: NSObject {
// MARK: - Property

/// Current SDK version. We hard code it here as currently there is no other way to get it dinamically when used with SPM
public static let sdkVersion = "3.4.0"
public static let sdkVersion = "3.4.1"
/// Current LogLevel
static var logLevel: LogLevel = .none
/// Current Loggers to handle log entries
Expand Down
Loading

0 comments on commit a124cfd

Please sign in to comment.