Skip to content

Commit a124cfd

Browse files
authored
Merge pull request #170 from ForgeRock/develop
ForgeRock iOS SDK 3.4.1 Release
2 parents 20ebe11 + 3529d16 commit a124cfd

File tree

27 files changed

+159
-93
lines changed

27 files changed

+159
-93
lines changed

CHANGELOG.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
# Version 3.4.0
1+
# Version 3.4.1
2+
## [3.4.1]
3+
#### Changed
4+
- Updated legacy encryption algorithm for iOS SE [SDKS-1994]
5+
- Fixed an issue related to push notifications timeout [SDKS-2164]
6+
- Fixed an unexpected error occurring during the decoding of some push notifications [SDKS-2199]
7+
28
## [3.4.0]
39
#### Added
410
- Dynamic SDK Configuration [SDKS-1760]
@@ -8,7 +14,6 @@
814
- Fixed build errors on Xcode 14 [SDKS-2073]
915
- Fixed bug where the `state` parameter value was not verified upon calling the `Authorize` endpoint [SDKS-2077]
1016

11-
# Version 3.3.2
1217
## [3.3.2]
1318
#### Added
1419
- Interface for log management [SDKS-1863]

FRAuth.podspec

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
Pod::Spec.new do |s|
1010
s.name = 'FRAuth'
11-
s.version = '3.4.0'
11+
s.version = '3.4.1'
1212
s.summary = 'ForgeRock Auth SDK for iOS'
1313
s.description = <<-DESC
1414
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.
@@ -29,5 +29,5 @@ Pod::Spec.new do |s|
2929

3030
base_dir = "FRAuth/FRAuth"
3131
s.source_files = base_dir + '/**/*.swift', base_dir + '/**/*.c', base_dir + '/**/*.h'
32-
s.ios.dependency 'FRCore', '~> 3.4.0'
32+
s.ios.dependency 'FRCore', '~> 3.4.1'
3333
end

FRAuth/FRAuth.xcodeproj/project.pbxproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2132,7 +2132,7 @@
21322132
"@executable_path/Frameworks",
21332133
"@loader_path/Frameworks",
21342134
);
2135-
MARKETING_VERSION = 3.4.0;
2135+
MARKETING_VERSION = 3.4.1;
21362136
MODULEMAP_FILE = "${PROJECT_DIR}/FRAuth/SharedC/FRAuth.modulemap";
21372137
OTHER_CFLAGS = "-DXCODE_FRAMEWORK=1";
21382138
PRODUCT_BUNDLE_IDENTIFIER = com.forgerock.ios.FRAuth;
@@ -2166,7 +2166,7 @@
21662166
"@executable_path/Frameworks",
21672167
"@loader_path/Frameworks",
21682168
);
2169-
MARKETING_VERSION = 3.4.0;
2169+
MARKETING_VERSION = 3.4.1;
21702170
MODULEMAP_FILE = "${PROJECT_DIR}/FRAuth/SharedC/FRAuth.modulemap";
21712171
OTHER_CFLAGS = "-DXCODE_FRAMEWORK=1";
21722172
PRODUCT_BUNDLE_IDENTIFIER = com.forgerock.ios.FRAuth;

FRAuth/FRAuthTests/FRAuthSwiftTests/FRAuth/Cookie/CookieTests.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// CookieTests.swift
33
// FRAuthTests
44
//
5-
// Copyright (c) 2020 ForgeRock. All rights reserved.
5+
// Copyright (c) 2020-2022 ForgeRock. All rights reserved.
66
//
77
// This software may be modified and distributed under the terms
88
// of the MIT license. See the LICENSE file for details.
@@ -219,7 +219,7 @@ class CookieTests: FRAuthBaseTest {
219219
self.performLogin()
220220
let url = URL(string: "https://openam.example.com")!
221221

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

225225
guard let cookie = cookies.first, let frAuth = FRAuth.shared else {

FRAuth/FRAuthTests/FRAuthSwiftTests/FRAuth/Cookie/CookieValidationTests.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// CookieValidationTests.swift
33
// FRAuthTests
44
//
5-
// Copyright (c) 2020 ForgeRock. All rights reserved.
5+
// Copyright (c) 2020-2022 ForgeRock. All rights reserved.
66
//
77
// This software may be modified and distributed under the terms
88
// of the MIT license. See the LICENSE file for details.
@@ -202,7 +202,7 @@ class CookieValidationTests: FRAuthBaseTest {
202202

203203

204204
func test_10_cookie_is_expired_validation_not_expired() {
205-
let setCookie: [String: String] = ["Set-Cookie":"iPlanetDirectoryPro=token; Expires=Wed, 21 Oct 2022 01:00:00 GMT; Domain=openam.example.com"]
205+
let setCookie: [String: String] = ["Set-Cookie":"iPlanetDirectoryPro=token; Expires=Wed, 21 Oct 2032 01:00:00 GMT; Domain=openam.example.com"]
206206
let cookies = HTTPCookie.cookies(withResponseHeaderFields: setCookie, for: URL(string: "https://openam.example.com")!)
207207
guard let cookie = cookies.first else {
208208
XCTFail("Failed to parse Cookies from response header")

FRAuthenticator.podspec

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
Pod::Spec.new do |s|
1010
s.name = 'FRAuthenticator'
11-
s.version = '3.4.0'
11+
s.version = '3.4.1'
1212
s.summary = 'ForgeRock OTP/Push Authentication SDK for iOS'
1313
s.description = <<-DESC
1414
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.
@@ -29,5 +29,5 @@ Pod::Spec.new do |s|
2929

3030
base_dir = "FRAuthenticator/FRAuthenticator"
3131
s.source_files = base_dir + '/**/*.swift', base_dir + '/**/*.c', base_dir + '/**/*.h'
32-
s.ios.dependency 'FRCore', '~> 3.4.0'
32+
s.ios.dependency 'FRCore', '~> 3.4.1'
3333
end

FRAuthenticator/FRAuthenticator.xcodeproj/project.pbxproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1264,7 +1264,7 @@
12641264
"@executable_path/Frameworks",
12651265
"@loader_path/Frameworks",
12661266
);
1267-
MARKETING_VERSION = 3.4.0;
1267+
MARKETING_VERSION = 3.4.1;
12681268
MODULEMAP_FILE = "${PROJECT_DIR}/FRAuthenticator/SharedC/FRAuthenticator.modulemap";
12691269
OTHER_CFLAGS = "-DXCODE_FRAMEWORK=1";
12701270
PRODUCT_BUNDLE_IDENTIFIER = com.forgerock.ios.FRAuthenticator;
@@ -1293,7 +1293,7 @@
12931293
"@executable_path/Frameworks",
12941294
"@loader_path/Frameworks",
12951295
);
1296-
MARKETING_VERSION = 3.4.0;
1296+
MARKETING_VERSION = 3.4.1;
12971297
MODULEMAP_FILE = "${PROJECT_DIR}/FRAuthenticator/SharedC/FRAuthenticator.modulemap";
12981298
OTHER_CFLAGS = "-DXCODE_FRAMEWORK=1";
12991299
PRODUCT_BUNDLE_IDENTIFIER = com.forgerock.ios.FRAuthenticator;

FRAuthenticator/FRAuthenticator/JWT/FRCompactJWT.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// FRCompactJWT.swift
33
// FRAuthenticator
44
//
5-
// Copyright (c) 2020 ForgeRock. All rights reserved.
5+
// Copyright (c) 2020-2022 ForgeRock. All rights reserved.
66
//
77
// This software may be modified and distributed under the terms
88
// of the MIT license. See the LICENSE file for details.
@@ -117,7 +117,7 @@ struct FRCompactJWT {
117117
throw CryptoError.invalidJWT
118118
}
119119
var payloadStr = String(components[1])
120-
payloadStr = payloadStr.base64Pad()
120+
payloadStr = payloadStr.urlSafeDecoding().base64Pad()
121121

122122
guard let payloadData = Data(base64Encoded: payloadStr),
123123
let payload = try? JSONSerialization.jsonObject(with: payloadData, options: []) as? [String: Any] else {

FRAuthenticator/FRAuthenticator/Model/Notification/PushNotification.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,14 +57,14 @@ public class PushNotification: NSObject, NSSecureCoding, Codable {
5757
/// Boolean property indicating whether or not current Notification is still pending for approval
5858
public var isPending: Bool {
5959
get {
60-
return self.pending && !self.isExpired
60+
return self.pending
6161
}
6262
}
6363

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

FRAuthenticator/FRAuthenticatorTests/UnitTests/JWT/FRCompactJWTTests.swift

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// FRCompactJWTTests.swift
33
// FRAuthenticatorTests
44
//
5-
// Copyright (c) 2020 ForgeRock. All rights reserved.
5+
// Copyright (c) 2020-2022 ForgeRock. All rights reserved.
66
//
77
// This software may be modified and distributed under the terms
88
// of the MIT license. See the LICENSE file for details.
@@ -193,4 +193,21 @@ class FRCompactJWTTests: FRABaseTests {
193193
XCTFail("JWT extracting payload with invalid payload segment failed with unexpected error: \(error.localizedDescription)")
194194
}
195195
}
196+
197+
func test_10_extract_payload_with_extra_data() {
198+
let jwt1 = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJwIjoieyAgfSIsImMiOiJ2TGhoaW9FNTIxVlcyYmNsNUM2aktERGp1bXk3Um01d2NwVkpYQllUY2ZFPSIsInQiOiIyMCIsInUiOiI0NkQ2QkUzQi02NTEyLTQ4QTQtODY4Ni1DQUIxQTkxNTZCNDQiLCJpIjoiMTY2Nzk0MDI3NDk0MiIsImsiOiJjaGFsbGVuZ2UiLCJsIjoiWVcxc1ltTnZiMnRwWlQwd01RPT0iLCJtIjoiRGlkIHlvdSB0cnkgdG8gbG9naW4_IiwibiI6IjUwLDYyLDg5In0.GXCMwE1VJTC1zVzLfBcSeiGEfPiY5i13lrtf6Fpwz6w"
199+
let jwt2 = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJwIjoieyAgfSIsImMiOiJqK0NBWlhrUnlRdEdxdHljYmFMc3EwTWtjcFJZbU9SSzRhUzgyQWNlTWNrPSIsInQiOiIyMCIsInUiOiI0NkQ2QkUzQi02NTEyLTQ4QTQtODY4Ni1DQUIxQTkxNTZCNDQiLCJpIjoiMTY2Nzk0MTA5MTMwNiIsImsiOiJkZWZhdWx0IiwibCI6IllXMXNZbU52YjJ0cFpUMHdNUT09IiwibSI6IkRpZCB5b3UgdHJ5IHRvIGxvZ2luPyJ9.L2WjxnumzIgA9gpNN8p7onip0As5Rytb0RuOW8_sDWI"
200+
201+
do {
202+
let payload1 = try FRCompactJWT.extractPayload(jwt: jwt1)
203+
let payload2 = try FRCompactJWT.extractPayload(jwt: jwt2)
204+
205+
XCTAssertEqual(payload1.keys.count, 9)
206+
XCTAssertEqual(payload2.keys.count, 8)
207+
208+
}
209+
catch {
210+
XCTFail("Failed to extract JWT payload: \(error.localizedDescription)")
211+
}
212+
}
196213
}

FRAuthenticator/FRAuthenticatorTests/UnitTests/Model/NotificationTests.swift

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ class NotificationTests: FRABaseTests {
177177
func test_07_1_notification_is_pending_with_interval() {
178178
do {
179179
let notification = try PushNotification(messageId: messageId, payload: payload)
180-
XCTAssertFalse(notification.isPending)
180+
XCTAssertTrue(notification.isPending)
181181
XCTAssertFalse(notification.isDenied)
182182
XCTAssertFalse(notification.isApproved)
183183
}
@@ -195,7 +195,7 @@ class NotificationTests: FRABaseTests {
195195
XCTAssertTrue(notification.isApproved)
196196
XCTAssertFalse(notification.isDenied)
197197
XCTAssertFalse(notification.isPending)
198-
XCTAssertFalse(notification.isExpired)
198+
XCTAssertTrue(notification.isExpired)
199199
}
200200
catch {
201201
XCTFail("Failed with unexpected error: \(error.localizedDescription)")
@@ -211,7 +211,7 @@ class NotificationTests: FRABaseTests {
211211
XCTAssertTrue(notification.isDenied)
212212
XCTAssertFalse(notification.isPending)
213213
XCTAssertFalse(notification.isApproved)
214-
XCTAssertFalse(notification.isExpired)
214+
XCTAssertTrue(notification.isExpired)
215215
}
216216
catch {
217217
XCTFail("Failed with unexpected error: \(error.localizedDescription)")
@@ -249,6 +249,19 @@ class NotificationTests: FRABaseTests {
249249
}
250250
}
251251

252+
func test_09_2_notification_is_not_expired() {
253+
do {
254+
let notification = try PushNotification(messageId: messageId, payload: payload)
255+
XCTAssertTrue(notification.isExpired)
256+
let calendar = Calendar.current
257+
let future = calendar.date(byAdding: .minute, value: 1, to: Date())
258+
notification.timeAdded = future!
259+
XCTAssertFalse(notification.isExpired)
260+
}
261+
catch {
262+
XCTFail("Failed with unexpected error: \(error.localizedDescription)")
263+
}
264+
}
252265

253266
func test_10_notification_archive_obj() {
254267
do {

FRAuthenticator/FRAuthenticatorTests/UnitTests/Push/PushNotificationAuthenticationTests.swift

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
//
1010

1111
import XCTest
12+
@testable import FRCore
1213
@testable import FRAuthenticator
1314

1415
class PushNotificationAuthenticationTests: FRABaseTests {
@@ -292,6 +293,9 @@ class PushNotificationAuthenticationTests: FRABaseTests {
292293

293294

294295
func test_07_push_notification_expired() {
296+
297+
self.loadMockResponses(["AM_Push_Authentication_Fail"])
298+
295299
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")!
296300

297301
do {
@@ -315,11 +319,11 @@ class PushNotificationAuthenticationTests: FRABaseTests {
315319
ex.fulfill()
316320
}) { (error) in
317321
switch error {
318-
case PushNotificationError.notificationInvalidStatus:
322+
case NetworkError.apiRequestFailure(_, _, _):
319323
break
320324
default:
321-
XCTFail("Push authentication is expected to failed with PushNotificationError.notificationInvalidStatus for expired status, but failed with different reason: \(error.localizedDescription)")
322-
break
325+
XCTFail("Push authentication is expected to failed for expired status, but failed with different reason: \(error.localizedDescription)")
326+
break
323327
}
324328
ex.fulfill()
325329
}

FRCore.podspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
Pod::Spec.new do |s|
1010
s.name = 'FRCore'
11-
s.version = '3.4.0'
11+
s.version = '3.4.1'
1212
s.summary = 'ForgeRock Core SDK for iOS'
1313
s.description = <<-DESC
1414
FRCore is a SDK that allows you to consume some of core functionalities and security features built for FRAuth SDK.

FRCore/FRCore.xcodeproj/project.pbxproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -768,7 +768,7 @@
768768
"@executable_path/Frameworks",
769769
"@loader_path/Frameworks",
770770
);
771-
MARKETING_VERSION = 3.4.0;
771+
MARKETING_VERSION = 3.4.1;
772772
PRODUCT_BUNDLE_IDENTIFIER = com.forgerock.ios.FRCore;
773773
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
774774
SKIP_INSTALL = YES;
@@ -795,7 +795,7 @@
795795
"@executable_path/Frameworks",
796796
"@loader_path/Frameworks",
797797
);
798-
MARKETING_VERSION = 3.4.0;
798+
MARKETING_VERSION = 3.4.1;
799799
PRODUCT_BUNDLE_IDENTIFIER = com.forgerock.ios.FRCore;
800800
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
801801
SKIP_INSTALL = YES;

FRCore/FRCore/Keychain/SecuredKey.swift

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// SecuredKey.swift
33
// FRCore
44
//
5-
// Copyright (c) 2020 - 2021 ForgeRock. All rights reserved.
5+
// Copyright (c) 2020 - 2022 ForgeRock. All rights reserved.
66
//
77
// This software may be modified and distributed under the terms
88
// of the MIT license. See the LICENSE file for details.
@@ -22,7 +22,7 @@ public struct SecuredKey {
2222
/// Public Key of SecuredKey
2323
fileprivate var publicKey: SecKey
2424
/// Algorithm to be used for encryption/decryption using SecuredKey
25-
fileprivate let algorithm: SecKeyAlgorithm = .eciesEncryptionCofactorX963SHA256AESGCM
25+
fileprivate let oldAlgorithm: SecKeyAlgorithm = .eciesEncryptionCofactorX963SHA256AESGCM
2626

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

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

166-
guard SecKeyIsAlgorithmSupported(publicKey, .encrypt, algorithm) else {
167-
Log.e("\(algorithm) is not supported on the device.")
166+
guard SecKeyIsAlgorithmSupported(publicKey, .encrypt, secAlgorithm) else {
167+
Log.e("\(secAlgorithm) is not supported on the device.")
168168
return nil
169169
}
170170

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

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

185-
guard SecKeyIsAlgorithmSupported(privateKey, .decrypt, algorithm) else {
186-
Log.e("\(algorithm) is not supported on the device.")
185+
guard SecKeyIsAlgorithmSupported(privateKey, .decrypt, secAlgorithm) else {
186+
Log.e("\(secAlgorithm) is not supported on the device.")
187187
return nil
188188
}
189189

190190
var error: Unmanaged<CFError>?
191-
let decryptedData = SecKeyCreateDecryptedData(privateKey, algorithm, data as CFData, &error) as Data?
191+
let decryptedData = SecKeyCreateDecryptedData(privateKey, secAlgorithm, data as CFData, &error) as Data?
192192
if let error = error {
193-
Log.e("Failed to decrypt data: \(error)")
193+
Log.e("Failed to decrypt data - attempting Legacy Algorithm: \(error)")
194+
var decryptError: Unmanaged<CFError>?
195+
let decryptedData = SecKeyCreateDecryptedData(privateKey, oldAlgorithm, data as CFData, &decryptError) as Data?
196+
if let decryptError = decryptError {
197+
Log.e("Failed to decrypt data: \(decryptError)")
198+
} else {
199+
return decryptedData
200+
}
201+
194202
}
195203
return decryptedData
196204
}

FRCore/FRCore/Log/Log.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ public class Log: NSObject {
129129
// MARK: - Property
130130

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

0 commit comments

Comments
 (0)