From aaac61c0c382be2654a4571cb81075d1e892b2bc Mon Sep 17 00:00:00 2001 From: Sergey Demchenko Date: Tue, 20 Feb 2024 16:58:24 -0800 Subject: [PATCH 01/41] Enable gettoken and signout browser sso operations. --- .../MSIDBrowserNativeMessageGetTokenRequest.m | 2 +- .../MSIDBrowserNativeMessageSignOutRequest.m | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/IdentityCore/src/broker_operation/request/browser_native_message_request/MSIDBrowserNativeMessageGetTokenRequest.m b/IdentityCore/src/broker_operation/request/browser_native_message_request/MSIDBrowserNativeMessageGetTokenRequest.m index 0f31c9ba8..ca908d360 100644 --- a/IdentityCore/src/broker_operation/request/browser_native_message_request/MSIDBrowserNativeMessageGetTokenRequest.m +++ b/IdentityCore/src/broker_operation/request/browser_native_message_request/MSIDBrowserNativeMessageGetTokenRequest.m @@ -48,7 +48,7 @@ @implementation MSIDBrowserNativeMessageGetTokenRequest + (void)load { -// [MSIDJsonSerializableFactory registerClass:self forClassType:self.operation]; + [MSIDJsonSerializableFactory registerClass:self forClassType:self.operation]; } + (NSString *)operation diff --git a/IdentityCore/src/broker_operation/request/browser_native_message_request/MSIDBrowserNativeMessageSignOutRequest.m b/IdentityCore/src/broker_operation/request/browser_native_message_request/MSIDBrowserNativeMessageSignOutRequest.m index 3f0372f94..0fb0f37af 100644 --- a/IdentityCore/src/broker_operation/request/browser_native_message_request/MSIDBrowserNativeMessageSignOutRequest.m +++ b/IdentityCore/src/broker_operation/request/browser_native_message_request/MSIDBrowserNativeMessageSignOutRequest.m @@ -32,7 +32,7 @@ @implementation MSIDBrowserNativeMessageSignOutRequest + (void)load { -// [MSIDJsonSerializableFactory registerClass:self forClassType:self.operation]; + [MSIDJsonSerializableFactory registerClass:self forClassType:self.operation]; } + (NSString *)operation From 17aa11f19d7f3de82ad96a830b41abdc9c04136b Mon Sep 17 00:00:00 2001 From: Juan Arias Roldan <1686668+juan-arias@users.noreply.github.com> Date: Fri, 15 Mar 2024 15:31:35 -0700 Subject: [PATCH 02/41] Add new error code when SSO ext config doesn't contain valid Error Handling config --- IdentityCore/src/MSIDError.h | 3 +++ IdentityCore/src/MSIDError.m | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/IdentityCore/src/MSIDError.h b/IdentityCore/src/MSIDError.h index db3bbf5a0..cef8d7439 100644 --- a/IdentityCore/src/MSIDError.h +++ b/IdentityCore/src/MSIDError.h @@ -323,6 +323,9 @@ typedef NS_ENUM(NSInteger, MSIDErrorCode) // In PSSO, KeyId stored in passkey provider storage does not match NGC key, needs to configure and retry MSIDErrorPSSOKeyIdMismatch = -51838, + // JIT - Error Handling config invalid or not found + MSIDErrorJITErrorHandlingConfigNotFound = -51839, + // Throttling errors MSIDErrorThrottleCacheNoRecord = -51900, MSIDErrorThrottleCacheInvalidSignature = -51901, diff --git a/IdentityCore/src/MSIDError.m b/IdentityCore/src/MSIDError.m index 3c6265667..83183c789 100644 --- a/IdentityCore/src/MSIDError.m +++ b/IdentityCore/src/MSIDError.m @@ -197,6 +197,7 @@ MSIDErrorCode MSIDErrorCodeForOAuthErrorWithSubErrorCode(NSString *oauthError, M @(MSIDErrorJITTroubleshootingAcquireToken), @(MSIDErrorDeviceNotPSSORegistered), @(MSIDErrorPSSOKeyIdMismatch), + @(MSIDErrorJITErrorHandlingConfigNotFound), ], MSIDOAuthErrorDomain : @[// Server Errors @@ -397,6 +398,9 @@ void MSIDFillAndLogError(NSError **error, MSIDErrorCode errorCode, NSString *err return @"MSIDErrorJITTroubleshootingResultUnknown"; case MSIDErrorJITTroubleshootingAcquireToken: return @"MSIDErrorJITTroubleshootingAcquireToken"; + case MSIDErrorJITErrorHandlingConfigNotFound: + return @"MSIDErrorJITErrorHandlingConfigNotFound"; + // PSSO errors case MSIDErrorDeviceNotPSSORegistered: return @"MSIDErrorDeviceNotPSSORegistered"; case MSIDErrorPSSOKeyIdMismatch: From eb5e2f1dcac3469755ad46c78b6eaef5f5e72f1d Mon Sep 17 00:00:00 2001 From: Juan Arias Roldan <1686668+juan-arias@users.noreply.github.com> Date: Wed, 20 Mar 2024 12:15:57 -0700 Subject: [PATCH 03/41] Update unit tests after changes on NSURL URLWithString on iOS 17 --- IdentityCore/tests/MSIDURLExtensionsTests.m | 21 ++++++++++++++----- IdentityCore/tests/util/MSIDTestIdentifiers.h | 2 +- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/IdentityCore/tests/MSIDURLExtensionsTests.m b/IdentityCore/tests/MSIDURLExtensionsTests.m index 64bcafd03..bf0348075 100644 --- a/IdentityCore/tests/MSIDURLExtensionsTests.m +++ b/IdentityCore/tests/MSIDURLExtensionsTests.m @@ -45,16 +45,27 @@ - (void)tearDown //which should have been handled by the NSURL class - (void)testFragmentParameters { + NSDictionary* empty = [NSDictionary new]; + //Missing or invalid fragment: XCTAssertNil(((NSURL*)[NSURL URLWithString:@"https://stuff.com"]).msidFragmentParameters); XCTAssertNil(((NSURL*)[NSURL URLWithString:@"https://stuff.com?foo=bar"]).msidFragmentParameters); - XCTAssertNil(((NSURL*)[NSURL URLWithString:@"https://stuff.com#bar=foo#"]).msidFragmentParameters); - XCTAssertNil(((NSURL*)[NSURL URLWithString:@"https://stuff.com?foo=bar#bar=foo#foo=bar"]).msidFragmentParameters); - XCTAssertNil(((NSURL*)[NSURL URLWithString:@"https://stuff.com?foo=bar#bar=foo#foo=bar#"]).msidFragmentParameters); - XCTAssertNil(((NSURL*)[NSURL URLWithString:@"https://stuff.com?foo=bar# "]).msidFragmentParameters); + if (@available(iOS 17.0, *)) + { + XCTAssertEqualObjects(@{@"bar":@"foo#"}, ((NSURL*)[NSURL URLWithString:@"https://stuff.com#bar=foo#"]).msidFragmentParameters); + XCTAssertEqualObjects(empty, ((NSURL*)[NSURL URLWithString:@"https://stuff.com?foo=bar#bar=foo#foo=bar"]).msidFragmentParameters); + XCTAssertEqualObjects(empty, ((NSURL*)[NSURL URLWithString:@"https://stuff.com?foo=bar#bar=foo#foo=bar#"]).msidFragmentParameters); + XCTAssertEqualObjects(empty, ((NSURL*)[NSURL URLWithString:@"https://stuff.com?foo=bar# "]).msidFragmentParameters); + } + else + { + XCTAssertNil(((NSURL*)[NSURL URLWithString:@"https://stuff.com#bar=foo#"]).msidFragmentParameters); + XCTAssertNil(((NSURL*)[NSURL URLWithString:@"https://stuff.com?foo=bar#bar=foo#foo=bar"]).msidFragmentParameters); + XCTAssertNil(((NSURL*)[NSURL URLWithString:@"https://stuff.com?foo=bar#bar=foo#foo=bar#"]).msidFragmentParameters); + XCTAssertNil(((NSURL*)[NSURL URLWithString:@"https://stuff.com?foo=bar# "]).msidFragmentParameters); + } //Valid fragment, but missing/invalid configuration: - NSDictionary* empty = [NSDictionary new]; XCTAssertEqualObjects(@{@"bar":@""}, ((NSURL*)[NSURL URLWithString:@"https://stuff.com#bar"]).msidFragmentParameters); XCTAssertEqualObjects(@{@"bar":@""}, ((NSURL*)[NSURL URLWithString:@"https://stuff.com?foo=bar#bar"]).msidFragmentParameters); XCTAssertEqualObjects(empty, ((NSURL*)[NSURL URLWithString:@"https://stuff.com?foo=bar#bar=foo=bar"]).msidFragmentParameters); diff --git a/IdentityCore/tests/util/MSIDTestIdentifiers.h b/IdentityCore/tests/util/MSIDTestIdentifiers.h index 3206b00f1..0657903e8 100644 --- a/IdentityCore/tests/util/MSIDTestIdentifiers.h +++ b/IdentityCore/tests/util/MSIDTestIdentifiers.h @@ -40,6 +40,6 @@ #define DEFAULT_TEST_ID_TOKEN @"id_token" #define DEFAULT_TEST_FAMILY_ID @"family" #define DEFAULT_TEST_ID_TOKEN_SUBJECT @"sub" -#define DEFAULT_TEST_REDIRECT_SCHEME @"msid"DEFAULT_TEST_CLIENT_ID +#define DEFAULT_TEST_REDIRECT_SCHEME @"msidtest-client-id" #define DEFAULT_TEST_REDIRECT_URI DEFAULT_TEST_REDIRECT_SCHEME"://auth" #define DEFAULT_TEST_SLICE_PARAMS_DICT @{ @"slice" : @"myslice" } From 9051aaa4ab5f98bf250184f0c9d72c73d8c7c41d Mon Sep 17 00:00:00 2001 From: Juan Arias Roldan <1686668+juan-arias@users.noreply.github.com> Date: Thu, 21 Mar 2024 10:41:38 -0700 Subject: [PATCH 04/41] Apply the change to macOS 14+ as well. --- IdentityCore/tests/MSIDURLExtensionsTests.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IdentityCore/tests/MSIDURLExtensionsTests.m b/IdentityCore/tests/MSIDURLExtensionsTests.m index bf0348075..ba6f79829 100644 --- a/IdentityCore/tests/MSIDURLExtensionsTests.m +++ b/IdentityCore/tests/MSIDURLExtensionsTests.m @@ -50,7 +50,7 @@ - (void)testFragmentParameters //Missing or invalid fragment: XCTAssertNil(((NSURL*)[NSURL URLWithString:@"https://stuff.com"]).msidFragmentParameters); XCTAssertNil(((NSURL*)[NSURL URLWithString:@"https://stuff.com?foo=bar"]).msidFragmentParameters); - if (@available(iOS 17.0, *)) + if (@available(iOS 17.0, macOS 14.0, *)) { XCTAssertEqualObjects(@{@"bar":@"foo#"}, ((NSURL*)[NSURL URLWithString:@"https://stuff.com#bar=foo#"]).msidFragmentParameters); XCTAssertEqualObjects(empty, ((NSURL*)[NSURL URLWithString:@"https://stuff.com?foo=bar#bar=foo#foo=bar"]).msidFragmentParameters); From 01a2a265e92b3feb270b872a95fbb4f3d2a9f96b Mon Sep 17 00:00:00 2001 From: kaisong1990 Date: Thu, 4 Apr 2024 15:57:11 -0700 Subject: [PATCH 05/41] init commit --- .../IdentityCore.xcodeproj/project.pbxproj | 10 ++++ IdentityCore/src/MSIDConstants.h | 1 + .../MSIDAuthenticationSchemeSshCert.h | 34 ++++++++++++ .../MSIDAuthenticationSchemeSshCert.m | 52 +++++++++++++++++++ IdentityCore/src/util/MSIDAuthScheme.m | 2 + 5 files changed, 99 insertions(+) create mode 100644 IdentityCore/src/auth_scheme/MSIDAuthenticationSchemeSshCert.h create mode 100644 IdentityCore/src/auth_scheme/MSIDAuthenticationSchemeSshCert.m diff --git a/IdentityCore/IdentityCore.xcodeproj/project.pbxproj b/IdentityCore/IdentityCore.xcodeproj/project.pbxproj index bb1d3c994..3c1344672 100644 --- a/IdentityCore/IdentityCore.xcodeproj/project.pbxproj +++ b/IdentityCore/IdentityCore.xcodeproj/project.pbxproj @@ -517,6 +517,9 @@ 58543C8B24930FBC00F7AC14 /* MSIDMacKeychainTokenCache+Test.h in Headers */ = {isa = PBXBuildFile; fileRef = 58543C8A24930FBC00F7AC14 /* MSIDMacKeychainTokenCache+Test.h */; }; 586CD77E293FD77100550710 /* MSIDRequestControllerFactoryTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 586CD77B293FD76100550710 /* MSIDRequestControllerFactoryTests.m */; }; 586CD77F293FD77200550710 /* MSIDRequestControllerFactoryTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 586CD77B293FD76100550710 /* MSIDRequestControllerFactoryTests.m */; }; + 5887EBF12BBF6490005F9634 /* MSIDAuthenticationSchemeSshCert.h in Headers */ = {isa = PBXBuildFile; fileRef = 5887EBEF2BBF6490005F9634 /* MSIDAuthenticationSchemeSshCert.h */; }; + 5887EBF22BBF6490005F9634 /* MSIDAuthenticationSchemeSshCert.m in Sources */ = {isa = PBXBuildFile; fileRef = 5887EBF02BBF6490005F9634 /* MSIDAuthenticationSchemeSshCert.m */; }; + 5887EBF32BBF6490005F9634 /* MSIDAuthenticationSchemeSshCert.m in Sources */ = {isa = PBXBuildFile; fileRef = 5887EBF02BBF6490005F9634 /* MSIDAuthenticationSchemeSshCert.m */; }; 589842472525447B0075DFED /* MSIDAccountMetadataCacheMockRemoveAccountMetadataForHomeAccountIdParams.m in Sources */ = {isa = PBXBuildFile; fileRef = 5898422025253FE00075DFED /* MSIDAccountMetadataCacheMockRemoveAccountMetadataForHomeAccountIdParams.m */; }; 58984254252544850075DFED /* MSIDAccountMetadataCacheMockRemoveAccountMetadataForHomeAccountIdParams.m in Sources */ = {isa = PBXBuildFile; fileRef = 5898422025253FE00075DFED /* MSIDAccountMetadataCacheMockRemoveAccountMetadataForHomeAccountIdParams.m */; }; 5898426D2525448A0075DFED /* MSIDAccountMetadataCacheMockUpdatePrincipalAccountIdParams.m in Sources */ = {isa = PBXBuildFile; fileRef = 5898421025253F050075DFED /* MSIDAccountMetadataCacheMockUpdatePrincipalAccountIdParams.m */; }; @@ -2344,6 +2347,8 @@ 585337DF272775110080935B /* MSIDSSOExtensionGetDataBaseRequest+Internal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "MSIDSSOExtensionGetDataBaseRequest+Internal.h"; sourceTree = ""; }; 58543C8A24930FBC00F7AC14 /* MSIDMacKeychainTokenCache+Test.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "MSIDMacKeychainTokenCache+Test.h"; sourceTree = ""; }; 586CD77B293FD76100550710 /* MSIDRequestControllerFactoryTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSIDRequestControllerFactoryTests.m; sourceTree = ""; }; + 5887EBEF2BBF6490005F9634 /* MSIDAuthenticationSchemeSshCert.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSIDAuthenticationSchemeSshCert.h; sourceTree = ""; }; + 5887EBF02BBF6490005F9634 /* MSIDAuthenticationSchemeSshCert.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSIDAuthenticationSchemeSshCert.m; sourceTree = ""; }; 589841EF25253DF30075DFED /* MSIDAccountMetadataCacheMockUpdateAuthorityParameters.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSIDAccountMetadataCacheMockUpdateAuthorityParameters.h; sourceTree = ""; }; 589841F025253DF30075DFED /* MSIDAccountMetadataCacheMockUpdateAuthorityParameters.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSIDAccountMetadataCacheMockUpdateAuthorityParameters.m; sourceTree = ""; }; 589841FF25253E9F0075DFED /* MSIDAccountMetadataCacheMockGetAuthorityParameters.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSIDAccountMetadataCacheMockGetAuthorityParameters.h; sourceTree = ""; }; @@ -3425,6 +3430,8 @@ 1E36589A247EF3260044A072 /* MSIDAuthenticationSchemePop.m */, 1E5319A624A425B7007BCF30 /* MSIDAuthenticationScheme.h */, 1E5319A724A425B7007BCF30 /* MSIDAuthenticationScheme.m */, + 5887EBEF2BBF6490005F9634 /* MSIDAuthenticationSchemeSshCert.h */, + 5887EBF02BBF6490005F9634 /* MSIDAuthenticationSchemeSshCert.m */, ); path = auth_scheme; sourceTree = ""; @@ -5912,6 +5919,7 @@ B20657C81FC926AE00412B7D /* MSIDTelemetryHttpEvent.h in Headers */, 23B39A7E20990E5E000AA905 /* MSIDAuthorityResolving.h in Headers */, 58E2A1FC24E497400027A28A /* MSIDWebResponseOperationConstants.h in Headers */, + 5887EBF12BBF6490005F9634 /* MSIDAuthenticationSchemeSshCert.h in Headers */, B2AF1D2E218BCEDE0080C1A0 /* MSIDInteractiveTokenRequest.h in Headers */, 1E707FE22407337300716148 /* MSIDBrokerOperationResponse.h in Headers */, B251CC48204105A7005E0179 /* MSIDBaseToken.h in Headers */, @@ -6932,6 +6940,7 @@ 2352AF342AA7C7B700FA2253 /* MSIDBrowserNativeMessageGetTokenResponse.m in Sources */, 589BDB292718F18800BF3799 /* MSIDCredentialHeader.m in Sources */, B25A356F1FC4D70300C7FD43 /* MSIDLogger.m in Sources */, + 5887EBF32BBF6490005F9634 /* MSIDAuthenticationSchemeSshCert.m in Sources */, B2C7088F2198E48E00D917B8 /* NSData+AES.m in Sources */, 96F21B3320A65896002B87C3 /* MSIDWebviewAuthorization.m in Sources */, B27893832470CFE700627C28 /* MSIDAssymetricKeyGeneratorFactory.m in Sources */, @@ -7820,6 +7829,7 @@ B239564927A8DF6B00684CA5 /* MSIDWPJKeyPairWithCert.m in Sources */, 58BC23BD271F6B9D008A77BE /* MSIDSSOExtensionGetDataBaseRequest.m in Sources */, 2371A6192A4BAB43008A71F3 /* MSIDBrowserNativeMessageGetCookiesResponse.m in Sources */, + 5887EBF22BBF6490005F9634 /* MSIDAuthenticationSchemeSshCert.m in Sources */, B297E1DD20A0F5D600F370EC /* MSIDDefaultCredentialCacheQuery.m in Sources */, 60A504702374917B00648AC5 /* MSIDBrokerOperationGetAccountsResponse.m in Sources */, 1E37AAD4252196CC00EBED3B /* NSData+JWT.m in Sources */, diff --git a/IdentityCore/src/MSIDConstants.h b/IdentityCore/src/MSIDConstants.h index bffc35e62..039633f29 100644 --- a/IdentityCore/src/MSIDConstants.h +++ b/IdentityCore/src/MSIDConstants.h @@ -83,6 +83,7 @@ typedef NS_ENUM(NSInteger, MSIDAuthScheme) { MSIDAuthSchemeBearer, MSIDAuthSchemePop, + MSIDAuthSchemeSshCert, }; typedef NS_ENUM(NSInteger, MSIDHeaderType) diff --git a/IdentityCore/src/auth_scheme/MSIDAuthenticationSchemeSshCert.h b/IdentityCore/src/auth_scheme/MSIDAuthenticationSchemeSshCert.h new file mode 100644 index 000000000..6a9667979 --- /dev/null +++ b/IdentityCore/src/auth_scheme/MSIDAuthenticationSchemeSshCert.h @@ -0,0 +1,34 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import "MSIDAuthenticationScheme.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface MSIDAuthenticationSchemeSshCert : MSIDAuthenticationScheme + +@end + +NS_ASSUME_NONNULL_END diff --git a/IdentityCore/src/auth_scheme/MSIDAuthenticationSchemeSshCert.m b/IdentityCore/src/auth_scheme/MSIDAuthenticationSchemeSshCert.m new file mode 100644 index 000000000..af07de3f9 --- /dev/null +++ b/IdentityCore/src/auth_scheme/MSIDAuthenticationSchemeSshCert.m @@ -0,0 +1,52 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import "MSIDAuthenticationSchemeSshCert.h" +#import "MSIDJsonSerializableFactory.h" +#import "MSIDAuthScheme.h" + +@implementation MSIDAuthenticationSchemeSshCert + ++ (void)load +{ + [MSIDJsonSerializableFactory registerClass:self forClassType:MSIDAuthSchemeParamFromType(MSIDAuthSchemeSshCert)]; +} + +- (MSIDCredentialType)credentialType +{ + return MSIDCredentialTypeOther; +} + +- (NSString *)tokenType +{ + return MSIDAuthSchemeParamFromType(self.authScheme); +} + +- (MSIDAuthScheme)authSchemeFromParameters:(__unused NSDictionary *)schemeParameters +{ + return MSIDAuthSchemeSshCert; +} + +@end diff --git a/IdentityCore/src/util/MSIDAuthScheme.m b/IdentityCore/src/util/MSIDAuthScheme.m index 6de924d2b..86d3b416b 100644 --- a/IdentityCore/src/util/MSIDAuthScheme.m +++ b/IdentityCore/src/util/MSIDAuthScheme.m @@ -30,6 +30,8 @@ return @"Pop"; case MSIDAuthSchemeBearer: return @"Bearer"; + case MSIDAuthSchemeSshCert: + return @"SshCert"; default: return @"Bearer"; } From 555fe742e090380cbc9532cb1dbf0a072a67a593 Mon Sep 17 00:00:00 2001 From: kaisong1990 Date: Fri, 5 Apr 2024 15:43:40 -0700 Subject: [PATCH 06/41] Add new ssh_cert scheme --- .../MSIDAuthenticationSchemeSshCert.m | 101 ++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/IdentityCore/src/auth_scheme/MSIDAuthenticationSchemeSshCert.m b/IdentityCore/src/auth_scheme/MSIDAuthenticationSchemeSshCert.m index af07de3f9..4c6caff45 100644 --- a/IdentityCore/src/auth_scheme/MSIDAuthenticationSchemeSshCert.m +++ b/IdentityCore/src/auth_scheme/MSIDAuthenticationSchemeSshCert.m @@ -27,6 +27,13 @@ #import "MSIDJsonSerializableFactory.h" #import "MSIDAuthScheme.h" +@interface MSIDAuthenticationSchemeSshCert() + +@property (nonatomic) NSString *keyId; +@property (nonatomic) NSString *req_cnf; + +@end + @implementation MSIDAuthenticationSchemeSshCert + (void)load @@ -34,6 +41,36 @@ + (void)load [MSIDJsonSerializableFactory registerClass:self forClassType:MSIDAuthSchemeParamFromType(MSIDAuthSchemeSshCert)]; } +- (instancetype)initWithSchemeParameters:(NSDictionary *)schemeParameters +{ + self = [super initWithSchemeParameters:schemeParameters]; + + if (self) + { + if (_authScheme != MSIDAuthSchemeSshCert) + { + MSID_LOG_WITH_CTX(MSIDLogLevelError, nil, @"Wrong token_type string"); + return nil; + } + + _req_cnf = [_schemeParameters msidObjectForKey:MSID_OAUTH2_REQUEST_CONFIRMATION ofClass:[NSString class]]; + if ([NSString msidIsStringNilOrBlank:_req_cnf]) + { + MSID_LOG_WITH_CTX(MSIDLogLevelError, nil, @"Failed to read req_cnf from scheme parameters."); + return nil; + } + + _keyId = [_schemeParameters msidObjectForKey:@"key_id" ofClass:[NSString class]]; + if ([NSString msidIsStringNilOrBlank:_keyId]) + { + MSID_LOG_WITH_CTX(MSIDLogLevelError, nil, @"Failed to read _keyId from scheme parameters."); + return nil; + } + } + + return self; +} + - (MSIDCredentialType)credentialType { return MSIDCredentialTypeOther; @@ -49,4 +86,68 @@ - (MSIDAuthScheme)authSchemeFromParameters:(__unused NSDictionary *)schemeParame return MSIDAuthSchemeSshCert; } +- (instancetype)initWithJSONDictionary:(NSDictionary *)json error:(NSError **)error +{ + NSMutableDictionary *schemeParameters = [NSMutableDictionary new]; + NSString *requestConf = json[MSID_OAUTH2_REQUEST_CONFIRMATION]; + if ([NSString msidIsStringNilOrBlank:requestConf]) + { + NSString *message = [NSString stringWithFormat:@"Failed to init %@ from json: req_cnf is nil", self.class]; + if (error) *error = MSIDCreateError(MSIDErrorDomain, MSIDErrorInvalidInternalParameter, message, nil, nil, nil, nil, nil, YES); + return nil; + } + + NSString *authScheme = json[MSID_OAUTH2_TOKEN_TYPE]; + if ([NSString msidIsStringNilOrBlank:authScheme]) + { + NSString *message = [NSString stringWithFormat:@"Failed to init %@ from json: auth_scheme is nil", self.class]; + if (error) *error = MSIDCreateError(MSIDErrorDomain, MSIDErrorInvalidInternalParameter, message, nil, nil, nil, nil, nil, YES); + return nil; + } + + NSString *keyId = json[@"keyId"]; + if ([NSString msidIsStringNilOrBlank:authScheme]) + { + NSString *message = [NSString stringWithFormat:@"Failed to init %@ from json: key_id is nil", self.class]; + if (error) *error = MSIDCreateError(MSIDErrorDomain, MSIDErrorInvalidInternalParameter, message, nil, nil, nil, nil, nil, YES); + return nil; + } + + [schemeParameters setObject:keyId forKey:@"keyId"]; + [schemeParameters setObject:requestConf forKey:MSID_OAUTH2_REQUEST_CONFIRMATION]; + [schemeParameters setObject:authScheme forKey:MSID_OAUTH2_TOKEN_TYPE]; + + return [self initWithSchemeParameters:schemeParameters]; +} + +- (NSDictionary *)jsonDictionary +{ + NSMutableDictionary *json = [NSMutableDictionary new]; + if (self.authScheme != MSIDAuthSchemeSshCert) + { + MSID_LOG_WITH_CTX(MSIDLogLevelError, nil, @"Failed to create json for %@: invalid auth_scheme.", self.class); + return nil; + } + + json[MSID_OAUTH2_TOKEN_TYPE] = MSIDAuthSchemeParamFromType(self.authScheme); + + if ([NSString msidIsStringNilOrBlank:self.req_cnf]) + { + MSID_LOG_WITH_CTX(MSIDLogLevelError, nil, @"Failed to create json for %@: req_cnf is nil.", self.class); + return nil; + } + + json[MSID_OAUTH2_REQUEST_CONFIRMATION] = self.req_cnf; + + if ([NSString msidIsStringNilOrBlank:self.keyId]) + { + MSID_LOG_WITH_CTX(MSIDLogLevelError, nil, @"Failed to create json for %@: req_cnf is nil.", self.class); + return nil; + } + + json[@"key_id"] = self.keyId; + + return json; +} + @end From b7b284ff98dbc9654d59669b9ef5030d2203bfb6 Mon Sep 17 00:00:00 2001 From: kaisong1990 Date: Fri, 5 Apr 2024 17:25:34 -0700 Subject: [PATCH 07/41] Correct auth_scheme mapping --- .../auth_scheme/MSIDAuthenticationSchemeSshCert.m | 12 ++++++++++-- IdentityCore/src/util/MSIDAuthScheme.m | 6 +++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/IdentityCore/src/auth_scheme/MSIDAuthenticationSchemeSshCert.m b/IdentityCore/src/auth_scheme/MSIDAuthenticationSchemeSshCert.m index 4c6caff45..7ab2b6a60 100644 --- a/IdentityCore/src/auth_scheme/MSIDAuthenticationSchemeSshCert.m +++ b/IdentityCore/src/auth_scheme/MSIDAuthenticationSchemeSshCert.m @@ -105,7 +105,7 @@ - (instancetype)initWithJSONDictionary:(NSDictionary *)json error:(NSError **)er return nil; } - NSString *keyId = json[@"keyId"]; + NSString *keyId = json[@"key_id"]; if ([NSString msidIsStringNilOrBlank:authScheme]) { NSString *message = [NSString stringWithFormat:@"Failed to init %@ from json: key_id is nil", self.class]; @@ -113,7 +113,7 @@ - (instancetype)initWithJSONDictionary:(NSDictionary *)json error:(NSError **)er return nil; } - [schemeParameters setObject:keyId forKey:@"keyId"]; + [schemeParameters setObject:keyId forKey:@"key_id"]; [schemeParameters setObject:requestConf forKey:MSID_OAUTH2_REQUEST_CONFIRMATION]; [schemeParameters setObject:authScheme forKey:MSID_OAUTH2_TOKEN_TYPE]; @@ -150,4 +150,12 @@ - (NSDictionary *)jsonDictionary return json; } +- (id)copyWithZone:(NSZone *)zone +{ + MSIDAuthenticationSchemeSshCert *authScheme = [super copyWithZone:zone]; + authScheme->_keyId = [_keyId copyWithZone:zone]; + authScheme->_req_cnf = [_req_cnf copyWithZone:zone]; + return authScheme; +} + @end diff --git a/IdentityCore/src/util/MSIDAuthScheme.m b/IdentityCore/src/util/MSIDAuthScheme.m index 86d3b416b..10e4af887 100644 --- a/IdentityCore/src/util/MSIDAuthScheme.m +++ b/IdentityCore/src/util/MSIDAuthScheme.m @@ -31,7 +31,7 @@ case MSIDAuthSchemeBearer: return @"Bearer"; case MSIDAuthSchemeSshCert: - return @"SshCert"; + return @"ssh-cert"; default: return @"Bearer"; } @@ -47,6 +47,10 @@ MSIDAuthScheme MSIDAuthSchemeTypeFromString(NSString *authSchemeString) { return MSIDAuthSchemeBearer; } + else if ([authSchemeString isEqualToString:@"ssh-cert"]) + { + return MSIDAuthSchemeSshCert; + } return MSIDAuthSchemeBearer; } From 6b4a147fa9f58fea8c8099418de83770fe47427f Mon Sep 17 00:00:00 2001 From: kaisong1990 Date: Mon, 8 Apr 2024 13:19:17 -0700 Subject: [PATCH 08/41] Add constant --- IdentityCore/src/MSIDOAuth2Constants.h | 1 + IdentityCore/src/MSIDOAuth2Constants.m | 1 + IdentityCore/src/oauth2/aad_v2/MSIDAADV2Oauth2Factory.m | 6 ++++++ 3 files changed, 8 insertions(+) diff --git a/IdentityCore/src/MSIDOAuth2Constants.h b/IdentityCore/src/MSIDOAuth2Constants.h index f823b1eb8..27650452f 100644 --- a/IdentityCore/src/MSIDOAuth2Constants.h +++ b/IdentityCore/src/MSIDOAuth2Constants.h @@ -30,6 +30,7 @@ extern NSString *const MSID_OAUTH2_AUTHORIZATION_URI; extern NSString *const MSID_OAUTH2_AUTHORITY; extern NSString *const MSID_OAUTH2_BEARER; extern NSString *const MSID_OAUTH2_POP; +extern NSString *const MSID_OAUTH2_SSH_CERT; extern NSString *const MSID_OAUTH2_CLIENT_ID; extern NSString *const MSID_OAUTH2_CLAIMS; extern NSString *const MSID_OAUTH2_CODE; diff --git a/IdentityCore/src/MSIDOAuth2Constants.m b/IdentityCore/src/MSIDOAuth2Constants.m index c7f8f89fc..acf70594c 100644 --- a/IdentityCore/src/MSIDOAuth2Constants.m +++ b/IdentityCore/src/MSIDOAuth2Constants.m @@ -32,6 +32,7 @@ NSString *const MSID_OAUTH2_AUTHORIZATION_URI = @"authorization_uri"; NSString *const MSID_OAUTH2_BEARER = @"Bearer"; NSString *const MSID_OAUTH2_POP = @"Pop"; +NSString *const MSID_OAUTH2_SSH_CERT = @"ssh-cert"; NSString *const MSID_OAUTH2_CLIENT_ID = @"client_id"; NSString *const MSID_OAUTH2_CLAIMS = @"claims"; NSString *const MSID_OAUTH2_CODE = @"code"; diff --git a/IdentityCore/src/oauth2/aad_v2/MSIDAADV2Oauth2Factory.m b/IdentityCore/src/oauth2/aad_v2/MSIDAADV2Oauth2Factory.m index 3eb8407aa..4e8488514 100644 --- a/IdentityCore/src/oauth2/aad_v2/MSIDAADV2Oauth2Factory.m +++ b/IdentityCore/src/oauth2/aad_v2/MSIDAADV2Oauth2Factory.m @@ -47,6 +47,7 @@ #import "MSIDLastRequestTelemetry.h" #import "MSIDCurrentRequestTelemetry.h" #import "MSIDAADTokenRequestServerTelemetry.h" +#import "MSIDAuthenticationScheme.h" @implementation MSIDAADV2Oauth2Factory @@ -149,6 +150,11 @@ - (BOOL)fillAccessToken:(MSIDAccessToken *)accessToken { accessToken.redirectUri = configuration.redirectUri; } + + if ([MSID_OAUTH2_SSH_CERT isEqualToString:configuration.authScheme.tokenType]) + { + accessToken.tokenType = configuration.authScheme.tokenType; + } return YES; } From 4f4e72b7052ffe470cad82f603d76c487f342fe8 Mon Sep 17 00:00:00 2001 From: kaisong1990 Date: Mon, 8 Apr 2024 13:37:19 -0700 Subject: [PATCH 09/41] Add key_id --- IdentityCore/src/MSIDOAuth2Constants.h | 1 + IdentityCore/src/MSIDOAuth2Constants.m | 1 + 2 files changed, 2 insertions(+) diff --git a/IdentityCore/src/MSIDOAuth2Constants.h b/IdentityCore/src/MSIDOAuth2Constants.h index 27650452f..3897e0c5a 100644 --- a/IdentityCore/src/MSIDOAuth2Constants.h +++ b/IdentityCore/src/MSIDOAuth2Constants.h @@ -68,6 +68,7 @@ extern NSString *const MSID_OAUTH2_PROMPT_NONE; extern NSString *const MSID_OAUTH2_SIGNOUT_REDIRECT_URI; extern NSString *const MSID_OAUTH2_REQUEST_CONFIRMATION; extern NSString *const MSID_OAUTH2_REQUEST_ENDPOINT; +extern NSString *const MSID_OAUTH2_SSH_CERT_KEY_ID; extern NSString *const MSID_OAUTH2_EXPIRES_ON; extern NSString *const MSID_OAUTH2_EXT_EXPIRES_IN; diff --git a/IdentityCore/src/MSIDOAuth2Constants.m b/IdentityCore/src/MSIDOAuth2Constants.m index acf70594c..0c137060f 100644 --- a/IdentityCore/src/MSIDOAuth2Constants.m +++ b/IdentityCore/src/MSIDOAuth2Constants.m @@ -68,6 +68,7 @@ NSString *const MSID_OAUTH2_SIGNOUT_REDIRECT_URI = @"post_logout_redirect_uri"; NSString *const MSID_OAUTH2_REQUEST_CONFIRMATION = @"req_cnf"; NSString *const MSID_OAUTH2_REQUEST_ENDPOINT = @"endpointUrl"; +NSString *const MSID_OAUTH2_SSH_CERT_KEY_ID = @"key_id"; NSString *const MSID_OAUTH2_EXPIRES_ON = @"expires_on"; NSString *const MSID_OAUTH2_REFRESH_IN = @"refresh_in"; From 550f873122e2514b4c92210c570c6ede5aaaf96a Mon Sep 17 00:00:00 2001 From: kaisong1990 Date: Mon, 8 Apr 2024 13:44:55 -0700 Subject: [PATCH 10/41] Address typos --- .../auth_scheme/MSIDAuthenticationSchemeSshCert.m | 12 ++++++------ .../src/oauth2/aad_v2/MSIDAADV2Oauth2Factory.m | 3 ++- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/IdentityCore/src/auth_scheme/MSIDAuthenticationSchemeSshCert.m b/IdentityCore/src/auth_scheme/MSIDAuthenticationSchemeSshCert.m index 7ab2b6a60..31cff9afe 100644 --- a/IdentityCore/src/auth_scheme/MSIDAuthenticationSchemeSshCert.m +++ b/IdentityCore/src/auth_scheme/MSIDAuthenticationSchemeSshCert.m @@ -60,10 +60,10 @@ - (instancetype)initWithSchemeParameters:(NSDictionary *)schemeParameters return nil; } - _keyId = [_schemeParameters msidObjectForKey:@"key_id" ofClass:[NSString class]]; + _keyId = [_schemeParameters msidObjectForKey:MSID_OAUTH2_SSH_CERT_KEY_ID ofClass:[NSString class]]; if ([NSString msidIsStringNilOrBlank:_keyId]) { - MSID_LOG_WITH_CTX(MSIDLogLevelError, nil, @"Failed to read _keyId from scheme parameters."); + MSID_LOG_WITH_CTX(MSIDLogLevelError, nil, @"Failed to read key_id from scheme parameters."); return nil; } } @@ -105,7 +105,7 @@ - (instancetype)initWithJSONDictionary:(NSDictionary *)json error:(NSError **)er return nil; } - NSString *keyId = json[@"key_id"]; + NSString *keyId = json[MSID_OAUTH2_SSH_CERT_KEY_ID]; if ([NSString msidIsStringNilOrBlank:authScheme]) { NSString *message = [NSString stringWithFormat:@"Failed to init %@ from json: key_id is nil", self.class]; @@ -113,7 +113,7 @@ - (instancetype)initWithJSONDictionary:(NSDictionary *)json error:(NSError **)er return nil; } - [schemeParameters setObject:keyId forKey:@"key_id"]; + [schemeParameters setObject:keyId forKey:MSID_OAUTH2_SSH_CERT_KEY_ID]; [schemeParameters setObject:requestConf forKey:MSID_OAUTH2_REQUEST_CONFIRMATION]; [schemeParameters setObject:authScheme forKey:MSID_OAUTH2_TOKEN_TYPE]; @@ -141,11 +141,11 @@ - (NSDictionary *)jsonDictionary if ([NSString msidIsStringNilOrBlank:self.keyId]) { - MSID_LOG_WITH_CTX(MSIDLogLevelError, nil, @"Failed to create json for %@: req_cnf is nil.", self.class); + MSID_LOG_WITH_CTX(MSIDLogLevelError, nil, @"Failed to create json for %@: key_id is nil.", self.class); return nil; } - json[@"key_id"] = self.keyId; + json[MSID_OAUTH2_SSH_CERT_KEY_ID] = self.keyId; return json; } diff --git a/IdentityCore/src/oauth2/aad_v2/MSIDAADV2Oauth2Factory.m b/IdentityCore/src/oauth2/aad_v2/MSIDAADV2Oauth2Factory.m index 4e8488514..053e5a7d4 100644 --- a/IdentityCore/src/oauth2/aad_v2/MSIDAADV2Oauth2Factory.m +++ b/IdentityCore/src/oauth2/aad_v2/MSIDAADV2Oauth2Factory.m @@ -151,9 +151,10 @@ - (BOOL)fillAccessToken:(MSIDAccessToken *)accessToken accessToken.redirectUri = configuration.redirectUri; } + // Map token_type as "ssh-cert" flow for Azure CLI if ([MSID_OAUTH2_SSH_CERT isEqualToString:configuration.authScheme.tokenType]) { - accessToken.tokenType = configuration.authScheme.tokenType; + accessToken.tokenType = MSID_OAUTH2_SSH_CERT; } return YES; From 0bfc2554a052f370f096d8f9e6013681f40862b2 Mon Sep 17 00:00:00 2001 From: Sergei Demchenko Date: Tue, 9 Apr 2024 10:39:25 -0700 Subject: [PATCH 11/41] Fix crash in cert chooser. (#1344) --- .../ui/mac/MSIDCertificateChooser.m | 40 ++++++++++--------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/IdentityCore/src/webview/embeddedWebview/ui/mac/MSIDCertificateChooser.m b/IdentityCore/src/webview/embeddedWebview/ui/mac/MSIDCertificateChooser.m index 16e6d3073..55da3fce0 100644 --- a/IdentityCore/src/webview/embeddedWebview/ui/mac/MSIDCertificateChooser.m +++ b/IdentityCore/src/webview/embeddedWebview/ui/mac/MSIDCertificateChooser.m @@ -96,25 +96,27 @@ - (void)sheetDidEnd:(__unused NSWindow *)window - (void)webAuthDidFail:(__unused NSNotification *)aNotification { - if (!_panel || !_window) - { - return; - } - - // If web auth fails while the sheet is up that usually means the connection timed out, tear - // down the cert selection sheet. - - MSID_LOG_WITH_CORR(MSIDLogLevelInfo, _correlationId, @"Aborting cert selection due to web auth failure"); - NSArray *sheets = _window.sheets; - if (sheets.count < 1) - { - MSID_LOG_WITH_CORR(MSIDLogLevelError, _correlationId, @"Unable to find sheet to dismiss for client cert auth handler."); - return; - } - // It turns out the SFChooseIdentityPanel is not the real sheet that gets displayed, so telling the window to end it - // results in nothing happening. If I instead pull out the sheet from the window itself I can tell the window to end - // that and it works. - [_window endSheet:sheets[0] returnCode:NSModalResponseCancel]; + [MSIDMainThreadUtil executeOnMainThreadIfNeeded:^{ + if (!self->_panel || !self->_window) + { + return; + } + + // If web auth fails while the sheet is up that usually means the connection timed out, tear + // down the cert selection sheet. + + MSID_LOG_WITH_CORR(MSIDLogLevelInfo, self->_correlationId, @"Aborting cert selection due to web auth failure"); + NSArray *sheets = self->_window.sheets; + if (sheets.count < 1) + { + MSID_LOG_WITH_CORR(MSIDLogLevelError, self->_correlationId, @"Unable to find sheet to dismiss for client cert auth handler."); + return; + } + // It turns out the SFChooseIdentityPanel is not the real sheet that gets displayed, so telling the window to end it + // results in nothing happening. If I instead pull out the sheet from the window itself I can tell the window to end + // that and it works. + [self->_window endSheet:sheets[0] returnCode:NSModalResponseCancel]; + }]; } @end From 5c3f0fe01b25f3f3c7e7343bf34e1f634de58d95 Mon Sep 17 00:00:00 2001 From: kaisong1990 Date: Thu, 11 Apr 2024 16:03:39 -0700 Subject: [PATCH 12/41] WIP add ssh cert --- .../IdentityCore.xcodeproj/project.pbxproj | 6 + .../MSIDAuthenticationSchemeSshCert.m | 29 ++-- .../requests/broker/MSIDBrokerTokenRequest.m | 4 + .../MSIDAuthenticationSchemeSshCertTest.m | 138 ++++++++++++++++++ ...IDInteractiveTokenRequestParametersTests.m | 6 + .../tests/MSIDRequestParametersTests.m | 4 +- .../ios/MSIDBrokerTokenRequestTests.m | 68 +++++++++ 7 files changed, 240 insertions(+), 15 deletions(-) create mode 100644 IdentityCore/tests/MSIDAuthenticationSchemeSshCertTest.m diff --git a/IdentityCore/IdentityCore.xcodeproj/project.pbxproj b/IdentityCore/IdentityCore.xcodeproj/project.pbxproj index 3c1344672..b29954f22 100644 --- a/IdentityCore/IdentityCore.xcodeproj/project.pbxproj +++ b/IdentityCore/IdentityCore.xcodeproj/project.pbxproj @@ -517,6 +517,8 @@ 58543C8B24930FBC00F7AC14 /* MSIDMacKeychainTokenCache+Test.h in Headers */ = {isa = PBXBuildFile; fileRef = 58543C8A24930FBC00F7AC14 /* MSIDMacKeychainTokenCache+Test.h */; }; 586CD77E293FD77100550710 /* MSIDRequestControllerFactoryTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 586CD77B293FD76100550710 /* MSIDRequestControllerFactoryTests.m */; }; 586CD77F293FD77200550710 /* MSIDRequestControllerFactoryTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 586CD77B293FD76100550710 /* MSIDRequestControllerFactoryTests.m */; }; + 586DE2A82BC884600082137F /* MSIDAuthenticationSchemeSshCertTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 586DE2A72BC884600082137F /* MSIDAuthenticationSchemeSshCertTest.m */; }; + 586DE2A92BC884600082137F /* MSIDAuthenticationSchemeSshCertTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 586DE2A72BC884600082137F /* MSIDAuthenticationSchemeSshCertTest.m */; }; 5887EBF12BBF6490005F9634 /* MSIDAuthenticationSchemeSshCert.h in Headers */ = {isa = PBXBuildFile; fileRef = 5887EBEF2BBF6490005F9634 /* MSIDAuthenticationSchemeSshCert.h */; }; 5887EBF22BBF6490005F9634 /* MSIDAuthenticationSchemeSshCert.m in Sources */ = {isa = PBXBuildFile; fileRef = 5887EBF02BBF6490005F9634 /* MSIDAuthenticationSchemeSshCert.m */; }; 5887EBF32BBF6490005F9634 /* MSIDAuthenticationSchemeSshCert.m in Sources */ = {isa = PBXBuildFile; fileRef = 5887EBF02BBF6490005F9634 /* MSIDAuthenticationSchemeSshCert.m */; }; @@ -2347,6 +2349,7 @@ 585337DF272775110080935B /* MSIDSSOExtensionGetDataBaseRequest+Internal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "MSIDSSOExtensionGetDataBaseRequest+Internal.h"; sourceTree = ""; }; 58543C8A24930FBC00F7AC14 /* MSIDMacKeychainTokenCache+Test.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "MSIDMacKeychainTokenCache+Test.h"; sourceTree = ""; }; 586CD77B293FD76100550710 /* MSIDRequestControllerFactoryTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSIDRequestControllerFactoryTests.m; sourceTree = ""; }; + 586DE2A72BC884600082137F /* MSIDAuthenticationSchemeSshCertTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSIDAuthenticationSchemeSshCertTest.m; sourceTree = ""; }; 5887EBEF2BBF6490005F9634 /* MSIDAuthenticationSchemeSshCert.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSIDAuthenticationSchemeSshCert.h; sourceTree = ""; }; 5887EBF02BBF6490005F9634 /* MSIDAuthenticationSchemeSshCert.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSIDAuthenticationSchemeSshCert.m; sourceTree = ""; }; 589841EF25253DF30075DFED /* MSIDAccountMetadataCacheMockUpdateAuthorityParameters.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSIDAccountMetadataCacheMockUpdateAuthorityParameters.h; sourceTree = ""; }; @@ -5609,6 +5612,7 @@ B431B5252AF05B3F0020CD3D /* MSIDBrokerOperationPasskeyCredentialRequestTests.m */, B431B5282AF05C890020CD3D /* MSIDBrokerOperationGetPasskeyAssertionResponseTests.m */, B431B52B2AF19E230020CD3D /* MSIDBrokerOperationGetPasskeyCredentialResponseTests.m */, + 586DE2A72BC884600082137F /* MSIDAuthenticationSchemeSshCertTest.m */, ); path = tests; sourceTree = ""; @@ -6825,6 +6829,7 @@ 238A04792088561100989EE0 /* MSIDHttpRequestIntegrationTests.m in Sources */, B41163B929BAC9BF00E64619 /* MSIDWKNavigationActionMock.m in Sources */, 96928CEB2220C14600E8EA4E /* MSIDCBAWebAADAuthResponseTests.m in Sources */, + 586DE2A82BC884600082137F /* MSIDAuthenticationSchemeSshCertTest.m in Sources */, B24130DC247A1C5E002E70C4 /* MSIDPrimaryRefreshTokenTests.m in Sources */, B233F8D5219FA4AD00DC90E3 /* MSIDBrokerTokenRequestTests.m in Sources */, B431B53F2AF1C6BB0020CD3D /* MSIDSSOExtensionPasskeyAssertionRequestMock.m in Sources */, @@ -7443,6 +7448,7 @@ B431B5302AF1BCF10020CD3D /* MSIDSSOExtensionPasskeyAssertionRequestTests.m in Sources */, 58E2A1F924E492C30027A28A /* MSIDWebResponseOperationFactoryTests.m in Sources */, B20657D01FC92B8F00412B7D /* MSIDTelemetryUIEventTests.m in Sources */, + 586DE2A92BC884600082137F /* MSIDAuthenticationSchemeSshCertTest.m in Sources */, B2AE0FDB2427E96800B8FAF1 /* MSIDKeychainUtilTests.m in Sources */, B26A0B972072B9CB006BD95A /* MSIDAADV1Oauth2FactoryTests.m in Sources */, B208854C29ADC0FD00A50B88 /* MSIDPkeyAuthHelperTests.m in Sources */, diff --git a/IdentityCore/src/auth_scheme/MSIDAuthenticationSchemeSshCert.m b/IdentityCore/src/auth_scheme/MSIDAuthenticationSchemeSshCert.m index 31cff9afe..d7aa7297c 100644 --- a/IdentityCore/src/auth_scheme/MSIDAuthenticationSchemeSshCert.m +++ b/IdentityCore/src/auth_scheme/MSIDAuthenticationSchemeSshCert.m @@ -29,7 +29,7 @@ @interface MSIDAuthenticationSchemeSshCert() -@property (nonatomic) NSString *keyId; +@property (nonatomic) NSString *key_id; @property (nonatomic) NSString *req_cnf; @end @@ -60,8 +60,8 @@ - (instancetype)initWithSchemeParameters:(NSDictionary *)schemeParameters return nil; } - _keyId = [_schemeParameters msidObjectForKey:MSID_OAUTH2_SSH_CERT_KEY_ID ofClass:[NSString class]]; - if ([NSString msidIsStringNilOrBlank:_keyId]) + _key_id = [_schemeParameters msidObjectForKey:MSID_OAUTH2_SSH_CERT_KEY_ID ofClass:[NSString class]]; + if ([NSString msidIsStringNilOrBlank:_key_id]) { MSID_LOG_WITH_CTX(MSIDLogLevelError, nil, @"Failed to read key_id from scheme parameters."); return nil; @@ -71,19 +71,20 @@ - (instancetype)initWithSchemeParameters:(NSDictionary *)schemeParameters return self; } -- (MSIDCredentialType)credentialType -{ - return MSIDCredentialTypeOther; -} - - (NSString *)tokenType { return MSIDAuthSchemeParamFromType(self.authScheme); } -- (MSIDAuthScheme)authSchemeFromParameters:(__unused NSDictionary *)schemeParameters +- (MSIDAuthScheme)authSchemeFromParameters:(NSDictionary *)schemeParameters { - return MSIDAuthSchemeSshCert; + NSString *scheme = [schemeParameters msidObjectForKey:MSID_OAUTH2_TOKEN_TYPE ofClass:[NSString class]]; + if (!scheme) + { + MSID_LOG_WITH_CTX(MSIDLogLevelError, nil, @"Failed to read auth_scheme from scheme parameters."); + } + + return MSIDAuthSchemeTypeFromString(scheme); } - (instancetype)initWithJSONDictionary:(NSDictionary *)json error:(NSError **)error @@ -106,7 +107,7 @@ - (instancetype)initWithJSONDictionary:(NSDictionary *)json error:(NSError **)er } NSString *keyId = json[MSID_OAUTH2_SSH_CERT_KEY_ID]; - if ([NSString msidIsStringNilOrBlank:authScheme]) + if ([NSString msidIsStringNilOrBlank:keyId]) { NSString *message = [NSString stringWithFormat:@"Failed to init %@ from json: key_id is nil", self.class]; if (error) *error = MSIDCreateError(MSIDErrorDomain, MSIDErrorInvalidInternalParameter, message, nil, nil, nil, nil, nil, YES); @@ -139,13 +140,13 @@ - (NSDictionary *)jsonDictionary json[MSID_OAUTH2_REQUEST_CONFIRMATION] = self.req_cnf; - if ([NSString msidIsStringNilOrBlank:self.keyId]) + if ([NSString msidIsStringNilOrBlank:self.key_id]) { MSID_LOG_WITH_CTX(MSIDLogLevelError, nil, @"Failed to create json for %@: key_id is nil.", self.class); return nil; } - json[MSID_OAUTH2_SSH_CERT_KEY_ID] = self.keyId; + json[MSID_OAUTH2_SSH_CERT_KEY_ID] = self.key_id; return json; } @@ -153,7 +154,7 @@ - (NSDictionary *)jsonDictionary - (id)copyWithZone:(NSZone *)zone { MSIDAuthenticationSchemeSshCert *authScheme = [super copyWithZone:zone]; - authScheme->_keyId = [_keyId copyWithZone:zone]; + authScheme->_key_id = [_key_id copyWithZone:zone]; authScheme->_req_cnf = [_req_cnf copyWithZone:zone]; return authScheme; } diff --git a/IdentityCore/src/requests/broker/MSIDBrokerTokenRequest.m b/IdentityCore/src/requests/broker/MSIDBrokerTokenRequest.m index 6f38fb242..59e4aee96 100644 --- a/IdentityCore/src/requests/broker/MSIDBrokerTokenRequest.m +++ b/IdentityCore/src/requests/broker/MSIDBrokerTokenRequest.m @@ -152,6 +152,7 @@ - (NSDictionary *)defaultPayloadContents:(NSError **)error NSDictionary *schemeParameters = self.requestParameters.authScheme.schemeParameters; NSString *tokenType = schemeParameters[MSID_OAUTH2_TOKEN_TYPE]; NSString *requestConf = schemeParameters[MSID_OAUTH2_REQUEST_CONFIRMATION]; + NSString *keyId = schemeParameters[MSID_OAUTH2_SSH_CERT_KEY_ID]; NSMutableDictionary *queryDictionary = [NSMutableDictionary new]; [queryDictionary msidSetNonEmptyString:self.requestParameters.authority.url.absoluteString forKey:@"authority"]; @@ -172,6 +173,7 @@ - (NSDictionary *)defaultPayloadContents:(NSError **)error [queryDictionary msidSetNonEmptyString:self.brokerApplicationToken forKey:@"application_token"]; [queryDictionary msidSetNonEmptyString:tokenType forKey:MSID_OAUTH2_TOKEN_TYPE]; [queryDictionary msidSetNonEmptyString:requestConf forKey:MSID_OAUTH2_REQUEST_CONFIRMATION]; + [queryDictionary msidSetNonEmptyString:keyId forKey:MSID_OAUTH2_SSH_CERT_KEY_ID]; if ([self.sdkBrokerCapabilities count]) { @@ -206,8 +208,10 @@ - (NSDictionary *)defaultResumeDictionaryContents NSDictionary *schemeParameters = self.requestParameters.authScheme.schemeParameters; NSString *tokenType = schemeParameters[MSID_OAUTH2_TOKEN_TYPE]; NSString *requestConf = schemeParameters[MSID_OAUTH2_REQUEST_CONFIRMATION]; + NSString *keyId = schemeParameters[MSID_OAUTH2_SSH_CERT_KEY_ID]; [resumeDictionary msidSetNonEmptyString:tokenType forKey:MSID_OAUTH2_TOKEN_TYPE]; [resumeDictionary msidSetNonEmptyString:requestConf forKey:MSID_OAUTH2_REQUEST_CONFIRMATION]; + [resumeDictionary msidSetNonEmptyString:keyId forKey:MSID_OAUTH2_SSH_CERT_KEY_ID]; if ([self.requestParameters isNestedAuthProtocol]) { diff --git a/IdentityCore/tests/MSIDAuthenticationSchemeSshCertTest.m b/IdentityCore/tests/MSIDAuthenticationSchemeSshCertTest.m new file mode 100644 index 000000000..12768df21 --- /dev/null +++ b/IdentityCore/tests/MSIDAuthenticationSchemeSshCertTest.m @@ -0,0 +1,138 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import +#import "MSIDAuthenticationSchemeSshCert.h" + +@interface MSIDAuthenticationSchemeSshCertTest : XCTestCase + +@end + +@implementation MSIDAuthenticationSchemeSshCertTest + +- (void)test_InitWithCorrectParams_shouldReturnCompleteScheme +{ + MSIDAuthenticationSchemeSshCert *scheme = [[MSIDAuthenticationSchemeSshCert alloc] initWithSchemeParameters:[self prepareSshCertSchemeParameter]]; + [self test_assertDefaultAttributesInScheme:scheme]; +} + +- (void)test_InitWithInCorrectTokenType_shouldReturnNil +{ + MSIDAuthenticationSchemeSshCert *scheme = [[MSIDAuthenticationSchemeSshCert alloc] initWithSchemeParameters:[self prepareSshCertSchemeParameter_incorrectTokenType]]; + XCTAssertNil(scheme); +} + + +- (void)test_InitWithMissingTokenType_shouldReturnNil +{ + NSDictionary *json = [self prepareSshCertSchemeParameter_missingTokenType]; + NSError *error = nil; + MSIDAuthenticationSchemeSshCert *scheme = [[MSIDAuthenticationSchemeSshCert alloc] initWithJSONDictionary:json error:&error]; + XCTAssertNil(scheme); + XCTAssertNotNil(error); + XCTAssertEqual(error.code, MSIDErrorInvalidInternalParameter); +} + +- (void)test_InitWithMissingReqConf_shouldReturnNil +{ + MSIDAuthenticationSchemeSshCert *scheme = [[MSIDAuthenticationSchemeSshCert alloc] initWithSchemeParameters:[self prepareSshCertSchemeParameter_missingRequestConf]]; + XCTAssertNil(scheme); +} + +- (void)test_InitWithMissingKeyId_shouldReturnNil +{ + NSDictionary *json = [self prepareSshCertSchemeParameter_missingKeyId]; + NSError *error = nil; + MSIDAuthenticationSchemeSshCert *scheme = [[MSIDAuthenticationSchemeSshCert alloc] initWithJSONDictionary:json error:&error]; + XCTAssertNil(scheme); + XCTAssertNotNil(error); + XCTAssertEqual(error.code, MSIDErrorInvalidInternalParameter); +} + +- (NSDictionary *)prepareSshCertSchemeParameter +{ + NSMutableDictionary *params = [NSMutableDictionary new]; + [params setObject:@"ssh-cert" forKey:MSID_OAUTH2_TOKEN_TYPE]; + [params setObject:@"key_id_value" forKey:MSID_OAUTH2_SSH_CERT_KEY_ID]; + NSString *modulus = @"2tNr73xwcj6lH7bqRZrFzgSLj7OeLfbn8"; + NSString *exponent = @"AQAB"; + [params setObject:[NSString stringWithFormat:@"{\"kty\":\"RSA\", \"n\":\" + %@ + \", \"e\":\" + %@ + \"}", modulus, exponent] forKey:MSID_OAUTH2_REQUEST_CONFIRMATION]; + return params; +} + +- (NSDictionary *)prepareSshCertSchemeParameter_incorrectTokenType +{ + NSMutableDictionary *params = [NSMutableDictionary new]; + [params setObject:@"ssh_cert" forKey:MSID_OAUTH2_TOKEN_TYPE]; + [params setObject:@"key_id_value" forKey:MSID_OAUTH2_SSH_CERT_KEY_ID]; + NSString *modulus = @"2tNr73xwcj6lH7bqRZrFzgSLj7OeLfbn8"; + NSString *exponent = @"AQAB"; + [params setObject:[NSString stringWithFormat:@"{\"kty\":\"RSA\", \"n\":\" + %@ + \", \"e\":\" + %@ + \"}", modulus, exponent] forKey:MSID_OAUTH2_REQUEST_CONFIRMATION]; + return params; +} + +- (NSDictionary *)prepareSshCertSchemeParameter_missingRequestConf +{ + NSMutableDictionary *params = [NSMutableDictionary new]; + [params setObject:@"ssh-cert" forKey:MSID_OAUTH2_TOKEN_TYPE]; + [params setObject:@"key_id_value" forKey:MSID_OAUTH2_SSH_CERT_KEY_ID]; + NSString *modulus = @"2tNr73xwcj6lH7bqRZrFzgSLj7OeLfbn8"; + NSString *exponent = @"AQAB"; + [params setObject:[NSString stringWithFormat:@"{\"kty\":\"RSA\", \"n\":\" + %@ + \", \"e\":\" + %@ + \"}", modulus, exponent] forKey:@"req_cnf_1"]; + return params; +} + +- (NSDictionary *)prepareSshCertSchemeParameter_missingTokenType +{ + NSMutableDictionary *params = [NSMutableDictionary new]; + [params setObject:@"ssh-cert" forKey:@"token_type1"]; + [params setObject:@"key_id_value" forKey:MSID_OAUTH2_SSH_CERT_KEY_ID]; + NSString *modulus = @"2tNr73xwcj6lH7bqRZrFzgSLj7OeLfbn8"; + NSString *exponent = @"AQAB"; + [params setObject:[NSString stringWithFormat:@"{\"kty\":\"RSA\", \"n\":\" + %@ + \", \"e\":\" + %@ + \"}", modulus, exponent] forKey:MSID_OAUTH2_REQUEST_CONFIRMATION]; + return params; +} + +- (NSDictionary *)prepareSshCertSchemeParameter_missingKeyId +{ + NSMutableDictionary *params = [NSMutableDictionary new]; + [params setObject:@"ssh-cert" forKey:@"token_type"]; + [params setObject:@"key_id_value" forKey:@"key_id_1"]; + NSString *modulus = @"2tNr73xwcj6lH7bqRZrFzgSLj7OeLfbn8"; + NSString *exponent = @"AQAB"; + [params setObject:[NSString stringWithFormat:@"{\"kty\":\"RSA\", \"n\":\" + %@ + \", \"e\":\" + %@ + \"}", modulus, exponent] forKey:MSID_OAUTH2_REQUEST_CONFIRMATION]; + return params; +} + +- (void)test_assertDefaultAttributesInScheme:(MSIDAuthenticationSchemeSshCert *)scheme +{ + XCTAssertNotNil([scheme valueForKey:MSID_OAUTH2_SSH_CERT_KEY_ID]); + XCTAssertNotNil([scheme valueForKey:MSID_OAUTH2_REQUEST_CONFIRMATION]); + XCTAssertEqual(scheme.authScheme, MSIDAuthSchemeSshCert); + XCTAssertEqual(scheme.credentialType, MSIDAccessTokenType); + XCTAssertEqual(scheme.tokenType, MSID_OAUTH2_SSH_CERT); +} + +@end diff --git a/IdentityCore/tests/MSIDInteractiveTokenRequestParametersTests.m b/IdentityCore/tests/MSIDInteractiveTokenRequestParametersTests.m index 81f07688d..79bd9977b 100644 --- a/IdentityCore/tests/MSIDInteractiveTokenRequestParametersTests.m +++ b/IdentityCore/tests/MSIDInteractiveTokenRequestParametersTests.m @@ -29,6 +29,7 @@ #import "MSIDAccountIdentifier.h" #import "MSIDTestIdentifiers.h" #import "MSIDConfiguration.h" +#import "MSIDAuthenticationSchemeSshCert.h" @interface MSIDInteractiveTokenRequestParametersTests : XCTestCase @@ -46,6 +47,11 @@ - (void)testInitWithAllSupportedParameters_shouldInitialize_returnNilError_Beare [self testInitWithAllSupportedParameters_shouldInitialize_returnNilError:[MSIDAuthenticationScheme new]]; } +- (void)testInitWithAllSupportedParameters_shouldInitialize_returnNilError_SshCertflow +{ + [self testInitWithAllSupportedParameters_shouldInitialize_returnNilError:[MSIDAuthenticationSchemeSshCert new]]; +} + - (void)testInitWithAllSupportedParameters_shouldInitialize_returnNilError:(MSIDAuthenticationScheme *)authScheme { MSIDAuthority *authority = [@"https://login.microsoftonline.com/common" aadAuthority]; diff --git a/IdentityCore/tests/MSIDRequestParametersTests.m b/IdentityCore/tests/MSIDRequestParametersTests.m index 1fc00a2e2..966480e53 100644 --- a/IdentityCore/tests/MSIDRequestParametersTests.m +++ b/IdentityCore/tests/MSIDRequestParametersTests.m @@ -28,6 +28,7 @@ #import "NSString+MSIDTestUtil.h" #import "MSIDAuthenticationScheme.h" #import "MSIDAuthenticationSchemePop.h" +#import "MSIDAuthenticationSchemeSshCert.h" #import "MSIDAccountIdentifier.h" @interface MSIDRequestParametersTests : XCTestCase @@ -41,6 +42,7 @@ - (void )testInitParameters_withValidParameters_shouldInitReturnNonNil { [self testInitParameters_withValidParameters_shouldInitReturnNonNil_withAuthScheme:[MSIDAuthenticationScheme new]]; [self testInitParameters_withValidParameters_shouldInitReturnNonNil_withAuthScheme:[MSIDAuthenticationSchemePop new]]; + [self testInitParameters_withValidParameters_shouldInitReturnNonNil_withAuthScheme:[MSIDAuthenticationSchemeSshCert new]]; } - (void)testInitParameters_withValidParameters_shouldInitReturnNonNil_withAuthScheme:(MSIDAuthenticationScheme *)authScheme @@ -80,7 +82,7 @@ - (void)testInitParameters_withIntersectingOIDCScopes_shouldFailAndReturnNil_wit { [self testInitParameters_withIntersectingOIDCScopes_shouldFailAndReturnNil_withAuthScheme:[MSIDAuthenticationScheme new]]; [self testInitParameters_withIntersectingOIDCScopes_shouldFailAndReturnNil_withAuthScheme:[MSIDAuthenticationSchemePop new]]; - + [self testInitParameters_withIntersectingOIDCScopes_shouldFailAndReturnNil_withAuthScheme:[MSIDAuthenticationSchemeSshCert new]]; } - (void)testInitParameters_withIntersectingOIDCScopes_shouldFailAndReturnNil_withAuthScheme:(MSIDAuthenticationScheme *)authScheme diff --git a/IdentityCore/tests/integration/ios/MSIDBrokerTokenRequestTests.m b/IdentityCore/tests/integration/ios/MSIDBrokerTokenRequestTests.m index 24a2399ff..148920316 100644 --- a/IdentityCore/tests/integration/ios/MSIDBrokerTokenRequestTests.m +++ b/IdentityCore/tests/integration/ios/MSIDBrokerTokenRequestTests.m @@ -35,6 +35,7 @@ #import "MSIDClaimsRequest.h" #import "NSDictionary+MSIDTestUtil.h" #import "MSIDAuthenticationSchemePop.h" +#import "MSIDAuthenticationSchemeSshCert.h" @interface MSIDBrokerTokenRequestTests : XCTestCase @end @@ -82,6 +83,20 @@ - (MSIDInteractiveTokenRequestParameters *)defaultTestParametersATPop return parameters; } +- (MSIDInteractiveTokenRequestParameters *)defaultTestParametersSshCert +{ + MSIDInteractiveTokenRequestParameters *parameters = [self defaultTestParameters]; + NSString *modulus = @"2tNr73xwcj6lH7bqRZrFzgSLj7OeLfbn8"; + NSString *exponent = @"AQAB"; + NSDictionary *schemeParams = @{ + @"token_type":@"ssh-cert", + @"key_id":@"key_id_value", + @"req_cnf":[NSString stringWithFormat:@"{\"kty\":\"RSA\",\"n\":\"%@\",\"e\":\"%@\"}", modulus, exponent] + }; + parameters.authScheme = [[MSIDAuthenticationSchemeSshCert alloc] initWithSchemeParameters:schemeParams]; + return parameters; +} + - (NSString *)clientSku { NSString *clientSku = nil; @@ -251,6 +266,59 @@ - (void)testInitBrokerRequest_whenValidParameters_shouldReturnValidPayload_ATPop XCTAssertEqualObjects(expectedResumeDictionary, request.resumeDictionary); } +- (void)testInitBrokerRequest_whenValidParameters_shouldReturnValidPayload_SshCertFlow +{ + MSIDInteractiveTokenRequestParameters *parameters = [self defaultTestParametersSshCert]; + + NSError *error = nil; + MSIDBrokerTokenRequest *request = [[MSIDBrokerTokenRequest alloc] initWithRequestParameters:parameters brokerKey:@"brokerKey" brokerApplicationToken:@"brokerApplicationToken" sdkCapabilities:nil error:&error]; + XCTAssertNotNil(request); + XCTAssertNil(error); + + NSString *modulus = @"2tNr73xwcj6lH7bqRZrFzgSLj7OeLfbn8"; + NSString *exponent = @"AQAB"; + NSDictionary *expectedRequest = @{@"authority": @"https://login.microsoftonline.com/contoso.com", + @"client_id": @"my_client_id", + @"correlation_id": [parameters.correlationId UUIDString], + @"redirect_uri": @"my-redirect://com.microsoft.test", + @"broker_key": @"brokerKey", + @"client_version": [MSIDVersion sdkVersion], + @"client_app_name": @"MSIDTestsHostApp", + @"client_app_version": @"1.0", + @"broker_nonce" : [MSIDTestIgnoreSentinel sentinel], + @"application_token" : @"brokerApplicationToken", + @"key_id":@"key_id_value", + @"req_cnf" : [NSString stringWithFormat:@"{\"kty\":\"RSA\",\"n\":\"%@\",\"e\":\"%@\"}", modulus, exponent], + @"token_type" : @"ssh-cert", + @"client_sku" : [self clientSku], + @"skip_validate_result_account" : @"NO" + }; + + NSURL *actualURL = request.brokerRequestURL; + + NSString *expectedUrlString = [NSString stringWithFormat:@"msauthv2://broker?%@", [expectedRequest msidURLEncode]]; + NSURL *expectedURL = [NSURL URLWithString:expectedUrlString]; + XCTAssertTrue([expectedURL matchesURL:actualURL]); + + NSString *brokerNonce = [actualURL msidQueryParameters][@"broker_nonce"]; + XCTAssertNotNil(brokerNonce); + + NSDictionary *expectedResumeDictionary = @{@"authority": @"https://login.microsoftonline.com/contoso.com", + @"client_id": @"my_client_id", + @"correlation_id": [parameters.correlationId UUIDString], + @"redirect_uri": @"my-redirect://com.microsoft.test", + @"keychain_group": @"com.microsoft.mygroup", + @"broker_nonce": brokerNonce, + @"key_id":@"key_id_value", + @"req_cnf" : [NSString stringWithFormat:@"{\"kty\":\"RSA\",\"n\":\"%@\",\"e\":\"%@\"}", modulus, exponent], + @"token_type" : @"ssh-cert", + @"client_sku" : [self clientSku], + @"skip_validate_result_account" : @"NO" + }; + + XCTAssertEqualObjects(expectedResumeDictionary, request.resumeDictionary); +} + - (void)testInitBrokerRequest_whenValidParameters_andUniversalLinkRequest_shouldReturnUniversalLinkPayload { MSIDInteractiveTokenRequestParameters *parameters = [self defaultTestParameters]; From de558f7ddd7d53e5946ac848a92e408859d0cbd9 Mon Sep 17 00:00:00 2001 From: kaisong1990 Date: Thu, 11 Apr 2024 20:35:41 -0700 Subject: [PATCH 13/41] add UT and correct scheme --- .../MSIDAuthenticationSchemeSshCert.m | 14 +++ .../MSIDAuthenticationSchemeSshCertTest.m | 2 +- .../MSIDCacheSchemaValidationTests.m | 94 +++++++++++++++++++ 3 files changed, 109 insertions(+), 1 deletion(-) diff --git a/IdentityCore/src/auth_scheme/MSIDAuthenticationSchemeSshCert.m b/IdentityCore/src/auth_scheme/MSIDAuthenticationSchemeSshCert.m index d7aa7297c..ed8381488 100644 --- a/IdentityCore/src/auth_scheme/MSIDAuthenticationSchemeSshCert.m +++ b/IdentityCore/src/auth_scheme/MSIDAuthenticationSchemeSshCert.m @@ -26,6 +26,7 @@ #import "MSIDAuthenticationSchemeSshCert.h" #import "MSIDJsonSerializableFactory.h" #import "MSIDAuthScheme.h" +#import "MSIDAccessTokenWithAuthScheme.h" @interface MSIDAuthenticationSchemeSshCert() @@ -151,6 +152,19 @@ - (NSDictionary *)jsonDictionary return json; } +- (MSIDCredentialType)credentialType +{ + return MSIDAccessTokenWithAuthSchemeType; +} + +- (MSIDAccessToken *)accessToken +{ + MSIDAccessTokenWithAuthScheme *accessToken = [MSIDAccessTokenWithAuthScheme new]; + accessToken.tokenType = self.tokenType; + accessToken.kid = self.key_id; + return accessToken; +} + - (id)copyWithZone:(NSZone *)zone { MSIDAuthenticationSchemeSshCert *authScheme = [super copyWithZone:zone]; diff --git a/IdentityCore/tests/MSIDAuthenticationSchemeSshCertTest.m b/IdentityCore/tests/MSIDAuthenticationSchemeSshCertTest.m index 12768df21..12ad0e742 100644 --- a/IdentityCore/tests/MSIDAuthenticationSchemeSshCertTest.m +++ b/IdentityCore/tests/MSIDAuthenticationSchemeSshCertTest.m @@ -131,7 +131,7 @@ - (void)test_assertDefaultAttributesInScheme:(MSIDAuthenticationSchemeSshCert *) XCTAssertNotNil([scheme valueForKey:MSID_OAUTH2_SSH_CERT_KEY_ID]); XCTAssertNotNil([scheme valueForKey:MSID_OAUTH2_REQUEST_CONFIRMATION]); XCTAssertEqual(scheme.authScheme, MSIDAuthSchemeSshCert); - XCTAssertEqual(scheme.credentialType, MSIDAccessTokenType); + XCTAssertEqual(scheme.credentialType, MSIDAccessTokenWithAuthSchemeType); XCTAssertEqual(scheme.tokenType, MSID_OAUTH2_SSH_CERT); } diff --git a/IdentityCore/tests/integration/MSIDCacheSchemaValidationTests.m b/IdentityCore/tests/integration/MSIDCacheSchemaValidationTests.m index 4f33a0d99..d8affed30 100644 --- a/IdentityCore/tests/integration/MSIDCacheSchemaValidationTests.m +++ b/IdentityCore/tests/integration/MSIDCacheSchemaValidationTests.m @@ -38,6 +38,8 @@ #import "MSIDJsonSerializer.h" #import "MSIDAuthenticationSchemePop.h" #import "MSIDAccessTokenWithAuthScheme.h" +#import "MSIDAuthenticationSchemeSshCert.h" + /* Those tests validate full schema compliance to test cases defined in the schema spec */ @@ -84,6 +86,23 @@ - (MSIDTokenResponse *)aadTestTokenResponseATPop return response; } +- (MSIDTokenResponse *)aadTestTokenResponseATSshCert +{ + NSString *jsonResponse = @"{\"token_type\": \"ssh-cert\",\"scope\": \"https://pas.windows.net/CheckMyAccess/Linux/user_impersonation https://pas.windows.net/CheckMyAccess/Linux/.default\",\"expires_in\": 3600,\"ext_expires_in\": 262800,\"access_token\": \"\",\"refresh_token\": \"", + @"target": @"https://pas.windows.net/CheckMyAccess/Linux/user_impersonation https://pas.windows.net/CheckMyAccess/Linux/.default", + @"extended_expires_on": extExpiresOn, + @"credential_type": @"AccessToken_With_AuthScheme", + @"environment": @"login.microsoftonline.com", + @"realm": @"f645ad92-e38d-4d1a-b510-d1b09a74a8ca", + @"expires_on": expiresOn, + @"cached_at": cachedAt, + @"client_id": @"b6c69a37-df96-4db0-9088-2ab96e1d8215", + @"home_account_id": @"9f4880d8-80ba-4c40-97bc-f7a23c703084.f645ad92-e38d-4d1a-b510-d1b09a74a8ca", + @"kid" : @"key1" + }; + + XCTAssertEqualObjects(accessTokenJSON, expectedJSON); + + // 2. Verify cache key + MSIDDefaultCredentialCacheKey *key = [[MSIDDefaultCredentialCacheKey alloc] initWithHomeAccountId:credential.homeAccountId + environment:credential.environment + clientId:credential.clientId + credentialType:credential.credentialType]; + + key.familyId = credential.familyId; + key.realm = credential.realm; + key.target = credential.target; + + NSString *expectedServiceKey = @"accesstoken_with_authscheme-b6c69a37-df96-4db0-9088-2ab96e1d8215-f645ad92-e38d-4d1a-b510-d1b09a74a8ca-https://pas.windows.net/checkmyaccess/linux/user_impersonation https://pas.windows.net/checkmyaccess/linux/.default"; + XCTAssertEqualObjects(key.service, expectedServiceKey); + + NSString *expectedAccountKey = @"9f4880d8-80ba-4c40-97bc-f7a23c703084.f645ad92-e38d-4d1a-b510-d1b09a74a8ca-login.microsoftonline.com"; + XCTAssertEqualObjects(key.account, expectedAccountKey); + + NSString *expectedGenericKey = @"accesstoken_with_authscheme-b6c69a37-df96-4db0-9088-2ab96e1d8215-f645ad92-e38d-4d1a-b510-d1b09a74a8ca"; + XCTAssertEqualObjects(key.generic, [expectedGenericKey dataUsingEncoding:NSUTF8StringEncoding]); + + XCTAssertEqualObjects(key.type, @2007); +} + - (void)testSchemaComplianceForIDToken_whenMSSTSResponse_withAADAccount { MSIDAADV2Oauth2Factory *factory = [MSIDAADV2Oauth2Factory new]; From d6b66c8635622f6d2543356582daf431d7f6e81c Mon Sep 17 00:00:00 2001 From: Sergey Demchenko Date: Mon, 15 Apr 2024 13:12:55 -0700 Subject: [PATCH 14/41] Return UPN in properties of GetToken response. --- ...MSIDBrowserNativeMessageGetTokenResponse.m | 5 + ...rowserNativeMessageGetTokenResponseTests.m | 101 ++++++++++++++++++ 2 files changed, 106 insertions(+) create mode 100644 IdentityCore/tests/MSIDBrowserNativeMessageGetTokenResponseTests.m diff --git a/IdentityCore/src/broker_operation/response/browser_native_message_response/MSIDBrowserNativeMessageGetTokenResponse.m b/IdentityCore/src/broker_operation/response/browser_native_message_response/MSIDBrowserNativeMessageGetTokenResponse.m index f1536b9e4..02caa6b31 100644 --- a/IdentityCore/src/broker_operation/response/browser_native_message_response/MSIDBrowserNativeMessageGetTokenResponse.m +++ b/IdentityCore/src/broker_operation/response/browser_native_message_response/MSIDBrowserNativeMessageGetTokenResponse.m @@ -77,6 +77,11 @@ - (NSDictionary *)jsonDictionary response[@"account"] = accountJson; response[@"state"] = self.state; + __auto_type propertiesJson = [NSMutableDictionary new]; + // TODO: once ests follow the latest protocol, this should be removed. Account ID should be read from accountJson. + propertiesJson[@"UPN"] = tokenResponse.idTokenObj.username; + response[@"properties"] = propertiesJson; + return response; } diff --git a/IdentityCore/tests/MSIDBrowserNativeMessageGetTokenResponseTests.m b/IdentityCore/tests/MSIDBrowserNativeMessageGetTokenResponseTests.m new file mode 100644 index 000000000..4da688a71 --- /dev/null +++ b/IdentityCore/tests/MSIDBrowserNativeMessageGetTokenResponseTests.m @@ -0,0 +1,101 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import +#import "MSIDBrowserNativeMessageGetTokenResponse.h" +#import "MSIDBrokerOperationTokenResponse.h" +#import "MSIDAADV2TokenResponse.h" +#import "MSIDTestIdTokenUtil.h" +#import "MSIDTokenResponse.h" +#import "MSIDTestIdentifiers.h" + +@interface MSIDTokenResponseMock : MSIDTokenResponse + +@property (nonatomic) NSDictionary *responseJson; + +@end + +@implementation MSIDTokenResponseMock + +- (NSDictionary *)jsonDictionary +{ + return self.responseJson; +} + +@end + +@interface MSIDBrowserNativeMessageGetTokenResponseTests : XCTestCase + +@end + +@implementation MSIDBrowserNativeMessageGetTokenResponseTests + +- (void)testResponseType_shouldBeGenericResponse +{ + // We don't use this operation directly, it is wrapped by "BrokerOperationBrowserNativeMessage" operation, so we don't care about response type and return generic response. + XCTAssertEqualObjects(@"operation_generic_response", [MSIDBrowserNativeMessageGetTokenResponse responseType]); +} + +- (void)testJsonDictionary_whenNoResposne_shouldReturnNil +{ + __auto_type tokenResponse = [[MSIDBrokerOperationTokenResponse alloc] initWithDeviceInfo:nil]; + __auto_type response = [[MSIDBrowserNativeMessageGetTokenResponse alloc] initWithTokenResponse:tokenResponse]; + + XCTAssertNil([response jsonDictionary]); +} + +- (void)testJsonDictionary_whenPayloadExist_shouldBeCorrect +{ + NSString *idToken = [MSIDTestIdTokenUtil idTokenWithPreferredUsername:DEFAULT_TEST_ID_TOKEN_USERNAME + subject:DEFAULT_TEST_ID_TOKEN_SUBJECT]; + + NSDictionary *jsonInput = @{@"id_token": idToken}; + + MSIDTokenResponseMock *tokenResponseMock = [[MSIDTokenResponseMock alloc] initWithJSONDictionary:jsonInput error:nil]; + tokenResponseMock.responseJson = @{@"some_key": @"some_value"}; + + __auto_type operationTokenResponse = [[MSIDBrokerOperationTokenResponse alloc] initWithDeviceInfo:nil]; + operationTokenResponse.tokenResponse = tokenResponseMock; + + __auto_type response = [[MSIDBrowserNativeMessageGetTokenResponse alloc] initWithTokenResponse:operationTokenResponse]; + response.state = @"1234"; + + __auto_type expectedJson = @{ + @"account": @{ + @"id": tokenResponseMock.accountIdentifier, + @"userName": tokenResponseMock.idTokenObj.username + }, + @"properties": @{ + @"UPN": tokenResponseMock.idTokenObj.username + }, + @"state": @"1234", + @"some_key": @"some_value" + }; + + XCTAssertNotNil([response jsonDictionary]); + XCTAssertEqualObjects(expectedJson, [response jsonDictionary]); +} + +@end From a9d40bbaf6e23f542e49103e1551e61fb99a1614 Mon Sep 17 00:00:00 2001 From: Sergey Demchenko Date: Mon, 15 Apr 2024 13:58:00 -0700 Subject: [PATCH 15/41] Add SignOut api tests for browser core. --- .../IdentityCore.xcodeproj/project.pbxproj | 18 +++++ ...DBrowserNativeMessageSignOutRequestTests.m | 75 +++++++++++++++++++ ...BrowserNativeMessageSignOutResponseTests.m | 48 ++++++++++++ 3 files changed, 141 insertions(+) create mode 100644 IdentityCore/tests/MSIDBrowserNativeMessageSignOutRequestTests.m create mode 100644 IdentityCore/tests/MSIDBrowserNativeMessageSignOutResponseTests.m diff --git a/IdentityCore/IdentityCore.xcodeproj/project.pbxproj b/IdentityCore/IdentityCore.xcodeproj/project.pbxproj index bb1d3c994..84f1fafaa 100644 --- a/IdentityCore/IdentityCore.xcodeproj/project.pbxproj +++ b/IdentityCore/IdentityCore.xcodeproj/project.pbxproj @@ -148,6 +148,8 @@ 232C658C2138BED1002A41FE /* MSIDAADAuthorityMetadataResponseSerializerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 232C658B2138BED0002A41FE /* MSIDAADAuthorityMetadataResponseSerializerTests.m */; }; 232C658D2138BED1002A41FE /* MSIDAADAuthorityMetadataResponseSerializerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 232C658B2138BED0002A41FE /* MSIDAADAuthorityMetadataResponseSerializerTests.m */; }; 23368C0326436E4100374103 /* MSIDRequestParameters+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 23368C0226436E4100374103 /* MSIDRequestParameters+Internal.h */; }; + 233827912BC8C40C0079C82F /* MSIDBrowserNativeMessageGetTokenResponseTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 233827902BC8C40C0079C82F /* MSIDBrowserNativeMessageGetTokenResponseTests.m */; }; + 233827922BC8C40C0079C82F /* MSIDBrowserNativeMessageGetTokenResponseTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 233827902BC8C40C0079C82F /* MSIDBrowserNativeMessageGetTokenResponseTests.m */; }; 2338ECCB208A675D00809B9E /* MSIDAADRequestErrorHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 2338ECC8208A675D00809B9E /* MSIDAADRequestErrorHandler.m */; }; 2338ECCC208A675D00809B9E /* MSIDAADRequestErrorHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 2338ECC8208A675D00809B9E /* MSIDAADRequestErrorHandler.m */; }; 2338ECCD208A675D00809B9E /* MSIDHttpRequestErrorHandling.h in Headers */ = {isa = PBXBuildFile; fileRef = 2338ECC9208A675D00809B9E /* MSIDHttpRequestErrorHandling.h */; }; @@ -191,6 +193,10 @@ 23419F83239B36F500EA78C5 /* MSIDAccountIdentifierTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 23419F81239B36F500EA78C5 /* MSIDAccountIdentifierTests.m */; }; 234858DF20490EF8004FBC3C /* MSIDDefaultTokenCacheIntegrationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 965981041FF4C9B400E31CDE /* MSIDDefaultTokenCacheIntegrationTests.m */; }; 2348C313221B4EFF00498D56 /* MSIDBasicContext.m in Sources */ = {isa = PBXBuildFile; fileRef = 2323A6C42217AD4A00727088 /* MSIDBasicContext.m */; }; + 234A0BE02BCDC4B900AFBBAA /* MSIDBrowserNativeMessageSignOutResponseTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 234A0BDF2BCDC4B900AFBBAA /* MSIDBrowserNativeMessageSignOutResponseTests.m */; }; + 234A0BE12BCDC4B900AFBBAA /* MSIDBrowserNativeMessageSignOutResponseTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 234A0BDF2BCDC4B900AFBBAA /* MSIDBrowserNativeMessageSignOutResponseTests.m */; }; + 234A0BE32BCDCCB100AFBBAA /* MSIDBrowserNativeMessageSignOutRequestTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 234A0BE22BCDCCB100AFBBAA /* MSIDBrowserNativeMessageSignOutRequestTests.m */; }; + 234A0BE42BCDCCB100AFBBAA /* MSIDBrowserNativeMessageSignOutRequestTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 234A0BE22BCDCCB100AFBBAA /* MSIDBrowserNativeMessageSignOutRequestTests.m */; }; 234DE5832A9456F600E244B3 /* MSIDBrowserNativeMessageRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 234DE5812A9456F600E244B3 /* MSIDBrowserNativeMessageRequest.h */; }; 234DE5842A9456F600E244B3 /* MSIDBrowserNativeMessageRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 234DE5822A9456F600E244B3 /* MSIDBrowserNativeMessageRequest.m */; }; 234DE5852A9456F600E244B3 /* MSIDBrowserNativeMessageRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 234DE5822A9456F600E244B3 /* MSIDBrowserNativeMessageRequest.m */; }; @@ -2055,6 +2061,7 @@ 232C65872138BDC5002A41FE /* MSIDAADAuthorityMetadataResponse.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSIDAADAuthorityMetadataResponse.m; sourceTree = ""; }; 232C658B2138BED0002A41FE /* MSIDAADAuthorityMetadataResponseSerializerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSIDAADAuthorityMetadataResponseSerializerTests.m; sourceTree = ""; }; 23368C0226436E4100374103 /* MSIDRequestParameters+Internal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "MSIDRequestParameters+Internal.h"; sourceTree = ""; }; + 233827902BC8C40C0079C82F /* MSIDBrowserNativeMessageGetTokenResponseTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSIDBrowserNativeMessageGetTokenResponseTests.m; sourceTree = ""; }; 2338ECC8208A675D00809B9E /* MSIDAADRequestErrorHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MSIDAADRequestErrorHandler.m; sourceTree = ""; }; 2338ECC9208A675D00809B9E /* MSIDHttpRequestErrorHandling.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MSIDHttpRequestErrorHandling.h; sourceTree = ""; }; 2338ECCA208A675D00809B9E /* MSIDAADRequestErrorHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MSIDAADRequestErrorHandler.h; sourceTree = ""; }; @@ -2084,6 +2091,8 @@ 23419F7B239B0D1C00EA78C5 /* MSIDAuthorityTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSIDAuthorityTests.m; sourceTree = ""; }; 23419F7E239B33E400EA78C5 /* MSIDAADV2TokenResponseTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSIDAADV2TokenResponseTests.m; sourceTree = ""; }; 23419F81239B36F500EA78C5 /* MSIDAccountIdentifierTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSIDAccountIdentifierTests.m; sourceTree = ""; }; + 234A0BDF2BCDC4B900AFBBAA /* MSIDBrowserNativeMessageSignOutResponseTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSIDBrowserNativeMessageSignOutResponseTests.m; sourceTree = ""; }; + 234A0BE22BCDCCB100AFBBAA /* MSIDBrowserNativeMessageSignOutRequestTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSIDBrowserNativeMessageSignOutRequestTests.m; sourceTree = ""; }; 234DE5812A9456F600E244B3 /* MSIDBrowserNativeMessageRequest.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSIDBrowserNativeMessageRequest.h; sourceTree = ""; }; 234DE5822A9456F600E244B3 /* MSIDBrowserNativeMessageRequest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSIDBrowserNativeMessageRequest.m; sourceTree = ""; }; 2352AF302AA7C7B700FA2253 /* MSIDBrowserNativeMessageGetTokenResponse.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSIDBrowserNativeMessageGetTokenResponse.h; sourceTree = ""; }; @@ -5602,6 +5611,9 @@ B431B5252AF05B3F0020CD3D /* MSIDBrokerOperationPasskeyCredentialRequestTests.m */, B431B5282AF05C890020CD3D /* MSIDBrokerOperationGetPasskeyAssertionResponseTests.m */, B431B52B2AF19E230020CD3D /* MSIDBrokerOperationGetPasskeyCredentialResponseTests.m */, + 233827902BC8C40C0079C82F /* MSIDBrowserNativeMessageGetTokenResponseTests.m */, + 234A0BDF2BCDC4B900AFBBAA /* MSIDBrowserNativeMessageSignOutResponseTests.m */, + 234A0BE22BCDCCB100AFBBAA /* MSIDBrowserNativeMessageSignOutRequestTests.m */, ); path = tests; sourceTree = ""; @@ -6784,6 +6796,7 @@ B2936F7920ABF8310050C585 /* MSIDLegacyAccessTokenTests.m in Sources */, 60747FF62354F04F00C5308F /* MSIDBrokerOperationGetAccountsRequestTests.m in Sources */, 586CD77E293FD77100550710 /* MSIDRequestControllerFactoryTests.m in Sources */, + 233827912BC8C40C0079C82F /* MSIDBrowserNativeMessageGetTokenResponseTests.m in Sources */, 238EF086209161830035ABE6 /* MSIDAADJsonResponsePreprocessorTests.m in Sources */, B20657C61FC9265800412B7D /* MSIDTelemetryExtensionsTests.m in Sources */, B2BE924F21A24A5300F5AB8C /* MSIDSilentControllerIntegrationTests.m in Sources */, @@ -6824,6 +6837,7 @@ 963553BF20CA7C52005235E5 /* MSIDSystemWebviewControllerTests.m in Sources */, 963CFAF320AD817600BDA25F /* MSIDWebviewAuthorizationTests.m in Sources */, B2525C752330623E006FBA4B /* MSIDMainThreadUtilTests.m in Sources */, + 234A0BE32BCDCCB100AFBBAA /* MSIDBrowserNativeMessageSignOutRequestTests.m in Sources */, 2338ECDA208A7CBD00809B9E /* MSIDAADRequestErrorHandlerTests.m in Sources */, 23CA0C4A220A3B6900768729 /* MSIDPKeyAuthHandlerTests.m in Sources */, 80B6BF3C2480A3E30031BFE8 /* MSIDWorkPlaceJoinUtilTests.m in Sources */, @@ -6857,6 +6871,7 @@ B2DD4B4020A934170047A66E /* MSIDCredentialTypeTests.m in Sources */, 580E254E271A1815003D1795 /* MSIDBrokerOperationGetSsoCookiesResponseTests.m in Sources */, B2C708DF219BC67F00D917B8 /* MSIDDefaultSilentTokenRequestTests.m in Sources */, + 234A0BE02BCDC4B900AFBBAA /* MSIDBrowserNativeMessageSignOutResponseTests.m in Sources */, B210F4501FDDF5D2005A8F76 /* MSIDClientInfoTests.m in Sources */, 6080B9A523886DD9009B1322 /* MSIDBrokerOperationGetDeviceInfoRequestTests.m in Sources */, B431B5292AF05C890020CD3D /* MSIDBrokerOperationGetPasskeyAssertionResponseTests.m in Sources */, @@ -7310,6 +7325,7 @@ B2DD5B9C20475E780084313F /* MSIDBaseTokenTests.m in Sources */, 239DF9C420E04BC9002D428B /* MSIDADFSAuthorityTests.m in Sources */, B431B5422AF1C6C10020CD3D /* MSIDSSOExtensionPasskeyCredentialRequestMock.m in Sources */, + 233827922BC8C40C0079C82F /* MSIDBrowserNativeMessageGetTokenResponseTests.m in Sources */, 23419F6123974C0D00EA78C5 /* MSIDBrokerOperationTokenRequestTests.m in Sources */, 236CB13F2A609A1B005A6F5F /* MSIDBrokerOperationBrowserNativeMessageRequestTests.m in Sources */, B2807FFF204CB25E00944D89 /* MSIDTokenResponseTests.m in Sources */, @@ -7321,6 +7337,7 @@ B20657C71FC9265800412B7D /* MSIDTelemetryExtensionsTests.m in Sources */, 239DF9C720E04ECF002D428B /* MSIDAuthorityIntegrationTests.m in Sources */, B2E7698F206096A7000F3F2B /* MSIDTelemetryCacheEventTests.m in Sources */, + 234A0BE12BCDC4B900AFBBAA /* MSIDBrowserNativeMessageSignOutResponseTests.m in Sources */, 23419F7D239B0D1C00EA78C5 /* MSIDAuthorityTests.m in Sources */, E733EE0D25C0A50A00ACB79A /* MSIDThumbprintCalculatorTests.m in Sources */, 234858DF20490EF8004FBC3C /* MSIDDefaultTokenCacheIntegrationTests.m in Sources */, @@ -7336,6 +7353,7 @@ 728D9E492824A323001D990F /* MSIDPkeyAuthHelperTests.m in Sources */, 589BDB1E2718CD7D00BF3799 /* MSIDBrokerOperationGetSsoCookiesRequestTests.m in Sources */, B26A0B9A2072BABE006BD95A /* MSIDAADV2Oauth2FactoryTests.m in Sources */, + 234A0BE42BCDCCB100AFBBAA /* MSIDBrowserNativeMessageSignOutRequestTests.m in Sources */, B287C4CF26A132FA004303F1 /* MSIDSSOExtensionRequestDelegateTests.m in Sources */, 60BF06052051F9A200DE7C1C /* MSIDTelemetryTestDispatcher.m in Sources */, 23CAB3912A60ACB50066CFA2 /* MSIDBrokerOperationBrowserNativeMessageResponseTests.m in Sources */, diff --git a/IdentityCore/tests/MSIDBrowserNativeMessageSignOutRequestTests.m b/IdentityCore/tests/MSIDBrowserNativeMessageSignOutRequestTests.m new file mode 100644 index 000000000..682aad482 --- /dev/null +++ b/IdentityCore/tests/MSIDBrowserNativeMessageSignOutRequestTests.m @@ -0,0 +1,75 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import +#import "MSIDBrowserNativeMessageSignOutRequest.h" +#import "MSIDAccountIdentifier.h" + +@interface MSIDBrowserNativeMessageSignOutRequestTests : XCTestCase + +@end + +@implementation MSIDBrowserNativeMessageSignOutRequestTests + +- (void)testOperation_shouldBeCorrect +{ + XCTAssertEqualObjects(@"SignOut", [MSIDBrowserNativeMessageSignOutRequest operation]); +} + +- (void)testInitWithJSONDictionary_whenAccountIdIsValid_shouldInit +{ + __auto_type json = @{ + @"method": @"SignOut", + @"accountId": @"uid.utid", + @"sender": @"https://login.microsoft.com" + }; + + NSError *error; + __auto_type request = [[MSIDBrowserNativeMessageSignOutRequest alloc] initWithJSONDictionary:json error:&error]; + + XCTAssertNil(error); + XCTAssertNotNil(request); + XCTAssertEqualObjects(@"https://login.microsoft.com", request.sender.absoluteString); + XCTAssertEqualObjects(@"uid", request.accountId.uid); + XCTAssertEqualObjects(@"utid", request.accountId.utid); +} + +- (void)testInitWithJSONDictionary_whenAccountIdIsInvalid_shouldFail +{ + __auto_type json = @{ + @"method": @"SignOut", + @"accountId": @"qwerty", + @"sender": @"https://localhost:8000" + }; + + NSError *error; + __auto_type request = [[MSIDBrowserNativeMessageSignOutRequest alloc] initWithJSONDictionary:json error:&error]; + + XCTAssertNil(request); + XCTAssertNotNil(error); + XCTAssertEqualObjects(error.userInfo[MSIDErrorDescriptionKey], @"account Id is invalid."); +} + +@end diff --git a/IdentityCore/tests/MSIDBrowserNativeMessageSignOutResponseTests.m b/IdentityCore/tests/MSIDBrowserNativeMessageSignOutResponseTests.m new file mode 100644 index 000000000..5a7718001 --- /dev/null +++ b/IdentityCore/tests/MSIDBrowserNativeMessageSignOutResponseTests.m @@ -0,0 +1,48 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import +#import "MSIDBrowserNativeMessageSignOutResponse.h" + +@interface MSIDBrowserNativeMessageSignOutResponseTests : XCTestCase + +@end + +@implementation MSIDBrowserNativeMessageSignOutResponseTests + +- (void)testResponseType_shouldBeGenericResponse +{ + // We don't use this operation directly, it is wrapped by "BrokerOperationBrowserNativeMessage" operation, so we don't care about response type and return generic response. + XCTAssertEqualObjects(@"operation_generic_response", [MSIDBrowserNativeMessageSignOutResponse responseType]); +} + +- (void)testJsonDictionary_shouldBeEmptyJson +{ + __auto_type response = [[MSIDBrowserNativeMessageSignOutResponse alloc] initWithDeviceInfo:nil]; + + XCTAssertNotNil([response jsonDictionary]); + XCTAssertEqualObjects(@{}, [response jsonDictionary]); +} +@end From e62e3171b7ad8c9b4642045206b60726fe761b42 Mon Sep 17 00:00:00 2001 From: Juan Arias Roldan <1686668+juan-arias@users.noreply.github.com> Date: Wed, 17 Apr 2024 16:03:05 -0700 Subject: [PATCH 16/41] Include email as scope returned if it was requested and server did not include it. --- IdentityCore/src/MSIDOAuth2Constants.h | 1 + IdentityCore/src/MSIDOAuth2Constants.m | 1 + .../msal/MSIDDefaultTokenResponseValidator.m | 13 ++- .../MSIDDefaultTokenResponseValidatorTests.m | 80 +++++++++++++++++++ 4 files changed, 94 insertions(+), 1 deletion(-) diff --git a/IdentityCore/src/MSIDOAuth2Constants.h b/IdentityCore/src/MSIDOAuth2Constants.h index f823b1eb8..37d52b1ea 100644 --- a/IdentityCore/src/MSIDOAuth2Constants.h +++ b/IdentityCore/src/MSIDOAuth2Constants.h @@ -60,6 +60,7 @@ extern NSString *const MSID_OAUTH2_SAML2_BEARER_VALUE; extern NSString *const MSID_OAUTH2_SCOPE_OPENID_VALUE; extern NSString *const MSID_OAUTH2_SCOPE_OFFLINE_ACCESS_VALUE; extern NSString *const MSID_OAUTH2_SCOPE_PROFILE_VALUE; +extern NSString *const MSID_OAUTH2_SCOPE_EMAIL_VALUE; extern NSString *const MSID_OAUTH2_ASSERTION; extern NSString *const MSID_OAUTH2_CLIENT_TELEMETRY; extern NSString *const MSID_OAUTH2_PROMPT; diff --git a/IdentityCore/src/MSIDOAuth2Constants.m b/IdentityCore/src/MSIDOAuth2Constants.m index c7f8f89fc..6b9378a18 100644 --- a/IdentityCore/src/MSIDOAuth2Constants.m +++ b/IdentityCore/src/MSIDOAuth2Constants.m @@ -60,6 +60,7 @@ NSString *const MSID_OAUTH2_SAML2_BEARER_VALUE = @"urn:ietf:params:oauth:grant-type:saml2-bearer"; NSString *const MSID_OAUTH2_SCOPE_OPENID_VALUE = @"openid"; NSString *const MSID_OAUTH2_SCOPE_PROFILE_VALUE = @"profile"; +NSString *const MSID_OAUTH2_SCOPE_EMAIL_VALUE = @"email"; NSString *const MSID_OAUTH2_SCOPE_OFFLINE_ACCESS_VALUE = @"offline_access"; NSString *const MSID_OAUTH2_CLIENT_TELEMETRY = @"x-ms-clitelem"; NSString *const MSID_OAUTH2_PROMPT = @"prompt"; diff --git a/IdentityCore/src/requests/sdk/msal/MSIDDefaultTokenResponseValidator.m b/IdentityCore/src/requests/sdk/msal/MSIDDefaultTokenResponseValidator.m index ec5a31262..7bb3ae405 100644 --- a/IdentityCore/src/requests/sdk/msal/MSIDDefaultTokenResponseValidator.m +++ b/IdentityCore/src/requests/sdk/msal/MSIDDefaultTokenResponseValidator.m @@ -50,8 +50,19 @@ - (BOOL)validateTokenResult:(MSIDTokenResult *)tokenResult NSOrderedSet *grantedScopes = tokenResult.accessToken.scopes; NSOrderedSet *normalizedGrantedScopes = grantedScopes.normalizedScopeSet; + NSOrderedSet *requestedScopes = configuration.scopes; + NSOrderedSet *normalizedRequestedScopes = requestedScopes.normalizedScopeSet; + + // Include email as scope returned if it was requested and server did not include it. + if ([normalizedRequestedScopes containsObject:MSID_OAUTH2_SCOPE_EMAIL_VALUE] && + ![normalizedGrantedScopes containsObject:MSID_OAUTH2_SCOPE_EMAIL_VALUE]) + { + NSMutableOrderedSet *extendedScopes = [normalizedGrantedScopes mutableCopy]; + [extendedScopes addObject:MSID_OAUTH2_SCOPE_EMAIL_VALUE]; + normalizedGrantedScopes = extendedScopes; + } - if (![configuration.scopes.normalizedScopeSet isSubsetOfOrderedSet:normalizedGrantedScopes]) + if (![normalizedRequestedScopes isSubsetOfOrderedSet:normalizedGrantedScopes]) { if (error) { diff --git a/IdentityCore/tests/MSIDDefaultTokenResponseValidatorTests.m b/IdentityCore/tests/MSIDDefaultTokenResponseValidatorTests.m index d02c3d0f7..995c1c67c 100644 --- a/IdentityCore/tests/MSIDDefaultTokenResponseValidatorTests.m +++ b/IdentityCore/tests/MSIDDefaultTokenResponseValidatorTests.m @@ -98,6 +98,86 @@ - (void)testValidateTokenResult_whenSomeScopesRejectedByServer_shouldReturnError XCTAssertEqualObjects(error.userInfo[MSIDGrantedScopesKey], grantedScopes); } +- (void)testValidateTokenResult_whenEmailScopesNotIncludedByServer_shouldReturnValidResult +{ + __auto_type defaultOidcScope = @"openid profile offline_access"; + __auto_type correlationID = [NSUUID new]; + __auto_type authority = [@"https://login.microsoftonline.com/contoso.com" aadAuthority]; + MSIDConfiguration *configuration = [[MSIDConfiguration alloc] initWithAuthority:authority + redirectUri:@"some_uri" + clientId:@"myclient" + target:@"email user.read user.write"]; + NSDictionary *testResponse = [MSIDTestURLResponse tokenResponseWithAT:nil + responseRT:nil + responseID:nil + responseScope:@"User.Read User.Write" + responseClientInfo:nil + expiresIn:nil + foci:nil + extExpiresIn:nil]; + MSIDAADV2Oauth2Factory *factory = [MSIDAADV2Oauth2Factory new]; + MSIDTokenResponse *response = [factory tokenResponseFromJSON:testResponse context:nil error:nil]; + MSIDAccessToken *accessToken = [factory accessTokenFromResponse:response configuration:configuration]; + MSIDAccount *account = [factory accountFromResponse:response configuration:configuration]; + MSIDTokenResult *result = [[MSIDTokenResult alloc] initWithAccessToken:accessToken + refreshToken:nil + idToken:response.idToken + account:account + authority:authority + correlationId:correlationID + tokenResponse:response]; + NSError *error; + + BOOL validated = [self.validator validateTokenResult:result + configuration:configuration + oidcScope:defaultOidcScope + correlationID:correlationID + error:&error]; + + XCTAssertTrue(validated); + XCTAssertNil(error); +} + +- (void)testValidateTokenResult_whenEmailScopesIncludedByServer_shouldReturnValidResult +{ + __auto_type defaultOidcScope = @"openid profile offline_access"; + __auto_type correlationID = [NSUUID new]; + __auto_type authority = [@"https://login.microsoftonline.com/contoso.com" aadAuthority]; + MSIDConfiguration *configuration = [[MSIDConfiguration alloc] initWithAuthority:authority + redirectUri:@"some_uri" + clientId:@"myclient" + target:@"email user.read user.write"]; + NSDictionary *testResponse = [MSIDTestURLResponse tokenResponseWithAT:nil + responseRT:nil + responseID:nil + responseScope:@"email User.Read User.Write" + responseClientInfo:nil + expiresIn:nil + foci:nil + extExpiresIn:nil]; + MSIDAADV2Oauth2Factory *factory = [MSIDAADV2Oauth2Factory new]; + MSIDTokenResponse *response = [factory tokenResponseFromJSON:testResponse context:nil error:nil]; + MSIDAccessToken *accessToken = [factory accessTokenFromResponse:response configuration:configuration]; + MSIDAccount *account = [factory accountFromResponse:response configuration:configuration]; + MSIDTokenResult *result = [[MSIDTokenResult alloc] initWithAccessToken:accessToken + refreshToken:nil + idToken:response.idToken + account:account + authority:authority + correlationId:correlationID + tokenResponse:response]; + NSError *error; + + BOOL validated = [self.validator validateTokenResult:result + configuration:configuration + oidcScope:defaultOidcScope + correlationID:correlationID + error:&error]; + + XCTAssertTrue(validated); + XCTAssertNil(error); +} + - (void)testValidateTokenResult_whenWithValidResponse_shouldReturnValidResult { __auto_type defaultOidcScope = @"openid profile offline_access"; From deedb0f924784e272332a742586e96747f5d9ea7 Mon Sep 17 00:00:00 2001 From: Juan Arias Roldan <1686668+juan-arias@users.noreply.github.com> Date: Wed, 17 Apr 2024 16:07:52 -0700 Subject: [PATCH 17/41] Update changelog --- changelog.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/changelog.txt b/changelog.txt index 723cfc8b3..72dd8fcf9 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,6 @@ +Version TBD +* Include email as scope returned if it was requested and server did not include it. (#1364) + Version 1.7.34 * Ignore local cache in broker request From a96ac0f15fbcbc21b2e0bcdebce796d30c5ec3a0 Mon Sep 17 00:00:00 2001 From: Sergey Demchenko Date: Thu, 18 Apr 2024 15:04:30 -0700 Subject: [PATCH 18/41] Extend test mocks. --- .../MSIDAccountMetadataCacheAccessorMock.h | 3 + .../MSIDAccountMetadataCacheAccessorMock.m | 13 ++++ .../tests/util/MSIDTestCacheDataSource.m | 61 ++++++++++++++++--- 3 files changed, 68 insertions(+), 9 deletions(-) diff --git a/IdentityCore/tests/mocks/MSIDAccountMetadataCacheAccessorMock.h b/IdentityCore/tests/mocks/MSIDAccountMetadataCacheAccessorMock.h index 07ed78da9..77313b2a8 100644 --- a/IdentityCore/tests/mocks/MSIDAccountMetadataCacheAccessorMock.h +++ b/IdentityCore/tests/mocks/MSIDAccountMetadataCacheAccessorMock.h @@ -52,6 +52,9 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic) NSInteger removeAccountMetadataForHomeAccountIdInvokedCount; @property (nonatomic) MSIDAccountMetadataCacheMockRemoveAccountMetadataForHomeAccountIdParams *removeAccountMetadataForHomeAccountIdParams; +@property (nonatomic) NSInteger updateSignInStateForHomeAccountIdInvokedCount; +@property (nonatomic) NSError *updateSignInStateForHomeAccountIdError; +@property (nonatomic) BOOL updateSignInStateForHomeAccountIdResult; @end diff --git a/IdentityCore/tests/mocks/MSIDAccountMetadataCacheAccessorMock.m b/IdentityCore/tests/mocks/MSIDAccountMetadataCacheAccessorMock.m index a3197760b..addf910ab 100644 --- a/IdentityCore/tests/mocks/MSIDAccountMetadataCacheAccessorMock.m +++ b/IdentityCore/tests/mocks/MSIDAccountMetadataCacheAccessorMock.m @@ -119,4 +119,17 @@ - (BOOL)removeAccountMetadataForHomeAccountId:(NSString *)homeAccountId return self.removeAccountMetadataForHomeAccountIdResult; } +- (BOOL)updateSignInStateForHomeAccountId:(NSString *)homeAccountId + clientId:(NSString *)clientId + state:(MSIDAccountMetadataState)state + context:(id)context + error:(NSError **)error +{ + self.updateSignInStateForHomeAccountIdInvokedCount++; + + if (error) *error = self.updateSignInStateForHomeAccountIdError; + + return self.updateSignInStateForHomeAccountIdResult; +} + @end diff --git a/IdentityCore/tests/util/MSIDTestCacheDataSource.m b/IdentityCore/tests/util/MSIDTestCacheDataSource.m index cfa610eae..24f3de4ce 100644 --- a/IdentityCore/tests/util/MSIDTestCacheDataSource.m +++ b/IdentityCore/tests/util/MSIDTestCacheDataSource.m @@ -35,6 +35,7 @@ #import "MSIDAccountCacheItem.h" #import "MSIDAccountMetadata.h" #import "MSIDAccountMetadataCacheItem.h" +#import "MSIDJsonObject.h" @interface MSIDTestCacheDataSource() { @@ -320,19 +321,61 @@ - (MSIDAccountCacheItem *)accountWithKey:(MSIDCacheKey *)key context:(__unused id)context error:(__unused NSError *__autoreleasing *)error { - // TODO - return nil; + if (!serializer) + { + if (error) + { + *error = MSIDCreateError(MSIDErrorDomain, MSIDErrorInvalidInternalParameter, @"Missing parameter", nil, nil, nil, nil, nil, YES); + } + + return nil; + } + + NSMutableArray *resultItems = [NSMutableArray array]; + + NSArray *items = [self itemsWithKey:key + keysDictionary:_tokenKeys + contentDictionary:_tokenContents + context:context + error:error]; + + for (NSData *itemData in items) + { + MSIDJsonObject *jsonObject = (MSIDJsonObject *)[serializer deserializeCacheItem:itemData ofClass:[MSIDJsonObject class]]; + + if (jsonObject) + { + [resultItems addObject:jsonObject]; + } + } + + return resultItems; } -- (BOOL)saveJsonObject:(__unused MSIDJsonObject *)jsonObject - serializer:(__unused id)serializer - key:(__unused MSIDCacheKey *)key - context:(__unused id)context - error:(__unused NSError *__autoreleasing *)error +- (BOOL)saveJsonObject:(MSIDJsonObject *)jsonObject + serializer:(id)serializer + key:(MSIDCacheKey *)key + context:(id)context + error:(NSError **)error { - // TODO - return NO; + if (!jsonObject || !serializer) + { + if (error) + { + *error = MSIDCreateError(MSIDErrorDomain, MSIDErrorInvalidInternalParameter, @"Missing parameter", nil, nil, nil, nil, nil, YES); + } + + return NO; + } + + NSData *serializedItem = [serializer serializeCacheItem:jsonObject]; + return [self saveItemData:serializedItem + key:key + cacheKeys:_tokenKeys + cacheContent:_tokenKeys + context:context + error:error]; } From 4218e31c2088755426db690b7f8c5b4e3e64ff9e Mon Sep 17 00:00:00 2001 From: kaisong1990 Date: Tue, 30 Apr 2024 15:56:05 -0700 Subject: [PATCH 19/41] Add -1001 timeout as a network retry condition --- .../MSIDAADRequestErrorHandler.m | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/IdentityCore/src/network/error_handler/MSIDAADRequestErrorHandler.m b/IdentityCore/src/network/error_handler/MSIDAADRequestErrorHandler.m index 20e9d0b45..31a278f07 100644 --- a/IdentityCore/src/network/error_handler/MSIDAADRequestErrorHandler.m +++ b/IdentityCore/src/network/error_handler/MSIDAADRequestErrorHandler.m @@ -30,6 +30,12 @@ #import "MSIDPKeyAuthHandler.h" #import "MSIDMainThreadUtil.h" +static const NSArray *retryErrorPool = @[@(NSURLErrorTimedOut), + @(NSURLErrorCannotFindHost), + @(NSURLErrorCannotConnectToHost), + @(NSURLErrorNetworkConnectionLost), + @(NSURLErrorNotConnectedToInternet)]; + @implementation MSIDAADRequestErrorHandler - (void)handleError:(NSError *)error @@ -48,8 +54,8 @@ - (void)handleError:(NSError *)error BOOL shouldRetryNetworkingFailure = NO; if (shouldRetry && error) { - // Networking errors (-1003. -1004. -1005. -1009) - shouldRetryNetworkingFailure = error.code == NSURLErrorCannotFindHost || error.code == NSURLErrorCannotConnectToHost || error.code == NSURLErrorNetworkConnectionLost || error.code == NSURLErrorNotConnectedToInternet; + // Networking errors (-1001, -1003. -1004. -1005. -1009) + shouldRetryNetworkingFailure = [retryErrorPool containsObject:@(error.code)]; } shouldRetry &= shouldRetryNetworkingFailure; @@ -140,4 +146,15 @@ - (void)handleError:(NSError *)error if (completionBlock) completionBlock(nil, httpError); } +//- (BOOL)shouldRetyOn:(NSInteger)errorCode { +// NSArray *retryErrorPool = @[ +// @(NSURLErrorTimedOut), +// @(NSURLErrorCannotFindHost), +// @(NSURLErrorCannotConnectToHost), +// @(NSURLErrorNetworkConnectionLost), +// @(NSURLErrorNotConnectedToInternet) +// ]; +// return [retryErrorPool containsObject:@(errorCode)]; +//} + @end From b7e55caffb3bfcb393916f3107d4d3e67c793fbc Mon Sep 17 00:00:00 2001 From: kaisong1990 Date: Tue, 30 Apr 2024 15:57:32 -0700 Subject: [PATCH 20/41] clean up --- .../error_handler/MSIDAADRequestErrorHandler.m | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/IdentityCore/src/network/error_handler/MSIDAADRequestErrorHandler.m b/IdentityCore/src/network/error_handler/MSIDAADRequestErrorHandler.m index 31a278f07..c9efef07a 100644 --- a/IdentityCore/src/network/error_handler/MSIDAADRequestErrorHandler.m +++ b/IdentityCore/src/network/error_handler/MSIDAADRequestErrorHandler.m @@ -146,15 +146,4 @@ - (void)handleError:(NSError *)error if (completionBlock) completionBlock(nil, httpError); } -//- (BOOL)shouldRetyOn:(NSInteger)errorCode { -// NSArray *retryErrorPool = @[ -// @(NSURLErrorTimedOut), -// @(NSURLErrorCannotFindHost), -// @(NSURLErrorCannotConnectToHost), -// @(NSURLErrorNetworkConnectionLost), -// @(NSURLErrorNotConnectedToInternet) -// ]; -// return [retryErrorPool containsObject:@(errorCode)]; -//} - @end From d4a98b9b1277728f07c2961706df91eb604c2839 Mon Sep 17 00:00:00 2001 From: kaisong1990 Date: Tue, 30 Apr 2024 18:26:02 -0700 Subject: [PATCH 21/41] resolve compiling issue on Mac --- .../MSIDAADRequestErrorHandler.m | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/IdentityCore/src/network/error_handler/MSIDAADRequestErrorHandler.m b/IdentityCore/src/network/error_handler/MSIDAADRequestErrorHandler.m index c9efef07a..ba34c72ca 100644 --- a/IdentityCore/src/network/error_handler/MSIDAADRequestErrorHandler.m +++ b/IdentityCore/src/network/error_handler/MSIDAADRequestErrorHandler.m @@ -30,12 +30,6 @@ #import "MSIDPKeyAuthHandler.h" #import "MSIDMainThreadUtil.h" -static const NSArray *retryErrorPool = @[@(NSURLErrorTimedOut), - @(NSURLErrorCannotFindHost), - @(NSURLErrorCannotConnectToHost), - @(NSURLErrorNetworkConnectionLost), - @(NSURLErrorNotConnectedToInternet)]; - @implementation MSIDAADRequestErrorHandler - (void)handleError:(NSError *)error @@ -55,7 +49,7 @@ - (void)handleError:(NSError *)error if (shouldRetry && error) { // Networking errors (-1001, -1003. -1004. -1005. -1009) - shouldRetryNetworkingFailure = [retryErrorPool containsObject:@(error.code)]; + shouldRetryNetworkingFailure = [self shouldRetryNetworkingFailure:error.code]; } shouldRetry &= shouldRetryNetworkingFailure; @@ -146,4 +140,18 @@ - (void)handleError:(NSError *)error if (completionBlock) completionBlock(nil, httpError); } +- (BOOL)shouldRetryNetworkingFailure:(NSInteger)errorCode +{ + switch (errorCode) { + case NSURLErrorTimedOut: + case NSURLErrorCannotFindHost: + case NSURLErrorCannotConnectToHost: + case NSURLErrorNetworkConnectionLost: + case NSURLErrorNotConnectedToInternet: + return YES; + default: + return NO; + } +} + @end From bf34356292ce300a8a7036366e06a6a20de429c3 Mon Sep 17 00:00:00 2001 From: Sergey Demchenko Date: Wed, 1 May 2024 10:47:03 -0700 Subject: [PATCH 22/41] Improve test utils. --- .../tests/util/MSIDTestCacheDataSource.m | 2 +- .../tests/util/MSIDTestURLResponse+Util.h | 1 + .../tests/util/MSIDTestURLResponse+Util.m | 30 +++++++++++++++++++ 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/IdentityCore/tests/util/MSIDTestCacheDataSource.m b/IdentityCore/tests/util/MSIDTestCacheDataSource.m index 24f3de4ce..06351f544 100644 --- a/IdentityCore/tests/util/MSIDTestCacheDataSource.m +++ b/IdentityCore/tests/util/MSIDTestCacheDataSource.m @@ -373,7 +373,7 @@ - (BOOL)saveJsonObject:(MSIDJsonObject *)jsonObject return [self saveItemData:serializedItem key:key cacheKeys:_tokenKeys - cacheContent:_tokenKeys + cacheContent:_tokenContents context:context error:error]; } diff --git a/IdentityCore/tests/util/MSIDTestURLResponse+Util.h b/IdentityCore/tests/util/MSIDTestURLResponse+Util.h index 47601198e..5cce09dbe 100644 --- a/IdentityCore/tests/util/MSIDTestURLResponse+Util.h +++ b/IdentityCore/tests/util/MSIDTestURLResponse+Util.h @@ -26,6 +26,7 @@ @interface MSIDTestURLResponse (Util) + (NSDictionary *)msidDefaultRequestHeaders; ++ (NSMutableDictionary *)msidIgnoreRequestHeaders; + (MSIDTestURLResponse *)oidcResponseForAuthority:(NSString *)authority; + (MSIDTestURLResponse *)discoveryResponseForAuthority:(NSString *)authority; diff --git a/IdentityCore/tests/util/MSIDTestURLResponse+Util.m b/IdentityCore/tests/util/MSIDTestURLResponse+Util.m index 85bc5198f..0f77b022c 100644 --- a/IdentityCore/tests/util/MSIDTestURLResponse+Util.m +++ b/IdentityCore/tests/util/MSIDTestURLResponse+Util.m @@ -53,6 +53,36 @@ + (NSDictionary *)msidDefaultRequestHeaders return s_msidHeaders; } ++ (NSMutableDictionary *)msidIgnoreRequestHeaders +{ + static NSMutableDictionary *s_msidHeaders = nil; + static dispatch_once_t headersOnce; + + dispatch_once(&headersOnce, ^{ + NSDictionary *headers = + @{ + @"Accept" : [[MSIDTestIgnoreSentinel alloc] init], + @"Content-Length" : [[MSIDTestIgnoreSentinel alloc] init], + @"Content-Type" : [[MSIDTestIgnoreSentinel alloc] init], + @"User-Agent" : [[MSIDTestIgnoreSentinel alloc] init], + @"x-client-SKU": [[MSIDTestIgnoreSentinel alloc] init], + @"x-client-OS": [[MSIDTestIgnoreSentinel alloc] init], + @"x-app-name": [[MSIDTestIgnoreSentinel alloc] init], + @"x-ms-PkeyAuth+": [[MSIDTestIgnoreSentinel alloc] init], + @"x-client-Ver": [[MSIDTestIgnoreSentinel alloc] init], + @"x-client-CPU": [[MSIDTestIgnoreSentinel alloc] init], + @"x-app-ver": [[MSIDTestIgnoreSentinel alloc] init], + @"x-client-DM": [[MSIDTestIgnoreSentinel alloc] init], + @"Connection": [MSIDTestIgnoreSentinel sentinel], + }; + + + s_msidHeaders = [headers mutableCopy]; + }); + + return s_msidHeaders; +} + + (MSIDTestURLResponse *)discoveryResponseForAuthority:(NSString *)authority { NSURL *authorityURL = [NSURL URLWithString:authority]; From a3717c6558c3314418fd94dac5cb7960c1d3e599 Mon Sep 17 00:00:00 2001 From: Antonio Alwan Date: Mon, 6 May 2024 10:58:49 -0700 Subject: [PATCH 23/41] Fix headers. --- IdentityCore/src/MSIDError.h | 3 +++ IdentityCore/src/logger/MSIDLogger+Internal.h | 3 +++ IdentityCore/src/logger/MSIDLogger.h | 5 +++++ IdentityCore/src/logger/MSIDMaskedHashableLogParameter.h | 4 ++++ IdentityCore/src/logger/MSIDMaskedUsernameLogParameter.h | 4 ++++ IdentityCore/src/util/NSString+MSIDExtensions.h | 5 +++++ 6 files changed, 24 insertions(+) diff --git a/IdentityCore/src/MSIDError.h b/IdentityCore/src/MSIDError.h index db3bbf5a0..f5d0d5f5f 100644 --- a/IdentityCore/src/MSIDError.h +++ b/IdentityCore/src/MSIDError.h @@ -21,6 +21,8 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. +#ifndef MSIDERROR_H +#define MSIDERROR_H extern NSString * _Nonnull MSIDErrorDescriptionKey; extern NSString * _Nonnull MSIDOAuthErrorKey; extern NSString * _Nonnull MSIDOAuthSubErrorKey; @@ -346,3 +348,4 @@ extern void MSIDFillAndLogError(NSError * _Nullable __autoreleasing * _Nullable #define MSIDException(name, message, info) [NSException exceptionWithName:name reason:[NSString stringWithFormat:@"%@ (function:%s line:%i)", message, __PRETTY_FUNCTION__, __LINE__] userInfo:info] extern NSString * _Nullable MSIDErrorCodeToString(MSIDErrorCode errorCode); +#endif diff --git a/IdentityCore/src/logger/MSIDLogger+Internal.h b/IdentityCore/src/logger/MSIDLogger+Internal.h index 7e25e7cde..7b1e9dd7d 100644 --- a/IdentityCore/src/logger/MSIDLogger+Internal.h +++ b/IdentityCore/src/logger/MSIDLogger+Internal.h @@ -24,6 +24,8 @@ // THE SOFTWARE. // //------------------------------------------------------------------------------ +#ifndef MSIDLOGGER_INTERNAL_H +#define MSIDLOGGER_INTERNAL_H #import "MSIDLogger.h" #import "MSIDRequestContext.h" @@ -97,3 +99,4 @@ @end +#endif diff --git a/IdentityCore/src/logger/MSIDLogger.h b/IdentityCore/src/logger/MSIDLogger.h index 6852f9308..ac639846b 100644 --- a/IdentityCore/src/logger/MSIDLogger.h +++ b/IdentityCore/src/logger/MSIDLogger.h @@ -21,6 +21,10 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. + +#ifndef MSIDLOGGERCONNECTING_H +#define MSIDLOGGERCONNECTING_H + #import @protocol MSIDLoggerConnecting; @@ -96,3 +100,4 @@ typedef void (^MSIDLogCallback)(MSIDLogLevel level, NSString *message, BOOL cont - (void)setCallback:(MSIDLogCallback)callback; @end +#endif diff --git a/IdentityCore/src/logger/MSIDMaskedHashableLogParameter.h b/IdentityCore/src/logger/MSIDMaskedHashableLogParameter.h index fd9127fd4..310ec101f 100644 --- a/IdentityCore/src/logger/MSIDMaskedHashableLogParameter.h +++ b/IdentityCore/src/logger/MSIDMaskedHashableLogParameter.h @@ -21,6 +21,9 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. +#ifndef MSIDMASKEDHASHABLELOGPARAMETER_H +#define MSIDMASKEDHASHABLELOGPARAMETER_H + #import "MSIDMaskedLogParameter.h" NS_ASSUME_NONNULL_BEGIN @@ -30,3 +33,4 @@ NS_ASSUME_NONNULL_BEGIN @end NS_ASSUME_NONNULL_END +#endif diff --git a/IdentityCore/src/logger/MSIDMaskedUsernameLogParameter.h b/IdentityCore/src/logger/MSIDMaskedUsernameLogParameter.h index f46d93c34..32d852017 100644 --- a/IdentityCore/src/logger/MSIDMaskedUsernameLogParameter.h +++ b/IdentityCore/src/logger/MSIDMaskedUsernameLogParameter.h @@ -21,6 +21,9 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. +#ifndef MSIDMASKEDUSERNAMELOGPARAMETER_H +#define MSIDMASKEDUSERNAMELOGPARAMETER_H + #import "MSIDMaskedLogParameter.h" NS_ASSUME_NONNULL_BEGIN @@ -30,3 +33,4 @@ NS_ASSUME_NONNULL_BEGIN @end NS_ASSUME_NONNULL_END +#endif diff --git a/IdentityCore/src/util/NSString+MSIDExtensions.h b/IdentityCore/src/util/NSString+MSIDExtensions.h index 7369c952a..4e18684b1 100644 --- a/IdentityCore/src/util/NSString+MSIDExtensions.h +++ b/IdentityCore/src/util/NSString+MSIDExtensions.h @@ -21,6 +21,9 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. +#ifndef NSSTRING_MSIDEXTENSIONS_H +#define NSSTRING_MSIDEXTENSIONS_H + #import @interface NSString (MSIDExtensions) @@ -121,3 +124,5 @@ - (NSString *)msidSanitizedDomainName; @end + +#endif From be2735fd238c35178331ad552462b4cda14a4dee Mon Sep 17 00:00:00 2001 From: kaisong1990 Date: Mon, 6 May 2024 15:52:16 -0700 Subject: [PATCH 24/41] This is the minimum effort to remove lab client secret with credential replacement. Also move away from AppleADALKeyvaultApp --- .../ui_tests_lib/KeyvaultAuthentication.swift | 2 +- .../MSIDTestConfigurationProvider.m | 2 + ...MSIDAutomationOperationAPIRequestHandler.h | 2 + ...MSIDAutomationOperationAPIRequestHandler.m | 46 ++++++++++++------- 4 files changed, 35 insertions(+), 17 deletions(-) diff --git a/IdentityCore/tests/automation/ui_tests_lib/KeyvaultAuthentication.swift b/IdentityCore/tests/automation/ui_tests_lib/KeyvaultAuthentication.swift index 2339473e4..c3d961768 100644 --- a/IdentityCore/tests/automation/ui_tests_lib/KeyvaultAuthentication.swift +++ b/IdentityCore/tests/automation/ui_tests_lib/KeyvaultAuthentication.swift @@ -28,7 +28,7 @@ public class KeyvaultAuthentication : NSObject { private var certificateContents : String private var certificateData : Data private var certificatePassword : String - private let clientId = "b71232ea-9ba1-4974-b9a6-e4682dd0ab6c" + private let clientId = "f62c5ae3-bf3a-4af5-afa8-a68b800396e9" @objc public init?(certContents: String, certPassword: String) { diff --git a/IdentityCore/tests/automation/ui_tests_lib/MSIDTestConfigurationProvider.m b/IdentityCore/tests/automation/ui_tests_lib/MSIDTestConfigurationProvider.m index 787e8afd8..927241332 100644 --- a/IdentityCore/tests/automation/ui_tests_lib/MSIDTestConfigurationProvider.m +++ b/IdentityCore/tests/automation/ui_tests_lib/MSIDTestConfigurationProvider.m @@ -76,6 +76,8 @@ - (instancetype)initWithClientCertificateContents:(NSString *)certificate MSIDAutomationOperationAPIInMemoryCacheHandler *cacheHandler = [[MSIDAutomationOperationAPIInMemoryCacheHandler alloc] initWithDictionary:additionalConfigurations]; _operationAPIRequestHandler = [[MSIDAutomationOperationAPIRequestHandler alloc] initWithAPIPath:operationAPIConfiguration[@"operation_api_path"] + encodedCertificate:certificate + certificatePassword:password operationAPIConfiguration:operationAPIConfiguration]; _operationAPIRequestHandler.apiCacheHandler = cacheHandler; diff --git a/IdentityCore/tests/automation/ui_tests_lib/lab_api/MSIDAutomationOperationAPIRequestHandler.h b/IdentityCore/tests/automation/ui_tests_lib/lab_api/MSIDAutomationOperationAPIRequestHandler.h index f4822294a..7a7429afa 100644 --- a/IdentityCore/tests/automation/ui_tests_lib/lab_api/MSIDAutomationOperationAPIRequestHandler.h +++ b/IdentityCore/tests/automation/ui_tests_lib/lab_api/MSIDAutomationOperationAPIRequestHandler.h @@ -43,6 +43,8 @@ @property (nonatomic) id apiCacheHandler; - (instancetype)initWithAPIPath:(NSString *)apiPath + encodedCertificate:(NSString *)encodedCertificate + certificatePassword:(NSString *)certificatePassword operationAPIConfiguration:(NSDictionary *)operationAPIConfiguration; - (void)executeAPIRequest:(MSIDAutomationBaseApiRequest *)apiRequest diff --git a/IdentityCore/tests/automation/ui_tests_lib/lab_api/MSIDAutomationOperationAPIRequestHandler.m b/IdentityCore/tests/automation/ui_tests_lib/lab_api/MSIDAutomationOperationAPIRequestHandler.m index e69e8ec29..900f7a321 100644 --- a/IdentityCore/tests/automation/ui_tests_lib/lab_api/MSIDAutomationOperationAPIRequestHandler.m +++ b/IdentityCore/tests/automation/ui_tests_lib/lab_api/MSIDAutomationOperationAPIRequestHandler.m @@ -29,6 +29,8 @@ @interface MSIDAutomationOperationAPIRequestHandler() @property (nonatomic) NSString *labAPIPath; @property (nonatomic) NSDictionary *configurationParams; +@property (nonatomic) NSString *encodedCertificate; +@property (nonatomic) NSString *certificatePassword; @end @@ -37,6 +39,8 @@ @implementation MSIDAutomationOperationAPIRequestHandler #pragma mark - Init - (instancetype)initWithAPIPath:(NSString *)apiPath + encodedCertificate:(NSString *)encodedCertificate + certificatePassword:(NSString *)certificatePassword operationAPIConfiguration:(NSDictionary *)operationAPIConfiguration { self = [super init]; @@ -45,6 +49,8 @@ - (instancetype)initWithAPIPath:(NSString *)apiPath { _labAPIPath = apiPath; _configurationParams = operationAPIConfiguration; + _encodedCertificate = encodedCertificate; + _certificatePassword = certificatePassword; } return self; @@ -81,25 +87,33 @@ - (void)getAccessTokenAndCallLabAPI:(MSIDAutomationBaseApiRequest *)request responseHandler:(id)responseHandler completionHandler:(void (^)(id result, NSError *error))completionHandler { + NSData *base64EncodedCert = [[NSData alloc] initWithBase64EncodedString:self.encodedCertificate options:0]; + if (!base64EncodedCert || base64EncodedCert.length == 0) { + NSLog(@"Couldn't fetch certificate data, make sure certificate path is correct"); + return; + } + [MSIDClientCredentialHelper getAccessTokenForAuthority:self.configurationParams[@"operation_api_authority"] resource:self.configurationParams[@"operation_api_resource"] clientId:self.configurationParams[@"operation_api_client_id"] - clientCredential:self.configurationParams[@"operation_api_client_secret"] - completionHandler:^(NSString *accessToken, NSError *error) { - - if (!accessToken) - { - dispatch_async(dispatch_get_main_queue(), ^{ - completionHandler(nil, error); - }); - return; - } - - [self executeAPIRequestImpl:request - responseHandler:responseHandler - accessToken:accessToken - completionHandler:completionHandler]; - }]; + certificate:base64EncodedCert + certificatePassword:self.certificatePassword + completionHandler:^(NSString *accessToken, NSError *error) + { + + if (!accessToken) + { + dispatch_async(dispatch_get_main_queue(), ^{ + completionHandler(nil, error); + }); + return; + } + + [self executeAPIRequestImpl:request + responseHandler:responseHandler + accessToken:accessToken + completionHandler:completionHandler]; + }]; } #pragma mark - Execute request From c2d022a7f5ea82090e925b54d99edfd97f769f1b Mon Sep 17 00:00:00 2001 From: Hieu Nguyen Date: Tue, 7 May 2024 17:56:26 -0700 Subject: [PATCH 25/41] add --- .../ios/MSIDBrokerInteractiveController.m | 15 ++++ ...kerInteractiveControllerIntegrationTests.m | 71 +++++++++++++++++++ 2 files changed, 86 insertions(+) diff --git a/IdentityCore/src/controllers/broker/ios/MSIDBrokerInteractiveController.m b/IdentityCore/src/controllers/broker/ios/MSIDBrokerInteractiveController.m index d57947111..4a5383c22 100644 --- a/IdentityCore/src/controllers/broker/ios/MSIDBrokerInteractiveController.m +++ b/IdentityCore/src/controllers/broker/ios/MSIDBrokerInteractiveController.m @@ -43,6 +43,10 @@ #import "MSIDBrokerKeyProvider.h" #import "MSIDMainThreadUtil.h" #import "NSString+MSIDExtensions.h" +#import "MSIDThrottlingService.h" +#import "MSIDDefaultTokenRequestProvider.h" +#import "MSIDDefaultTokenRequestProvider+Internal.h" +#import "MSIDDefaultTokenCacheAccessor.h" static MSIDBrokerInteractiveController *s_currentExecutingController; @@ -165,6 +169,17 @@ - (void)acquireTokenImpl:(nonnull MSIDRequestCompletionBlock)completionBlock MSIDRequestCompletionBlock completionBlockWrapper = ^(MSIDTokenResult *result, NSError *error) { MSID_LOG_WITH_CTX(MSIDLogLevelInfo, self.requestParameters, @"Broker flow finished."); + + // Refresh throttling by updating last_refresh_time flag if an legacy interactive call succeed (in case of fallback from SSO-Ext interactive) + if (!error) + { + if ([self.tokenRequestProvider isKindOfClass:[MSIDDefaultTokenRequestProvider class]]) + { + id cache = ((MSIDDefaultTokenRequestProvider *)self.tokenRequestProvider).tokenCache.accountCredentialCache.dataSource; + [MSIDThrottlingService updateLastRefreshTimeDatasource:cache context:self.interactiveParameters error:nil]; + } + } + completionBlock(result, error); }; diff --git a/IdentityCore/tests/integration/ios/MSIDBrokerInteractiveControllerIntegrationTests.m b/IdentityCore/tests/integration/ios/MSIDBrokerInteractiveControllerIntegrationTests.m index 97f468f70..e586c2aed 100644 --- a/IdentityCore/tests/integration/ios/MSIDBrokerInteractiveControllerIntegrationTests.m +++ b/IdentityCore/tests/integration/ios/MSIDBrokerInteractiveControllerIntegrationTests.m @@ -53,6 +53,10 @@ #import "MSIDTestBrokerKeyProviderHelper.h" #import "MSIDTestSwizzle.h" #import "MSIDAppExtensionUtil.h" +#import "MSIDThrottlingService.h" +#import "MSIDDefaultTokenRequestProvider.h" +#import "MSIDAccountMetadataCacheAccessor.h" +#import "MSIDDefaultTokenCacheAccessor.h" @interface MSIDBrokerInteractiveControllerIntegrationTests : XCTestCase @@ -247,6 +251,73 @@ - (void)testAcquireToken_whenSuccessfulBrokerResponse_shouldReturnSuccess [self waitForExpectationsWithTimeout:1.0 handler:nil]; } +- (void)testAcquireToken_whenSuccessfulBrokerResponse_shouldUpdateThrottleLastRefresh +{ + // setup telemetry callback + MSIDTelemetryTestDispatcher *dispatcher = [MSIDTelemetryTestDispatcher new]; + + NSMutableArray *receivedEvents = [NSMutableArray array]; + + // the dispatcher will store the telemetry events it receives + [dispatcher setTestCallback:^(id event) + { + [receivedEvents addObject:event]; + }]; + + // register the dispatcher + [[MSIDTelemetry sharedInstance] addDispatcher:dispatcher]; + [MSIDTelemetry sharedInstance].piiEnabled = YES; + + // Setup test request providers + MSIDInteractiveTokenRequestParameters *parameters = [self requestParameters]; + parameters.telemetryApiId = @"api_broker_success"; + + MSIDDefaultTokenRequestProvider *provider = [[MSIDDefaultTokenRequestProvider alloc] initWithOauthFactory:[MSIDAADV2Oauth2Factory new] + defaultAccessor:[MSIDDefaultTokenCacheAccessor new] + accountMetadataAccessor:[MSIDAccountMetadataCacheAccessor new] + tokenResponseValidator:[MSIDDefaultTokenResponseValidator new]]; + + NSError *error = nil; + MSIDBrokerInteractiveController *brokerController = [[MSIDBrokerInteractiveController alloc] initWithInteractiveRequestParameters:parameters + tokenRequestProvider:provider + fallbackController:nil + error:&error]; + + XCTAssertNotNil(brokerController); + XCTAssertNil(error); + + MSIDTokenResult *testResult = [self resultWithParameters:parameters]; + + [MSIDApplicationTestUtil onOpenURL:^BOOL(NSURL *url, __unused NSDictionary *options) { + MSIDTestBrokerResponseHandler *brokerResponseHandler = [[MSIDTestBrokerResponseHandler alloc] initWithTestResponse:testResult testError:nil]; + [MSIDBrokerInteractiveController completeAcquireToken:[NSURL URLWithString:@"https://contoso.com"] + sourceApplication:@"com.microsoft.azureauthenticator" + brokerResponseHandler:brokerResponseHandler]; + return YES; + }]; + + + MSIDTestURLResponse *discoveryResponse = [MSIDTestURLResponse discoveryResponseForAuthority:@"https://login.microsoftonline.com/common"]; + [MSIDTestURLSession addResponse:discoveryResponse]; + __block int count = 0; + [MSIDTestSwizzle classMethod:@selector(updateLastRefreshTimeDatasource:context:error:) + class:[MSIDThrottlingService class] + block:(id)^(id obj) + { + count++; + return YES; + }]; + XCTestExpectation *expectation = [self expectationWithDescription:@"Acquire token"]; + + [brokerController acquireToken:^(MSIDTokenResult * _Nullable result, NSError * _Nullable acquireTokenError) { + + XCTAssertEqual(count, 1); + [expectation fulfill]; + }]; + + [self waitForExpectationsWithTimeout:1.0 handler:nil]; +} + - (void)testAcquireToken_whenInsufficientScopesReturned_shouldReturnNilResultAndError { // setup telemetry callback From ad3ef480761c30f864886bfeac4617a80b23d825 Mon Sep 17 00:00:00 2001 From: Hieu Nguyen Date: Tue, 7 May 2024 17:59:06 -0700 Subject: [PATCH 26/41] change log --- changelog.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/changelog.txt b/changelog.txt index 72dd8fcf9..f1560bf8e 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,6 @@ Version TBD * Include email as scope returned if it was requested and server did not include it. (#1364) +* Fix throttling bug in fallback legacy broker interactive controller. (#1371) Version 1.7.34 * Ignore local cache in broker request From a625f6766a6749bd0ae827471a6cae59467d5e8b Mon Sep 17 00:00:00 2001 From: Hieu Nguyen Date: Wed, 8 May 2024 15:09:27 -0700 Subject: [PATCH 27/41] fix pipeline --- .../ios/MSIDBrokerInteractiveControllerIntegrationTests.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IdentityCore/tests/integration/ios/MSIDBrokerInteractiveControllerIntegrationTests.m b/IdentityCore/tests/integration/ios/MSIDBrokerInteractiveControllerIntegrationTests.m index e586c2aed..1464a0064 100644 --- a/IdentityCore/tests/integration/ios/MSIDBrokerInteractiveControllerIntegrationTests.m +++ b/IdentityCore/tests/integration/ios/MSIDBrokerInteractiveControllerIntegrationTests.m @@ -288,7 +288,7 @@ - (void)testAcquireToken_whenSuccessfulBrokerResponse_shouldUpdateThrottleLastRe MSIDTokenResult *testResult = [self resultWithParameters:parameters]; - [MSIDApplicationTestUtil onOpenURL:^BOOL(NSURL *url, __unused NSDictionary *options) { + [MSIDApplicationTestUtil onOpenURL:^BOOL(__unused NSURL *url, __unused NSDictionary *options) { MSIDTestBrokerResponseHandler *brokerResponseHandler = [[MSIDTestBrokerResponseHandler alloc] initWithTestResponse:testResult testError:nil]; [MSIDBrokerInteractiveController completeAcquireToken:[NSURL URLWithString:@"https://contoso.com"] sourceApplication:@"com.microsoft.azureauthenticator" From ae9c4c5d24a69ede68b0e533a0fa5a95784fd4a3 Mon Sep 17 00:00:00 2001 From: Hieu Nguyen Date: Wed, 8 May 2024 15:27:00 -0700 Subject: [PATCH 28/41] update --- .../ios/MSIDBrokerInteractiveControllerIntegrationTests.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/IdentityCore/tests/integration/ios/MSIDBrokerInteractiveControllerIntegrationTests.m b/IdentityCore/tests/integration/ios/MSIDBrokerInteractiveControllerIntegrationTests.m index 1464a0064..7649865a7 100644 --- a/IdentityCore/tests/integration/ios/MSIDBrokerInteractiveControllerIntegrationTests.m +++ b/IdentityCore/tests/integration/ios/MSIDBrokerInteractiveControllerIntegrationTests.m @@ -302,14 +302,14 @@ - (void)testAcquireToken_whenSuccessfulBrokerResponse_shouldUpdateThrottleLastRe __block int count = 0; [MSIDTestSwizzle classMethod:@selector(updateLastRefreshTimeDatasource:context:error:) class:[MSIDThrottlingService class] - block:(id)^(id obj) + block:(id)^(__unused id obj) { count++; return YES; }]; XCTestExpectation *expectation = [self expectationWithDescription:@"Acquire token"]; - [brokerController acquireToken:^(MSIDTokenResult * _Nullable result, NSError * _Nullable acquireTokenError) { + [brokerController acquireToken:^(__unused MSIDTokenResult * _Nullable result, __unused NSError * _Nullable acquireTokenError) { XCTAssertEqual(count, 1); [expectation fulfill]; From 30e6a75b08f465f92e34413ed7192f4eab3a9480 Mon Sep 17 00:00:00 2001 From: Juan Arias Roldan <1686668+juan-arias@users.noreply.github.com> Date: Wed, 8 May 2024 17:03:39 -0700 Subject: [PATCH 29/41] Use correct prefix for constant. --- IdentityCore/src/MSIDBrokerConstants.h | 2 +- IdentityCore/src/MSIDBrokerConstants.m | 2 +- .../src/webview/response/MSIDJITTroubleshootingResponse.m | 2 +- IdentityCore/tests/MSIDJITTroubleshootingResponseTests.m | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/IdentityCore/src/MSIDBrokerConstants.h b/IdentityCore/src/MSIDBrokerConstants.h index 08bc01f2b..d18468a74 100644 --- a/IdentityCore/src/MSIDBrokerConstants.h +++ b/IdentityCore/src/MSIDBrokerConstants.h @@ -92,7 +92,7 @@ extern NSString * _Nonnull const MSID_BROKER_REQUEST_SENT_TIMESTAMP; extern NSString * _Nonnull const MSID_BROKER_ACCOUNT_HOME_TENANT_ID; extern NSString * _Nonnull const MSID_CLIENT_SKU_KEY; extern NSString * _Nonnull const MSID_SKIP_VALIDATE_RESULT_ACCOUNT_KEY; -extern NSString * _Nonnull const JIT_TROUBLESHOOTING_HOST; +extern NSString * _Nonnull const MSID_JIT_TROUBLESHOOTING_HOST; extern NSString * _Nonnull const MSID_IS_CALLER_MANAGED_KEY; extern NSString * _Nonnull const MSID_BROKER_PREFERRED_AUTH_CONFIGURATION_KEY; extern NSString * _Nonnull const MSID_BROKER_SDM_WPJ_ATTEMPTED; diff --git a/IdentityCore/src/MSIDBrokerConstants.m b/IdentityCore/src/MSIDBrokerConstants.m index 6ea9bfe7f..f32ec3d8d 100644 --- a/IdentityCore/src/MSIDBrokerConstants.m +++ b/IdentityCore/src/MSIDBrokerConstants.m @@ -91,7 +91,7 @@ NSString *const MSID_PRIMARY_REGISTRATION_CLOUD = @"primary_registration_metadata_cloud_host"; NSString *const MSID_PRIMARY_REGISTRATION_CERTIFICATE_THUMBPRINT = @"primary_registration_metadata_certificate_thumbprint"; NSString *const MSID_PLATFORM_SSO_STATUS_KEY = @"platform_sso_status"; -NSString *const JIT_TROUBLESHOOTING_HOST = @"jit_troubleshooting"; +NSString *const MSID_JIT_TROUBLESHOOTING_HOST = @"jit_troubleshooting"; NSString *const MSID_IS_CALLER_MANAGED_KEY = @"isCallerAppManaged"; NSString *const MSID_BROKER_SDM_WPJ_ATTEMPTED = @"sdm_reg_attempted"; NSString *const MSID_FORCE_REFRESH_KEY = @"force_refresh"; diff --git a/IdentityCore/src/webview/response/MSIDJITTroubleshootingResponse.m b/IdentityCore/src/webview/response/MSIDJITTroubleshootingResponse.m index 6d6ca6985..d09d66a8a 100644 --- a/IdentityCore/src/webview/response/MSIDJITTroubleshootingResponse.m +++ b/IdentityCore/src/webview/response/MSIDJITTroubleshootingResponse.m @@ -73,7 +73,7 @@ - (BOOL)isJITRetryResponse:(NSURL *)url - (BOOL)isJITTroubleshootingResponse:(NSURL *)url { if (!url) return NO; - return ([@"msauth" caseInsensitiveCompare:url.scheme] == NSOrderedSame && [JIT_TROUBLESHOOTING_HOST caseInsensitiveCompare:url.host] == NSOrderedSame); + return ([@"msauth" caseInsensitiveCompare:url.scheme] == NSOrderedSame && [MSID_JIT_TROUBLESHOOTING_HOST caseInsensitiveCompare:url.host] == NSOrderedSame); } - (NSError *)getErrorFromResponseWithContext:(id )context diff --git a/IdentityCore/tests/MSIDJITTroubleshootingResponseTests.m b/IdentityCore/tests/MSIDJITTroubleshootingResponseTests.m index 16b285cb8..1dd5f3b77 100644 --- a/IdentityCore/tests/MSIDJITTroubleshootingResponseTests.m +++ b/IdentityCore/tests/MSIDJITTroubleshootingResponseTests.m @@ -135,7 +135,7 @@ - (void)testIsJITTroubleshootingResponse_whenQueryCorrectValue_shouldReturnStatu - (void)testIsJITTroubleshootingResponse_whenIsJITTroubleshootingResponse_shouldReturnStatusAndJITTTroubleshootingRequiredError { - NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"msauth://%@", JIT_TROUBLESHOOTING_HOST]]; + NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"msauth://%@", MSID_JIT_TROUBLESHOOTING_HOST]]; NSError *error; MSIDJITTroubleshootingResponse *response = [[MSIDJITTroubleshootingResponse alloc] initWithURL:url context:nil error:&error]; From 4477d6f3270ed7ae0def9b8366171e2492d544d3 Mon Sep 17 00:00:00 2001 From: Sergey Demchenko Date: Sun, 12 May 2024 15:37:06 -0700 Subject: [PATCH 30/41] Disable get token & signout request. --- .../MSIDBrowserNativeMessageGetTokenRequest.m | 2 +- .../MSIDBrowserNativeMessageSignOutRequest.m | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/IdentityCore/src/broker_operation/request/browser_native_message_request/MSIDBrowserNativeMessageGetTokenRequest.m b/IdentityCore/src/broker_operation/request/browser_native_message_request/MSIDBrowserNativeMessageGetTokenRequest.m index edd5069f8..6342648ca 100644 --- a/IdentityCore/src/broker_operation/request/browser_native_message_request/MSIDBrowserNativeMessageGetTokenRequest.m +++ b/IdentityCore/src/broker_operation/request/browser_native_message_request/MSIDBrowserNativeMessageGetTokenRequest.m @@ -48,7 +48,7 @@ @implementation MSIDBrowserNativeMessageGetTokenRequest + (void)load { - [MSIDJsonSerializableFactory registerClass:self forClassType:self.operation]; +// [MSIDJsonSerializableFactory registerClass:self forClassType:self.operation]; } + (NSString *)operation diff --git a/IdentityCore/src/broker_operation/request/browser_native_message_request/MSIDBrowserNativeMessageSignOutRequest.m b/IdentityCore/src/broker_operation/request/browser_native_message_request/MSIDBrowserNativeMessageSignOutRequest.m index 0fb0f37af..3f0372f94 100644 --- a/IdentityCore/src/broker_operation/request/browser_native_message_request/MSIDBrowserNativeMessageSignOutRequest.m +++ b/IdentityCore/src/broker_operation/request/browser_native_message_request/MSIDBrowserNativeMessageSignOutRequest.m @@ -32,7 +32,7 @@ @implementation MSIDBrowserNativeMessageSignOutRequest + (void)load { - [MSIDJsonSerializableFactory registerClass:self forClassType:self.operation]; +// [MSIDJsonSerializableFactory registerClass:self forClassType:self.operation]; } + (NSString *)operation From 519cc0f3a6a7229c7ecbaead0bb76b53558709af Mon Sep 17 00:00:00 2001 From: Sergei Demchenko Date: Wed, 22 May 2024 09:18:47 -0700 Subject: [PATCH 31/41] Add UT for GetToken & SignOut apis (#1343) * Enable gettoken and signout browser sso operations. * Return UPN in properties of GetToken response. * Add SignOut api tests for browser core. * Extend test mocks. * Improve test utils. * Disable get token & signout request. --- .../IdentityCore.xcodeproj/project.pbxproj | 18 ++++ ...MSIDBrowserNativeMessageGetTokenResponse.m | 5 + ...rowserNativeMessageGetTokenResponseTests.m | 101 ++++++++++++++++++ ...DBrowserNativeMessageSignOutRequestTests.m | 75 +++++++++++++ ...BrowserNativeMessageSignOutResponseTests.m | 48 +++++++++ .../MSIDAccountMetadataCacheAccessorMock.h | 3 + .../MSIDAccountMetadataCacheAccessorMock.m | 13 +++ .../tests/util/MSIDTestCacheDataSource.m | 61 +++++++++-- .../tests/util/MSIDTestURLResponse+Util.h | 1 + .../tests/util/MSIDTestURLResponse+Util.m | 30 ++++++ 10 files changed, 346 insertions(+), 9 deletions(-) create mode 100644 IdentityCore/tests/MSIDBrowserNativeMessageGetTokenResponseTests.m create mode 100644 IdentityCore/tests/MSIDBrowserNativeMessageSignOutRequestTests.m create mode 100644 IdentityCore/tests/MSIDBrowserNativeMessageSignOutResponseTests.m diff --git a/IdentityCore/IdentityCore.xcodeproj/project.pbxproj b/IdentityCore/IdentityCore.xcodeproj/project.pbxproj index b29954f22..8564d8e3f 100644 --- a/IdentityCore/IdentityCore.xcodeproj/project.pbxproj +++ b/IdentityCore/IdentityCore.xcodeproj/project.pbxproj @@ -148,6 +148,8 @@ 232C658C2138BED1002A41FE /* MSIDAADAuthorityMetadataResponseSerializerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 232C658B2138BED0002A41FE /* MSIDAADAuthorityMetadataResponseSerializerTests.m */; }; 232C658D2138BED1002A41FE /* MSIDAADAuthorityMetadataResponseSerializerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 232C658B2138BED0002A41FE /* MSIDAADAuthorityMetadataResponseSerializerTests.m */; }; 23368C0326436E4100374103 /* MSIDRequestParameters+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 23368C0226436E4100374103 /* MSIDRequestParameters+Internal.h */; }; + 233827912BC8C40C0079C82F /* MSIDBrowserNativeMessageGetTokenResponseTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 233827902BC8C40C0079C82F /* MSIDBrowserNativeMessageGetTokenResponseTests.m */; }; + 233827922BC8C40C0079C82F /* MSIDBrowserNativeMessageGetTokenResponseTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 233827902BC8C40C0079C82F /* MSIDBrowserNativeMessageGetTokenResponseTests.m */; }; 2338ECCB208A675D00809B9E /* MSIDAADRequestErrorHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 2338ECC8208A675D00809B9E /* MSIDAADRequestErrorHandler.m */; }; 2338ECCC208A675D00809B9E /* MSIDAADRequestErrorHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 2338ECC8208A675D00809B9E /* MSIDAADRequestErrorHandler.m */; }; 2338ECCD208A675D00809B9E /* MSIDHttpRequestErrorHandling.h in Headers */ = {isa = PBXBuildFile; fileRef = 2338ECC9208A675D00809B9E /* MSIDHttpRequestErrorHandling.h */; }; @@ -191,6 +193,10 @@ 23419F83239B36F500EA78C5 /* MSIDAccountIdentifierTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 23419F81239B36F500EA78C5 /* MSIDAccountIdentifierTests.m */; }; 234858DF20490EF8004FBC3C /* MSIDDefaultTokenCacheIntegrationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 965981041FF4C9B400E31CDE /* MSIDDefaultTokenCacheIntegrationTests.m */; }; 2348C313221B4EFF00498D56 /* MSIDBasicContext.m in Sources */ = {isa = PBXBuildFile; fileRef = 2323A6C42217AD4A00727088 /* MSIDBasicContext.m */; }; + 234A0BE02BCDC4B900AFBBAA /* MSIDBrowserNativeMessageSignOutResponseTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 234A0BDF2BCDC4B900AFBBAA /* MSIDBrowserNativeMessageSignOutResponseTests.m */; }; + 234A0BE12BCDC4B900AFBBAA /* MSIDBrowserNativeMessageSignOutResponseTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 234A0BDF2BCDC4B900AFBBAA /* MSIDBrowserNativeMessageSignOutResponseTests.m */; }; + 234A0BE32BCDCCB100AFBBAA /* MSIDBrowserNativeMessageSignOutRequestTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 234A0BE22BCDCCB100AFBBAA /* MSIDBrowserNativeMessageSignOutRequestTests.m */; }; + 234A0BE42BCDCCB100AFBBAA /* MSIDBrowserNativeMessageSignOutRequestTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 234A0BE22BCDCCB100AFBBAA /* MSIDBrowserNativeMessageSignOutRequestTests.m */; }; 234DE5832A9456F600E244B3 /* MSIDBrowserNativeMessageRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 234DE5812A9456F600E244B3 /* MSIDBrowserNativeMessageRequest.h */; }; 234DE5842A9456F600E244B3 /* MSIDBrowserNativeMessageRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 234DE5822A9456F600E244B3 /* MSIDBrowserNativeMessageRequest.m */; }; 234DE5852A9456F600E244B3 /* MSIDBrowserNativeMessageRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 234DE5822A9456F600E244B3 /* MSIDBrowserNativeMessageRequest.m */; }; @@ -2060,6 +2066,7 @@ 232C65872138BDC5002A41FE /* MSIDAADAuthorityMetadataResponse.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSIDAADAuthorityMetadataResponse.m; sourceTree = ""; }; 232C658B2138BED0002A41FE /* MSIDAADAuthorityMetadataResponseSerializerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSIDAADAuthorityMetadataResponseSerializerTests.m; sourceTree = ""; }; 23368C0226436E4100374103 /* MSIDRequestParameters+Internal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "MSIDRequestParameters+Internal.h"; sourceTree = ""; }; + 233827902BC8C40C0079C82F /* MSIDBrowserNativeMessageGetTokenResponseTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSIDBrowserNativeMessageGetTokenResponseTests.m; sourceTree = ""; }; 2338ECC8208A675D00809B9E /* MSIDAADRequestErrorHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MSIDAADRequestErrorHandler.m; sourceTree = ""; }; 2338ECC9208A675D00809B9E /* MSIDHttpRequestErrorHandling.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MSIDHttpRequestErrorHandling.h; sourceTree = ""; }; 2338ECCA208A675D00809B9E /* MSIDAADRequestErrorHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MSIDAADRequestErrorHandler.h; sourceTree = ""; }; @@ -2089,6 +2096,8 @@ 23419F7B239B0D1C00EA78C5 /* MSIDAuthorityTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSIDAuthorityTests.m; sourceTree = ""; }; 23419F7E239B33E400EA78C5 /* MSIDAADV2TokenResponseTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSIDAADV2TokenResponseTests.m; sourceTree = ""; }; 23419F81239B36F500EA78C5 /* MSIDAccountIdentifierTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSIDAccountIdentifierTests.m; sourceTree = ""; }; + 234A0BDF2BCDC4B900AFBBAA /* MSIDBrowserNativeMessageSignOutResponseTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSIDBrowserNativeMessageSignOutResponseTests.m; sourceTree = ""; }; + 234A0BE22BCDCCB100AFBBAA /* MSIDBrowserNativeMessageSignOutRequestTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSIDBrowserNativeMessageSignOutRequestTests.m; sourceTree = ""; }; 234DE5812A9456F600E244B3 /* MSIDBrowserNativeMessageRequest.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSIDBrowserNativeMessageRequest.h; sourceTree = ""; }; 234DE5822A9456F600E244B3 /* MSIDBrowserNativeMessageRequest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSIDBrowserNativeMessageRequest.m; sourceTree = ""; }; 2352AF302AA7C7B700FA2253 /* MSIDBrowserNativeMessageGetTokenResponse.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSIDBrowserNativeMessageGetTokenResponse.h; sourceTree = ""; }; @@ -5612,6 +5621,9 @@ B431B5252AF05B3F0020CD3D /* MSIDBrokerOperationPasskeyCredentialRequestTests.m */, B431B5282AF05C890020CD3D /* MSIDBrokerOperationGetPasskeyAssertionResponseTests.m */, B431B52B2AF19E230020CD3D /* MSIDBrokerOperationGetPasskeyCredentialResponseTests.m */, + 233827902BC8C40C0079C82F /* MSIDBrowserNativeMessageGetTokenResponseTests.m */, + 234A0BDF2BCDC4B900AFBBAA /* MSIDBrowserNativeMessageSignOutResponseTests.m */, + 234A0BE22BCDCCB100AFBBAA /* MSIDBrowserNativeMessageSignOutRequestTests.m */, 586DE2A72BC884600082137F /* MSIDAuthenticationSchemeSshCertTest.m */, ); path = tests; @@ -6796,6 +6808,7 @@ B2936F7920ABF8310050C585 /* MSIDLegacyAccessTokenTests.m in Sources */, 60747FF62354F04F00C5308F /* MSIDBrokerOperationGetAccountsRequestTests.m in Sources */, 586CD77E293FD77100550710 /* MSIDRequestControllerFactoryTests.m in Sources */, + 233827912BC8C40C0079C82F /* MSIDBrowserNativeMessageGetTokenResponseTests.m in Sources */, 238EF086209161830035ABE6 /* MSIDAADJsonResponsePreprocessorTests.m in Sources */, B20657C61FC9265800412B7D /* MSIDTelemetryExtensionsTests.m in Sources */, B2BE924F21A24A5300F5AB8C /* MSIDSilentControllerIntegrationTests.m in Sources */, @@ -6837,6 +6850,7 @@ 963553BF20CA7C52005235E5 /* MSIDSystemWebviewControllerTests.m in Sources */, 963CFAF320AD817600BDA25F /* MSIDWebviewAuthorizationTests.m in Sources */, B2525C752330623E006FBA4B /* MSIDMainThreadUtilTests.m in Sources */, + 234A0BE32BCDCCB100AFBBAA /* MSIDBrowserNativeMessageSignOutRequestTests.m in Sources */, 2338ECDA208A7CBD00809B9E /* MSIDAADRequestErrorHandlerTests.m in Sources */, 23CA0C4A220A3B6900768729 /* MSIDPKeyAuthHandlerTests.m in Sources */, 80B6BF3C2480A3E30031BFE8 /* MSIDWorkPlaceJoinUtilTests.m in Sources */, @@ -6870,6 +6884,7 @@ B2DD4B4020A934170047A66E /* MSIDCredentialTypeTests.m in Sources */, 580E254E271A1815003D1795 /* MSIDBrokerOperationGetSsoCookiesResponseTests.m in Sources */, B2C708DF219BC67F00D917B8 /* MSIDDefaultSilentTokenRequestTests.m in Sources */, + 234A0BE02BCDC4B900AFBBAA /* MSIDBrowserNativeMessageSignOutResponseTests.m in Sources */, B210F4501FDDF5D2005A8F76 /* MSIDClientInfoTests.m in Sources */, 6080B9A523886DD9009B1322 /* MSIDBrokerOperationGetDeviceInfoRequestTests.m in Sources */, B431B5292AF05C890020CD3D /* MSIDBrokerOperationGetPasskeyAssertionResponseTests.m in Sources */, @@ -7324,6 +7339,7 @@ B2DD5B9C20475E780084313F /* MSIDBaseTokenTests.m in Sources */, 239DF9C420E04BC9002D428B /* MSIDADFSAuthorityTests.m in Sources */, B431B5422AF1C6C10020CD3D /* MSIDSSOExtensionPasskeyCredentialRequestMock.m in Sources */, + 233827922BC8C40C0079C82F /* MSIDBrowserNativeMessageGetTokenResponseTests.m in Sources */, 23419F6123974C0D00EA78C5 /* MSIDBrokerOperationTokenRequestTests.m in Sources */, 236CB13F2A609A1B005A6F5F /* MSIDBrokerOperationBrowserNativeMessageRequestTests.m in Sources */, B2807FFF204CB25E00944D89 /* MSIDTokenResponseTests.m in Sources */, @@ -7335,6 +7351,7 @@ B20657C71FC9265800412B7D /* MSIDTelemetryExtensionsTests.m in Sources */, 239DF9C720E04ECF002D428B /* MSIDAuthorityIntegrationTests.m in Sources */, B2E7698F206096A7000F3F2B /* MSIDTelemetryCacheEventTests.m in Sources */, + 234A0BE12BCDC4B900AFBBAA /* MSIDBrowserNativeMessageSignOutResponseTests.m in Sources */, 23419F7D239B0D1C00EA78C5 /* MSIDAuthorityTests.m in Sources */, E733EE0D25C0A50A00ACB79A /* MSIDThumbprintCalculatorTests.m in Sources */, 234858DF20490EF8004FBC3C /* MSIDDefaultTokenCacheIntegrationTests.m in Sources */, @@ -7350,6 +7367,7 @@ 728D9E492824A323001D990F /* MSIDPkeyAuthHelperTests.m in Sources */, 589BDB1E2718CD7D00BF3799 /* MSIDBrokerOperationGetSsoCookiesRequestTests.m in Sources */, B26A0B9A2072BABE006BD95A /* MSIDAADV2Oauth2FactoryTests.m in Sources */, + 234A0BE42BCDCCB100AFBBAA /* MSIDBrowserNativeMessageSignOutRequestTests.m in Sources */, B287C4CF26A132FA004303F1 /* MSIDSSOExtensionRequestDelegateTests.m in Sources */, 60BF06052051F9A200DE7C1C /* MSIDTelemetryTestDispatcher.m in Sources */, 23CAB3912A60ACB50066CFA2 /* MSIDBrokerOperationBrowserNativeMessageResponseTests.m in Sources */, diff --git a/IdentityCore/src/broker_operation/response/browser_native_message_response/MSIDBrowserNativeMessageGetTokenResponse.m b/IdentityCore/src/broker_operation/response/browser_native_message_response/MSIDBrowserNativeMessageGetTokenResponse.m index f1536b9e4..02caa6b31 100644 --- a/IdentityCore/src/broker_operation/response/browser_native_message_response/MSIDBrowserNativeMessageGetTokenResponse.m +++ b/IdentityCore/src/broker_operation/response/browser_native_message_response/MSIDBrowserNativeMessageGetTokenResponse.m @@ -77,6 +77,11 @@ - (NSDictionary *)jsonDictionary response[@"account"] = accountJson; response[@"state"] = self.state; + __auto_type propertiesJson = [NSMutableDictionary new]; + // TODO: once ests follow the latest protocol, this should be removed. Account ID should be read from accountJson. + propertiesJson[@"UPN"] = tokenResponse.idTokenObj.username; + response[@"properties"] = propertiesJson; + return response; } diff --git a/IdentityCore/tests/MSIDBrowserNativeMessageGetTokenResponseTests.m b/IdentityCore/tests/MSIDBrowserNativeMessageGetTokenResponseTests.m new file mode 100644 index 000000000..4da688a71 --- /dev/null +++ b/IdentityCore/tests/MSIDBrowserNativeMessageGetTokenResponseTests.m @@ -0,0 +1,101 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import +#import "MSIDBrowserNativeMessageGetTokenResponse.h" +#import "MSIDBrokerOperationTokenResponse.h" +#import "MSIDAADV2TokenResponse.h" +#import "MSIDTestIdTokenUtil.h" +#import "MSIDTokenResponse.h" +#import "MSIDTestIdentifiers.h" + +@interface MSIDTokenResponseMock : MSIDTokenResponse + +@property (nonatomic) NSDictionary *responseJson; + +@end + +@implementation MSIDTokenResponseMock + +- (NSDictionary *)jsonDictionary +{ + return self.responseJson; +} + +@end + +@interface MSIDBrowserNativeMessageGetTokenResponseTests : XCTestCase + +@end + +@implementation MSIDBrowserNativeMessageGetTokenResponseTests + +- (void)testResponseType_shouldBeGenericResponse +{ + // We don't use this operation directly, it is wrapped by "BrokerOperationBrowserNativeMessage" operation, so we don't care about response type and return generic response. + XCTAssertEqualObjects(@"operation_generic_response", [MSIDBrowserNativeMessageGetTokenResponse responseType]); +} + +- (void)testJsonDictionary_whenNoResposne_shouldReturnNil +{ + __auto_type tokenResponse = [[MSIDBrokerOperationTokenResponse alloc] initWithDeviceInfo:nil]; + __auto_type response = [[MSIDBrowserNativeMessageGetTokenResponse alloc] initWithTokenResponse:tokenResponse]; + + XCTAssertNil([response jsonDictionary]); +} + +- (void)testJsonDictionary_whenPayloadExist_shouldBeCorrect +{ + NSString *idToken = [MSIDTestIdTokenUtil idTokenWithPreferredUsername:DEFAULT_TEST_ID_TOKEN_USERNAME + subject:DEFAULT_TEST_ID_TOKEN_SUBJECT]; + + NSDictionary *jsonInput = @{@"id_token": idToken}; + + MSIDTokenResponseMock *tokenResponseMock = [[MSIDTokenResponseMock alloc] initWithJSONDictionary:jsonInput error:nil]; + tokenResponseMock.responseJson = @{@"some_key": @"some_value"}; + + __auto_type operationTokenResponse = [[MSIDBrokerOperationTokenResponse alloc] initWithDeviceInfo:nil]; + operationTokenResponse.tokenResponse = tokenResponseMock; + + __auto_type response = [[MSIDBrowserNativeMessageGetTokenResponse alloc] initWithTokenResponse:operationTokenResponse]; + response.state = @"1234"; + + __auto_type expectedJson = @{ + @"account": @{ + @"id": tokenResponseMock.accountIdentifier, + @"userName": tokenResponseMock.idTokenObj.username + }, + @"properties": @{ + @"UPN": tokenResponseMock.idTokenObj.username + }, + @"state": @"1234", + @"some_key": @"some_value" + }; + + XCTAssertNotNil([response jsonDictionary]); + XCTAssertEqualObjects(expectedJson, [response jsonDictionary]); +} + +@end diff --git a/IdentityCore/tests/MSIDBrowserNativeMessageSignOutRequestTests.m b/IdentityCore/tests/MSIDBrowserNativeMessageSignOutRequestTests.m new file mode 100644 index 000000000..682aad482 --- /dev/null +++ b/IdentityCore/tests/MSIDBrowserNativeMessageSignOutRequestTests.m @@ -0,0 +1,75 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import +#import "MSIDBrowserNativeMessageSignOutRequest.h" +#import "MSIDAccountIdentifier.h" + +@interface MSIDBrowserNativeMessageSignOutRequestTests : XCTestCase + +@end + +@implementation MSIDBrowserNativeMessageSignOutRequestTests + +- (void)testOperation_shouldBeCorrect +{ + XCTAssertEqualObjects(@"SignOut", [MSIDBrowserNativeMessageSignOutRequest operation]); +} + +- (void)testInitWithJSONDictionary_whenAccountIdIsValid_shouldInit +{ + __auto_type json = @{ + @"method": @"SignOut", + @"accountId": @"uid.utid", + @"sender": @"https://login.microsoft.com" + }; + + NSError *error; + __auto_type request = [[MSIDBrowserNativeMessageSignOutRequest alloc] initWithJSONDictionary:json error:&error]; + + XCTAssertNil(error); + XCTAssertNotNil(request); + XCTAssertEqualObjects(@"https://login.microsoft.com", request.sender.absoluteString); + XCTAssertEqualObjects(@"uid", request.accountId.uid); + XCTAssertEqualObjects(@"utid", request.accountId.utid); +} + +- (void)testInitWithJSONDictionary_whenAccountIdIsInvalid_shouldFail +{ + __auto_type json = @{ + @"method": @"SignOut", + @"accountId": @"qwerty", + @"sender": @"https://localhost:8000" + }; + + NSError *error; + __auto_type request = [[MSIDBrowserNativeMessageSignOutRequest alloc] initWithJSONDictionary:json error:&error]; + + XCTAssertNil(request); + XCTAssertNotNil(error); + XCTAssertEqualObjects(error.userInfo[MSIDErrorDescriptionKey], @"account Id is invalid."); +} + +@end diff --git a/IdentityCore/tests/MSIDBrowserNativeMessageSignOutResponseTests.m b/IdentityCore/tests/MSIDBrowserNativeMessageSignOutResponseTests.m new file mode 100644 index 000000000..5a7718001 --- /dev/null +++ b/IdentityCore/tests/MSIDBrowserNativeMessageSignOutResponseTests.m @@ -0,0 +1,48 @@ +// +// Copyright (c) Microsoft Corporation. +// All rights reserved. +// +// This code is licensed under the MIT License. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import +#import "MSIDBrowserNativeMessageSignOutResponse.h" + +@interface MSIDBrowserNativeMessageSignOutResponseTests : XCTestCase + +@end + +@implementation MSIDBrowserNativeMessageSignOutResponseTests + +- (void)testResponseType_shouldBeGenericResponse +{ + // We don't use this operation directly, it is wrapped by "BrokerOperationBrowserNativeMessage" operation, so we don't care about response type and return generic response. + XCTAssertEqualObjects(@"operation_generic_response", [MSIDBrowserNativeMessageSignOutResponse responseType]); +} + +- (void)testJsonDictionary_shouldBeEmptyJson +{ + __auto_type response = [[MSIDBrowserNativeMessageSignOutResponse alloc] initWithDeviceInfo:nil]; + + XCTAssertNotNil([response jsonDictionary]); + XCTAssertEqualObjects(@{}, [response jsonDictionary]); +} +@end diff --git a/IdentityCore/tests/mocks/MSIDAccountMetadataCacheAccessorMock.h b/IdentityCore/tests/mocks/MSIDAccountMetadataCacheAccessorMock.h index 07ed78da9..77313b2a8 100644 --- a/IdentityCore/tests/mocks/MSIDAccountMetadataCacheAccessorMock.h +++ b/IdentityCore/tests/mocks/MSIDAccountMetadataCacheAccessorMock.h @@ -52,6 +52,9 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic) NSInteger removeAccountMetadataForHomeAccountIdInvokedCount; @property (nonatomic) MSIDAccountMetadataCacheMockRemoveAccountMetadataForHomeAccountIdParams *removeAccountMetadataForHomeAccountIdParams; +@property (nonatomic) NSInteger updateSignInStateForHomeAccountIdInvokedCount; +@property (nonatomic) NSError *updateSignInStateForHomeAccountIdError; +@property (nonatomic) BOOL updateSignInStateForHomeAccountIdResult; @end diff --git a/IdentityCore/tests/mocks/MSIDAccountMetadataCacheAccessorMock.m b/IdentityCore/tests/mocks/MSIDAccountMetadataCacheAccessorMock.m index a3197760b..addf910ab 100644 --- a/IdentityCore/tests/mocks/MSIDAccountMetadataCacheAccessorMock.m +++ b/IdentityCore/tests/mocks/MSIDAccountMetadataCacheAccessorMock.m @@ -119,4 +119,17 @@ - (BOOL)removeAccountMetadataForHomeAccountId:(NSString *)homeAccountId return self.removeAccountMetadataForHomeAccountIdResult; } +- (BOOL)updateSignInStateForHomeAccountId:(NSString *)homeAccountId + clientId:(NSString *)clientId + state:(MSIDAccountMetadataState)state + context:(id)context + error:(NSError **)error +{ + self.updateSignInStateForHomeAccountIdInvokedCount++; + + if (error) *error = self.updateSignInStateForHomeAccountIdError; + + return self.updateSignInStateForHomeAccountIdResult; +} + @end diff --git a/IdentityCore/tests/util/MSIDTestCacheDataSource.m b/IdentityCore/tests/util/MSIDTestCacheDataSource.m index cfa610eae..06351f544 100644 --- a/IdentityCore/tests/util/MSIDTestCacheDataSource.m +++ b/IdentityCore/tests/util/MSIDTestCacheDataSource.m @@ -35,6 +35,7 @@ #import "MSIDAccountCacheItem.h" #import "MSIDAccountMetadata.h" #import "MSIDAccountMetadataCacheItem.h" +#import "MSIDJsonObject.h" @interface MSIDTestCacheDataSource() { @@ -320,19 +321,61 @@ - (MSIDAccountCacheItem *)accountWithKey:(MSIDCacheKey *)key context:(__unused id)context error:(__unused NSError *__autoreleasing *)error { - // TODO - return nil; + if (!serializer) + { + if (error) + { + *error = MSIDCreateError(MSIDErrorDomain, MSIDErrorInvalidInternalParameter, @"Missing parameter", nil, nil, nil, nil, nil, YES); + } + + return nil; + } + + NSMutableArray *resultItems = [NSMutableArray array]; + + NSArray *items = [self itemsWithKey:key + keysDictionary:_tokenKeys + contentDictionary:_tokenContents + context:context + error:error]; + + for (NSData *itemData in items) + { + MSIDJsonObject *jsonObject = (MSIDJsonObject *)[serializer deserializeCacheItem:itemData ofClass:[MSIDJsonObject class]]; + + if (jsonObject) + { + [resultItems addObject:jsonObject]; + } + } + + return resultItems; } -- (BOOL)saveJsonObject:(__unused MSIDJsonObject *)jsonObject - serializer:(__unused id)serializer - key:(__unused MSIDCacheKey *)key - context:(__unused id)context - error:(__unused NSError *__autoreleasing *)error +- (BOOL)saveJsonObject:(MSIDJsonObject *)jsonObject + serializer:(id)serializer + key:(MSIDCacheKey *)key + context:(id)context + error:(NSError **)error { - // TODO - return NO; + if (!jsonObject || !serializer) + { + if (error) + { + *error = MSIDCreateError(MSIDErrorDomain, MSIDErrorInvalidInternalParameter, @"Missing parameter", nil, nil, nil, nil, nil, YES); + } + + return NO; + } + + NSData *serializedItem = [serializer serializeCacheItem:jsonObject]; + return [self saveItemData:serializedItem + key:key + cacheKeys:_tokenKeys + cacheContent:_tokenContents + context:context + error:error]; } diff --git a/IdentityCore/tests/util/MSIDTestURLResponse+Util.h b/IdentityCore/tests/util/MSIDTestURLResponse+Util.h index 47601198e..5cce09dbe 100644 --- a/IdentityCore/tests/util/MSIDTestURLResponse+Util.h +++ b/IdentityCore/tests/util/MSIDTestURLResponse+Util.h @@ -26,6 +26,7 @@ @interface MSIDTestURLResponse (Util) + (NSDictionary *)msidDefaultRequestHeaders; ++ (NSMutableDictionary *)msidIgnoreRequestHeaders; + (MSIDTestURLResponse *)oidcResponseForAuthority:(NSString *)authority; + (MSIDTestURLResponse *)discoveryResponseForAuthority:(NSString *)authority; diff --git a/IdentityCore/tests/util/MSIDTestURLResponse+Util.m b/IdentityCore/tests/util/MSIDTestURLResponse+Util.m index 85bc5198f..0f77b022c 100644 --- a/IdentityCore/tests/util/MSIDTestURLResponse+Util.m +++ b/IdentityCore/tests/util/MSIDTestURLResponse+Util.m @@ -53,6 +53,36 @@ + (NSDictionary *)msidDefaultRequestHeaders return s_msidHeaders; } ++ (NSMutableDictionary *)msidIgnoreRequestHeaders +{ + static NSMutableDictionary *s_msidHeaders = nil; + static dispatch_once_t headersOnce; + + dispatch_once(&headersOnce, ^{ + NSDictionary *headers = + @{ + @"Accept" : [[MSIDTestIgnoreSentinel alloc] init], + @"Content-Length" : [[MSIDTestIgnoreSentinel alloc] init], + @"Content-Type" : [[MSIDTestIgnoreSentinel alloc] init], + @"User-Agent" : [[MSIDTestIgnoreSentinel alloc] init], + @"x-client-SKU": [[MSIDTestIgnoreSentinel alloc] init], + @"x-client-OS": [[MSIDTestIgnoreSentinel alloc] init], + @"x-app-name": [[MSIDTestIgnoreSentinel alloc] init], + @"x-ms-PkeyAuth+": [[MSIDTestIgnoreSentinel alloc] init], + @"x-client-Ver": [[MSIDTestIgnoreSentinel alloc] init], + @"x-client-CPU": [[MSIDTestIgnoreSentinel alloc] init], + @"x-app-ver": [[MSIDTestIgnoreSentinel alloc] init], + @"x-client-DM": [[MSIDTestIgnoreSentinel alloc] init], + @"Connection": [MSIDTestIgnoreSentinel sentinel], + }; + + + s_msidHeaders = [headers mutableCopy]; + }); + + return s_msidHeaders; +} + + (MSIDTestURLResponse *)discoveryResponseForAuthority:(NSString *)authority { NSURL *authorityURL = [NSURL URLWithString:authority]; From bea56edf9319abd3dd68723f8e46720684a19cfa Mon Sep 17 00:00:00 2001 From: Marcos Borges Date: Thu, 23 May 2024 13:25:35 +0100 Subject: [PATCH 32/41] Added property to allow removing the redirect URI from a request. --- IdentityCore/src/parameters/MSIDRequestParameters.h | 1 + IdentityCore/src/parameters/MSIDRequestParameters.m | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/IdentityCore/src/parameters/MSIDRequestParameters.h b/IdentityCore/src/parameters/MSIDRequestParameters.h index 88bbf2acd..5d1bcd514 100644 --- a/IdentityCore/src/parameters/MSIDRequestParameters.h +++ b/IdentityCore/src/parameters/MSIDRequestParameters.h @@ -57,6 +57,7 @@ @property (nonatomic) NSString *clientSku; @property (nonatomic) BOOL skipValidateResultAccount; @property (nonatomic) BOOL forceRefresh; +@property (nonatomic) BOOL skipSendRedirectUri; // Additional body parameters that will be appended to all token requests @property (nonatomic) NSDictionary *extraTokenRequestParameters; diff --git a/IdentityCore/src/parameters/MSIDRequestParameters.m b/IdentityCore/src/parameters/MSIDRequestParameters.m index 012424452..465e4efdc 100644 --- a/IdentityCore/src/parameters/MSIDRequestParameters.m +++ b/IdentityCore/src/parameters/MSIDRequestParameters.m @@ -349,6 +349,11 @@ - (BOOL)validateParametersWithError:(NSError **)error MSIDFillAndLogError(error, MSIDErrorInvalidDeveloperParameter, @"Missing target parameter", self.correlationId); return NO; } + + if (self.skipSendRedirectUri) + { + self.redirectUri = nil; + } return YES; } From 101f0d46b6c2521dba6f0ef9ac55c738f07af933 Mon Sep 17 00:00:00 2001 From: Marcos Borges Date: Fri, 24 May 2024 09:52:04 +0100 Subject: [PATCH 33/41] Changed parameter name to align with MSAL configuration property Bypassing redirect URI validation if set by developer --- IdentityCore/src/parameters/MSIDRequestParameters.h | 2 +- IdentityCore/src/parameters/MSIDRequestParameters.m | 7 +------ 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/IdentityCore/src/parameters/MSIDRequestParameters.h b/IdentityCore/src/parameters/MSIDRequestParameters.h index 5d1bcd514..99344c80d 100644 --- a/IdentityCore/src/parameters/MSIDRequestParameters.h +++ b/IdentityCore/src/parameters/MSIDRequestParameters.h @@ -57,7 +57,7 @@ @property (nonatomic) NSString *clientSku; @property (nonatomic) BOOL skipValidateResultAccount; @property (nonatomic) BOOL forceRefresh; -@property (nonatomic) BOOL skipSendRedirectUri; +@property (nonatomic) BOOL bypassRedirectURIValidation; // Additional body parameters that will be appended to all token requests @property (nonatomic) NSDictionary *extraTokenRequestParameters; diff --git a/IdentityCore/src/parameters/MSIDRequestParameters.m b/IdentityCore/src/parameters/MSIDRequestParameters.m index 465e4efdc..0be8063e3 100644 --- a/IdentityCore/src/parameters/MSIDRequestParameters.m +++ b/IdentityCore/src/parameters/MSIDRequestParameters.m @@ -332,7 +332,7 @@ - (BOOL)validateParametersWithError:(NSError **)error return NO; } - if (!self.redirectUri) + if (!self.redirectUri && !self.bypassRedirectURIValidation) { MSIDFillAndLogError(error, MSIDErrorInvalidDeveloperParameter, @"Missing redirectUri parameter", self.correlationId); return NO; @@ -349,11 +349,6 @@ - (BOOL)validateParametersWithError:(NSError **)error MSIDFillAndLogError(error, MSIDErrorInvalidDeveloperParameter, @"Missing target parameter", self.correlationId); return NO; } - - if (self.skipSendRedirectUri) - { - self.redirectUri = nil; - } return YES; } From e64b46eed3d050593a497ec926b984698889b5de Mon Sep 17 00:00:00 2001 From: Marcos Borges Date: Mon, 27 May 2024 07:19:55 +0100 Subject: [PATCH 34/41] - Added unit tests for nil redirect URI validation --- .../tests/MSIDRequestParametersTests.m | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/IdentityCore/tests/MSIDRequestParametersTests.m b/IdentityCore/tests/MSIDRequestParametersTests.m index 966480e53..47451a3d2 100644 --- a/IdentityCore/tests/MSIDRequestParametersTests.m +++ b/IdentityCore/tests/MSIDRequestParametersTests.m @@ -165,6 +165,63 @@ - (void)testInitParameters_withClientIdAsScope_andB2CAuthority_shouldInitReturnN XCTAssertNotNil(parameters.appRequestMetadata); } +- (void)testParameterValidation_withNoBypassRedirectUriValidation_andNilRedirectUri_shouldFail +{ + MSIDAuthority *authority = [@"https://login.microsoftonline.com/common" aadAuthority]; + NSOrderedSet *scopes = [NSOrderedSet orderedSetWithObjects:@"myscope1", @"myscope2", nil]; + NSOrderedSet *oidcScopes = [NSOrderedSet orderedSetWithObjects:@"openid", @"offline_access", @"profile", nil]; + + NSError *error = nil; + MSIDRequestParameters *parameters = [[MSIDRequestParameters alloc] initWithAuthority:authority + authScheme:[MSIDAuthenticationScheme new] + redirectUri:nil + clientId:@"myclient_id" + scopes:scopes + oidcScopes:oidcScopes + correlationId:nil + telemetryApiId:nil + intuneAppIdentifier:@"com.microsoft.mytest" + requestType:MSIDRequestLocalType + error:&error]; + XCTAssertNil(error); + XCTAssertNotNil(parameters); + + parameters.bypassRedirectURIValidation = false; + BOOL result = [parameters validateParametersWithError:&error]; + + XCTAssertNotNil(error); + XCTAssertEqual(result, false); + XCTAssertEqual(error.code, MSIDErrorInvalidDeveloperParameter); +} + +- (void)testParameterValidation_withBypassRedirectUriValidation_andNilRedirectUri_shouldNotFail +{ + MSIDAuthority *authority = [@"https://login.microsoftonline.com/common" aadAuthority]; + NSOrderedSet *scopes = [NSOrderedSet orderedSetWithObjects:@"myscope1", @"myscope2", nil]; + NSOrderedSet *oidcScopes = [NSOrderedSet orderedSetWithObjects:@"openid", @"offline_access", @"profile", nil]; + + NSError *error = nil; + MSIDRequestParameters *parameters = [[MSIDRequestParameters alloc] initWithAuthority:authority + authScheme:[MSIDAuthenticationScheme new] + redirectUri:nil + clientId:@"myclient_id" + scopes:scopes + oidcScopes:oidcScopes + correlationId:nil + telemetryApiId:nil + intuneAppIdentifier:@"com.microsoft.mytest" + requestType:MSIDRequestLocalType + error:&error]; + XCTAssertNil(error); + XCTAssertNotNil(parameters); + + parameters.bypassRedirectURIValidation = true; + BOOL result = [parameters validateParametersWithError:&error]; + + XCTAssertNil(error); + XCTAssertEqual(result, true); +} + - (void)testUpdateAppRequestMetadata_whenAccountIdIsNil_shouldNotChangeMetadata { MSIDAuthority *authority = [@"https://login.microsoftonline.com/common" aadAuthority]; From 92a570871481ea8fe0457686e7dcefcbd951df19 Mon Sep 17 00:00:00 2001 From: kaisong1990 Date: Mon, 3 Jun 2024 22:51:46 -0700 Subject: [PATCH 35/41] init change --- .../automation/ui_tests_lib/MSIDBaseUITest.h | 1 + .../automation/ui_tests_lib/MSIDBaseUITest.m | 36 +++++++++++++++++++ .../MSIDTestConfigurationProvider.m | 4 +++ .../lab_api/MSIDAutomationBaseApiRequest.h | 1 + .../lab_api/MSIDAutomationBaseApiRequest.m | 25 +++++++++++++ ...MSIDAutomationOperationAPIRequestHandler.h | 2 ++ ...MSIDAutomationOperationAPIRequestHandler.m | 18 +++++++++- .../lab_api/MSIDAutomationResetAPIRequest.m | 7 +++- .../MSIDAutomationTemporaryAccountRequest.m | 5 +++ 9 files changed, 97 insertions(+), 2 deletions(-) diff --git a/IdentityCore/tests/automation/ui_tests_lib/MSIDBaseUITest.h b/IdentityCore/tests/automation/ui_tests_lib/MSIDBaseUITest.h index b4a774e29..aed13e629 100644 --- a/IdentityCore/tests/automation/ui_tests_lib/MSIDBaseUITest.h +++ b/IdentityCore/tests/automation/ui_tests_lib/MSIDBaseUITest.h @@ -77,6 +77,7 @@ NS_ASSUME_NONNULL_BEGIN - (void)aadEnterPassword:(XCUIApplication *)application; - (void)enterPassword:(NSString *)password app:(XCUIApplication *)application; - (void)enterPassword:(NSString *)password app:(XCUIApplication *)app isMainApp:(BOOL)isMainApp; +- (void)setupPassword:(NSString *)password app:(XCUIApplication *)application; - (void)adfsEnterPassword:(XCUIApplication *)application;; - (void)adfsEnterPassword:(NSString *)password app:(XCUIApplication *)application; diff --git a/IdentityCore/tests/automation/ui_tests_lib/MSIDBaseUITest.m b/IdentityCore/tests/automation/ui_tests_lib/MSIDBaseUITest.m index 9179ac5d6..0f8ee0189 100644 --- a/IdentityCore/tests/automation/ui_tests_lib/MSIDBaseUITest.m +++ b/IdentityCore/tests/automation/ui_tests_lib/MSIDBaseUITest.m @@ -266,6 +266,8 @@ - (void)enterEmail:(NSString *)email app:(XCUIApplication *)application isMainAp - (void)aadEnterPassword:(XCUIApplication *)application { [self enterPassword:self.primaryAccount.password app:application]; + // New Password reset API requires to force providing a new password after logging in with original password. + [self setupPassword:self.primaryAccount.password app:application]; } - (void)enterPassword:(NSString *)password app:(XCUIApplication *)application @@ -273,6 +275,40 @@ - (void)enterPassword:(NSString *)password app:(XCUIApplication *)application [self enterPassword:password app:application isMainApp:YES]; } +- (void)setupPassword:(NSString *)password app:(XCUIApplication *)application +{ + [self setupPassword:password app:application isMainApp:YES]; +} + +- (void)setupPassword:(NSString *)password app:(XCUIApplication *)application isMainApp:(BOOL)isMainApp +{ + sleep(3); + if (application.secureTextFields.count > 1) + { + // New password flow + //Current password + NSPredicate *passwordFieldPredicate = [NSPredicate predicateWithFormat:@"placeholderValue CONTAINS[c] %@", @"Current password"]; + XCUIElement *currentPasswordSecureTextField = [[application.secureTextFields matchingPredicate:passwordFieldPredicate] elementBoundByIndex:0]; + [self tapElementAndWaitForKeyboardToAppear:currentPasswordSecureTextField app:application]; + NSString *passwordString = [NSString stringWithFormat:@"%@\n", password]; + [self enterText:currentPasswordSecureTextField isMainApp:isMainApp text:passwordString]; + + passwordFieldPredicate = [NSPredicate predicateWithFormat:@"placeholderValue CONTAINS[c] %@", @"New password"]; + XCUIElement *newPasswordSecureTextField = [[application.secureTextFields matchingPredicate:passwordFieldPredicate] elementBoundByIndex:0]; + [self tapElementAndWaitForKeyboardToAppear:newPasswordSecureTextField app:application]; + passwordString = [NSString stringWithFormat:@"%@apple\n", password]; + [self enterText:newPasswordSecureTextField isMainApp:isMainApp text:passwordString]; + + passwordFieldPredicate = [NSPredicate predicateWithFormat:@"placeholderValue CONTAINS[c] %@", @"Confirm password"]; + XCUIElement *confirmPasswordSecureTextField = [[application.secureTextFields matchingPredicate:passwordFieldPredicate] elementBoundByIndex:0]; + [self tapElementAndWaitForKeyboardToAppear:confirmPasswordSecureTextField app:application]; + passwordString = [NSString stringWithFormat:@"%@apple\n", password]; + [self enterText:confirmPasswordSecureTextField isMainApp:isMainApp text:passwordString]; + + } +} + + - (void)enterPassword:(NSString *)password app:(XCUIApplication *)application isMainApp:(BOOL)isMainApp { // Enter password diff --git a/IdentityCore/tests/automation/ui_tests_lib/MSIDTestConfigurationProvider.m b/IdentityCore/tests/automation/ui_tests_lib/MSIDTestConfigurationProvider.m index 927241332..7ab4767dd 100644 --- a/IdentityCore/tests/automation/ui_tests_lib/MSIDTestConfigurationProvider.m +++ b/IdentityCore/tests/automation/ui_tests_lib/MSIDTestConfigurationProvider.m @@ -58,6 +58,7 @@ - (instancetype)initWithClientCertificateContents:(NSString *)certificate defaultScopes:(NSDictionary *)defaultScopes defaultResources:(NSDictionary *)defaultResources operationAPIConf:(NSDictionary *)operationAPIConfiguration + funcAppAPIConf:(NSDictionary *)funcAppAPIConfiguration jitConfig:(NSDictionary *)jitConfig { self = [super init]; @@ -76,6 +77,8 @@ - (instancetype)initWithClientCertificateContents:(NSString *)certificate MSIDAutomationOperationAPIInMemoryCacheHandler *cacheHandler = [[MSIDAutomationOperationAPIInMemoryCacheHandler alloc] initWithDictionary:additionalConfigurations]; _operationAPIRequestHandler = [[MSIDAutomationOperationAPIRequestHandler alloc] initWithAPIPath:operationAPIConfiguration[@"operation_api_path"] + newAPIPath:funcAppAPIConfiguration[@"operation_api_path"] + newAPICode:funcAppAPIConfiguration encodedCertificate:certificate certificatePassword:password operationAPIConfiguration:operationAPIConfiguration]; @@ -147,6 +150,7 @@ - (instancetype)initWithConfigurationPath:(NSString *)configurationPath defaultScopes:configurationDictionary[@"scopes"] defaultResources:configurationDictionary[@"resources"] operationAPIConf:configurationDictionary[@"operation_api_conf"] + funcAppAPIConf:configurationDictionary[@"function_app_api_code"] jitConfig:configurationDictionary[@"jit_intune_ids"]]; } diff --git a/IdentityCore/tests/automation/ui_tests_lib/lab_api/MSIDAutomationBaseApiRequest.h b/IdentityCore/tests/automation/ui_tests_lib/lab_api/MSIDAutomationBaseApiRequest.h index e5ee0d42d..2b58d9952 100644 --- a/IdentityCore/tests/automation/ui_tests_lib/lab_api/MSIDAutomationBaseApiRequest.h +++ b/IdentityCore/tests/automation/ui_tests_lib/lab_api/MSIDAutomationBaseApiRequest.h @@ -28,6 +28,7 @@ NS_ASSUME_NONNULL_BEGIN @interface MSIDAutomationBaseApiRequest : NSObject - (NSURL *)requestURLWithAPIPath:(NSString *)apiPath; +- (NSURL *)requestURLWithAPIPath:(NSString *)apiPath apiCode:(NSDictionary *)apiCode; + (MSIDAutomationBaseApiRequest *)requestWithDictionary:(NSDictionary *)dictionary; - (NSString *)httpMethod; - (BOOL)shouldCacheResponse; diff --git a/IdentityCore/tests/automation/ui_tests_lib/lab_api/MSIDAutomationBaseApiRequest.m b/IdentityCore/tests/automation/ui_tests_lib/lab_api/MSIDAutomationBaseApiRequest.m index deefe5e4a..4bdb6b5b7 100644 --- a/IdentityCore/tests/automation/ui_tests_lib/lab_api/MSIDAutomationBaseApiRequest.m +++ b/IdentityCore/tests/automation/ui_tests_lib/lab_api/MSIDAutomationBaseApiRequest.m @@ -23,6 +23,12 @@ #import "MSIDAutomationBaseApiRequest.h" +@interface MSIDAutomationBaseApiRequest() + +@property(nonatomic) NSDictionary *requestOperationCode; + +@end + @implementation MSIDAutomationBaseApiRequest #pragma mark - NSCopying @@ -35,6 +41,12 @@ - (nonnull id)copyWithZone:(nullable NSZone *)zone #pragma mark - MSIDTestAutomationRequest +- (NSURL *)requestURLWithAPIPath:(NSString *)apiPath apiCode:(NSDictionary *)apiCode +{ + self.requestOperationCode = apiCode; + return [self requestURLWithAPIPath:apiPath]; +} + - (NSURL *)requestURLWithAPIPath:(NSString *)apiPath { NSString *requestOperationPath = [self requestOperationPath]; @@ -56,6 +68,13 @@ - (NSURL *)requestURLWithAPIPath:(NSString *)apiPath return nil; } + + if (![NSString msidIsStringNilOrBlank:[self requestOperationCodeKey]] + && ![NSString msidIsStringNilOrBlank:self.requestOperationCode[[self requestOperationCodeKey]]]) + { + [queryItems addObject:[[NSURLQueryItem alloc] initWithName:@"code" value:self.requestOperationCode[[self requestOperationCodeKey]]]]; + } + [queryItems addObjectsFromArray:extraQueryItems]; components.queryItems = queryItems; NSURL *resultURL = [components URL]; @@ -70,6 +89,12 @@ - (NSString *)requestOperationPath return nil; } +- (NSString *)requestOperationCodeKey +{ + //Implement in subclasses, otherwise leave as nil + return nil; +} + - (NSArray *)queryItems { NSAssert(NO, @"Abstract method, implement in subclasses"); diff --git a/IdentityCore/tests/automation/ui_tests_lib/lab_api/MSIDAutomationOperationAPIRequestHandler.h b/IdentityCore/tests/automation/ui_tests_lib/lab_api/MSIDAutomationOperationAPIRequestHandler.h index 7a7429afa..a69a5d5eb 100644 --- a/IdentityCore/tests/automation/ui_tests_lib/lab_api/MSIDAutomationOperationAPIRequestHandler.h +++ b/IdentityCore/tests/automation/ui_tests_lib/lab_api/MSIDAutomationOperationAPIRequestHandler.h @@ -43,6 +43,8 @@ @property (nonatomic) id apiCacheHandler; - (instancetype)initWithAPIPath:(NSString *)apiPath + newAPIPath:(NSString *)funcAppAPIPath + newAPICode:(NSDictionary *)funcAppAPICode encodedCertificate:(NSString *)encodedCertificate certificatePassword:(NSString *)certificatePassword operationAPIConfiguration:(NSDictionary *)operationAPIConfiguration; diff --git a/IdentityCore/tests/automation/ui_tests_lib/lab_api/MSIDAutomationOperationAPIRequestHandler.m b/IdentityCore/tests/automation/ui_tests_lib/lab_api/MSIDAutomationOperationAPIRequestHandler.m index 900f7a321..c03ea0e53 100644 --- a/IdentityCore/tests/automation/ui_tests_lib/lab_api/MSIDAutomationOperationAPIRequestHandler.m +++ b/IdentityCore/tests/automation/ui_tests_lib/lab_api/MSIDAutomationOperationAPIRequestHandler.m @@ -24,10 +24,14 @@ #import "MSIDAutomationOperationAPIRequestHandler.h" #import "MSIDAutomation-Swift.h" #import "MSIDClientCredentialHelper.h" +#import "MSIDAutomationTemporaryAccountRequest.h" +#import "MSIDAutomationResetAPIRequest.h" @interface MSIDAutomationOperationAPIRequestHandler() @property (nonatomic) NSString *labAPIPath; +@property (nonatomic) NSString *funcAppAPIPath; +@property (nonatomic) NSDictionary *funcAppAPICode; @property (nonatomic) NSDictionary *configurationParams; @property (nonatomic) NSString *encodedCertificate; @property (nonatomic) NSString *certificatePassword; @@ -39,6 +43,8 @@ @implementation MSIDAutomationOperationAPIRequestHandler #pragma mark - Init - (instancetype)initWithAPIPath:(NSString *)apiPath + newAPIPath:(NSString *)funcAppAPIPath + newAPICode:(NSDictionary *)funcAppAPICode encodedCertificate:(NSString *)encodedCertificate certificatePassword:(NSString *)certificatePassword operationAPIConfiguration:(NSDictionary *)operationAPIConfiguration @@ -48,6 +54,8 @@ - (instancetype)initWithAPIPath:(NSString *)apiPath if (self) { _labAPIPath = apiPath; + _funcAppAPIPath = funcAppAPIPath; + _funcAppAPICode = funcAppAPICode; _configurationParams = operationAPIConfiguration; _encodedCertificate = encodedCertificate; _certificatePassword = certificatePassword; @@ -123,7 +131,15 @@ - (void)executeAPIRequestImpl:(MSIDAutomationBaseApiRequest *)request accessToken:(NSString *)accessToken completionHandler:(void (^)(id result, NSError *error))completionHandler { - NSURL *resultURL = [request requestURLWithAPIPath:self.labAPIPath]; + NSURL *resultURL = nil; + if ([request isKindOfClass:[MSIDAutomationTemporaryAccountRequest class]] || [request isKindOfClass:[MSIDAutomationResetAPIRequest class]]) + { + resultURL = [request requestURLWithAPIPath:self.funcAppAPIPath apiCode:self.funcAppAPICode]; + } + else + { + resultURL = [request requestURLWithAPIPath:self.labAPIPath]; + } NSMutableURLRequest *urlRequest = [[NSMutableURLRequest alloc] initWithURL:resultURL]; NSString *bearerHeader = [NSString stringWithFormat:@"Bearer %@", accessToken]; diff --git a/IdentityCore/tests/automation/ui_tests_lib/lab_api/MSIDAutomationResetAPIRequest.m b/IdentityCore/tests/automation/ui_tests_lib/lab_api/MSIDAutomationResetAPIRequest.m index ea16a7f83..9d6c08231 100644 --- a/IdentityCore/tests/automation/ui_tests_lib/lab_api/MSIDAutomationResetAPIRequest.m +++ b/IdentityCore/tests/automation/ui_tests_lib/lab_api/MSIDAutomationResetAPIRequest.m @@ -32,9 +32,14 @@ - (NSString *)requestOperationPath return @"Reset"; } +- (NSString *)requestOperationCodeKey +{ + return @"reset_api_code"; +} + - (NSString *)httpMethod { - return @"PUT"; + return @"POST"; } - (NSArray *)queryItems diff --git a/IdentityCore/tests/automation/ui_tests_lib/lab_api/MSIDAutomationTemporaryAccountRequest.m b/IdentityCore/tests/automation/ui_tests_lib/lab_api/MSIDAutomationTemporaryAccountRequest.m index 32d4d4c84..feb90ed20 100644 --- a/IdentityCore/tests/automation/ui_tests_lib/lab_api/MSIDAutomationTemporaryAccountRequest.m +++ b/IdentityCore/tests/automation/ui_tests_lib/lab_api/MSIDAutomationTemporaryAccountRequest.m @@ -41,6 +41,11 @@ - (NSString *)requestOperationPath return @"CreateTempUser"; } +- (NSString *)requestOperationCodeKey +{ + return @"create_user_api_code"; +} + - (NSArray *)queryItems { NSString *accountType = [self accountTypeAsString]; From 46d48b135aebe6b456e4b51263189873fdce349b Mon Sep 17 00:00:00 2001 From: kaisong1990 Date: Thu, 6 Jun 2024 14:42:19 -0700 Subject: [PATCH 36/41] Update delete device API --- .../lab_api/MSIDAutomationDeleteDeviceAPIRequest.m | 7 ++++++- .../lab_api/MSIDAutomationOperationAPIRequestHandler.m | 5 ++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/IdentityCore/tests/automation/ui_tests_lib/lab_api/MSIDAutomationDeleteDeviceAPIRequest.m b/IdentityCore/tests/automation/ui_tests_lib/lab_api/MSIDAutomationDeleteDeviceAPIRequest.m index 62abeb1f7..76870c520 100644 --- a/IdentityCore/tests/automation/ui_tests_lib/lab_api/MSIDAutomationDeleteDeviceAPIRequest.m +++ b/IdentityCore/tests/automation/ui_tests_lib/lab_api/MSIDAutomationDeleteDeviceAPIRequest.m @@ -34,7 +34,7 @@ - (NSString *)requestOperationPath - (NSString *)httpMethod { - return @"DELETE"; + return @"POST"; } - (NSArray *)queryItems @@ -54,6 +54,11 @@ - (NSString *)httpMethod return queryItems; } +- (NSString *)requestOperationCodeKey +{ + return @"delete_device_api_code"; +} + - (NSUInteger)hash { NSUInteger hash = self.userUPN.hash; diff --git a/IdentityCore/tests/automation/ui_tests_lib/lab_api/MSIDAutomationOperationAPIRequestHandler.m b/IdentityCore/tests/automation/ui_tests_lib/lab_api/MSIDAutomationOperationAPIRequestHandler.m index c03ea0e53..7e439c8bf 100644 --- a/IdentityCore/tests/automation/ui_tests_lib/lab_api/MSIDAutomationOperationAPIRequestHandler.m +++ b/IdentityCore/tests/automation/ui_tests_lib/lab_api/MSIDAutomationOperationAPIRequestHandler.m @@ -26,6 +26,7 @@ #import "MSIDClientCredentialHelper.h" #import "MSIDAutomationTemporaryAccountRequest.h" #import "MSIDAutomationResetAPIRequest.h" +#import "MSIDAutomationDeleteDeviceAPIRequest.h" @interface MSIDAutomationOperationAPIRequestHandler() @@ -132,7 +133,9 @@ - (void)executeAPIRequestImpl:(MSIDAutomationBaseApiRequest *)request completionHandler:(void (^)(id result, NSError *error))completionHandler { NSURL *resultURL = nil; - if ([request isKindOfClass:[MSIDAutomationTemporaryAccountRequest class]] || [request isKindOfClass:[MSIDAutomationResetAPIRequest class]]) + if ([request isKindOfClass:[MSIDAutomationTemporaryAccountRequest class]] + || [request isKindOfClass:[MSIDAutomationResetAPIRequest class]] + || [request isKindOfClass:[MSIDAutomationDeleteDeviceAPIRequest class]]) { resultURL = [request requestURLWithAPIPath:self.funcAppAPIPath apiCode:self.funcAppAPICode]; } From 6fc8e2e116682a959f13e1eb0727c493732bcd7b Mon Sep 17 00:00:00 2001 From: Sergei Demchenko Date: Mon, 10 Jun 2024 15:32:58 -0700 Subject: [PATCH 37/41] Add platfrom sequence telemetry param (#1378) * Add platfrom sequence telemetry param. * Update IdentityCore/src/util/NSString+MSIDTelemetryExtensions.m Co-authored-by: Ameya Patil * Update IdentityCore/src/util/NSString+MSIDTelemetryExtensions.m Co-authored-by: Ameya Patil * Update IdentityCore/src/util/NSString+MSIDTelemetryExtensions.m Co-authored-by: Ameya Patil * Add more tests and refactor the code. --------- Co-authored-by: Ameya Patil --- IdentityCore/src/MSIDConstants.h | 12 +++++ IdentityCore/src/MSIDConstants.m | 1 + .../request/MSIDBrokerOperationRequest.h | 1 + .../request/MSIDBrokerOperationRequest.m | 4 ++ .../src/parameters/MSIDRequestParameters.h | 3 ++ .../src/parameters/MSIDRequestParameters.m | 1 + .../requests/broker/MSIDBrokerTokenRequest.m | 2 + .../util/NSString+MSIDTelemetryExtensions.h | 2 + .../util/NSString+MSIDTelemetryExtensions.m | 52 +++++++++++++++++++ .../tests/MSIDTelemetryExtensionsTests.m | 39 ++++++++++++++ changelog.txt | 3 ++ 11 files changed, 120 insertions(+) diff --git a/IdentityCore/src/MSIDConstants.h b/IdentityCore/src/MSIDConstants.h index 039633f29..44efbba2d 100644 --- a/IdentityCore/src/MSIDConstants.h +++ b/IdentityCore/src/MSIDConstants.h @@ -114,6 +114,7 @@ typedef void (^MSIDPasskeyCredentialRequestCompletionBlock)(MSIDPasskeyCredentia extern NSString * _Nonnull const MSID_PLATFORM_KEY;//The SDK platform. iOS or OSX extern NSString * _Nonnull const MSID_SOURCE_PLATFORM_KEY;//The source SDK platform. iOS or OSX +extern NSString * _Nonnull const MSID_PLATFORM_SEQUENCE_KEY; extern NSString * _Nonnull const MSID_VERSION_KEY; extern NSString * _Nonnull const MSID_CPU_KEY;//E.g. ARM64 extern NSString * _Nonnull const MSID_OS_VER_KEY;//iOS/OSX version @@ -161,4 +162,15 @@ extern NSString * _Nonnull const MSID_CLIENT_SKU_ADAL_IOS; extern NSString * _Nonnull const MSID_BROWSER_NATIVE_MESSAGE_ACCOUNT_ID_KEY; +typedef NS_ENUM(NSInteger, MSIDPlatformSequenceKey) +{ + MSIDPlatformSequenceKeySrcSku = 0, + MSIDPlatformSequenceKeySrcVer = 1, + MSIDPlatformSequenceKeyMsalRuntimeVer = 2, + MSIDPlatformSequenceKeyBrowserExtSku = 3, + MSIDPlatformSequenceKeyBrowserExtVer = 4, + MSIDPlatformSequenceKeyBrowserCoreVer = 5, + MSIDPlatformSequenceKeyLast = MSIDPlatformSequenceKeyBrowserCoreVer, +}; + #define METHODANDLINE [NSString stringWithFormat:@"%s [Line %d]", __PRETTY_FUNCTION__, __LINE__] diff --git a/IdentityCore/src/MSIDConstants.m b/IdentityCore/src/MSIDConstants.m index ba8917804..431b406f5 100644 --- a/IdentityCore/src/MSIDConstants.m +++ b/IdentityCore/src/MSIDConstants.m @@ -25,6 +25,7 @@ NSString *const MSID_PLATFORM_KEY = @"x-client-SKU"; NSString *const MSID_SOURCE_PLATFORM_KEY = @"x-client-src-SKU"; +NSString *const MSID_PLATFORM_SEQUENCE_KEY = @"x-client-xtra-sku"; NSString *const MSID_VERSION_KEY = @"x-client-Ver"; NSString *const MSID_CPU_KEY = @"x-client-CPU"; NSString *const MSID_OS_VER_KEY = @"x-client-OS"; diff --git a/IdentityCore/src/broker_operation/request/MSIDBrokerOperationRequest.h b/IdentityCore/src/broker_operation/request/MSIDBrokerOperationRequest.h index d4e45eadb..3a06a8256 100644 --- a/IdentityCore/src/broker_operation/request/MSIDBrokerOperationRequest.h +++ b/IdentityCore/src/broker_operation/request/MSIDBrokerOperationRequest.h @@ -37,6 +37,7 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, nullable) NSString *clientAppName; @property (nonatomic) MSIDClientSDKType clientSDK; @property (nonatomic) BOOL clientBrokerKeyCapabilityNotSupported; +@property (nonatomic, nullable) NSString *platformSequence; + (BOOL)fillRequest:(MSIDBrokerOperationRequest *)request keychainAccessGroup:(nullable NSString *)keychainAccessGroup diff --git a/IdentityCore/src/broker_operation/request/MSIDBrokerOperationRequest.m b/IdentityCore/src/broker_operation/request/MSIDBrokerOperationRequest.m index a29ba53a1..7aeb8267e 100644 --- a/IdentityCore/src/broker_operation/request/MSIDBrokerOperationRequest.m +++ b/IdentityCore/src/broker_operation/request/MSIDBrokerOperationRequest.m @@ -80,6 +80,8 @@ - (instancetype)initWithJSONDictionary:(NSDictionary *)json error:(NSError **)er NSString *sdkTypeString = [json msidStringObjectForKey:MSID_BROKER_CLIENT_SDK_KEY]; _clientSDK = MSIDClientSDKTypeFromString(sdkTypeString); + + _platformSequence = [json msidStringObjectForKey:MSID_PLATFORM_SEQUENCE_KEY]; } return self; @@ -120,6 +122,8 @@ - (NSDictionary *)jsonDictionary NSString *sdkTypeString = MSIDClientSDKTypeToString(self.clientSDK); json[MSID_BROKER_CLIENT_SDK_KEY] = sdkTypeString; + + json[MSID_PLATFORM_SEQUENCE_KEY] = self.platformSequence; return json; } diff --git a/IdentityCore/src/parameters/MSIDRequestParameters.h b/IdentityCore/src/parameters/MSIDRequestParameters.h index 99344c80d..b7931a106 100644 --- a/IdentityCore/src/parameters/MSIDRequestParameters.h +++ b/IdentityCore/src/parameters/MSIDRequestParameters.h @@ -59,6 +59,9 @@ @property (nonatomic) BOOL forceRefresh; @property (nonatomic) BOOL bypassRedirectURIValidation; +// Telemetry metadata +@property (nonatomic) NSString *platformSequence; + // Additional body parameters that will be appended to all token requests @property (nonatomic) NSDictionary *extraTokenRequestParameters; // Additional URL query parameters that will be added to both token and authorize requests diff --git a/IdentityCore/src/parameters/MSIDRequestParameters.m b/IdentityCore/src/parameters/MSIDRequestParameters.m index 0be8063e3..5e9c566bb 100644 --- a/IdentityCore/src/parameters/MSIDRequestParameters.m +++ b/IdentityCore/src/parameters/MSIDRequestParameters.m @@ -387,6 +387,7 @@ - (instancetype)copyWithZone:(NSZone*)zone parameters->_clientCapabilities = [_clientCapabilities copyWithZone:zone]; parameters->_msidConfiguration = [_msidConfiguration copyWithZone:zone]; parameters->_keychainAccessGroup = [_keychainAccessGroup copyWithZone:zone]; + parameters->_platformSequence = [_platformSequence copyWithZone:zone]; return parameters; } diff --git a/IdentityCore/src/requests/broker/MSIDBrokerTokenRequest.m b/IdentityCore/src/requests/broker/MSIDBrokerTokenRequest.m index 59e4aee96..95b13e459 100644 --- a/IdentityCore/src/requests/broker/MSIDBrokerTokenRequest.m +++ b/IdentityCore/src/requests/broker/MSIDBrokerTokenRequest.m @@ -191,6 +191,7 @@ - (NSDictionary *)defaultPayloadContents:(NSError **)error [queryDictionary msidSetNonEmptyString:self.requestParameters.clientSku forKey:MSID_CLIENT_SKU_KEY]; [queryDictionary msidSetNonEmptyString:self.requestParameters.skipValidateResultAccount ? @"YES" : @"NO" forKey:MSID_SKIP_VALIDATE_RESULT_ACCOUNT_KEY]; + [queryDictionary msidSetNonEmptyString:self.requestParameters.platformSequence forKey:MSID_PLATFORM_SEQUENCE_KEY]; return queryDictionary; } @@ -222,6 +223,7 @@ - (NSDictionary *)defaultResumeDictionaryContents [resumeDictionary msidSetNonEmptyString:self.requestParameters.clientSku forKey:MSID_CLIENT_SKU_KEY]; [resumeDictionary msidSetNonEmptyString:self.requestParameters.skipValidateResultAccount ? @"YES" : @"NO" forKey:MSID_SKIP_VALIDATE_RESULT_ACCOUNT_KEY]; + [resumeDictionary msidSetNonEmptyString:self.requestParameters.platformSequence forKey:MSID_PLATFORM_SEQUENCE_KEY]; return resumeDictionary; } diff --git a/IdentityCore/src/util/NSString+MSIDTelemetryExtensions.h b/IdentityCore/src/util/NSString+MSIDTelemetryExtensions.h index 1ee2ac677..fd40cf8da 100644 --- a/IdentityCore/src/util/NSString+MSIDTelemetryExtensions.h +++ b/IdentityCore/src/util/NSString+MSIDTelemetryExtensions.h @@ -27,4 +27,6 @@ - (NSDictionary *)msidParsedClientTelemetry; ++ (NSString *)msidUpdatePlatformSequenceParamWithName:(NSString *)name version:(NSString *)version toSequence:(NSString *)sequence; + @end diff --git a/IdentityCore/src/util/NSString+MSIDTelemetryExtensions.m b/IdentityCore/src/util/NSString+MSIDTelemetryExtensions.m index 97a0f8fe6..683a2ff54 100644 --- a/IdentityCore/src/util/NSString+MSIDTelemetryExtensions.m +++ b/IdentityCore/src/util/NSString+MSIDTelemetryExtensions.m @@ -24,6 +24,7 @@ #import "NSString+MSIDTelemetryExtensions.h" #import "MSIDTelemetryEventStrings.h" #import "MSIDVersion.h" +#import "MSIDConstants.h" #define MSID_CLIENT_TELEMETRY_VERSION_NUMBER @"1" @@ -73,4 +74,55 @@ - (NSDictionary *)msidParsedClientTelemetry return telemetryDict; } ++ (NSString *)msidUpdatePlatformSequenceParamWithName:(NSString *)name version:(NSString *)version toSequence:(NSString *)sequence +{ + static NSString *const kDelimeter = @","; + + NSMutableArray *sequenceItems; + if ([NSString msidIsStringNilOrBlank:sequence]) + { + // Init array of empty items. + sequenceItems = [NSMutableArray new]; + for (NSInteger key= 0; key <= MSIDPlatformSequenceKeyLast; key++) + { + [sequenceItems addObject:@""]; + } + } + else + { + sequenceItems = [[sequence componentsSeparatedByString:kDelimeter] mutableCopy]; + } + + // Validate count. + if (sequenceItems.count <= MSIDPlatformSequenceKeyLast) + { + MSID_LOG_WITH_CTX(MSIDLogLevelError,nil, @"Failed to add platform sequence param: sequence count %lu is invalid.", (unsigned long)sequenceItems.count); + return nil; + } + + // Validate name. + if ([NSString msidIsStringNilOrBlank:name]) + { + MSID_LOG_WITH_CTX(MSIDLogLevelWarning,nil, @"Failed to add platform sequence param: name is empty/nil."); + return sequence; + } + + // Validate version. + if ([NSString msidIsStringNilOrBlank:version]) + { + MSID_LOG_WITH_CTX(MSIDLogLevelWarning,nil, @"Failed to add platform sequence param: version is empty/nil."); + } + + sequenceItems[MSIDPlatformSequenceKeySrcSku] = name; + + if (![NSString msidIsStringNilOrBlank:version]) + { + sequenceItems[MSIDPlatformSequenceKeySrcVer] = version; + } + + NSString *resultSequence = [sequenceItems componentsJoinedByString:kDelimeter]; + + return resultSequence; +} + @end diff --git a/IdentityCore/tests/MSIDTelemetryExtensionsTests.m b/IdentityCore/tests/MSIDTelemetryExtensionsTests.m index 5381d2038..bd776bfec 100644 --- a/IdentityCore/tests/MSIDTelemetryExtensionsTests.m +++ b/IdentityCore/tests/MSIDTelemetryExtensionsTests.m @@ -142,4 +142,43 @@ - (void)testParsedClientTelemetry_whenErrorHasZeroes_shouldReturnAllPropertiesBu XCTAssertEqualObjects([parsedTelemetry objectForKey:MSID_TELEMETRY_KEY_SPE_INFO], @"I"); } +- (void)testMsidUpdatePlatformSequenceParamWithName_whenValidNameAndVersionNewSequence_shouldCreateValidSequence +{ + NSString *platformSequence = [NSString msidUpdatePlatformSequenceParamWithName:@"name" version:@"v1" toSequence:nil]; + + XCTAssertNotNil(platformSequence); + XCTAssertEqualObjects(platformSequence, @"name,v1,,,,"); +} + +- (void)testMsidUpdatePlatformSequenceParamWithName_whenValidNameAndVersionAndInvalidSequence_shouldReturnNil +{ + NSString *platformSequence = [NSString msidUpdatePlatformSequenceParamWithName:@"name" version:@"v1" toSequence:@"0,1,2,3,4"]; + + XCTAssertNil(platformSequence); +} + +- (void)testMsidUpdatePlatformSequenceParamWithName_whenValidNameAndVersionAndValidSequence_shouldReturnNil +{ + NSString *platformSequence = [NSString msidUpdatePlatformSequenceParamWithName:@"name" version:@"v1" toSequence:@"0,1,2,3,4,5"]; + + XCTAssertNotNil(platformSequence); + XCTAssertEqualObjects(platformSequence, @"name,v1,2,3,4,5"); +} + +- (void)testMsidUpdatePlatformSequenceParamWithName_whenValidNameAndNilVersionAndValidSequence_shouldUpdateNameOnly +{ + NSString *platformSequence = [NSString msidUpdatePlatformSequenceParamWithName:@"name" version:nil toSequence:@"0,1,2,3,4,5"]; + + XCTAssertNotNil(platformSequence); + XCTAssertEqualObjects(platformSequence, @"name,1,2,3,4,5"); +} + +- (void)testMsidUpdatePlatformSequenceParamWithName_whenNilNameAndValidVersionAndValidSequence_shouldReturnOriginalSequence +{ + NSString *platformSequence = [NSString msidUpdatePlatformSequenceParamWithName:nil version:@"v1" toSequence:@"0,1,2,3,4,5"]; + + XCTAssertNotNil(platformSequence); + XCTAssertEqualObjects(platformSequence, @"0,1,2,3,4,5"); +} + @end diff --git a/changelog.txt b/changelog.txt index 36fabaf56..6ddb30f09 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,6 @@ +TBD +* Add platform sequence telemetry param #1378 + Version 1.7.35 * Include email as scope returned if it was requested and server did not include it. (#1364) * Fix throttling bug in fallback legacy broker interactive controller. (#1371) From c4017fd6b1b4b9669b4093afe5ecccfe08222cf6 Mon Sep 17 00:00:00 2001 From: Juan Arias Roldan <1686668+juan-arias@users.noreply.github.com> Date: Mon, 10 Jun 2024 21:32:08 -0700 Subject: [PATCH 38/41] Update release changelog --- changelog.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/changelog.txt b/changelog.txt index 6ddb30f09..19e481218 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,7 @@ -TBD -* Add platform sequence telemetry param #1378 +Version 1.7.36 +* Add platform sequence telemetry param. (#1378) +* Update broker automations lab API. (#1377) +* Fix incorrect constant name without MSID prefix. (#1374) Version 1.7.35 * Include email as scope returned if it was requested and server did not include it. (#1364) From b7a6ac3e018cdefbc21b16ebf3f7986c4294c092 Mon Sep 17 00:00:00 2001 From: Sergey Demchenko Date: Tue, 11 Jun 2024 21:09:50 -0700 Subject: [PATCH 39/41] Update platfrom sequence format. --- IdentityCore/src/MSIDConstants.h | 14 ++++----- .../util/NSString+MSIDTelemetryExtensions.h | 2 +- .../util/NSString+MSIDTelemetryExtensions.m | 16 ++++------ .../tests/MSIDTelemetryExtensionsTests.m | 31 ++++++++++--------- 4 files changed, 29 insertions(+), 34 deletions(-) diff --git a/IdentityCore/src/MSIDConstants.h b/IdentityCore/src/MSIDConstants.h index 44efbba2d..c5651b0a8 100644 --- a/IdentityCore/src/MSIDConstants.h +++ b/IdentityCore/src/MSIDConstants.h @@ -162,15 +162,13 @@ extern NSString * _Nonnull const MSID_CLIENT_SKU_ADAL_IOS; extern NSString * _Nonnull const MSID_BROWSER_NATIVE_MESSAGE_ACCOUNT_ID_KEY; -typedef NS_ENUM(NSInteger, MSIDPlatformSequenceKey) +typedef NS_ENUM(NSInteger, MSIDPlatformSequenceIndex) { - MSIDPlatformSequenceKeySrcSku = 0, - MSIDPlatformSequenceKeySrcVer = 1, - MSIDPlatformSequenceKeyMsalRuntimeVer = 2, - MSIDPlatformSequenceKeyBrowserExtSku = 3, - MSIDPlatformSequenceKeyBrowserExtVer = 4, - MSIDPlatformSequenceKeyBrowserCoreVer = 5, - MSIDPlatformSequenceKeyLast = MSIDPlatformSequenceKeyBrowserCoreVer, + MSIDPlatformSequenceIndexSrc = 0, + MSIDPlatformSequenceIndexMsalRuntime = 1, + MSIDPlatformSequenceIndexBrowserExt = 2, + MSIDPlatformSequenceIndexBrowserCore = 3, + MSIDPlatformSequenceIndexLast = MSIDPlatformSequenceIndexBrowserCore, }; #define METHODANDLINE [NSString stringWithFormat:@"%s [Line %d]", __PRETTY_FUNCTION__, __LINE__] diff --git a/IdentityCore/src/util/NSString+MSIDTelemetryExtensions.h b/IdentityCore/src/util/NSString+MSIDTelemetryExtensions.h index fd40cf8da..27270d2c0 100644 --- a/IdentityCore/src/util/NSString+MSIDTelemetryExtensions.h +++ b/IdentityCore/src/util/NSString+MSIDTelemetryExtensions.h @@ -27,6 +27,6 @@ - (NSDictionary *)msidParsedClientTelemetry; -+ (NSString *)msidUpdatePlatformSequenceParamWithName:(NSString *)name version:(NSString *)version toSequence:(NSString *)sequence; ++ (NSString *)msidUpdatePlatformSequenceParamWithSrcName:(NSString *)name srcVersion:(NSString *)version sequence:(NSString *)sequence; @end diff --git a/IdentityCore/src/util/NSString+MSIDTelemetryExtensions.m b/IdentityCore/src/util/NSString+MSIDTelemetryExtensions.m index 683a2ff54..670f41a57 100644 --- a/IdentityCore/src/util/NSString+MSIDTelemetryExtensions.m +++ b/IdentityCore/src/util/NSString+MSIDTelemetryExtensions.m @@ -74,7 +74,7 @@ - (NSDictionary *)msidParsedClientTelemetry return telemetryDict; } -+ (NSString *)msidUpdatePlatformSequenceParamWithName:(NSString *)name version:(NSString *)version toSequence:(NSString *)sequence ++ (NSString *)msidUpdatePlatformSequenceParamWithSrcName:(NSString *)name srcVersion:(NSString *)version sequence:(NSString *)sequence { static NSString *const kDelimeter = @","; @@ -83,7 +83,7 @@ + (NSString *)msidUpdatePlatformSequenceParamWithName:(NSString *)name version:( { // Init array of empty items. sequenceItems = [NSMutableArray new]; - for (NSInteger key= 0; key <= MSIDPlatformSequenceKeyLast; key++) + for (NSInteger key= 0; key <= MSIDPlatformSequenceIndexLast; key++) { [sequenceItems addObject:@""]; } @@ -94,10 +94,10 @@ + (NSString *)msidUpdatePlatformSequenceParamWithName:(NSString *)name version:( } // Validate count. - if (sequenceItems.count <= MSIDPlatformSequenceKeyLast) + if (sequenceItems.count <= MSIDPlatformSequenceIndexLast) { MSID_LOG_WITH_CTX(MSIDLogLevelError,nil, @"Failed to add platform sequence param: sequence count %lu is invalid.", (unsigned long)sequenceItems.count); - return nil; + return sequence; } // Validate name. @@ -111,14 +111,10 @@ + (NSString *)msidUpdatePlatformSequenceParamWithName:(NSString *)name version:( if ([NSString msidIsStringNilOrBlank:version]) { MSID_LOG_WITH_CTX(MSIDLogLevelWarning,nil, @"Failed to add platform sequence param: version is empty/nil."); + return sequence; } - sequenceItems[MSIDPlatformSequenceKeySrcSku] = name; - - if (![NSString msidIsStringNilOrBlank:version]) - { - sequenceItems[MSIDPlatformSequenceKeySrcVer] = version; - } + sequenceItems[MSIDPlatformSequenceIndexSrc] = [NSString stringWithFormat:@"%@|%@", name, version]; NSString *resultSequence = [sequenceItems componentsJoinedByString:kDelimeter]; diff --git a/IdentityCore/tests/MSIDTelemetryExtensionsTests.m b/IdentityCore/tests/MSIDTelemetryExtensionsTests.m index bd776bfec..63613ef87 100644 --- a/IdentityCore/tests/MSIDTelemetryExtensionsTests.m +++ b/IdentityCore/tests/MSIDTelemetryExtensionsTests.m @@ -142,43 +142,44 @@ - (void)testParsedClientTelemetry_whenErrorHasZeroes_shouldReturnAllPropertiesBu XCTAssertEqualObjects([parsedTelemetry objectForKey:MSID_TELEMETRY_KEY_SPE_INFO], @"I"); } -- (void)testMsidUpdatePlatformSequenceParamWithName_whenValidNameAndVersionNewSequence_shouldCreateValidSequence +- (void)testmsidUpdatePlatformSequenceParamWithSrcName_whenValidNameAndVersionNewSequence_shouldCreateValidSequence { - NSString *platformSequence = [NSString msidUpdatePlatformSequenceParamWithName:@"name" version:@"v1" toSequence:nil]; + NSString *platformSequence = [NSString msidUpdatePlatformSequenceParamWithSrcName:@"name" srcVersion:@"v1" sequence:nil]; XCTAssertNotNil(platformSequence); - XCTAssertEqualObjects(platformSequence, @"name,v1,,,,"); + XCTAssertEqualObjects(platformSequence, @"name|v1,,,"); } -- (void)testMsidUpdatePlatformSequenceParamWithName_whenValidNameAndVersionAndInvalidSequence_shouldReturnNil +- (void)testmsidUpdatePlatformSequenceParamWithSrcName_whenValidNameAndVersionAndInvalidSequence_shouldReturnOriginal { - NSString *platformSequence = [NSString msidUpdatePlatformSequenceParamWithName:@"name" version:@"v1" toSequence:@"0,1,2,3,4"]; + NSString *platformSequence = [NSString msidUpdatePlatformSequenceParamWithSrcName:@"name" srcVersion:@"v1" sequence:@"0,1"]; - XCTAssertNil(platformSequence); + XCTAssertNotNil(platformSequence); + XCTAssertEqualObjects(platformSequence, @"0,1"); } -- (void)testMsidUpdatePlatformSequenceParamWithName_whenValidNameAndVersionAndValidSequence_shouldReturnNil +- (void)testmsidUpdatePlatformSequenceParamWithSrcName_whenValidNameAndVersionAndValidSequence_shouldUpdate { - NSString *platformSequence = [NSString msidUpdatePlatformSequenceParamWithName:@"name" version:@"v1" toSequence:@"0,1,2,3,4,5"]; + NSString *platformSequence = [NSString msidUpdatePlatformSequenceParamWithSrcName:@"name" srcVersion:@"v1" sequence:@"0,1,2,3"]; XCTAssertNotNil(platformSequence); - XCTAssertEqualObjects(platformSequence, @"name,v1,2,3,4,5"); + XCTAssertEqualObjects(platformSequence, @"name|v1,1,2,3"); } -- (void)testMsidUpdatePlatformSequenceParamWithName_whenValidNameAndNilVersionAndValidSequence_shouldUpdateNameOnly +- (void)testmsidUpdatePlatformSequenceParamWithSrcName_whenValidNameAndNilVersionAndValidSequence_shouldReturnOriginal { - NSString *platformSequence = [NSString msidUpdatePlatformSequenceParamWithName:@"name" version:nil toSequence:@"0,1,2,3,4,5"]; + NSString *platformSequence = [NSString msidUpdatePlatformSequenceParamWithSrcName:@"name" srcVersion:nil sequence:@"0,1,2,3"]; XCTAssertNotNil(platformSequence); - XCTAssertEqualObjects(platformSequence, @"name,1,2,3,4,5"); + XCTAssertEqualObjects(platformSequence, @"0,1,2,3"); } -- (void)testMsidUpdatePlatformSequenceParamWithName_whenNilNameAndValidVersionAndValidSequence_shouldReturnOriginalSequence +- (void)testmsidUpdatePlatformSequenceParamWithSrcName_whenNilNameAndValidVersionAndValidSequence_shouldReturnOriginal { - NSString *platformSequence = [NSString msidUpdatePlatformSequenceParamWithName:nil version:@"v1" toSequence:@"0,1,2,3,4,5"]; + NSString *platformSequence = [NSString msidUpdatePlatformSequenceParamWithSrcName:nil srcVersion:@"v1" sequence:@"0,1,2,3"]; XCTAssertNotNil(platformSequence); - XCTAssertEqualObjects(platformSequence, @"0,1,2,3,4,5"); + XCTAssertEqualObjects(platformSequence, @"0,1,2,3"); } @end From e76a170898b35a24ba6dfe9630e5174e6d8c6403 Mon Sep 17 00:00:00 2001 From: Juan Arias Date: Wed, 12 Jun 2024 13:42:54 -0700 Subject: [PATCH 40/41] Update verify_msalcpp_per_pr_mac.yml for Azure Pipelines --- azure_pipelines/verify_msalcpp_per_pr_mac.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure_pipelines/verify_msalcpp_per_pr_mac.yml b/azure_pipelines/verify_msalcpp_per_pr_mac.yml index 61512e95b..3c4bf9a84 100644 --- a/azure_pipelines/verify_msalcpp_per_pr_mac.yml +++ b/azure_pipelines/verify_msalcpp_per_pr_mac.yml @@ -60,7 +60,7 @@ jobs: displayName: 'Build x64 Debug macOS' inputs: scriptPath: build.py - arguments: '--clean --arch x64 --configuration Debug --platform macOS --djinni hashfail --test --test-type unit integration' + arguments: '--clean --arch x64 --configuration Debug --platform macOS --djinni hashfail --test --test-type unit integration --build-projects tests' env: MSAL_LAB_VAULT_ACCESS_CERT_LOCATION: $(Agent.TempDirectory) MSAL_CERTIFICATE_PASSWORD: $(MSAL_CERTIFICATE_PASSWORD) From 2851e18de470da276be83f2d32df9b24837eb1a4 Mon Sep 17 00:00:00 2001 From: Juan Arias Date: Wed, 12 Jun 2024 13:41:37 -0700 Subject: [PATCH 41/41] Update verify_msalcpp_per_pr_ios.yml for Azure Pipelines --- azure_pipelines/verify_msalcpp_per_pr_ios.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure_pipelines/verify_msalcpp_per_pr_ios.yml b/azure_pipelines/verify_msalcpp_per_pr_ios.yml index 9afedef55..841295627 100644 --- a/azure_pipelines/verify_msalcpp_per_pr_ios.yml +++ b/azure_pipelines/verify_msalcpp_per_pr_ios.yml @@ -59,7 +59,7 @@ jobs: displayName: 'Build x64 Debug iOS' inputs: scriptPath: build.py - arguments: '--clean --arch x64 --configuration Debug --platform iOS --djinni hashfail --test --test-type unit integration' + arguments: '--clean --arch x64 --configuration Debug --platform iOS --djinni hashfail --test --test-type unit integration --build-projects tests' env: MSAL_LAB_VAULT_ACCESS_CERT_LOCATION: $(Agent.TempDirectory) MSAL_CERTIFICATE_PASSWORD: $(MSAL_CERTIFICATE_PASSWORD)